FRED webhooks: receive events and parcel tracking
Configure, secure and monitor your application's notifications.
Published by FRED
Create an integration
curl -X POST https://api.fredpod.com/v1/webhook_endpoints \
-H "X-API-Key: YOUR_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: creation-boutique-001" \
-d '{"description":"My store","url":"https://your-app.example/webhooks/fred","events":["order.*","shipment.*"]}'The webhooks:manage scope is required. The URL must use HTTPS, port 80 or 443 and a public destination, without credentials or a fragment. Private and local addresses and redirects are rejected; DNS resolution is checked and pinned for each delivery to limit SSRF attacks.
The creation response contains the whsec_… secret. Save it in your secrets manager: it does not appear in lists. Repeating the same creation with the same idempotency key retrieves its response. Secrets and these stored responses are encrypted in the database, and management HTTP responses carry Cache-Control: no-store.
GET /v1/webhook_endpoints/event-types provides the catalogue of events and families. Use specific types, a family such as order.*, or * alone. Empty lists and unknown types are rejected.
Test and production
An sk_test_… key operates in the sandbox; it cannot access production. From a seller session, management pages and routes accept ?mode=test to manage that same environment. A production key can also select its sandbox using this parameter.
Sandbox notifications are actually sent to the configured URL, with test data. They do not create any real charges.
Update your customer's order
Subscribe to order.* and shipment.*. Events use an envelope
containing id, type and data.object.
| Event | Storefront action |
|---|---|
order.in_production | Display “In production” |
order.shipped | Display “Shipped” and reload the parcels |
order.delivered | Display “Delivered” |
shipment.created | Save shipping and tracking information; the label exists, but the parcel may not have left yet |
shipment.updated | Update the parcel's status and tracking link |
shipment.delivered | Record the reported delivery |
Order events carry the ID in data.object.id. Shipment events
carry data.object.order_id, data.object.tracking_number and data.object.tracking_url.
Read GET /v1/storefront/orders/{order_id} again to get the current state and
parcel list. Events do not necessarily arrive in order.
FRED sends parcel tracking to your application. Shipping labels and manufacturing files are managed by the workshop.
To check reception, call
POST /v1/webhook_endpoints/{endpoint_id}/test. The 202 means the
webhook.test event is queued; it creates neither an order nor a payment. Deliveries,
failures, retries and secret rotations are managed in Developers → Webhooks
in the dashboard.
Verify signatures
New endpoints use Standard Webhooks: remove the whsec_ prefix, base64-decode the secret, then compute HMAC-SHA256 over the bytes webhook-id.webhook-timestamp.raw_body. The body must not be parsed and serialised again before verification.
import base64
import hashlib
import hmac
import time
def verifier(secret: str, headers: dict, body: bytes) -> bool:
try:
msg_id = headers["webhook-id"]
timestamp = headers["webhook-timestamp"]
if not timestamp.isdigit() or abs(time.time() - int(timestamp)) > 300:
return False
key = base64.b64decode(secret.removeprefix("whsec_"), validate=True)
message = f"{msg_id}.{timestamp}.".encode() + body
expected = base64.b64encode(hmac.new(key, message, hashlib.sha256).digest()).decode()
return any(
hmac.compare_digest(part[3:], expected)
for part in headers["webhook-signature"].split()
if part.startswith("v1,")
)
except (KeyError, ValueError, TypeError):
return FalseKeep a short clock tolerance (five minutes here) and deduplicate events by webhook-id. Respond with 2xx only after durably storing the event, then process it in your own queue. A successful delivery confirms the receiver's HTTP response, not the success of your business processing.
Legacy endpoints remain identified by signing_version: 1: they use the secret's characters after whsec_ as the HMAC key, without base64 decoding. They continue working until rotation. New and rotated endpoints use signing_version: 2.
During rotation, signatures from both secrets are sent for one hour. Your verifier must accept any valid signature among those separated by spaces. The new secret is displayed once and secret_rotates_until indicates when the transition ends. A second rotation is blocked during that hour.
Receive without duplicates
Delivery is at least once: deduplicate by webhook-id, durably store
the event, then respond with 2xx. Process it afterwards in your work
queue. On failure, FRED retries with increasing delays, up to eight
attempts. Redirects are not followed.
Review attempts and retry terminal failures from the dashboard. Use the order GET to reconcile your tracking if your website has been unavailable.