Webhooks
Webhooks let your application receive real-time notifications when events happen in your store — instead of polling the API for changes. When an order is placed, paid, fulfilled, or updated, TakeTheme sends an HTTP POST request to a URL you control with a JSON description of the event.
Use webhooks to keep external systems in sync with TakeTheme: update an ERP or accounting system when orders are paid, trigger fulfillment in a warehouse platform, notify a Slack channel, or refresh a customer-facing dashboard.
How it works
- You register one or more endpoints — HTTPS URLs on your server that will receive events.
- For each endpoint you choose which events to subscribe to (for example,
order.paid). - When a subscribed event occurs, TakeTheme delivers a signed JSON payload to your endpoint.
- Your endpoint verifies the signature, does its work, and responds with a
2xxstatus code. - If your endpoint is unreachable or returns a non-
2xxstatus, TakeTheme retries with exponential backoff.
Store event TakeTheme Your server
───────────── ───────────────── ──────── ───────────────────────
order.paid ───▶ sign + POST payload ───▶ verify signature
process event
mark delivered ◀─── respond 200 OK
Requirements
Webhooks are available on plans that include webhook access (canAccessWebhooks). If your current plan doesn't include webhooks, endpoint management requests return 403 Forbidden. See your Dashboard billing page to upgrade.
Your receiving endpoint must:
- Be served over HTTPS — plain
http://URLs are rejected. - Be publicly reachable. Internal or private IP addresses (loopback, link-local, private ranges) are blocked to prevent SSRF.
- Not redirect. Redirects (
3xx) are not followed — respond at the endpoint URL directly. - Respond within 10 seconds with a
2xxstatus code.
Available events
TakeTheme currently emits order lifecycle events:
| Event | Sent when… |
|---|---|
order.placed | A new order is created. |
order.paid | An order's payment is captured / marked as paid. |
order.fulfilled | An order (or the remaining items) is marked as fulfilled. |
order.cancelled | An order is cancelled. |
order.returned | An order is marked as returned. |
order.refunded | An order is refunded. |
order.updated | An order is edited or its status is reconciled (debounced — see below). |
Each endpoint subscribes to at least one event. See the Events Reference for the full payload of each event.
order.updated is debouncedA single admin action (editing an order, reconciling fulfillment or payment) can emit many internal order.updated signals. TakeTheme collapses a burst into one order.updated delivery per order within a short window (~5 seconds). Lifecycle events (order.paid, order.fulfilled, …) are never debounced — you receive one delivery per occurrence.
Payload structure
Every webhook body is a JSON envelope with the same top-level shape, regardless of event type:
{
"id": "3f1c2b9e-8a4d-4c7e-9b1a-2d6f8e0c1a34",
"type": "order.paid",
"created": 1751371200.123,
"data": {
"object": {
"id": "665f1b2c9a3e4d0012ab34cd",
"status": "open",
"paymentStatus": "paid",
"fulfillmentStatus": "unfulfilled",
"totalPrice": 349.99,
"currency": "EGP",
"customer": { "...": "..." },
"items": [ { "...": "..." } ],
"shippingAddress": { "...": "..." },
"createdAt": "2026-07-01T12:00:00.000Z"
}
}
}
| Field | Type | Description |
|---|---|---|
id | string | Unique delivery/event ID (UUID). Matches the X-TakeTheme-Delivery header. Use it to deduplicate. |
type | string | The event type, e.g. order.paid. |
created | number | Unix timestamp (seconds, with fractional part) of when the event was generated. |
data.object | object | The resource the event relates to — for order events, the order object. |
created is not the signature timestampThe created field describes when the event occurred. The timestamp used to verify the signature is carried separately in the X-TakeTheme-Signature header (t=…). Always verify against the header timestamp, not created. See Verifying Signatures.
Quick start
1. Create an endpoint
Register an HTTPS URL and subscribe it to events. This can be done from the Dashboard (Settings → Webhooks) or via the API:
curl -X POST "https://api.taketheme.com/api/v1/store/webhooks/endpoints" \
-H "tt-api-key: tt_xxx" \
-H "Content-Type: application/json" \
-d '{
"url": "https://example.com/webhooks/taketheme",
"events": ["order.placed", "order.paid", "order.fulfilled"],
"description": "Production order sync"
}'
The response includes a one-time signing secret (whsec_…). Store it securely — it's shown only once:
{
"id": "665f1b2c9a3e4d0012ab34cd",
"url": "https://example.com/webhooks/taketheme",
"events": ["order.placed", "order.paid", "order.fulfilled"],
"isActive": true,
"secret": "whsec_3a7f...c9d2"
}
2. Receive and verify
Your endpoint should verify the signature before trusting the payload:
import express from "express";
import crypto from "node:crypto";
const app = express();
const SIGNING_SECRET = process.env.TAKETHEME_WEBHOOK_SECRET; // whsec_...
// Capture the RAW body — signature is computed over the exact bytes sent.
app.post(
"/webhooks/taketheme",
express.raw({ type: "application/json" }),
(req, res) => {
const header = req.get("X-TakeTheme-Signature");
const rawBody = req.body; // Buffer
if (!verifySignature(rawBody, header, SIGNING_SECRET)) {
return res.status(400).send("Invalid signature");
}
const event = JSON.parse(rawBody.toString("utf8"));
// Respond fast, then do the heavy lifting asynchronously.
res.status(200).send("ok");
switch (event.type) {
case "order.paid":
// fulfill(event.data.object)
break;
// ...
}
}
);
The full verifySignature implementation (and versions in Python, PHP, Ruby, and Go) is in Verifying Signatures.
Design principles
- At-least-once delivery. A delivery may occasionally arrive more than once (for example, if your server responds slowly and TakeTheme retries). Make your handler idempotent by deduplicating on the event
id/X-TakeTheme-Deliveryheader. - No strict ordering. Events are delivered as they happen, but network retries mean they may arrive out of order. Reconcile using the fields on the payload (e.g.
paymentStatus) rather than assuming order. - Respond quickly. Acknowledge with
2xximmediately and defer slow work (database writes, third-party calls) to a background job. TakeTheme treats a response slower than 10 seconds as a failure. - Always verify. Never act on an unverified payload — anyone who learns your URL could otherwise forge events.
Next steps
- Events Reference — every event and its payload fields.
- Verifying Signatures — validate authenticity in your language.
- Delivery, Retries & Management — headers, retry schedule, logs, and endpoint management.