Fulfillment Manager API · customer

The customer declines the quote the link opens

POST /customer/{tenantId}/{token}/decline

The customer declines the quote the link opens, saying why if they choose (reason, up to 1000 characters): appends fulfillment.quote-declined, and the quote stays for a person to reopen and revise, place anyway or let lie.

409 QuoteNotAnswerable while it is being revised, once placed, expired or cancelled. Idempotent by state: a quote is declined once until it is reopened, so a retried decline 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 declined once until it is reopened, so a retried decline answers the page as it stands and appends nothing.

Why every write carries a key: Idempotency and retries.

Facts appended

  • fulfillment.quote-declined

What a fact is: Facts and the journal.

AI agent tool

No agent tool. the customer's own answer through their signed link; an agent never answers for the customer

Connecting an agent: AI agents.

Example

curl
curl -X POST 'https://fulfillment.getmanifold.io/customer/org_01a1586e-f9f6-7a8b-9c7d-6e5f4a3b2c1d/01a1565263f77a819b92d8e9f0a1b2c3.01a156531a2b7c3d8e4f5a6b7c8d9e0f.q0W8rTz3mPd5LkXv2NfYbA/decline' \
  -H 'Content-Type: application/json' \
  -d '{
  "reason": "We found the bowls cheaper elsewhere"
}'
JavaScript (fetch)
const response = await fetch("https://fulfillment.getmanifold.io/customer/org_01a1586e-f9f6-7a8b-9c7d-6e5f4a3b2c1d/01a1565263f77a819b92d8e9f0a1b2c3.01a156531a2b7c3d8e4f5a6b7c8d9e0f.q0W8rTz3mPd5LkXv2NfYbA/decline", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({
    "reason": "We found the bowls cheaper elsewhere"
  }),
});
if (!response.ok) throw new Error(`${response.status}: ${await response.text()}`);
const answer = await response.json();
Request body · application/json
{
  "reason": "We found the bowls cheaper elsewhere"
}
Response · 200 · application/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": "declined",
    "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": []
      }
    },
    "declinedAt": "2026-10-19T23:02:44.310Z",
    "declineReason": "We found the bowls cheaper elsewhere"
  }
}

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

RefusalWhat it meansWhat to do
CustomerLinkNotFound No such record in this organization.Check the id in the path or the body.

409

RefusalWhat it meansWhat to do
QuoteNotAnswerable reason The request was refused. reason says why.Nothing changed. Read the record, then decide.

429

RefusalWhat it meansWhat to do
CustomerLinkThrottled retryAfterSeconds The request was refused, and nothing changed.Nothing changed.

How refusals work everywhere: Errors.

Used in