API conventions
Idempotency
Section titled “Idempotency”Send an Idempotency-Key header (any string you generate, unique per logical operation) on any mutating POST. A retried request with the same key returns the exact original response — byte-identical, not just logically equivalent — instead of creating a second resource. A duplicate request that arrives while the first is still in flight gets 409 idempotency_conflict; retry it once the first has actually completed.
Idempotency-Key: create-referral-order-4471Keys are scoped to your tenant and never expire early — always generate a fresh one per genuinely new operation, not per HTTP attempt.
Pagination
Section titled “Pagination”List endpoints use cursor pagination via starting_after, not page numbers — ids sort the same way they were generated (prefixed ULIDs), so a cursor is just “the last id you saw”:
GET /v1/patients?limit=20GET /v1/patients?limit=20&starting_after=pat_01H8X...Every list response has the same envelope:
{ "data": [ /* up to `limit` items */ ], "has_more": true }limit defaults to 20, maximum 100.
Versioning
Section titled “Versioning”Railflo pins your integration to a specific API version, Stripe-style — set once at signup (currently 2026-09-01, the only version that exists at P0, but the pinning mechanism is real from day one). Override per-request with:
Railflo-Version: 2026-09-01The response always echoes back the version it was actually served under in a Railflo-Version response header, so you can confirm which shape you got.
Rate limits
Section titled “Rate limits”Every endpoint is rate-limited per API key (token-bucket). A limited request gets 429 rate_limited with a Retry-After header telling you how many seconds to wait. Sandbox limits are the same as production — the sandbox is for testing your integration logic, not for load-testing Railflo itself.