Skip to main content

Webhook deliveries

When you register a webhook subscription, UGiftMe POSTs JSON to your HTTPS URL whenever a subscribed event occurs. This page documents those inbound deliveries to your server — not the subscription CRUD endpoints.

Delivery contract

Production deliveries use a 5 s timeout. Manual test deliveries (POST /webhooks/test) use 10 s and include X-Webhook-Delivery: test.

Headers

Match X-Webhook-Event to the payload shape you parse. The event name is not repeated inside most order payloads (except webhook.test, which includes type).

Verify signatures

When you create a webhook, the API returns a secret once. Store it securely. UGiftMe signs each delivery as:
Important: Verification must use the exact JSON bytes UGiftMe sent. Prefer reading the raw request body before parsing JSON. Re-serializing a parsed object can change key order or whitespace and break verification.

Node.js example

Reject requests with invalid or missing signatures before processing the event.

Retries

Failed deliveries (non-2xx, timeout, or connection error) are retried up to 5 attempts total, with backoff approximately: After the final attempt, the delivery is marked failed. deliveryStats on your subscription (visible via GET /webhooks) tracks success and failure counts. Design your handler to be idempotent: the same event may be delivered more than once if a retry occurs after your server already processed the first attempt but returned a non-2xx or timed out.

Order lifecycle (async)

When async order processing is enabled, subscribed order.* events typically fire in sequence:
Synchronous order creation (201 Created) does not emit order.queued / order.processing / order.succeeded / order.failed. It may still emit wallet.updated when the wallet balance changes. Poll GET /orders/order-requests/{id} if you need full request state in addition to webhooks.

Event payloads

order.queued

Emitted when an async order request is accepted (202). Single order:
Bulk order — includes orderCount:

order.processing

Worker picked up the order request:
type is "single" or "bulk".

order.succeeded

Fulfillment completed. result shape depends on type: Single — one created order id:
Bulk — summary of created orders:
Use GET /orders/{orderId} for full order details; the webhook carries ids and summary only.

order.failed

Processing failed after retries exhausted:

wallet.updated

Balance changed on your business wallet (orders, top-ups, holds, etc.).

product.updated

Full product catalog document as stored internally (same fields you see from the products API). Shape varies by product; treat as a catalog record update notification and refresh via GET /products or search as needed.

webhook.test (test deliveries only)

Not subscribable via events. Sent only through POST /webhooks/test:
Header X-Webhook-Event is webhook.test. Header X-Webhook-Delivery is test.

Test your endpoint

Use the Business API (with X-API-Key) after registering a webhook: POST /test response:
On failure, ok is false and errorMessage describes the problem (e.g. non-2xx from your URL).