Import / Export API · exports

Ask for the organization's rows for a target as CSV

POST /exports

Ask for the organization's rows for a target as CSV, and get back where to fetch them: a download link (download, a path on this service) signed by the service and good for five minutes (expiresAt).

from/to narrow the period for the accounting targets; catalogId narrows catalog.price to one catalog's sheet. columns picks which of the target's columns are written (in the target's order) and rules keeps only the rows meeting every rule; an unknown column or a rule without its value is 422 InvalidExportOptions, before anything is appended. Appends import.export-requested, naming the target, columns, rules and the link's expiry — the one record that the export ran; its download appends nothing. The rows are read when the link is followed, from the owning services and as this caller — the link carries no more than the session that asked for it, and lives no longer than five minutes or that session's token, whichever ends first. Idempotent on exportId, scoped to the caller: the same caller's retry is acknowledged, appends nothing and answers the link first minted, which is dead once expired — a fresh download is a fresh exportId; another caller's request under that exportId is 409 ExportIdTaken and never sees the link. An organisation whose subscription has lapsed may still ask (it is read-only, not cut off from its data). An app is refused with 403 ExportNotForApps: the link is for a person in a browser, and an app reads the same rows through the owning services' list APIs.

Access

Requires imports:write.

How scopes come from roles: Scopes and roles. Getting a token: Authentication and app tokens.

Retries

Idempotent on exportId, scoped to the caller: the same caller's retry is acknowledged, appends nothing and answers the link first minted, which is dead once expired — a fresh download is a fresh exportId; another caller's request under that exportId is 409 ExportIdTaken and never sees the link.

A retry with the same key answers 200, with what the first call recorded.

Why every write carries a key: Idempotency and retries.

Facts appended

  • import.export-requested

What a fact is: Facts and the journal.

AI agent tool

No agent tool. It answers a five-minute download link for a browser to follow, which an agent cannot hand a person nor stream into a chat; an agent reads the same rows with imports_preview_export or the owning service's list tools.

Connecting an agent: AI agents.

Example

curl
curl -X POST 'https://import.getmanifold.io/exports' \
  -H "Authorization: Bearer $MANIFOLD_TOKEN" \
  -H 'Content-Type: application/json' \
  -d '{
  "exportId": "exp_01a15892-1b60-7d41-9e52-6f7a8b9cadb3",
  "target": "inventory.item",
  "columns": [
    "sku",
    "name",
    "locationId",
    "quantity"
  ],
  "rules": [
    {
      "column": "quantity",
      "op": "greater-than",
      "value": "0"
    }
  ]
}'
JavaScript (fetch)
const response = await fetch("https://import.getmanifold.io/exports", {
  method: "POST",
  headers: { Authorization: `Bearer ${process.env.MANIFOLD_TOKEN}`, "Content-Type": "application/json" },
  body: JSON.stringify({
    "exportId": "exp_01a15892-1b60-7d41-9e52-6f7a8b9cadb3",
    "target": "inventory.item",
    "columns": [
      "sku",
      "name",
      "locationId",
      "quantity"
    ],
    "rules": [
      {
        "column": "quantity",
        "op": "greater-than",
        "value": "0"
      }
    ]
  }),
});
if (!response.ok) throw new Error(`${response.status}: ${await response.text()}`);
const answer = await response.json();
Request body · application/json
{
  "exportId": "exp_01a15892-1b60-7d41-9e52-6f7a8b9cadb3",
  "target": "inventory.item",
  "columns": [
    "sku",
    "name",
    "locationId",
    "quantity"
  ],
  "rules": [
    {
      "column": "quantity",
      "op": "greater-than",
      "value": "0"
    }
  ]
}
Response · 200 · application/json
{
  "exportId": "exp_01a15892-1b60-7d41-9e52-6f7a8b9cadb3",
  "target": "inventory.item",
  "download": "/exports/exp_01a15892-1b60-7d41-9e52-6f7a8b9cadb3/download?tenant=org_01a1586e-f9f6-7a8b-9c7d-6e5f4a3b2c1d&expires=1792476300000&sig=q3V8m1kQ0yJ7xR2bT5nW9cL4hF6dG8sA1pZ0eU3iK7o",
  "expiresAt": "2026-10-20T06:05:00.000Z"
}

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: import-export.openapi.json. Base URL https://import.getmanifold.io.

Errors

Every refusal is a status and a JSON body whose _tag names it. A refused call changes nothing.

401

RefusalWhat it meansWhat to do
Unauthorized reason The token is missing, expired or not one Manifold issued.Get a fresh token and send the call again.
TokenAlreadyUsed tokenId A single-use app token was already spent.Mint a new token for this call.

402

RefusalWhat it meansWhat to do
SubscriptionRequired status The organization's subscription has lapsed, so writes are refused.An owner settles billing. Reads still work meanwhile.

403

RefusalWhat it meansWhat to do
ExportNotForApps appId An app may not ask for an export.A person in the organization asks for it.
TenantRequired userId The token names no organization.Choose the organization, then get a new token.
ScopeRequired required The token's roles do not grant the scope this call needs.Ask an owner or admin for a role that grants it.

409

RefusalWhat it meansWhat to do
ExportIdTaken exportId Another export already has this id.Make a new exportId.
MirroredFromSource source This area is fed by your source system until the organization goes live.Make the change in the source system, or go live first.

422

RefusalWhat it meansWhat to do
InvalidExportOptions reason, column The export names a column or filter the target does not have.Use the target's own columns.

503

RefusalWhat it meansWhat to do
RequestLogUnavailable tokenId, reason The service could not record the request, so it did nothing.Send the same request again, with the same key.

How refusals work everywhere: Errors.

Used in