Webhooks
Get a callback the moment mail arrives — or a scan, open request, or shipment changes — instead of polling.
A webhook tells your system that something happened in the mailbox as it happens. Instead of polling
/v1/mails on a timer, you give USGM an HTTPS endpoint and we POST a JSON payload to it the moment
mail arrives or a request changes state — enough to drive a CRM, a Slack alert, or any downstream
automation.
Each subscription pairs one event with one endpoint URL. Every delivery is signed with a secret only you and USGM know, so you can prove it came from us before you act on it.
Webhooks are configured in the dashboard — there are no webhook endpoints in the REST API. They require a plan that includes webhooks; if yours doesn’t, the settings page explains how to upgrade.
Set up a webhook
You can deactivate a subscription to pause delivery without losing it, reactivate it later, or delete it permanently. An account can have up to 10 active webhooks — only active ones count, so deactivating one frees a slot.
Events
Payloads
Every delivery is a POST with Content-Type: application/json. The body is the event payload —
there is no envelope, so the event type is implied by the endpoint you registered for it.
Payload fields mirror the mailroom’s internal vocabulary, so statuses and types are uppercase
here (INBOX, LETTER, COMPLETED) — unlike the REST API, which returns them lowercase.
new-mail
id is the mail item’s id — pass it to GET /v1/mails/{id} to pull the full
item. weight is in pounds and measurement is in inches.
scan-update
uuid is the scan’s id (the one GET /v1/scans/{id} takes); id is the mail
item it belongs to. ai_label and ai_summary are only present on plans that include scan labeling.
open-update
shipment-update
Here id is the shipment’s own id (a UUID). tracking_data is the carrier tracking number once the
shipment has one.
scan_result_url, open_result_url, and image_url are pre-signed links that expire 3 days
after delivery. Download the file and store it yourself rather than saving the URL.
Verifying the signature
Anyone can POST to a public URL, so verify every request before acting on it. Each delivery carries two headers:
The signed string is the timestamp, a period, and the raw request body:
Compute the HMAC-SHA256 of that string with your webhook secret, hex-encode it, and compare it to the signature header using a timing-safe comparison.
Sign the raw body bytes, exactly as received. Parsing the JSON and re-serializing it can change key order or spacing, which produces a different signature and fails verification.
The webhook secret
Your secret is shown on the Settings → Developer → Webhooks page and is shared by every webhook on the account. Reset secret rotates it — deliveries are signed with the new secret immediately, so roll it out to your endpoint at the same time.
Treat the secret like a password: keep it in an environment variable or a secrets manager, never in source control or client-side code. Reset it immediately if it leaks.
Delivery behavior
- Respond quickly with a 2xx. Acknowledge first and do the real work in a background job — a slow endpoint holds the delivery open.
- Failed deliveries are not retried. A non-2xx, a timeout, or an unreachable endpoint means that
event is missed, so treat webhooks as a fast notification layer rather than a system of record. If
you need to be certain nothing was dropped, reconcile periodically against
GET /v1/mails. - Expect duplicates and out-of-order arrival. Make your handler idempotent — key on
id/uuidrather than assuming each event lands exactly once, in order. - Use HTTPS. Payloads carry mail metadata and, for shipments, the destination address.