{"slug": "bol-ai-api-documentation", "title": "Bol.ai API documentation", "summary": "Bol.ai launched a new API that extracts structured JSON data from Bill of Lading and other freight documents via a single endpoint. The API automatically classifies document types and returns key fields like carrier, vessel, and container numbers, with ISO 6346 check digit validation. The service is metered per document and includes batch processing for up to 10 files.", "body_md": "Send a Bill of Lading document, receive structured JSON. One endpoint does the heavy lifting; two more let you retrieve past extractions and CSV exports.\n\n`POST /api/bol/extract`\n\n— body is the raw file (PDF, PNG or JPG, max 10 MB). The document type — Bill of Lading, commercial invoice, packing list or CMR — is detected automatically and returned as `doc_type`\n\n. Each successful extraction bills one document (metered on subscriptions, or one prepaid credit), regardless of type.\n\n```\ncurl -X POST https://bol.ai/api/bol/extract \\\n  -H \"Authorization: Bearer bolai_YOUR_KEY\" \\\n  -H \"Content-Type: application/pdf\" \\\n  -H \"X-Filename: maersk-bl-4711.pdf\" \\\n  --data-binary @maersk-bl-4711.pdf\n```\n\nResponse (`200`\n\n):\n\n```\n{\n  \"id\": \"0d7c2f86-9f3e-4a4b-8e9a-1c2d3e4f5a6b\",\n  \"status\": \"done\",\n  \"doc_type\": \"bill_of_lading\",\n  \"doc_label\": \"Bill of Lading\",\n  \"fields\": {\n    \"doc_type\": \"bill_of_lading\",\n    \"bl_number\": \"MAEU123456789\",\n    \"booking_number\": \"610203040\",\n    \"scac\": \"MAEU\",\n    \"carrier\": \"Maersk Line\",\n    \"vessel\": \"EMMA MAERSK\",\n    \"voyage\": \"124W\",\n    \"shipper\":      { \"name\": \"...\", \"address\": \"...\" },\n    \"consignee\":    { \"name\": \"...\", \"address\": \"...\" },\n    \"notify_party\": { \"name\": \"...\", \"address\": \"...\" },\n    \"port_of_loading\": \"Rotterdam, NL\",\n    \"port_of_discharge\": \"New York, US\",\n    \"place_of_receipt\": null,\n    \"place_of_delivery\": null,\n    \"containers\": [{\n      \"container_number\": \"MSKU1234565\",\n      \"seal_number\": \"NL445566\",\n      \"container_type\": \"40RF\",\n      \"packages\": \"1100 cartons\",\n      \"description\": \"Frozen dairy products\",\n      \"gross_weight_kg\": 21500,\n      \"volume_cbm\": 58.4\n    }],\n    \"freight_terms\": \"PREPAID\",\n    \"incoterms\": \"CIF\",\n    \"date_of_issue\": \"2026-05-28\"\n  }\n}\n```\n\nFields that cannot be read from the document are `null`\n\n— they are never guessed.\n\nWhen a container number fails its ISO 6346 check digit but a single unambiguous OCR-confusion fix passes, the corrected value is offered as `container_number_suggestion`\n\non that container (and echoed in `warnings`\n\n). The read value is never overwritten.\n\nOne endpoint handles the freight documents that travel with a shipment. The type is classified automatically and returned as `doc_type`\n\n(with a human `doc_label`\n\n); `fields`\n\nthen carries the schema for that type. Each type has its own deterministic verification checks, and the CSV export adapts (one row per container, line item, package or goods line).\n\n`doc_type` | Document | Key fields |\n|---|---|---|\n`bill_of_lading` | Bill of Lading | `bl_number` , carrier, vessel/voyage, ports, `containers[]` (ISO 6346 checked) |\n`commercial_invoice` | Commercial / proforma invoice | `invoice_number` , seller, buyer, `line_items[]` , currency, `total_amount` |\n`packing_list` | Packing list | `packing_list_number` , `packages[]` , net/gross weights, totals |\n`cmr` | CMR road waybill | `cmr_number` , sender, consignee, carrier, `goods[]` , gross weight |\n\nThe full per-type schemas are in the [OpenAPI spec](/docs/openapi.json) (`BolFields`\n\n, `InvoiceFields`\n\n, `PackingListFields`\n\n, `CmrFields`\n\n). To pin extraction to a known type, omit it — classification is automatic; if a file is none of the supported types it is rejected and not billed.\n\n`POST /api/bol/batch`\n\n— `multipart/form-data`\n\nwith up to **10** files under the field `files`\n\n. Each file is processed and billed independently; the response reports a per-file outcome, so a batch that runs out of credits part-way through still returns the documents that succeeded.\n\n```\ncurl -X POST https://bol.ai/api/bol/batch \\\n  -H \"Authorization: Bearer bolai_YOUR_KEY\" \\\n  -F \"files=@maersk-bl-4711.pdf\" \\\n  -F \"files=@msc-bl-8842.pdf\"\n{\n  \"results\": [\n    { \"filename\": \"maersk-bl-4711.pdf\", \"ok\": true,  \"id\": \"0d7c…\", \"status\": \"done\", \"fields\": { … }, \"warnings\": [] },\n    { \"filename\": \"msc-bl-8842.pdf\",    \"ok\": false, \"id\": null,    \"status\": null,   \"error\": \"payment required: …\" }\n  ]\n}\n```\n\nFor larger volumes, call the single `/extract`\n\nendpoint concurrently, or forward BOLs to `extract@bol.ai`\n\n(below). The web app accepts a multi-file drop and runs the same batch for you.\n\n`GET /api/bol`\n\n— your 100 most recent documents with status (`pending`\n\n| `done`\n\n| `failed`\n\n).\n\n```\ncurl https://bol.ai/api/bol -H \"Authorization: Bearer bolai_YOUR_KEY\"\n```\n\n`GET /api/bol/:id`\n\n— full extraction result. `GET /api/bol/:id/csv`\n\n— the same data as CSV (one row per container).\n\n```\ncurl https://bol.ai/api/bol/0d7c2f86-.../csv \\\n  -H \"Authorization: Bearer bolai_YOUR_KEY\" -o extraction.csv\n```\n\n`PATCH /api/bol/:id`\n\n— overwrite extracted fields with corrected values. Corrections are stored alongside the original output and used for CSV exports.\n\n```\ncurl -X PATCH https://bol.ai/api/bol/0d7c2f86-... \\\n  -H \"Authorization: Bearer bolai_YOUR_KEY\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"fields\": { ...full corrected fields object... }}'\n```\n\nTurn a whole account's extractions into one master sheet. `GET /api/bol/export`\n\nflattens every completed document into a normalized \"shipment line\" schema — one row per container, invoice line, package or goods line — so mixed document types land in a single file.\n\n```\ncurl -H \"Authorization: Bearer bolai_YOUR_KEY\" \\\n  \"https://bol.ai/api/bol/export?format=xlsx\" -o shipments.xlsx\n```\n\n`format` | Returns |\n|---|---|\n`csv` (default) | Normalized master sheet, one row per line item |\n`xlsx` | The same data as a real Excel workbook |\n`json` | `{ count, rows: [...] }` — structured rows for a TMS/ERP integration |\n`customs` | Customs-declaration draft from your Bills of Lading (HS code, parties, weights, container) |\n\nOptional `?type=bill_of_lading|commercial_invoice|packing_list|cmr`\n\nlimits the export to one document type. `?template=<id>`\n\napplies a saved **column template** — subset, reorder and rename columns to match your TMS/ERP import format. Manage templates in the app (Documents → *Columns…*) or via `GET/PUT /api/me/export-templates`\n\n.\n\nAn export covers up to **1,000 documents** (newest first). Above that the response carries an `X-Export-Truncated: true`\n\nheader (and `truncated: true`\n\nin the `json`\n\nformat) so you can page the rest via the API.\n\n**Native connectors.** One-click Google Sheets and direct TMS push (CargoWise, Descartes, Magaya) are roadmap items — they require a Google OAuth app and each vendor's API credentials respectively. Until then, the `json`\n\nexport plus [webhooks](#webhooks) are the integration path: point a webhook at Zapier/Make/n8n/Sheets, or pull `format=json`\n\nstraight into your own backend.\n\nEvery account has a unique, private email-in address — `in-<token>@bol.ai`\n\n, shown in the app under *Extract → Email documents in*. Forward or scan-to-email any freight document to it and the attachments (PDF/PNG/JPG) are extracted automatically and appear in your document list — same billing as uploads. Because the account is identified by the **address** rather than the sender, it works from any source: office scanners, shared mailboxes, auto-forward rules. Keep the address private (anyone with it can send into your account) and regenerate it if it leaks.\n\nLegacy: `extract@bol.ai`\n\nstill works, matched by the sender address on your account.\n\nEvery extraction includes a `warnings`\n\narray from a deterministic verification pass: ISO 6346 container check digits (`container_number_checksum_valid`\n\nper container), weight and date plausibility, and Incoterms/freight-terms validation. An empty array means nothing suspicious was found — it is not a guarantee of correctness.\n\nA shipment's documents must agree or the customs entry gets held. `GET /api/bol/:id/related`\n\nlinks the other documents in the same shipment (by shared reference numbers — B/L number, invoice number) and reconciles the overlapping fields, returning each linked document with field-by-field `match`\n\n/`mismatch`\n\nresults for shipper/seller, consignee/buyer, total gross weight (5% tolerance) and total package count. In the app, open any document to see the discrepancies inline. Deterministic — no extra usage is billed.\n\nSet a webhook URL in the [app](/app/) (or `PUT /api/me/webhook`\n\nwith `{\"url\": \"https://...\"}`\n\n) and every completed extraction — uploads, batch, API and email-in — is POSTed to it. That single primitive is how you connect Bol.ai to **Zapier, Make, n8n, a Google Sheet, or your own backend** without polling. Use *Send test event* in the app to fire a sample first.\n\nPayload (`application/json`\n\n, header `User-Agent: bol-ai-webhook/1.0`\n\n, 5 s timeout, best-effort):\n\n```\n{\n  \"id\": \"0d7c2f86-…\",\n  \"filename\": \"maersk-bl-4711.pdf\",\n  \"status\": \"done\",\n  \"fields\": { …the full BolFields object… },\n  \"warnings\": [\"Container 1 (MSKU7234565): fails the ISO 6346 check digit — likely a misread… Did you mean MSKU1234565?\"]\n}\n```\n\n| Tool | How to receive it |\n|---|---|\nZapier | New Zap → trigger Webhooks by Zapier → Catch Hook. Copy the generated URL into Bol.ai, click Send test event, then map `fields.*` to any action (Sheets, Airtable, email…). |\nMake | Add a Custom webhook module, copy its address into Bol.ai, run Send test event so Make learns the data structure, then build the scenario. |\nn8n | Start with a Webhook node (POST), paste its production URL into Bol.ai. |\nGoogle Sheets | Publish a Google Apps Script `doPost(e)` web app that appends `JSON.parse(e.postData.contents).fields` as a row, then use its `/exec` URL as the webhook. |\n\nTip: include a hard-to-guess path or token in the URL (e.g. `https://you.example.com/bol/9f3a…`\n\n) and reject anything else — that authenticates the caller without a shared secret.\n\nBol.ai is also a [Model Context Protocol](https://modelcontextprotocol.io) server, so Claude and other AI agents can extract BOLs directly. Endpoint: `https://bol.ai/api/mcp`\n\n(streamable HTTP), authenticated with the same Bearer API key. Tools: `extract_bol`\n\n(url or base64), `list_documents`\n\n, `get_document`\n\n.\n\n```\n{\n  \"mcpServers\": {\n    \"bol-ai\": {\n      \"type\": \"http\",\n      \"url\": \"https://bol.ai/api/mcp\",\n      \"headers\": { \"Authorization\": \"Bearer bolai_YOUR_KEY\" }\n    }\n  }\n}\n```\n\n| Status | Meaning |\n|---|---|\n`401` | Missing, invalid or revoked API key |\n`402` | No active subscription or credits — subscribe or buy a credit pack |\n`413` | File larger than 10 MB |\n`422` | Extraction failed (unreadable document) — you are not billed; status is recorded as `failed` |\n\nDocuments and extracted data are stored exclusively in the European Union (database in Western Europe, file storage under EU jurisdiction).", "url": "https://wpnews.pro/news/bol-ai-api-documentation", "canonical_source": "https://bol.ai/docs/", "published_at": "2026-06-14 00:00:00+00:00", "updated_at": "2026-07-01 10:40:52.653987+00:00", "lang": "en", "topics": ["ai-products", "ai-tools", "natural-language-processing", "computer-vision", "developer-tools"], "entities": ["Bol.ai", "Maersk Line", "EMMA MAERSK", "MSC"], "alternates": {"html": "https://wpnews.pro/news/bol-ai-api-documentation", "markdown": "https://wpnews.pro/news/bol-ai-api-documentation.md", "text": "https://wpnews.pro/news/bol-ai-api-documentation.txt", "jsonld": "https://wpnews.pro/news/bol-ai-api-documentation.jsonld"}}