Developer quickstart

Get a token for your organization, read your stock, and send a write you can retry without doing it twice. About ten minutes.

Before you start

  • Work in your sandbox. Every organization has one: a copy of its settings with sample data (or a copy of what it imported), that nothing outside Manifold is connected to. Open it from the organization menu in the admin: choose Open sandbox. It uses the same addresses as your live organization; its id starts org_test_. From code, choose it the way step 2 chooses any organization, after opening it.
  • A Manifold account in an organization, with a password. If you sign in with Google, the steps below do not apply; an agent can connect instead (see AI agents).
  • A role that can read and receive stock. What each operation needs is on its page, under Access.
  • curl, or any language that can send HTTP. The examples also show JavaScript's fetch.

Each Manifold service has its own address: inventory is https://inventory.getmanifold.io, sign-in is https://auth.getmanifold.io. The API reference lists every service's address.

1. Sign in

Send your email and password. The answer's set-auth-token header is your session token.

curl
curl -i -X POST 'https://auth.getmanifold.io/api/auth/sign-in/email' \
  -H 'Content-Type: application/json' \
  -d '{ "email": "you@example.com", "password": "your-password" }'

Keep it in a variable:

shell
export SESSION_TOKEN='…the set-auth-token value…'

The session token proves who you are. It does not name an organization, and no Manifold service accepts it. The next two steps turn it into a token that does.

2. Choose the organization

List the organizations you belong to, and note the id of the one you want. It starts org_.

curl
curl 'https://auth.getmanifold.io/api/auth/organization/list' \
  -H "Authorization: Bearer $SESSION_TOKEN"

Make it the session's active organization:

curl
curl -X POST 'https://auth.getmanifold.io/api/auth/organization/set-active' \
  -H "Authorization: Bearer $SESSION_TOKEN" \
  -H 'Content-Type: application/json' \
  -d '{ "organizationId": "org_…" }'

To work in the sandbox instead, open it with the live organization's id. Make a sbx_ id once (see Ids you make) and keep it. The call moves the session into the sandbox, making it the first time:

curl
curl -X POST 'https://auth.getmanifold.io/api/auth/sandbox/org_…/enter' \
  -H "Authorization: Bearer $SESSION_TOKEN" \
  -H 'Content-Type: application/json' \
  -d '{ "sandboxId": "sbx_…" }'

3. Get a token

curl
curl 'https://auth.getmanifold.io/api/auth/token' \
  -H "Authorization: Bearer $SESSION_TOKEN"
Response · 200
{ "token": "eyJhbGciOiJFZERTQSIs…" }
shell
export MANIFOLD_TOKEN='…the token value…'

This token carries your organization and your roles, and every service checks it. It lasts 15 minutes. When a call answers 401, ask for a new one with the same session token; you do not need to sign in again.

More on tokens, including the single-use tokens apps use: Authentication and app tokens.

4. Make a first call

Read the first five SKUs in your inventory:

curl
curl -X GET 'https://inventory.getmanifold.io/items?limit=5' \
  -H "Authorization: Bearer $MANIFOLD_TOKEN"
JavaScript (fetch)
const response = await fetch("https://inventory.getmanifold.io/items?limit=5", {
  method: "GET",
  headers: { Authorization: `Bearer ${process.env.MANIFOLD_TOKEN}` },
});
if (!response.ok) throw new Error(`${response.status}: ${await response.text()}`);
const answer = await response.json();

The answer is a page of items with their stock at each location. Lists take limit and offset; see GET /items for every filter.

If the call is refused, the status says why:

401
The token is missing or has expired. Get a new one (step 3).
403
Your roles do not hold the scope this operation needs. The operation's page names it.
402
The organization's subscription has lapsed. Reads still work; writes do not.

5. Write, and retry safely

Every write that records something carries a key you choose. For receiving stock the key is reference: the document the stock came in on, such as a delivery note number.

This adds stock. Run it in your sandbox, with a SKU from step 4 in place of WIDGET-BLUE.

curl
curl -X POST 'https://inventory.getmanifold.io/items/WIDGET-BLUE/receive' \
  -H "Authorization: Bearer $MANIFOLD_TOKEN" \
  -H 'Content-Type: application/json' \
  -d '{
  "quantity": 10,
  "reference": "dock-note-8841"
}'
JavaScript (fetch)
const response = await fetch("https://inventory.getmanifold.io/items/WIDGET-BLUE/receive", {
  method: "POST",
  headers: { Authorization: `Bearer ${process.env.MANIFOLD_TOKEN}`, "Content-Type": "application/json" },
  body: JSON.stringify({
    "quantity": 10,
    "reference": "dock-note-8841"
  }),
});
if (!response.ok) throw new Error(`${response.status}: ${await response.text()}`);
const answer = await response.json();

If it answers 409 with MirroredFromSource, your stock is still being copied from the system you are moving from, and only that system changes it until you go live.

For an untracked SKU, ten units of WIDGET-BLUE are now on hand. (A serial- or batch-tracked SKU's units wait to be identified first.) Send exactly the same request again, as a network retry would. It answers 200 with the item, records nothing and moves no stock: Manifold has seen that reference, so it returns the first answer. You still have ten, not twenty.

So the rule for every write is:

  • No answer, or a 5xx? Send the same request again, with the same key. It is applied once.
  • A 401? The token expired. Get a new one and send the same request again.
  • Any other 4xx, on a first try? The request was refused and nothing was recorded. Sending it again unchanged gets the same answer, so fix what the body names first. See Errors.
  • A 4xx on a retry? Your first call may have landed. A few operations answer a retry with a refusal because the record has moved on: a retried pick or pack answers 409 ShipmentNotInState. Read the record before doing anything else. Each operation's Errors marks these, and the full list says what to check.
  • A new piece of work? Use a new key. A key you reuse for different work is answered as the old work.

Each operation's page says what its key is under Retries. The rule in full: Idempotency and retries. See it end to end: What happens when you get it wrong, or send it twice.

Next

  • Flows: whole jobs done through the API, step by step.
  • Concepts: ids, facts, errors, scopes and the other rules every API follows.
  • POST /items/{sku}/receive: the operation you just called, with its access and the facts it records.