Substratal Apps Substratal Apps Hub specs
GitHub

Help Developers

Developers

Conventions

The rules every endpoint follows. The quickstart shows them in use; this page is the reference. The full detail is in the API's Conventions.

Base URL and version

https://api.substratalapps.com
Substratal-Version: 1

Every path is at the host root, and the version goes in the header, never the URL. See API versioning.

IDs

Every ID starts with its type:

Prefix Type
usr_ User
app_ Application
ent_ Entitlement
role_ Role
org_ Organization
key_ API key
evt_ Audit event
whk_ Webhook subscription

Treat everything after the prefix as opaque. Application IDs are app_ plus the slug, as in app_timetrack. Anywhere a path takes a user ID, me means the caller.

Errors

{
  "error": {
    "code": "entitlement_required",
    "message": "This user has no active entitlement to app_invoicer.",
    "details": { "application_id": "app_invoicer" }
  }
}

Build your logic on code, which never changes. message is for people and can be reworded. Validation failures are 422 validation_failed, with every failing field listed in details.fields.

Pagination

Lists take limit (default 25, maximum 100) and cursor, and return:

{ "data": [], "page": { "next_cursor": "eyJpZCI6…", "has_more": true } }

Pass next_cursor back as cursor until has_more is false. Cursors last 24 hours, and only work with the filters they were issued for.

Safe updates: ETag and If-Match

Single-resource reads and every write return an ETag, such as W/"7". Send it back as If-Match on a PATCH or DELETE. If someone else changed the resource in between, you get 409 version_conflict instead of silently overwriting their change.

Idempotency

Send Idempotency-Key: <a UUID> on creates. The same key with the same body returns the original response instead of creating a duplicate; the same key with a different body is 409. Keys are remembered for 24 hours.

It's required when granting access to a user or an Organization, and when starting a Stripe Checkout.

Rate limits

Scope Limit
Default, per API key or signed-in session 100 requests a minute
Creating users, granting access 20 a minute
effective-permissions, app tokens, OAuth token exchange 300 a minute
Sign-in, sign-up, MFA verification 10 a minute per IP address

Every response carries RateLimit-Remaining and RateLimit-Reset. A 429 carries Retry-After: wait that many seconds before retrying.

Request IDs

Every response has an X-Request-Id. Send your own in the request to match the API's logs with yours. Every audit event records the ID of the request that caused it, so quote it when asking for support.

Last updated 2026-10-23 · Built 2026-10-25 from a9ef3be · API 1.0.0-draft.13 · Substratal-Version: 1