# ReSync API v1 — runnable examples # # VS Code REST Client (humao.rest-client) or JetBrains HTTP Client. # Set the two variables, then click Send Request above any block. # # Blocks 1–8 are single reads. From block 10 on, the file walks one whole bid in the order of quickstart.md: each # request is named (# @name …) and later blocks read ids from earlier answers ({{customer.response.body.resource_id}}), # so run them top to bottom. Ids that come from YOUR data (a price level, a port, a status) are variables at the top of # their block — read them from the answer named beside them and paste them in. @baseUrl = https://api.limnal.dev @token = replace-with-your-key ### 1 — Who am I, and what may I touch? GET {{baseUrl}}/v1/api-keys/self Authorization: Bearer {{token}} ### 2 — List resources of a type (first page) GET {{baseUrl}}/v1/resources?typeKey=cab_bid&limit=2 Authorization: Bearer {{token}} ### 2b — Next page: paste nextCursor from the response above GET {{baseUrl}}/v1/resources?typeKey=cab_bid&limit=2&cursor=968 Authorization: Bearer {{token}} ### 2c — Include properties, so you do not fetch each row separately GET {{baseUrl}}/v1/resources?typeKey=cab_bid&limit=2&include=properties Authorization: Bearer {{token}} ### 3 — Read one resource GET {{baseUrl}}/v1/resources/13813 Authorization: Bearer {{token}} ### 4 — Change a property (merges; keys you omit are untouched) PATCH {{baseUrl}}/v1/resources/14211 Authorization: Bearer {{token}} Content-Type: application/json { "properties": { "customer_note": "call before delivery" } } ### 5 — Read the history, newest first GET {{baseUrl}}/v1/resources/14211/events?limit=3 Authorization: Bearer {{token}} ### 5b — Only changes, not messages GET {{baseUrl}}/v1/resources/14211/events?limit=10&filter=changes Authorization: Bearer {{token}} ### 6 — Send your own correlation id; it is echoed on the response GET {{baseUrl}}/v1/resources/13813 Authorization: Bearer {{token}} x-request-id: my-sync-run-0001 ### 7 — 403: a resource owned by another organization GET {{baseUrl}}/v1/resources/7 Authorization: Bearer {{token}} ### 8 — 400: an include member that does not exist GET {{baseUrl}}/v1/resources?typeKey=cab_bid&include=foo Authorization: Bearer {{token}} # ── The whole bid (quickstart.md, steps 2–15) ────────────────────────────────────────────────────────────────────── ### 10 — Type codes → ids (keep the map) GET {{baseUrl}}/v1/resource-types Authorization: Bearer {{token}} ### 11 — One type in full: a bid line's containment limit (paste cab_line's resourceTypeId from block 10) @lineTypeId = 3425 GET {{baseUrl}}/v1/resource-types/{{lineTypeId}} Authorization: Bearer {{token}} ### 12 — The attestation vocabulary (bid.sent, bid.accepted, bid.accepted_internally, bid.converted) GET {{baseUrl}}/v1/attestation-event-types Authorization: Bearer {{token}} ### 13 — Price levels and payment terms GET {{baseUrl}}/v1/resources?typeKey=cab_pricing_level&limit=10&include=properties Authorization: Bearer {{token}} ### GET {{baseUrl}}/v1/resources?typeKey=cab_payment_terms&limit=10&include=properties Authorization: Bearer {{token}} ### 14 — The customer, by your own identifier (snake_case body; idempotent) # external_system must name an external system ReSync already knows — ask your administrator which one is yours; # "resync" is refused (ReSync's own identifiers are not an external system). Identifiers are unique per system across # EVERY organization, not only yours, so prefix them with something that is yours. # @name customer POST {{baseUrl}}/v1/resources/find-or-create Authorization: Bearer {{token}} Content-Type: application/json { "type_key": "cab_customer", "external_system": "pdmac-sql", "external_key": "yourco-cust-10442", "name": "Harbor Homes", "properties": { "kind": "contractor" } } ### 14b — The same identifier again: 200, the same resource, the body ignored POST {{baseUrl}}/v1/resources/find-or-create Authorization: Bearer {{token}} Content-Type: application/json { "type_key": "cab_customer", "external_system": "pdmac-sql", "external_key": "yourco-cust-10442" } ### 15 — The customer's properties PATCH {{baseUrl}}/v1/resources/{{customer.response.body.resource_id}} Authorization: Bearer {{token}} Content-Type: application/json { "properties": { "customer_note": "call before delivery" } } ### 16 — The customer's ports (find `level` and `terms`: resourcePortId, defaultInteractionTypeId) GET {{baseUrl}}/v1/resources/{{customer.response.body.resource_id}}/ports Authorization: Bearer {{token}} ### 17 — What the `level` field may hold (paste the port id from block 16) @levelPortId = 0 GET {{baseUrl}}/v1/resources/{{customer.response.body.resource_id}}/ports/{{levelPortId}}/legal-targets?scope=type Authorization: Bearer {{token}} ### 18 — Fill the field (target = a legal candidate; targetPortId = its viableTargetPorts[0].portId) @levelId = 0 @levelTargetPortId = 0 @pricedAtTypeId = 0 POST {{baseUrl}}/v1/resource-interactions Authorization: Bearer {{token}} Content-Type: application/json { "sourceResourceId": {{customer.response.body.resource_id}}, "targetResourceId": {{levelId}}, "interactionTypeId": {{pricedAtTypeId}}, "sourcePortId": {{levelPortId}}, "targetPortId": {{levelTargetPortId}} } ### 19 — Read the customer back: its fields are in `edges` GET {{baseUrl}}/v1/resources/{{customer.response.body.resource_id}} Authorization: Bearer {{token}} ### 20 — The bid # @name bid POST {{baseUrl}}/v1/resources/find-or-create Authorization: Bearer {{token}} Content-Type: application/json { "type_key": "cab_bid", "external_system": "pdmac-sql", "external_key": "yourco-bid-20017", "name": "Harbor Homes — kitchen" } ### 20b — The bid's properties PATCH {{baseUrl}}/v1/resources/{{bid.response.body.resource_id}} Authorization: Bearer {{token}} Content-Type: application/json { "properties": { "tax_rate_bp": 825 } } ### 20c — The bid's ports: fill `customer`, `level` and `terms` as in blocks 17–18 GET {{baseUrl}}/v1/resources/{{bid.response.body.resource_id}}/ports Authorization: Bearer {{token}} ### 21 — A design set # @name set POST {{baseUrl}}/v1/resources/find-or-create Authorization: Bearer {{token}} Content-Type: application/json { "type_key": "cab_design_set", "external_system": "pdmac-sql", "external_key": "yourco-bid-20017-set-1", "name": "Kitchen" } ### 22 — Put the set inside the bid (childResourceId is a JSON number) POST {{baseUrl}}/v1/resources/{{bid.response.body.resource_id}}/members Authorization: Bearer {{token}} Content-Type: application/json { "childResourceId": {{set.response.body.resource_id}} } ### 23 — A line # @name line POST {{baseUrl}}/v1/resources/find-or-create Authorization: Bearer {{token}} Content-Type: application/json { "type_key": "cab_line", "external_system": "pdmac-sql", "external_key": "yourco-bid-20017-line-1", "name": "Sink base", "properties": { "qty": 1, "area": "Kitchen" } } ### 23b — Put the line inside the set POST {{baseUrl}}/v1/resources/{{set.response.body.resource_id}}/members Authorization: Bearer {{token}} Content-Type: application/json { "childResourceId": {{line.response.body.resource_id}} } ### 23c — The line's prices (your application computes them) PATCH {{baseUrl}}/v1/resources/{{line.response.body.resource_id}} Authorization: Bearer {{token}} Content-Type: application/json { "properties": { "unit_cents": 7001, "ext_cents": 7001 } } ### 24 — Find the product: narrow the line's `product` field with q (its identifier) and a limit @productPortId = 0 GET {{baseUrl}}/v1/resources/{{line.response.body.resource_id}}/ports/{{productPortId}}/legal-targets?scope=type&q=W3030&limit=5 Authorization: Bearer {{token}} ### 24b — Attach it (as block 18) @productId = 0 @productTargetPortId = 0 @sellsTypeId = 0 POST {{baseUrl}}/v1/resource-interactions Authorization: Bearer {{token}} Content-Type: application/json { "sourceResourceId": {{line.response.body.resource_id}}, "targetResourceId": {{productId}}, "interactionTypeId": {{sellsTypeId}}, "sourcePortId": {{productPortId}}, "targetPortId": {{productTargetPortId}} } ### 25 — Take a member out of a container (the path id is the MEMBER) POST {{baseUrl}}/v1/resources/{{line.response.body.resource_id}}/exit Authorization: Bearer {{token}} Content-Type: application/json { "containerId": {{set.response.body.resource_id}} } ### 25b — …and put it back (enrol again, as block 23b) POST {{baseUrl}}/v1/resources/{{set.response.body.resource_id}}/members Authorization: Bearer {{token}} Content-Type: application/json { "childResourceId": {{line.response.body.resource_id}} } ### 26 — Move a member from one container to another in one step @otherSetId = 0 POST {{baseUrl}}/v1/resources/{{line.response.body.resource_id}}/move Authorization: Bearer {{token}} Content-Type: application/json { "fromContainerId": {{set.response.body.resource_id}}, "toContainerId": {{otherSetId}} } ### 26b — …and back (the rest of the walk expects the line in its set) POST {{baseUrl}}/v1/resources/{{line.response.body.resource_id}}/move Authorization: Bearer {{token}} Content-Type: application/json { "fromContainerId": {{otherSetId}}, "toContainerId": {{set.response.body.resource_id}} } ### 27 — Where is it? GET {{baseUrl}}/v1/resources/{{line.response.body.resource_id}}/containers Authorization: Bearer {{token}} ### 28 — Which lines may still go into this set? GET {{baseUrl}}/v1/resources/search?q=Sink&types=cab_line&enrollInto={{set.response.body.resource_id}} Authorization: Bearer {{token}} ### 29 — Read the tree back (member rows carry no status: read each child for that) GET {{baseUrl}}/v1/resources/{{bid.response.body.resource_id}}/members Authorization: Bearer {{token}} ### GET {{baseUrl}}/v1/resources/{{set.response.body.resource_id}}/members Authorization: Bearer {{token}} ### 30 — The set's legal moves (fromStatusId = the set's statusId from block 29's child read) @setStatusId = 0 GET {{baseUrl}}/v1/state-transitions?resourceId={{set.response.body.resource_id}}&fromStatusId={{setStatusId}} Authorization: Bearer {{token}} ### 31 — What freezing the set needs (transitionId from block 30) @setFreezeTransitionId = 0 GET {{baseUrl}}/v1/resources/{{set.response.body.resource_id}}/requirements?transitionId={{setFreezeTransitionId}} Authorization: Bearer {{token}} ### 32 — Freeze the line first (toStatusId from its own legal moves) @frozenStatusId = 0 PATCH {{baseUrl}}/v1/resources/{{line.response.body.resource_id}}/status Authorization: Bearer {{token}} Content-Type: application/json { "toStatusId": {{frozenStatusId}} } ### 32b — Then the set (before its lines, this answers 422 with the requirements) @setFrozenStatusId = 0 PATCH {{baseUrl}}/v1/resources/{{set.response.body.resource_id}}/status Authorization: Bearer {{token}} Content-Type: application/json { "toStatusId": {{setFrozenStatusId}} } ### 33 — The line's history: the snapshot its freeze recorded (resource.captured) GET {{baseUrl}}/v1/resources/{{line.response.body.resource_id}}/events?limit=10 Authorization: Bearer {{token}} ### 34 — Submit, part 1: record the totals POST {{baseUrl}}/v1/resources/{{bid.response.body.resource_id}}/attestations Authorization: Bearer {{token}} Content-Type: application/json { "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 } } ### 34b — Submit, part 2: move to Sent (toStatusId from the bid's legal moves) @sentStatusId = 0 PATCH {{baseUrl}}/v1/resources/{{bid.response.body.resource_id}}/status Authorization: Bearer {{token}} Content-Type: application/json { "toStatusId": {{sentStatusId}} } ### 35 — The customer accepted (the bid then moves to Accepted on its own) POST {{baseUrl}}/v1/resources/{{bid.response.body.resource_id}}/attestations Authorization: Bearer {{token}} Content-Type: application/json { "eventType": "bid.accepted", "payload": {} } ### 35b — OR accept internally, naming the person who approved (any person of your organization) @approverPersonId = 0 POST {{baseUrl}}/v1/resources/{{bid.response.body.resource_id}}/attestations Authorization: Bearer {{token}} Content-Type: application/json { "eventType": "bid.accepted_internally", "payload": {}, "actorResourceId": {{approverPersonId}} } ### 36 — Convert, part 1: move to Converted @convertedStatusId = 0 PATCH {{baseUrl}}/v1/resources/{{bid.response.body.resource_id}}/status Authorization: Bearer {{token}} Content-Type: application/json { "toStatusId": {{convertedStatusId}} } ### 36b — Convert, part 2: record it (ReSync then creates the order) POST {{baseUrl}}/v1/resources/{{bid.response.body.resource_id}}/attestations Authorization: Bearer {{token}} Content-Type: application/json { "eventType": "bid.converted", "payload": {} } ### 37 — Find the order: the bid's `derivatives` (it appears a moment after 36b) GET {{baseUrl}}/v1/resources/{{bid.response.body.resource_id}} Authorization: Bearer {{token}} ### GET {{baseUrl}}/v1/resources?typeKey=cab_order&q=Harbor&limit=10 Authorization: Bearer {{token}} ### 38 — 409: a frozen line cannot go back to Draft @draftStatusId = 0 PATCH {{baseUrl}}/v1/resources/{{line.response.body.resource_id}}/status Authorization: Bearer {{token}} Content-Type: application/json { "toStatusId": {{draftStatusId}} } ### 39 — 409: a sent bid's properties are read-only PATCH {{baseUrl}}/v1/resources/{{bid.response.body.resource_id}} Authorization: Bearer {{token}} Content-Type: application/json { "properties": { "customer_note": "late change" } }