API & webhooks
Premium brands can receive signed JSON webhooks when orders are paid or fulfilled on Drape. Configure the endpoint in the brand portal under Integrations.
There is no public third-party REST catalog API yet. Day-to-day catalog, orders, and analytics stay in the brand portal / app; webhooks cover outbound order events for your own systems (ERP, fulfillment, Slack bots, etc.).
Prerequisites
| Requirement | Detail |
|---|---|
| Plan | Premium (custom_integrations entitlement) |
| Portal | brand.drape.to/integrations |
| HTTPS endpoint | Must accept POST with JSON body |
| Response | Return 2xx within ~10 seconds |
Configure in the portal
- Open Integrations.
- Under Order webhooks, set your endpoint URL.
- Select events (
order.paid,order.fulfilled). - Save — copy the signing secret when it is shown (create / rotate only).
- Keep the webhook active.
Rotate the secret anytime with Rotate secret, then update your verifier.
Events
| Event | When it fires |
|---|---|
order.paid | Shopper payment succeeds for an order that includes your store’s lines |
order.fulfilled | You mark the order shipped / fulfilled in Drape |
Default subscription when events are omitted: both of the above.
Delivery
Drape POSTs to your URL with:
| Header | Value |
|---|---|
Content-Type | application/json |
X-Drape-Event | Event name, e.g. order.paid |
X-Drape-Signature | Hex HMAC-SHA256 of the raw body using your signing secret |
Timeout: 10 seconds. Non-2xx or network errors are logged as failed deliveries; retries are not guaranteed yet — treat handlers as idempotent.
Envelope shape
{
"id": "9f3c2a1b-…",
"type": "order.paid",
"created_at": "2026-09-10T13:00:00.000000Z",
"store_id": "c373fbc1-…",
"data": {
"order": {
"id": "…",
"store_id": "…",
"status": "paid",
"total": 189.0
}
}
}
data.order is the serialized order row for your store (UUIDs as strings,
datetimes as ISO-8601). Fields may grow over time — ignore unknown keys.
Verify the signature
Compute HMAC-SHA256 over the exact request body bytes with your secret and
compare to X-Drape-Signature (hex digest).
Node.js
import crypto from "node:crypto";
function verifyDrapeSignature(rawBody, signatureHeader, secret) {
const expected = crypto
.createHmac("sha256", secret)
.update(rawBody)
.digest("hex");
const a = Buffer.from(expected, "utf8");
const b = Buffer.from(signatureHeader || "", "utf8");
return a.length === b.length && crypto.timingSafeEqual(a, b);
}
// Express: use express.raw({ type: "application/json" }) for this route
app.post("/webhooks/drape", (req, res) => {
const ok = verifyDrapeSignature(
req.body,
req.get("X-Drape-Signature"),
process.env.DRAPE_WEBHOOK_SECRET,
);
if (!ok) return res.status(401).send("invalid signature");
const event = JSON.parse(req.body.toString("utf8"));
// handle event.type …
res.status(200).json({ received: true });
});
Python
import hmac
import hashlib
def verify_drape_signature(raw_body: bytes, signature: str, secret: str) -> bool:
expected = hmac.new(secret.encode("utf-8"), raw_body, hashlib.sha256).hexdigest()
return hmac.compare_digest(expected, signature or "")
Brand portal API (authenticated)
Webhook settings are managed with the brand JWT (same session as the portal):
| Method | Path | Notes |
|---|---|---|
GET | /api/brand/integrations/webhook | Current config (secret not returned) |
PUT | /api/brand/integrations/webhook | Body: { "url", "events?", "is_active?" } — returns secret on create |
POST | /api/brand/integrations/webhook/rotate-secret | Returns new secret |
Base URL: https://api.drape.to. Requires Premium; otherwise 403.
Related
- Website button / shop bridge: Website widget & deep links
- Brand plans: For brands
- Portal: Integrations