Quickstart
One whole bid, from an empty start to a converted order, on an integration key. Every response below is a real capture from a running server — nothing here is illustrative. The resources in the captures are a test customer, "Harbor Homes", and its kitchen bid; your ids, names and price levels will differ.
The walk is the order an integration actually needs the doors in:
| # | Step | Doors |
|---|---|---|
| 1 | Who am I | GET /v1/api-keys/self |
| 2 | Map type codes to ids; read the limits a type declares | GET /v1/resource-types, GET /v1/resource-types/:id |
| 3 | Read the vocabulary you may attest | GET /v1/attestation-event-types |
| 4 | Read reference data (price levels, payment terms) | GET /v1/resources?typeKey=…&include=properties |
| 5 | Bring in the customer by your own identifier | POST /v1/resources/find-or-create |
| 6 | Set its properties | PATCH /v1/resources/:id |
| 7 | Fill its fields (price level, payment terms) | GET …/ports, GET …/ports/:portId/legal-targets, POST /v1/resource-interactions |
| 8 | The bid, its properties and its three fields | the same doors |
| 9 | A design set inside the bid | POST /v1/resources/find-or-create, POST /v1/resources/:id/members |
| 10 | Lines inside the set, each with its product | find-or-create, members, PATCH, legal-targets with q, POST /v1/resource-interactions |
| 11 | Read the tree back | GET /v1/resources/:id/members, GET /v1/resources/:id |
| 12 | Preview what a status move needs | GET /v1/state-transitions, GET /v1/resources/:id/requirements |
| 13 | Freeze bottom-up: lines, then the set | PATCH /v1/resources/:id/status |
| 14 | Submit: record the totals, then send | POST /v1/resources/:id/attestations, PATCH …/status |
| 15 | Accept and convert; find the order | attestations, PATCH …/status, GET /v1/resources/:id |
Steps that use the same doors again (a second field, the next line) are shown once. examples.http has one runnable block per door, in this order. The latest copy of this walk lives at docs.limnal.dev.
Set up
export BASE=https://api.limnal.dev
export TOKEN=... # the key your administrator gave you, shown once at creation
Every request carries the key as a bearer token, and nothing else:
curl -s -H "Authorization: Bearer $TOKEN" "$BASE/v1/..."
In code, one small wrapper is enough. This one never throws on an HTTP status — every answer, including a refusal,
comes back as { status, json, header }, so a step can decide what a 409 means for it — and it keeps the response
headers, because the rate-limit headers are worth watching (see Things to know):
const BASE = process.env.RESYNC_BASE! // https://api.limnal.dev
const TOKEN = process.env.RESYNC_TOKEN! // from your secret store — never a command-line argument, never logged
type Answer = { status: number; json: any; text: string; header: (name: string) => string | null }
async function api(method: string, path: string, body?: unknown): Promise<Answer> {
let res: Response
try {
res = await fetch(`${BASE}${path}`, {
method,
headers: { authorization: `Bearer ${TOKEN}`, ...(body != null ? { 'content-type': 'application/json' } : {}) },
body: body != null ? JSON.stringify(body) : undefined,
})
} catch (e) {
return { status: 0, json: { error: 'network', message: (e as Error).message }, text: '', header: () => null }
}
const text = await res.text()
let json: any = null
try { json = text ? JSON.parse(text) : null } catch { json = text }
return { status: res.status, json, text, header: (name) => res.headers.get(name) }
}
1. Who am I, and what may I touch?
curl -s -H "Authorization: Bearer $TOKEN" "$BASE/v1/api-keys/self"
From self.json — status 200:
{
"apiKeyId": 781,
"name": "bid-app-docs",
"scopes": {
"read_types": [
"cab_pricing_level",
"cab_payment_terms",
"cab_order",
"cab_catalog_product",
"cab_cat_accessory",
"cab_cat_base",
"cab_cat_molding",
"cab_cat_office",
"cab_cat_utility",
"cab_cat_vanity",
"cab_cat_wall",
"cab_fam_base_sink",
"cab_fam_bookcase",
"cab_fam_crown_molding",
"cab_fam_filler",
"cab_fam_lazy_susan",
"cab_fam_oven_cabinet",
"cab_fam_panel",
"cab_fam_post",
"cab_fam_utility_cabinet",
"cab_fam_vanity_combo",
"cab_fam_wall_cabinet",
"cab_fam_wall_drawer",
"cab_fam_wall_pantry_pullout_filler",
"cab_fam_wall_stacked",
"door_style_lower",
"door_style_upper",
"drawer",
"finish",
"front",
"hinge",
"interior",
"sheen",
"slide",
"species"
],
"operate_types": [
"cab_customer",
"cab_bid",
"cab_design_set",
"cab_line",
"cab_install",
"cab_adjustment",
"cab_modification"
],
"find_or_create_types": [
"cab_customer",
"cab_bid",
"cab_design_set",
"cab_line",
"cab_install",
"cab_adjustment",
"cab_modification"
],
"created_owner_resource_id": 5
},
"actsAt": null,
"owner": {
"resourceId": 5,
"name": "Popular Design Mill & Cabinet, Inc."
}
}
What to notice. owner is the organization your key belongs to — every resource you can reach is owned by it.
operate_types is what you may change; read_types is what you may additionally read; find_or_create_types is what
you may bring into existence. This key may create and change customers, bids, design sets and the four kinds of bid
line, and only read the price book, the price levels, the payment terms and the orders a converted bid produces. A type
code in none of the lists returns 403 everywhere, and that is working as intended.
Make this call at startup and log the result. When something later returns 403, this is the answer.
2. Map type codes to ids
Doors take a type's code (typeKey=cab_bid); a few answers carry its numeric id. Read the list once and keep the
code → id map:
curl -s -H "Authorization: Bearer $TOKEN" "$BASE/v1/resource-types"
The full answer is resource-types-list.json in the fixture set — one row per type your key can read, each with its
code and resourceTypeId. One type in full also says what it allows as a member — here, a bid line can sit inside at
most one design set:
curl -s -H "Authorization: Bearer $TOKEN" "$BASE/v1/resource-types/3425"
From resource-type-by-id.json — status 200:
{
"resourceTypeId": "3425",
"code": "cab_line",
"name": "Bid Line",
"description": null,
"propertySchema": {
"qty": {
"type": "number",
"label": "Quantity"
},
"area": {
"type": "text",
"label": "Area"
},
"taxable": {
"type": "select",
"label": "Taxable",
"options": [
"yes",
"no"
]
},
"ext_cents": {
"type": "number",
"label": "Extended price (cents)",
"derivable": false
},
"shop_note": {
"type": "text",
"label": "Shop note"
},
"unit_cents": {
"type": "number",
"label": "Unit price (cents)",
"derivable": false
},
"customer_note": {
"type": "text",
"label": "Customer note"
},
"finish_interior": {
"type": "select",
"label": "Finished interior",
"options": [
"yes",
"no"
]
},
"list_overridden": {
"type": "select",
"label": "List overridden",
"options": [
"yes",
"no"
]
},
"override_list_cents": {
"type": "number",
"label": "Override list price (cents)",
"derivable": false
}
},
"nameTemplate": null,
"parameterDefinitions": {},
"expressionContext": {},
"labelTemplate": "{name}",
"isSystem": false,
"canBeAllocated": false,
"isConsumable": false,
"defaultIsSerialized": false,
"defaultIsLotTracked": false,
"parentResourceTypeId": "170",
"defaultUnitTypeId": null,
"ownerResourceId": "5",
"lifecycleId": "656",
"orgName": "Popular Design Mill & Cabinet, Inc.",
"ownerOrgId": "1",
"canvasId": null,
"containmentCaps": [
{
"containmentCapId": 1,
"parentTypeId": 1171,
"maxParents": 1
}
]
}
3. Read the vocabulary you may attest
An attestation records that something happened — a bid was sent, accepted, converted — without changing the resource's own fields. The event types and the fields each declares are reference data:
curl -s -H "Authorization: Bearer $TOKEN" "$BASE/v1/attestation-event-types"
The full answer is attestation-event-types-read.json in the fixture set. Read it rather than caching it forever: a
declaration can change, and the changelog says when.
4. Read reference data
A list always needs a type. Add include=properties to get each row's values in the same request:
curl -s -H "Authorization: Bearer $TOKEN" "$BASE/v1/resources?typeKey=cab_pricing_level&limit=5&include=properties"
From list-include-properties.json — status 200:
{
"resources": [
{
"resourceId": "13806",
"name": "Dealer",
"identifier": null,
"ownerResourceId": 5,
"resourceTypeId": "1264",
"resourceTypeName": "Price Level",
"isSystem": false,
"createdAt": "2026-09-13T08:53:20.358Z",
"statusId": null,
"statusName": null,
"statusColor": null,
"archivedAt": null,
"icon": "box",
"properties": {
"name": "Dealer",
"pct_bp": 4536
},
"confirmedKeys": {}
},
{
"resourceId": "13807",
"name": "High-Volume Contractor",
"identifier": null,
"ownerResourceId": 5,
"resourceTypeId": "1264",
"resourceTypeName": "Price Level",
"isSystem": false,
"createdAt": "2026-09-13T08:53:22.255Z",
"statusId": null,
"statusName": null,
"statusColor": null,
"archivedAt": null,
"icon": "box",
"properties": {
"name": "High-Volume Contractor",
"pct_bp": 5025
},
"confirmedKeys": {}
},
{
"resourceId": "13808",
"name": "Contractor",
"identifier": null,
"ownerResourceId": 5,
"resourceTypeId": "1264",
"resourceTypeName": "Price Level",
"isSystem": false,
"createdAt": "2026-09-13T08:53:24.139Z",
"statusId": null,
"statusName": null,
"statusColor": null,
"archivedAt": null,
"icon": "box",
"properties": {
"name": "Contractor",
"pct_bp": 5678
},
"confirmedKeys": {}
},
{
"resourceId": "13809",
"name": "Homeowner",
"identifier": null,
"ownerResourceId": 5,
"resourceTypeId": "1264",
"resourceTypeName": "Price Level",
"isSystem": false,
"createdAt": "2026-09-13T08:53:26.009Z",
"statusId": null,
"statusName": null,
"statusColor": null,
"archivedAt": null,
"icon": "box",
"properties": {
"name": "Homeowner",
"pct_bp": 6937
},
"confirmedKeys": {}
},
{
"resourceId": "13810",
"name": "Internal",
"identifier": null,
"ownerResourceId": 5,
"resourceTypeId": "1264",
"resourceTypeName": "Price Level",
"isSystem": false,
"createdAt": "2026-09-13T08:53:27.881Z",
"statusId": null,
"statusName": null,
"statusColor": null,
"archivedAt": null,
"icon": "box",
"properties": {
"name": "Internal",
"pct_bp": 0
},
"confirmedKeys": {}
}
],
"nextCursor": "13810"
}
What to notice. resourceId is a string. nextCursor is an opaque token: pass it back as &cursor=… for the
next page, and stop when it comes back null. Payment terms are the same call with typeKey=cab_payment_terms. ReSync
stores these numbers; it never multiplies them — computing a price is your application's job.
5. Bring in the customer by your own identifier
find-or-create is the idempotent way in: the same identifier from your system always answers the same resource. Its
body is snake_case, unlike everywhere else.
curl -s -X POST -H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \
-d '{"type_key":"cab_customer","external_system":"pdmac-sql","external_key":"cust-10442","name":"Harbor Homes","properties":{"kind":"contractor"}}' \
"$BASE/v1/resources/find-or-create"
From foc-create.json — status 201:
{
"resource_id": 24786,
"created": true
}
Called again with the same identifier:
From foc-find.json — status 200:
{
"resource_id": 24786,
"created": false
}
What to notice. The second call does not update anything — see Things to know. external_system
names an external system ReSync already knows; your administrator tells you which.
6. Set its properties
curl -s -X PATCH -H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \
-d '{"properties":{"customer_note":"call before delivery"}}' "$BASE/v1/resources/$CUSTOMER"
properties merges — keys you do not send are left alone. The answer is the resource as it now stands (a capture
is under PATCH /v1/resources/:id in endpoints.md).
Behind this call ReSync recorded an event saying which property changed, from what, to what, and that your key wrote it — see events.md.
7. Fill its fields
A customer's price level and payment terms are fields: a port that holds one choice. Three calls fill one:
GET /v1/resources/$CUSTOMER/ports— find the port by itsportName(level,terms); keep itsresourcePortIdanddefaultInteractionTypeId.GET /v1/resources/$CUSTOMER/ports/$PORT/legal-targets?scope=type— the resources the field may hold, each with averdictand the target port to use (viableTargetPorts[0]).POST /v1/resource-interactions— the attachment.
A picker over a long list narrows with q and pages with limit (here a line's product field over the price book):
From legal-targets-limit.json — status 200:
{
"sourcePort": {
"portId": 6707,
"portName": "product",
"direction": "out",
"maxConnections": 1,
"held": 0,
"capRemaining": 1
},
"candidates": [
{
"resourceId": 24699,
"name": "WD Laminate Modern Vertical 30",
"resourceTypeId": 191,
"verdict": "legal",
"reasons": [],
"viableTargetPorts": [
{
"portId": 6623,
"portName": "Sold as",
"direction": "in"
}
]
},
{
"resourceId": 24697,
"name": "WD Laminate Modern Vertical",
"resourceTypeId": 191,
"verdict": "legal",
"reasons": [],
"viableTargetPorts": [
{
"portId": 6622,
"portName": "Sold as",
"direction": "in"
}
]
},
{
"resourceId": 13812,
"name": "MSDEV Line 2 W30-1/2*12",
"resourceTypeId": 182,
"verdict": "legal",
"reasons": [],
"viableTargetPorts": [
{
"portId": 6621,
"portName": "Sold as",
"direction": "in"
}
]
},
{
"resourceId": 12934,
"name": "WOCM3",
"resourceTypeId": 187,
"verdict": "legal",
"reasons": [],
"viableTargetPorts": [
{
"portId": 3712,
"portName": "Sold as",
"direction": "in"
}
]
},
{
"resourceId": 12933,
"name": "OCM3",
"resourceTypeId": 187,
"verdict": "legal",
"reasons": [],
"viableTargetPorts": [
{
"portId": 3711,
"portName": "Sold as",
"direction": "in"
}
]
}
],
"truncated": true,
"total": 3928
}
curl -s -X POST -H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \
-d '{"sourceResourceId":13811,"targetResourceId":7369,"interactionTypeId":135,"sourcePortId":1503,"targetPortId":1529}' \
"$BASE/v1/resource-interactions"
From interaction-create.json — status 201:
{
"interactionId": 2147,
"sourceResourceId": 13811,
"targetResourceId": 7369,
"interactionTypeId": 135,
"contextId": null
}
A field holds one choice: to change it, send replaceInteractionId with the connection it replaces.
8. The bid and its three fields
The bid is another find-or-create (type_key: "cab_bid"), a PATCH for its properties (for example tax_rate_bp),
and three fields filled exactly as in step 7: customer (to the customer), level and terms. Read it back with
GET /v1/resources/$BID; its edges list the three — see the converted bid in step 15.
9. A design set inside the bid
Create the set with find-or-create (type_key: "cab_design_set"), then put it inside the bid:
curl -s -X POST -H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \
-d '{"childResourceId":24788}' "$BASE/v1/resources/$BID/members"
From members-enrol.json — status 201:
{
"componentId": 253767,
"parentResourceId": 24787,
"childResourceId": 24788,
"componentRole": null,
"sourceSlotId": null,
"sourceRuleId": null,
"componentStatus": "active",
"statusChangedAt": "2026-10-20T04:44:03.377Z",
"sortOrder": 0,
"properties": {},
"createdAt": "2026-10-20T04:44:03.377Z"
}
childResourceId is a JSON number. A design set's ten material and hardware fields are filled like any field
(step 7); a line inherits each one unless it chooses its own.
10. Lines, each with its product
For each line: find-or-create (type_key: "cab_line"), POST /v1/resources/$SET/members, a PATCH for its
quantities and prices, and its product field — legal-targets with q=<the product's identifier>&limit=5, then the
attachment. A line never carries the product identifier itself; it points at the product.
11. Read the tree back
GET /v1/resources/$SET/members lists what a container holds:
From members-read.json — status 200:
[
{
"childResourceId": 24786,
"childResourceTypeId": 3425,
"childName": "Capture line",
"childTypeName": "Bid Line",
"componentStatus": "active",
"createdAt": "2026-10-19T05:24:35.450Z",
"roles": [],
"enrollmentCount": 1,
"applicableActions": []
},
{
"childResourceId": 24789,
"childResourceTypeId": 3425,
"childName": "Capture line two",
"childTypeName": "Bid Line",
"componentStatus": "active",
"createdAt": "2026-10-19T05:24:35.507Z",
"roles": [],
"enrollmentCount": 1,
"applicableActions": []
}
]
Member rows carry no status and no properties. To know each line's status, read each line
(GET /v1/resources/:id) — one request per child.
12. Preview what a status move needs
GET /v1/state-transitions?resourceId=$SET&fromStatusId=<its statusId> lists the moves; each has a transitionId.
The checklist for one move:
curl -s -H "Authorization: Bearer $TOKEN" "$BASE/v1/resources/$SET/requirements?transitionId=823"
From requirements-read.json — status 200:
{
"requirements": [
{
"requirementId": 2395,
"name": "Contents compatible",
"blocking": "hard",
"satisfied": true,
"missing": [],
"leaves": [
{
"leaf": "subtree_compat",
"label": "No design set settings conflicts",
"caption": "nothing inside receives a setting yet",
"satisfied": true,
"attestable": false,
"actionLabel": null,
"actor": null,
"actorRoles": [],
"payloadFields": [],
"blockedByActor": false,
"satisfiedEver": false,
"mayEmitUnvocab": false,
"violations": [],
"violationCount": 0,
"subtreeCompatVacuous": true
}
]
},
{
"requirementId": 1528,
"name": "R-SET-FREEZE — all lines frozen",
"blocking": "hard",
"satisfied": false,
"missing": [
"All lines frozen"
],
"leaves": [
{
"leaf": "members",
"label": "All lines frozen",
"caption": "0/1 members at required status",
"satisfied": false,
"attestable": false,
"actionLabel": null,
"actor": null,
"actorRoles": [],
"payloadFields": [],
"blockedByActor": false,
"satisfiedEver": false,
"mayEmitUnvocab": false,
"memberTotal": 1,
"memberSatisfied": 0
}
]
}
]
}
13. Freeze bottom-up
A set freezes only when every line in it is frozen. Ask too early and the answer is 422 with the same checklist:
From patch-status-422-requirements.json — status 422:
{
"error": "Transition blocked by unmet requirements",
"requirements": [
{
"requirementId": 2395,
"name": "Contents compatible",
"blocking": "hard",
"satisfied": true,
"missing": [],
"leaves": [
{
"leaf": "subtree_compat",
"label": "No design set settings conflicts",
"caption": "nothing inside receives a setting yet",
"satisfied": true,
"attestable": false,
"actionLabel": null,
"actor": null,
"actorRoles": [],
"payloadFields": [],
"blockedByActor": false,
"satisfiedEver": false,
"mayEmitUnvocab": false,
"violations": [],
"violationCount": 0,
"subtreeCompatVacuous": true
}
]
},
{
"requirementId": 1528,
"name": "R-SET-FREEZE — all lines frozen",
"blocking": "hard",
"satisfied": false,
"missing": [
"All lines frozen"
],
"leaves": [
{
"leaf": "members",
"label": "All lines frozen",
"caption": "0/1 members at required status",
"satisfied": false,
"attestable": false,
"actionLabel": null,
"actor": null,
"actorRoles": [],
"payloadFields": [],
"blockedByActor": false,
"satisfiedEver": false,
"mayEmitUnvocab": false,
"memberTotal": 1,
"memberSatisfied": 0
}
]
}
]
}
So freeze each line first:
curl -s -X PATCH -H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \
-d '{"toStatusId":1319}' "$BASE/v1/resources/$LINE/status"
From patch-status-200.json — status 200:
{
"resourceId": 24789,
"fromStatusId": 1318,
"statusId": 1319
}
Then the set. Freezing records a snapshot of the line — see resource.captured in events.md. A frozen
line is read-only, and there is no way back to Draft.
14. Submit
Record the totals your application computed, then move the bid to Sent:
curl -s -X POST -H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \
-d '{"eventType":"bid.sent","payload":{"subtotal_cents":7001,"discount_cents":0,"delivery_cents":0,"tax_cents":578,"install_cents":0,"total_cents":7579,"tax_rate_bp":825}}' \
"$BASE/v1/resources/$BID/attestations"
From attestation-create.json — status 201:
{
"eventUlid": "01M5BSZAZ3SV3132XNPYTKV77X",
"eventType": "bid.sent",
"resourceId": 24787,
"actorResourceId": 24784
}
Then PATCH /v1/resources/$BID/status to Sent. Submit checks that the bid holds at least one design set, that every design
set and install line is frozen, that the totals are recorded, and that the bid's level and terms are filled. A sent bid is read-only.
15. Accept, convert, find the order
The customer's acceptance is the bid.accepted attestation; the bid then moves to Accepted on its own. Convert is a
status move followed by the bid.converted attestation; ReSync then creates the order, a moment later. Read the bid
until its derivatives lists it:
From get-derivatives-after-convert.json — status 200:
{
"resourceId": "24787",
"resourceTypeId": "176",
"ownerResourceId": "5",
"name": "Harbor Homes — kitchen",
"identifier": null,
"properties": {
"tax_rate_bp": 825
},
"statusId": "1315",
"isVerified": false,
"createdAt": "2026-10-20T04:44:01.410Z",
"archivedAt": null,
"derivedFromTypeId": null,
"resourceTypeName": "Bid",
"propertySchema": {
"tax_rate_bp": {
"type": "number",
"label": "Tax rate (basis points)",
"derivable": false
}
},
"declaredPropertySchema": {
"tax_rate_bp": {
"type": "number",
"label": "Tax rate (basis points)",
"derivable": false
}
},
"orgName": "Popular Design Mill & Cabinet, Inc.",
"ownerOrgId": "1",
"canvasMode": null,
"statusName": "Converted",
"statusColorCode": null,
"icon": "box",
"lifecycleId": 108,
"canvasId": null,
"derivedFrom": [],
"derivatives": [
{
"resourceId": 24790,
"name": "Harbor Homes — kitchen",
"typeName": "Order",
"createdAt": "2026-10-20T04:44:05.245Z",
"archived": false
}
],
"derivedKeys": [],
"edges": [
{
"interactionId": 2572,
"typeName": "bid_for",
"direction": "out",
"otherResourceId": 24786,
"otherResourceName": "Harbor Homes",
"thisResourcePortId": 6700
},
{
"interactionId": 2573,
"typeName": "priced_at",
"direction": "out",
"otherResourceId": 13808,
"otherResourceName": "Contractor",
"thisResourcePortId": 6701
},
{
"interactionId": 2574,
"typeName": "pays_on",
"direction": "out",
"otherResourceId": 14013,
"otherResourceName": "Net 30",
"thisResourcePortId": 6702
}
],
"confirmedKeys": [],
"readOnly": {
"statusName": "Converted"
}
}
Things to know
- Every
find-or-createbinds one identifier in your external system — one per resource you create that way. A bid with one design set and five lines is seven identifiers; the customer is one more. - A second
find-or-createwith the same identifier changes nothing. It answers200with the existing resource and ignores thenameandpropertiesyou sent. To change a resource,PATCHit. - Budget about 8 requests per line, on top of roughly 130 for the bid itself (customer, bid, fields, a design set, freezes, Submit, accept, convert). A 40-line bid is about 450 requests.
- The rate limit is 300 requests per minute per key by default, counted in a fixed one-minute window that starts
with your first request. ReSync can set a different limit for your key — ask your administrator; your key's own
limit is in every response's
x-ratelimit-limit. On429, waitretry-afterseconds and continue. - Member rows carry no status. Reading a tree's statuses costs one
GETper child. - A freeze or a Submit records a snapshot (
resource.captured). Your key sees the snapshot's own property values; the settings and the product it photographed are kept on the record but are not passed to a key. - Who approves. An attestation or status move is attributed to your key's own service identity unless you name a
person:
actorResourceIdmay name any person of your organization; someone outside it is403 actor_not_readable. - Identifiers are unique per external system across every organization, not only yours. Prefix them with something that is yours.
- Freezing is one-way, and a sent bid is final. Nothing leaves Frozen (
409 Invalid status transition). A revision is a new bid; linking it to the one it replaces is not yet available to keys.
Where to go next
- auth-and-scopes.md — scopes, rate limits, request ids.
- endpoints.md — every door, with parameters and errors.
- errors.md — every error code and what to do about it.
- conventions.md — the rules that apply everywhere, and what you cannot do yet.