Worked request and response samples
Create a channel-scoped rule for single-channel throttling; create global when sends across channels share one quota; flip enabled to pause without deleting. The 422 object below points to window_seconds (one of the two fields readers most often mis-type), while the rule matrix below informs retry/discipline for the rest.
POST /api/v1/frequency-caps
window_seconds (60–2,592,000) names the rolling window; scope: "channel" counts one channel per contact while scope: "global" aggregates sends across every channel into one counter (use channel: "*"). applies_to_categories: null (or the field omitted) applies the rule to every category. Update via PATCH /api/v1/frequency-caps/{id}; disable with enabled: false to pause without deleting.
Errors worth branching on
These five failures cover the frequency-cap upsert (POST /api/v1/frequency-caps), saved from every quiet-hours form. Each block below is a full { error, meta } envelope as the API returns it, and the matrix at the bottom answers retry vs surface for the same five classes. For the platform-wide decision table these branches plug into, see the error handling guide.
401 — Unauthorized
A 401 on this page is the bearer key failing before the route ran — it never means the resource is wrong. Rotate the key or re-mint the scoped token; retrying the same request changes nothing.
403 — Forbidden
A 403 means the key authenticated but the operation is gated by scope — check the key’s scopes on the developer page; a 403 is never a data-not-found shape.
422 — Schema
A 422 means the payload did not match the request schema — branch on error.details.field and resend with one of minute, hour, day, week for the window instead of blind-retrying the same body.
429 — Rate
The Retry-After header and error.details.retry_after are both set on every 429 — resend the SAME request after the lower of the two.
409 — Conflict
Patch the existing rule or narrow the scope — a retry creates no new rule.
60-second retry matrix