Setup
Webhook secret
When you enable webhooks, US Global Mail generates a webhook secret — a private key used to sign every payload with an HMAC signature.
Each request we send includes a USGM-Webhook-Signature header so you can confirm the request is genuine and unaltered. Store this secret securely. You can rotate it at any time using Reset Secret.
Add a webhook endpoint
Log in and go to Settings → Automations → Webhooks
Select an Event from the dropdown
Enter your Endpoint URL
Click Add
Manage your webhooks
Activate / Deactivate — toggle delivery on or off at any time
Test — send a sample payload to your endpoint immediately
Delete — remove the endpoint permanently
For advanced management, you can also create, update, and delete webhooks via the API. Authenticate with your access token and refer to the Swagger Docs.
Supported events & payloads
Each event delivers a JSON payload to your endpoint. The table below summarises all events, with full payload samples for each one underneath.
Event key | Description |
| A new mail item has arrived |
| Shipment status has been updated |
| A scan request has completed |
| An open request has completed |
new-mail
Triggered when a new mail item arrives in your inbox.
{
"measurement": {
"width": "9",
"height": "0.01",
"length": "4"
},
"id": 111111,
"weight": "0.03",
"mail_status": "INBOX",
"mail_type": "LETTER",
"image_url": "https://usgm-fe-media-prod.s3.us-east-1.amazonaws.com/sample_mail.jpg",
"recipient_name": "John Smith",
"sender_name": "US Government",
"message": "New mail received."
}
shipment-update
Triggered when the status of a shipment request changes.
{
"id": "b3ba0f4f-9ae6-4256-8b70-cd5f404756a9",
"auto_forward": "false",
"destination_address": {
"name": "Home Address",
"address_line": "2204 18th Street NW",
"address_line_2": "Apt 3B",
"address_line_3": "",
"city": "Washington",
"state": "District of Columbia",
"postal_code": "20009",
"country": "United States",
"address_type": "residential",
"tax_id": "123-45-6789",
"phone_number": "+1-202-555-0143"
},
"service": "DHL Express Easy",
"status": "PROCESSED",
"tracking_data": "1234567890",
"message": "Shipment request updated"
}
scan-update
Triggered when a scan request finishes processing.
{
"id": 111111,
"uuid": "b3ba0f4f-9ae6-4256-8b70-cd5f404756a9",
"mail_type": "LETTER",
"scan_result_url": "https://usgm-fe-media-prod.s3.amazonaws.com/sample.pdf",
"current_status": "COMPLETED",
"ai_label": "Invoice",
"ai_summary": "Invoice #INV-2026-0423 from Acme Corp for $142.50, due April 30, 2026.",
"recipient_name": "John Smith",
"sender_name": "Acme Corp",
"message": "Your scan request has been updated!!"
}
open-update
Triggered when an open request finishes processing.
{
"id": 111111,
"uuid": "b3ba0f4f-9ae6-4256-8b70-cd5f404756a9",
"mail_type": "PACKAGE",
"open_result_url": "https://usgm-fe-media-prod.s3.amazonaws.com/sample.pdf",
"current_status": "COMPLETED",
"recipient_name": "John Smith",
"sender_name": "Acme Corp",
"message": "Your open request has been updated!!"
}
Verifying signatures
Every request we send includes two headers:
USGM-Webhook-Signature— HMAC-SHA256 signature of the payloadUSGM-Webhook-Timestamp— Unix timestamp of when the request was sent
To verify a request, concatenate the timestamp and raw request body with a period (.), then compute an HMAC-SHA256 using your webhook secret. Compare the result to the USGM-Webhook-Signature header using a timing-safe comparison.
Example in Node.js:
const express = require('express');
const crypto = require('crypto');
const app = express();
const PORT = 3000;
const webhookSecret = 'YOUR_WEBHOOK_SECRET';
app.use(express.json({
verify: (req, res, buf) => {
req.rawBody = buf;
}
}));
app.post('/webhook', (req, res) => {
const signature = req.get('USGM-Webhook-Signature');
const timestamp = req.get('USGM-Webhook-Timestamp');
if (!signature || !timestamp) {
return res.status(400).send('Missing signature or timestamp');
}
const dataToSign = `${timestamp}.${req.rawBody.toString()}`;
const expectedSignature = crypto
.createHmac('sha256', webhookSecret)
.update(dataToSign)
.digest('hex');
const valid = crypto.timingSafeEqual(
Buffer.from(signature, 'utf8'),
Buffer.from(expectedSignature, 'utf8')
);
if (!valid) {
return res.status(401).send('Invalid signature');
}
res.status(200).send('Webhook received');
});
app.listen(PORT, () => {
console.log(`Listening on http://localhost:${PORT}`);
});
Always serve your endpoint over HTTPS and validate the signature on every request.
Limits
Up to 10 active webhooks per account
Each endpoint URL must be unique per event
Failed deliveries are not retried automatically
No-code automation with Zapier
Prefer no-code integrations? You can connect US Global Mail events to thousands of apps without writing any code. See our Zapier Integration Guide to get started.
Need help? Email us at [email protected]
