Webhook Configuration
Receive real-time updates about your shipments with webhooks.
What Are Webhooks?
Webhooks are automated messages sent from atoship to your server when events happen:
- Label created
- Package shipped
- Delivery status changed
- Exception occurred
Benefits:
- Real-time updates (not polling)
- Trigger automated workflows
- Update your systems instantly
- Improve customer experience
Available Events
Shipment Events
| Event | Trigger | Use Case |
|---|---|---|
| shipment.created | Label purchased | Update inventory |
| shipment.cancelled | Label voided | Restore inventory |
| shipment.delivered | Package delivered | Send review request |
| shipment.returned | Return received | Process refund |
| shipment.exception | Delivery issue | Alert customer service |
Tracking Events
| Event | Trigger | Use Case |
|---|---|---|
| tracking.in_transit | First carrier scan | Notify customer |
| tracking.out_for_delivery | On delivery truck | Same-day alert |
| tracking.delivered | Confirmed delivery | Close order |
| tracking.failed_attempt | Delivery attempt failed | Alert customer |
| tracking.exception | Issue occurred | Investigate |
Order Events
| Event | Trigger | Use Case |
|---|---|---|
| order.imported | Order synced | Start fulfillment |
| order.updated | Order modified | Update records |
| order.cancelled | Order cancelled | Stop fulfillment |
Account Events
| Event | Trigger | Use Case |
|---|---|---|
| balance.low | Wallet below threshold | Add funds alert |
| billing.adjustment | Carrier adjustment | Review charge |
Setup Guide
Step 1: Create Endpoint
Your endpoint must:
- Accept POST requests
- Use HTTPS (required for production)
- Return 200 status within 5 seconds
- Handle retries idempotently
Example endpoint (Node.js/Express):
const express = require('express');
const app = express();
app.post('/webhooks/atoship', express.json(), (req, res) => {
// Acknowledge immediately
res.status(200).send('OK');
// Process asynchronously
processWebhook(req.body).catch(console.error);
});
async function processWebhook(event) {
switch (event.type) {
case 'shipment.delivered':
await markOrderDelivered(event.data.order_id);
await sendDeliveryEmail(event.data);
break;
case 'tracking.exception':
await alertCustomerService(event.data);
break;
// Handle other events...
}
}
Step 2: Register Webhook
- Go to Settings > Webhooks
- Click Add Webhook Endpoint
- Enter your URL: https://yoursite.com/webhooks/atoship
- Select events to receive
- Click Save
Step 3: Copy Webhook Secret
After saving:
- Click on your webhook
- Copy the Signing Secret
- Store securely (environment variable)
Step 4: Verify Signatures
IMPORTANT: Always verify webhook signatures to prevent spoofing.
const crypto = require('crypto');
function verifySignature(payload, signature, secret) {
const expectedSig = crypto
.createHmac('sha256', secret)
.update(JSON.stringify(payload))
.digest('hex');
// Use timing-safe comparison
return crypto.timingSafeEqual(
Buffer.from(signature, 'hex'),
Buffer.from(expectedSig, 'hex')
);
}
app.post('/webhooks/atoship', express.json(), (req, res) => {
const signature = req.headers['x-atoship-signature'];
const secret = process.env.ATOSHIP_WEBHOOK_SECRET;
if (!verifySignature(req.body, signature, secret)) {
console.error('Invalid webhook signature');
return res.status(401).send('Invalid signature');
}
// Signature valid, process event
res.status(200).send('OK');
processWebhook(req.body);
});
Event Payload Structure
Standard Format
{
"id": "evt_1234567890abcdef",
"type": "shipment.delivered",
"created_at": "2024-01-15T10:30:00Z",
"data": {
"shipment_id": "shp_abc123",
"tracking_number": "9400111899223456789012",
"carrier": "USPS",
"service": "Priority Mail",
"order_id": "order_xyz789",
"order_reference": "ORD-12345",
"delivered_at": "2024-01-15T10:28:00Z",
"delivery_location": "Front door",
"signed_by": "RESIDENT"
},
"metadata": {
"organization_id": "org_xxxxx",
"attempt": 1
}
}
Retry Logic
Automatic Retries
If your endpoint returns non-2xx or times out:
| Attempt | Delay |
|---|---|
| 1 | Immediate |
| 2 | 1 minute |
| 3 | 5 minutes |
| 4 | 30 minutes |
| 5 | 2 hours |
| 6 | 6 hours |
After 6 failures, webhook marked as failed.
Handling Retries
Idempotency is critical:
const processedEvents = new Map(); // Use Redis in production
async function processWebhook(event) {
// Check if already processed
if (processedEvents.has(event.id)) {
console.log('Event ' + event.id + ' already processed, skipping');
return;
}
// Mark as processing
processedEvents.set(event.id, { status: 'processing', timestamp: Date.now() });
try {
// Process event
await handleEvent(event);
processedEvents.set(event.id, { status: 'completed', timestamp: Date.now() });
} catch (error) {
processedEvents.set(event.id, { status: 'failed', error: error.message });
throw error; // Let retry happen
}
}
Testing Webhooks
Send Test Event
- Go to Settings > Webhooks
- Click on your endpoint
- Click Send Test Event
- Select event type
- View response
Local Development
Use ngrok for local testing:
# Install ngrok
npm install -g ngrok
# Expose local port
ngrok http 3000
# Use provided URL
# https://abc123.ngrok.io/webhooks/atoship
Webhook Logs
View delivery attempts:
- Go to webhook settings
- Click Delivery Logs
- See request/response details
- Retry failed deliveries
Best Practices
Response Time
Return 200 quickly:
// Good - Acknowledge immediately, process async
app.post('/webhooks', (req, res) => {
res.status(200).send('OK');
queue.add('process-webhook', req.body);
});
// Bad - Blocking response
app.post('/webhooks', async (req, res) => {
await processWebhook(req.body); // May timeout
res.status(200).send('OK');
});
Monitoring
Track webhook health:
- Delivery success rate
- Average response time
- Failed event types
- Retry frequency
Troubleshooting
Not Receiving Webhooks
Check:
- Endpoint URL correct
- HTTPS enabled
- Firewall allows atoship IPs
- Events subscribed
- Webhook enabled
Signature Verification Failing
Common causes:
- Using parsed JSON instead of raw body
- Wrong webhook secret
- Encoding mismatch
Timeout Errors
If webhook times out:
- Respond immediately with 200
- Process asynchronously
- Use message queue
- Check server performance
Need Help?
- API Docs: Full webhook reference
- Developer Chat: Technical support
- Email: [email protected]
- Support: Create Ticket at /dashboard/support