Fulfillment Manager API · customer
The customer accepts the quote the link opens
POST /customer/{tenantId}/{token}/accept
The customer accepts the quote the link opens: it is placed as an order under its number, as POST /orders/:orderId/place places one, with the customer (the link) as the actor — appends fulfillment.order-created and the allocation behind it.
409 QuoteNotAnswerable while it is being revised (not-issued), past its validUntil (expired), after a decline (declined), once cancelled, or when the business must look at it first (needs-review: a price or an order rule moved since it was issued); 409 CustomerActionHeld while the organization is read-only — accepting acts for the business — or its mode cannot be read; 503 InventoryUnavailable when stock cannot be asked. Idempotent by state: a quote is placed once, so a retried accept answers the page as it stands and appends nothing.
Access
Public: a customer holds no account: the signed link token in the path is the credential, checked before anything is read
No token: the link, the claim or the first message is the credential, as the description says.
How scopes come from roles: Scopes and roles. Getting a token: Authentication and app tokens.
Retries
Idempotent by state: a quote is placed once, so a retried accept answers the page as it stands and appends nothing.
Why every write carries a key: Idempotency and retries.
Facts appended
fulfillment.order-created
What a fact is: Facts and the journal.
AI agent tool
No agent tool. the customer's own answer through their signed link; staff and agents place a quote with fulfillment_place_order
Connecting an agent: AI agents.
Example
curl -X POST 'https://fulfillment.getmanifold.io/customer/org_01a1586e-f9f6-7a8b-9c7d-6e5f4a3b2c1d/01a1565263f77a819b92d8e9f0a1b2c3.01a156531a2b7c3d8e4f5a6b7c8d9e0f.q0W8rTz3mPd5LkXv2NfYbA/accept'const response = await fetch("https://fulfillment.getmanifold.io/customer/org_01a1586e-f9f6-7a8b-9c7d-6e5f4a3b2c1d/01a1565263f77a819b92d8e9f0a1b2c3.01a156531a2b7c3d8e4f5a6b7c8d9e0f.q0W8rTz3mPd5LkXv2NfYbA/accept", {
method: "POST",
});
if (!response.ok) throw new Error(`${response.status}: ${await response.text()}`);
const answer = await response.json();{
"tenantId": "org_01a1586e-f9f6-7a8b-9c7d-6e5f4a3b2c1d",
"linkId": "cpl_01a15653-1a2b-7c3d-8e4f-5a6b7c8d9e0f",
"orderId": "ord_01a15652-63f7-7a81-9b92-d8e9f0a1b2c3",
"country": "AU",
"timeZone": "Australia/Sydney",
"actions": {
"accept": false,
"decline": false
},
"document": {
"kind": "quote",
"status": "accepted",
"number": "SO-01041",
"quote": {
"currency": "AUD",
"reference": "QUOTE-HARBOUR-OCT",
"issuedAt": "2026-10-19T22:44:30.812Z",
"validUntil": "2026-11-02T00:00:00.000Z",
"companyName": "Harbour Ceramics",
"lines": [
{
"sku": "MUG-SPECKLE",
"name": "Speckled stoneware mug",
"quantity": 48,
"unitPriceCents": 2100,
"pricesIncludeTax": false,
"discountCents": 0,
"totalCents": 100800,
"taxCents": 10080,
"taxClasses": [
"standard"
]
},
{
"sku": "BOWL-SALT-L",
"name": "Salt-glaze serving bowl, large",
"quantity": 6,
"unitPriceCents": 3800,
"pricesIncludeTax": false,
"discountCents": 0,
"totalCents": 22800,
"taxCents": 2280,
"taxClasses": [
"standard"
]
}
],
"totals": {
"presentation": "exclusive",
"linesCents": 123600,
"discountCents": 0,
"shippingCents": 2500,
"netCents": 126100,
"taxCents": 12610,
"totalCents": 138710,
"breakdown": []
}
},
"acceptedAt": "2026-10-20T00:58:19.664Z"
}
}The panel writes this call in other languages. It does not send it: Manifold's APIs do not take calls from a web
page on another site, so run the call from your own code or terminal. The whole API as OpenAPI: fulfillment-manager.openapi.json. Base URL https://fulfillment.getmanifold.io.
Errors
Every refusal is a status and a JSON body whose _tag names it. A refused call changes nothing.
404
| Refusal | What it means | What to do |
|---|---|---|
CustomerLinkNotFound | No such record in this organization. | Check the id in the path or the body. |
409
| Refusal | What it means | What to do |
|---|---|---|
QuoteNotAnswerable reason | The request was refused. reason says why. | Nothing changed. Read the record, then decide. |
CustomerActionHeld reason | The organization is read-only — accepting acts for the business — or its mode cannot be read. | Nothing changed. Read the record, then decide. |
LineAttributeRequired sku, name | The request was refused, and nothing changed. | Nothing changed. Read the record, then decide. |
429
| Refusal | What it means | What to do |
|---|---|---|
CustomerLinkThrottled retryAfterSeconds | The request was refused, and nothing changed. | Nothing changed. |
502
| Refusal | What it means | What to do |
|---|---|---|
InventoryUnavailable reason | The inventory service did not answer, so nothing changed. | Send the same request again shortly. |
How refusals work everywhere: Errors.
Used in
- Share a quote your customer can accept, step 12: They accept