Webhooks

Webhooks allow your application to receive real-time notifications when events occur in the Flash Americas system. Instead of polling our API for updates, webhooks push event data directly to your application.

Overview

Flash Americas webhooks provide:

  • Real-time notifications for shipment events
  • Reliable delivery with retry mechanisms
  • Secure verification using HMAC signatures
  • Event filtering to receive only relevant notifications
  • Multiple endpoint support for different event types

Event Types

EventDescription
shipment.createdNew shipment was created
shipment.picked_upShipment was picked up by carrier
shipment.in_transitShipment is in transit
shipment.out_for_deliveryShipment is out for delivery
shipment.deliveredShipment was delivered
shipment.exceptionDelivery exception occurred
shipment.cancelledShipment was cancelled
quote.createdNew quote was generated
quote.expiredQuote has expired
tracking.updatedTracking information updated

Setting Up Webhooks

1. Create Webhook Endpoint

Express.js webhook handlerjavascript
const express = require('express');
const crypto = require('crypto');
const app = express();

// Middleware to capture raw body for signature verification
app.use('/webhooks', express.raw({type: 'application/json'}));

app.post('/webhooks/flash-americas', (req, res) => {
const signature = req.headers['x-flash-americas-signature'];
const payload = req.body;

// Verify webhook signature
if (!verifySignature(payload, signature)) {
  return res.status(401).send('Invalid signature');
}

const event = JSON.parse(payload);

// Process the webhook event
handleWebhookEvent(event);

res.status(200).send('OK');
});

function verifySignature(payload, signature) {
const secret = process.env.WEBHOOK_SECRET;
const expectedSignature = crypto
  .createHmac('sha256', secret)
  .update(payload)
  .digest('hex');
  
return signature === `sha256=${expectedSignature}`;
}

function handleWebhookEvent(event) {
console.log('Received webhook:', event.eventType);

switch (event.eventType) {
  case 'shipment.delivered':
    notifyCustomer(event.data);
    break;
  case 'shipment.exception':
    handleDeliveryException(event.data);
    break;
  default:
    console.log('Unhandled event type:', event.eventType);
}
}

2. Configure Webhook URL

POST /webhookshttp
POST https://api.flashamericas.com/api/v1/webhooks
Authorization: Bearer YOUR_API_KEY
Content-Type: application/json
Webhook configurationjson
{
"url": "https://your-app.com/webhooks/flash-americas",
"events": [
  "shipment.picked_up",
  "shipment.delivered",
  "shipment.exception"
],
"secret": "your_webhook_secret_key",
"active": true
}

Response

Webhook creation responsejson
{
"success": true,
"data": {
  "webhookId": "wh_123456789",
  "url": "https://your-app.com/webhooks/flash-americas",
  "events": [
    "shipment.picked_up",
    "shipment.delivered", 
    "shipment.exception"
  ],
  "secret": "your_webhook_secret_key",
  "active": true,
  "createdAt": "2025-01-15T10:30:00Z"
}
}

Webhook Payload Structure

All webhook payloads follow a consistent structure:

Standard webhook payloadjson
{
"eventId": "evt_550e8400-e29b-41d4-a716-446655440000",
"eventType": "shipment.delivered",
"timestamp": "2025-02-21T16:45:00Z",
"data": {
  "shipmentId": "660e8400-e29b-41d4-a716-446655440001",
  "trackingNumber": "1234567890",
  "status": "DELIVERED",
  // Event-specific data
},
"signature": "sha256=abc123..."
}

Event Examples

Shipment Delivered

Delivery webhookjson
{
"eventId": "evt_001",
"eventType": "shipment.delivered",
"timestamp": "2025-02-21T16:45:00Z",
"data": {
  "shipmentId": "660e8400-e29b-41d4-a716-446655440001",
  "trackingNumber": "1234567890",
  "status": "DELIVERED",
  "deliveredAt": "2025-02-21T16:45:00Z",
  "recipient": "J. DOE",
  "location": {
    "city": "Houston",
    "state": "TX",
    "country": "US"
  },
  "signatureUrl": "https://api.flashamericas.com/documents/signature_123.png"
}
}

Delivery Exception

