Receive guardrail actions safely.
On this page
Endpoint contract
Use a public HTTPS endpoint on port 443. Redirects are not followed. URLs may not contain credentials or fragments, and DNS must resolve only to public addresses—private, loopback, link-local, and reserved targets are blocked.
Store the per-action signing secret shown after creation or rotation. Traket does not show that plaintext secret again.
Traket-Delivery-IdTraket-Eventguardrail.triggered or guardrail.test.Traket-Actionnotify, flag, rate_limit, restrict, or ban.Traket-TimestampTraket-Signaturev1=<hex HMAC-SHA256>.Content-Typeapplication/json.User-AgentTraket-Guardrails/1.0.Verify before acting
Compute HMAC-SHA256 over the exact raw request body using timestamp.body. Reject timestamps outside a five-minute tolerance, compare signatures in constant time, then deduplicate by delivery ID in the same transaction that changes customer state or enqueues a durable action.
import { createHmac, timingSafeEqual } from "node:crypto";
export async function POST(request: Request) {
const body = await request.text(); // verify the exact raw body
const timestamp = request.headers.get("traket-timestamp") ?? "";
const signature = request.headers.get("traket-signature") ?? "";
const deliveryId = request.headers.get("traket-delivery-id") ?? "";
const timestampSeconds = Number(timestamp);
if (!deliveryId || !Number.isSafeInteger(timestampSeconds) ||
Math.abs(Date.now() / 1000 - timestampSeconds) > 300) {
return new Response("Stale signature", { status: 401 });
}
const expected = `v1=${createHmac(
"sha256",
process.env.TRAKET_ACTION_SECRET!,
)
.update(`${timestamp}.${body}`)
.digest("hex")}`;
const supplied = Buffer.from(signature);
const valid = supplied.length === Buffer.byteLength(expected) &&
timingSafeEqual(supplied, Buffer.from(expected));
if (!valid) return new Response("Invalid signature", { status: 401 });
const event = JSON.parse(body);
if (event.test) return new Response(null, { status: 204 });
// Commit the idempotency record and the customer action—or a durable
// job for it—in one transaction. Repeated delivery IDs are no-ops.
await applyCustomerActionOnce({
deliveryId,
customerId: event.customer.externalId,
effect: event.action.effect,
});
return new Response(null, { status: 204 });
}Delivery and retries
Return 2xx after durable work
Expect at-least-once delivery
- Endpoint timeouts are configurable from 1 to 10 seconds and default to 5 seconds.
- Actions support 1 to 10 automatic attempts and default to 6.
- Traket discards response bodies so your receiver cannot write prompts, outputs, or secrets into delivery diagnostics.
- Test events use the same signature and delivery rules. Return 2xx without changing customer state when
event.testis true.
Overlap secrets during rotation
Queued deliveries move to the new signing secret immediately, but an attempt already in flight can finish with the previous signature. Briefly accept both the new and previous secret, then retire the old value after the overlap window.
Keep versions explicit
Verify either, act once
Traket-Delivery-Id must remain a no-op.Triggered event payload
The customer external ID is the same imported Stripe customer ID sent through the Traket SDK. Optional rule filters and source-event fields are omitted when they were not supplied.
{
"schemaVersion": 1,
"id": "delivery_uuid",
"type": "guardrail.triggered",
"createdAt": "2026-07-13T18:30:00.000Z",
"projectId": "project_uuid",
"action": {
"id": "action_uuid",
"effect": "rate_limit"
},
"rule": {
"id": "rule_uuid",
"name": "Free plan request burst",
"scope": "plan",
"metric": "request_count",
"threshold": 100,
"currency": "usd",
"windowSeconds": 300
},
"incident": {
"id": "incident_uuid",
"observedValue": 101,
"windowStartedAt": "2026-07-13T18:25:00.000Z",
"windowEndedAt": "2026-07-13T18:30:00.000Z"
},
"customer": {
"id": "traket_customer_uuid",
"externalId": "cus_29ff",
"planId": "plan_uuid"
},
"sourceEvent": {
"id": "usage_event_uuid",
"occurredAt": "2026-07-13T18:30:00.000Z",
"provider": "openai",
"model": "gpt-5.4-mini",
"feature": "agent_run",
"environment": "production",
"status": "success"
}
}Usage events that can trigger this delivery enter through POST /api/v1/usage/events.
