REST quickstart
Four steps from nothing to a working integration: get a token, read a list, make one change that is safe to send twice, and read what an error says. The REST API page has the full rules, the API explorer every operation.
On this page
Section titled “On this page”- Get a token
- Read a list
- Make a change safely
- Read the errors
- See also
Get a token
Section titled “Get a token”Every request carries Authorization: Bearer <token>: an OAuth access token of a Floormode person whose role includes Use the API and AI agents (REST, MCP). The token can do what that person can do, and nothing more. To give an integration less than your own access, invite a person for it with a narrower role in Settings → Team.
Where to get the token is published:
curl https://prod.floormode.app/.well-known/oauth-protected-resource{ "resource": "https://prod.floormode.app/mcp", "authorization_servers": ["https://<sign-in domain>"], "bearer_methods_supported": ["header"]}Point any OAuth library at that document: it finds the sign-in, registers its client, and signs the person in once in a browser (authorization code with PKCE). Ask for the resource above. The same token works on /api/v1 and on the MCP server. Access tokens are short-lived; let your library renew them with its refresh token.
Read a list
Section titled “Read a list”Open orders that are short of stock, two at a time:
curl "https://prod.floormode.app/api/v1/orders/queue?allocationState=short&limit=2" \ -H "Authorization: Bearer $TOKEN"A success is always { "data": … }. A list answers a page of rows, whether the list was cut (capped), and a cursor for the next page:
{ "data": { "rows": [ { "_id": "orders_01K8C4Z3W9V7RS2A6J3QPMB5EN", "shopifyOrderId": "6253011468585", "name": "#1038", "allocationState": "short", "shortSkuCount": 1, "ageMs": 93600000 } ], "capped": true, "cursor": "1761036000000:orders_01K8C4Z3W9V7RS2A6J3QPMB5EN" }}Each row carries more fields than shown here; the explorer lists them. For the next page, send the same request with &cursor=<cursor>, until cursor is null. Pass the cursor back as it came; never build one.
Query values are read as their declared type, so limit=2 is the number 2. A parameter the operation does not have is refused with 400 unknown_parameter, which names the ones it accepts.
Make a change safely
Section titled “Make a change safely”Put an order on hold because its address is incomplete:
curl -X POST "https://prod.floormode.app/api/v1/holds/apply-for-orders" \ -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" \ -d '{ "shopifyOrderIds": ["6253011468585"], "reason": "address_issue", "note": "Street number missing", "requestKey": "7c4f0a52-2f0e-4c1e-9a41-0b8f6c2d1e33" }'{ "data": { "applied": 1, "skipped": [] } }requestKey is your own key for this one change, for example a new UUID. Keep it when you send the request again after a timeout:
- the same key with the same body answers the first answer again, and nothing happens twice;
- the same key with a different body is refused:
{ "error": "This request key was already used for a different request. Use a new key.", "code": "conflict", "details": { "code": "idempotency_key_reused" }}Operations that take a key say so in the explorer (requestKey or idempotencyKey). For one without a key, read before you send it again: for example, after a lost answer to picking_create_batch, list the open batches with picking_list_batches first.
Read the errors
Section titled “Read the errors”An error is { "error": "<sentence>", "code": "<code>" }, and details.code when Floormode names the exact reason. Branch on the codes; the sentence is written for people and may change.
A request whose input does not fit the operation’s schema (a missing field, a wrong type, limit=0) is the one error without a code: it is answered 400 with the schema’s own list of what failed.
{ "error": "Invalid input", "issues": [ { "origin": "number", "code": "too_small", "minimum": 1, "inclusive": true, "path": ["limit"], "message": "Too small: expected number to be >=1" } ]}| HTTP | code | Means |
|---|---|---|
| 400 | none, issues instead | The input does not fit the operation’s schema |
| 400 | unknown_parameter | A query parameter the operation does not have |
| 400 | invalid_input | The values fit, but Floormode refused them; the sentence says why |
| 401 | none | No token, or one that is not valid for Floormode |
| 403 | plan_required | Your plan does not include the API (it names requiredPlan) |
| 403 | forbidden | The person may not do this; details.code is permission_required |
| 404 | not_found | The record does not exist |
| 409 | conflict | The change cannot be applied as asked; the sentence says why |
| 429 | rate_limited | The store’s 60 calls for this minute are used up; send it again after Retry-After |
See also
Section titled “See also”- Connect an AI agent: the same operations through an AI client
- REST API: requests, responses, limits and changes in full
- API explorer: every operation with its inputs
- Webhooks: have Floormode call your system when something happens