Compatibility and versioning

What may change without notice, what may not, and how you are told.

This page states what Stria promises about its interfaces, and — just as

importantly — what it does not.

Two surfaces, one promise

**/functions/v1/api-v1/* — the partner API. Promised.**

Described by openapi.yaml, validated in CI by

npm run test:openapi, and inventoried by npm run api:check so an endpoint cannot

ship undocumented.

**Everything reachable through the Supabase Data API (PostgREST) — internal.

Not promised.**

The public schema is exposed, so a workspace member holding their own user JWT can

reach tables, views and several hundred RPCs directly. That surface exists for

Stria's own client. It is unversioned, undocumented, and changes without notice in

any migration.

We are saying this plainly rather than leaving it implied, because an undocumented

surface with real users quietly acquires the obligations of a documented one. If you

build billing automation on a SECURITY DEFINER RPC you found by watching network

traffic, it will break, and the breakage will look like an outage rather than a

deprecation.

Use it for one-off scripts and exploration. Build integrations on /api-v1. If

something you need is only available internally, that is a gap worth telling us

about — the v1 surface is deliberately narrow and additive.

What counts as a breaking change

These ship only in a new major version (/api-v2), never in place:

  • removing an endpoint, a field, or an enum value
  • renaming anything
  • narrowing a type, or making an optional request field required
  • changing the meaning of an existing field
  • adding a required scope to an existing endpoint

These ship without notice, so write clients that tolerate them:

  • new endpoints
  • new optional request parameters
  • new fields in a response object
  • new enum values in a field documented as extensible (status, code)
  • new webhook event types
  • new response headers

Concretely: parse JSON permissively, ignore unknown fields, and never assume a

response object has exactly the keys you saw during development.

Deprecation

When an endpoint is deprecated:

  1. It is marked deprecated: true in the OpenAPI document and in the changelog.
  2. It keeps working unchanged.
  3. Once a removal date is set, responses carry a Sunset header

(RFC 8594) with that date, and a

Deprecation header.

  1. Minimum notice before removal is 90 days from the first Sunset header.

Currently deprecated: GET /api-list-clients, superseded by

GET /api-v1/clients. No removal date set, so no Sunset header is being sent yet.

Webhook contract

Deliveries are at-least-once. Duplicates are the contract, not an edge case —

no HTTP-based delivery system can offer exactly-once, because a sender cannot

distinguish a lost request from a lost response.

Three things follow, and all three are on the receiver:

  • Deduplicate on the delivery id. The webhook-id header (also sent as

X-Stria-Delivery-Id) is stable across every retry and across an

admin-triggered replay. A 24-hour dedupe window is enough; the retry horizon is

~31 hours but a replay of something older is deliberate.

  • Do not assume ordering. There is none. Each payload carries created_at and

enough resource state to discard a stale event — an invoice.sent arriving after

an invoice.paid for the same invoice should be dropped, not applied.

  • Verify the signature over the raw body. See

webhooks.md. During a secret rotation, two signatures are valid

for the overlap window.

If a consumer outage means you missed deliveries, do not wait for a replay: poll the

matching list endpoint with updated_since. That is the supported recovery path and

it is correct regardless of what the queue did.

Rate limits

Published per plan in authentication.md. Responses carry

RateLimit-Limit and RateLimit-Policy; a 429 carries Retry-After.

RateLimit-Remaining is deliberately not sent. The limiter is a fixed-window

counter that raises on breach without reporting a remaining count, and advertising a

number we cannot compute would be worse than omitting it — clients would pace

against a value that is wrong. Back off on 429 using Retry-After with jitter.

Versioning of this policy

Changes to this document are listed in changelog.md. A change

that reduces a notice period applies only to deprecations announced after it.

More reference

  • Authentication — How tokens are minted, stored, presented and revoked.
  • Endpoints — Every request and response shape, with worked examples.
  • Outbound webhooks — Signed HTTPS POSTs when work is signed off, a change order moves, or an invoice is paid — plus how to verify one and how to survive a duplicate.
  • Rate limits — Per organization, per minute, and published rather than discovered as a random failure.
  • Errors — What each status means, what the body carries, and which ones to retry.
  • API changelog — Every change, dated, including the ones that were corrections.

OpenAPI specification · API access is on every paid plan · Start your 14-day trial