Draft

Conventions

Formats, idempotency, pagination, errors and rate limits.

Basics

  • Base URL https://api.wagend.app/v1. Breaking changes ship as a new version.
  • JSON in and out (Content-Type: application/json).
  • Timestamps in ISO 8601 with offset (2026-10-15T09:45:00-03:00). Stored in UTC.
  • Money in integer cents plus currency (BRL, ARS, PYG, USD).
  • IDs are opaque strings with a prefix (bkg_, svc_, res_, grp_, cus_).

Idempotency

POST /holds, POST /holds/{id}/confirm, POST /bookings and POST /bookings/{id}/reschedule require an Idempotency-Key header (for example a UUID). Repeating a request with the same key within 24 hours returns the original response. Reusing a key with a different body returns 422.

Pagination

List endpoints use cursors:

curl "https://api.wagend.app/v1/bookings?limit=50" -H "Authorization: Bearer $WAGEND_KEY"
# → { "data": [...], "next_cursor": "eyJpZCI6..." }
curl "https://api.wagend.app/v1/bookings?limit=50&cursor=eyJpZCI6..." -H "Authorization: Bearer $WAGEND_KEY"

Errors

Errors follow RFC 9457 (application/problem+json):

{
  "type": "https://wagend.app/docs/api/conventions#errors",
  "title": "Slot no longer available",
  "status": 409,
  "code": "slot_taken",
  "alternatives": [{ "start": "2026-10-15T10:15:00-03:00", "end": "2026-10-15T10:45:00-03:00" }]
}
codeStatusWhen
invalid_request400 / 422Validation failed
unauthorized401Missing, invalid or revoked key
insufficient_scope403Key lacks the scope
not_found404Unknown id (or belongs to another workspace)
slot_taken409Someone else got the slot
invalid_transition409For example confirming a cancelled booking
hold_expired410The hold expired before confirm
idempotency_mismatch422Same key, different body
rate_limited429Too many requests

Rate limits

Limits apply per key and per workspace. Every response includes RateLimit-Limit, RateLimit-Remaining and RateLimit-Reset. On 429, wait Retry-After seconds.