Exception webhookjson
{
"eventId": "evt_002",
"eventType": "shipment.exception",
"timestamp": "2025-02-21T15:30:00Z",
"data": {
  "shipmentId": "660e8400-e29b-41d4-a716-446655440001",
  "trackingNumber": "1234567890",
  "status": "EXCEPTION",
  "exceptionCode": "001",
  "exceptionReason": "RECIPIENT_NOT_AVAILABLE",
  "description": "Delivery attempted - no one available",
  "location": {
    "city": "Houston",
    "state": "TX",
    "country": "US"
  },
  "nextAttempt": "2025-02-22T15:00:00Z"
}
}

Security

Signature Verification

Always verify webhook signatures to ensure authenticity:

Signature verificationjavascript
function verifyWebhookSignature(payload, signature, secret) {
const expectedSignature = crypto
  .createHmac('sha256', secret)
  .update(payload, 'utf8')
  .digest('hex');
  
const expectedHeader = `sha256=${expectedSignature}`;

return crypto.timingSafeEqual(
  Buffer.from(signature, 'utf8'),
  Buffer.from(expectedHeader, 'utf8')
);
}

Best Practices

  1. Always verify signatures before processing webhook data
  2. Use HTTPS endpoints for webhook URLs
  3. Implement idempotency to handle duplicate events
  4. Return 200 status quickly to acknowledge receipt
  5. Process asynchronously for long-running operations

Retry Logic

Flash Americas implements automatic retry logic for failed webhook deliveries:

  • Initial attempt: Immediate delivery
  • Retry 1: After 1 minute
  • Retry 2: After 5 minutes
  • Retry 3: After 15 minutes
  • Retry 4: After 1 hour
  • Retry 5: After 6 hours

Webhooks are considered failed if they don't return a 2xx status code.

Managing Webhooks

List Webhooks

GET /webhookshttp
GET https://api.flashamericas.com/api/v1/webhooks
Authorization: Bearer YOUR_API_KEY

Update Webhook

PUT /webhooks/{id}http
PUT https://api.flashamericas.com/api/v1/webhooks/wh_123456789
Authorization: Bearer YOUR_API_KEY
Content-Type: application/json
Update webhookjson
{
"url": "https://your-app.com/webhooks/v2/flash-americas",
"events": [
  "shipment.picked_up",
  "shipment.delivered",
  "shipment.exception",
  "tracking.updated"
],
"active": true
}

Delete Webhook

DELETE /webhooks/{id}http
DELETE https://api.flashamericas.com/api/v1/webhooks/wh_123456789
Authorization: Bearer YOUR_API_KEY

Testing Webhooks

Webhook Testing Tool

Use our webhook testing tool to simulate events:

POST /webhooks/testhttp
POST https://api.flashamericas.com/api/v1/webhooks/wh_123456789/test
Authorization: Bearer YOUR_API_KEY
Content-Type: application/json
Test webhookjson
{
"eventType": "shipment.delivered",
"data": {
  "shipmentId": "test_shipment_123",
  "trackingNumber": "TEST123456789",
  "status": "DELIVERED"
}
}

Local Development

For local development, use tools like ngrok to expose your local server:

Expose local webhook endpointbash
# Install ngrok
npm install -g ngrok

# Expose local port 3000
ngrok http 3000

# Use the generated URL for webhook configuration
# https://abc123.ngrok.io/webhooks/flash-americas

Error Handling

Handle webhook errors gracefully:

Error handlingjavascript
app.post('/webhooks/flash-americas', async (req, res) => {
try {
  const signature = req.headers['x-flash-americas-signature'];
  const payload = req.body;
  
  if (!verifySignature(payload, signature)) {
    return res.status(401).json({ error: 'Invalid signature' });
  }
  
  const event = JSON.parse(payload);
  await processWebhookEvent(event);
  
  res.status(200).json({ received: true });
} catch (error) {
  console.error('Webhook processing error:', error);
  
  // Return 500 to trigger retry
  res.status(500).json({ 
    error: 'Internal server error',
    eventId: event?.eventId 
  });
}
});

async function processWebhookEvent(event) {
// Store event for processing
await storeWebhookEvent(event);

// Process in background queue
await addToQueue('webhook-processing', event);
}

Next Steps