Skip to main content

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​

RequirementDetail
PlanPremium (custom_integrations entitlement)
Portalbrand.drape.to/integrations
HTTPS endpointMust accept POST with JSON body
ResponseReturn 2xx within ~10 seconds

Configure in the portal​

  1. Open Integrations.
  2. Under Order webhooks, set your endpoint URL.
  3. Select events (order.paid, order.fulfilled).
  4. Save — copy the signing secret when it is shown (create / rotate only).
  5. Keep the webhook active.

Rotate the secret anytime with Rotate secret, then update your verifier.

Events​

EventWhen it fires
order.paidShopper payment succeeds for an order that includes your store’s lines
order.fulfilledYou mark the order shipped / fulfilled in Drape

Default subscription when events are omitted: both of the above.

Delivery​

Drape POSTs to your URL with:

HeaderValue
Content-Typeapplication/json
X-Drape-EventEvent name, e.g. order.paid
X-Drape-SignatureHex 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):

MethodPathNotes
GET/api/brand/integrations/webhookCurrent config (secret not returned)
PUT/api/brand/integrations/webhookBody: { "url", "events?", "is_active?" } — returns secret on create
POST/api/brand/integrations/webhook/rotate-secretReturns new secret

Base URL: https://api.drape.to. Requires Premium; otherwise 403.