Developer Docs

Build on Staple Invoice

A REST API and a native MCP server — both authenticated with the same personal access token. Connect AI agents, query documents, and integrate with your existing workflow.

Overview

Staple Invoice exposes two programmatic surfaces. The REST API provides full read and write access to bills (AP) and invoices (AR) over HTTP — create, update, soft-delete, restore, integrity verification, and Peppol UBL export. The MCP server lets any MCP-compatible AI agent — Claude Code, Claude Desktop, claude.ai — read and write invoice data directly from your AI workflow.

Both surfaces share the same authentication mechanism: personal access tokens minted in Settings → Developers. One token works for both.

Base URL: https://invoice.staple.jp

Authentication

Create a personal access token in the Staple Invoice app under Settings → Developers. The token is shown once — copy it immediately. It is stored only as a SHA-256 hash and is bound to your (orgId, userId)pair, so it inherits your organisation’s tenancy boundaries automatically.

Pass the token as a standard Bearer credential:

Authorization: Bearer <your-token>

Example

curl https://invoice.staple.jp/api/bills \
  -H "Authorization: Bearer $TOKEN"

Query-parameter fallback

The MCP server URL also accepts ?token=<token>. Clients like Claude Desktop and claude.ai only take a Name and URL with no header field, so this is the only way to attach a static token there. Prefer the Authorization header wherever the client supports it.

https://invoice.staple.jp/api/mcp?token=<your-token>
Tokens can be revoked anytime from Settings → Developers. Revoking immediately blocks all requests using that token — no expiry window.

List bills

GET/api/billsBearer token or session cookie

Returns all AP bills for your organisation, newest first. Soft-deleted bills are excluded.

curl https://invoice.staple.jp/api/bills \
  -H "Authorization: Bearer $TOKEN"

Create bill

POST/api/billsBearer token or session cookie

Create a new AP bill. The route runs vendor linking (find-or-create the canonical vendor row), AI category suggestion, duplicate detection (same vendor + number, or same vendor + amount within 30 days), and JPY-equivalent FX estimation for non-JPY bills.

For OCR-promoted bills the client posts with a triage id (id starts with "ocr-"); the route generates a stable inv-<ulid> id and the call is idempotent on reload. For direct creates, supply a final id and the call is idempotent on that id.

curl -X POST https://invoice.staple.jp/api/bills \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "id": "inv-01jxx...",
    "vendor": "Acme Cloud KK",
    "amount": 48000,
    "currency": "JPY",
    "received": "2026-06-01"
  }'

Returns the created bill with status 201. Returns 200 with the existing row if the id was already committed (idempotent).

Get bill

GET/api/bills/{id}Bearer token or session cookie

Fetch a single bill by ID. Returns 404 if not found or in a different organisation.

curl https://invoice.staple.jp/api/bills/inv-01jxx... \
  -H "Authorization: Bearer $TOKEN"

Update bill

PATCH/api/bills/{id}Bearer token or session cookie

Patch one or more fields. Only supplied fields are changed. A status change fires a status-changed event in the audit log; each other field change fires a field-edited event (訂正削除履歴 for 電子帳簿保存法). Changing currency or amount automatically re-estimates jpyAmount unless the caller also supplies jpyAmount or jpyConfirmed directly.

To restore a soft-deleted bill, send { "restore": true }.

# Approve a bill
curl -X PATCH https://invoice.staple.jp/api/bills/inv-01jxx... \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "status": "approved" }'

# Restore a deleted bill
curl -X PATCH https://invoice.staple.jp/api/bills/inv-01jxx... \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "restore": true }'

Delete bill

DELETE/api/bills/{id}Bearer token or session cookie

Soft-delete — the row is hidden from list/get but retained for 電子帳簿保存法 history, and can be un-deleted via PATCH { "restore": true }. An optional { "reason": "..." } body is recorded on the deleted audit event.

curl -X DELETE https://invoice.staple.jp/api/bills/inv-01jxx... \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "reason": "duplicate upload" }'

Returns 204 No Content. Returns 404 if not found or already deleted.

Bill activity log

GET/api/bills/{id}/activityBearer token or session cookie

Full 訂正削除履歴 audit trail for a bill — imports, status changes, field edits, and deletes/restores — oldest first.

curl https://invoice.staple.jp/api/bills/inv-01jxx.../activity \
  -H "Authorization: Bearer $TOKEN"
[
  {
    "id": "evt_...",
    "invoiceId": "inv-01jxx...",
    "userId": "usr_...",
    "userName": "Dev User",
    "userEmail": "dev@staple.local",
    "type": "status-changed",
    "fromStatus": "ai-review",
    "toStatus": "auto-approved",
    "data": null,
    "createdAt": "2026-06-04T02:11:00.000Z"
  }
]

Verify bill integrity

POST/api/bills/{id}/verifyBearer token or session cookie

電子帳簿保存法 真実性 check. Re-fetches the preserved source file from Blob storage, recomputes its SHA-256, and compares it to the hash captured at ingest. A mismatch means the stored bytes were altered after the fact. The check itself is logged immutably in the audit trail.

curl -X POST https://invoice.staple.jp/api/bills/inv-01jxx.../verify \
  -H "Authorization: Bearer $TOKEN"
{
  "ok": true,
  "expected": "e3b0c44298fc1c14...",
  "actual":   "e3b0c44298fc1c14...",
  "match": true
}

List invoices

GET/api/invoicesBearer token or session cookie

Returns all AR invoices for your organisation, newest first. Soft-deleted invoices are excluded.

curl https://invoice.staple.jp/api/invoices \
  -H "Authorization: Bearer $TOKEN"

Create invoice

POST/api/invoicesBearer token or session cookie

Create a new AR invoice. The route runs customer vendor linking (find-or-create a kind="payer" vendor), payment-terms inference from the issue → due gap, and duplicate detection (same customer + number, or same customer + amount within 30 days). Creation fires a created event in the immutable audit log.

curl -X POST https://invoice.staple.jp/api/invoices \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "number": "INV-2026-001",
    "customer": "Acme Corp",
    "amount": 100000,
    "currency": "JPY",
    "sentIso": "2026-06-01"
  }'

Returns the created invoice with status 201.

Get invoice

GET/api/invoices/{id}Bearer token or session cookie

Fetch a single invoice by ID. Returns 404 if not found or in a different organisation.

curl https://invoice.staple.jp/api/invoices/inv-01jxx... \
  -H "Authorization: Bearer $TOKEN"

Update invoice

PATCH/api/invoices/{id}Bearer token or session cookie

Patch one or more fields. A status change fires a status-changed event; each other field change fires a field-edited event in the immutable audit log. Pass { "restore": true } to un-delete a soft-deleted invoice.

# Mark an invoice paid
curl -X PATCH https://invoice.staple.jp/api/invoices/inv-01jxx... \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "status": "paid" }'

Delete invoice

DELETE/api/invoices/{id}Bearer token or session cookie

Soft-delete — the row is hidden from list/get but retained for 電子帳簿保存法 history, and can be un-deleted via PATCH { "restore": true }. An optional { "reason": "..." } body is recorded on the deleted audit event.

curl -X DELETE https://invoice.staple.jp/api/invoices/inv-01jxx... \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "reason": "sent to wrong customer" }'

Returns 204 No Content. Returns 404 if not found or already deleted.

Peppol UBL export

GET/api/invoices/{id}/peppolBearer token or session cookie

Generate a JP PINT-compliant UBL 2.1 XML document for the invoice. The generated XML is persisted to Blob storage as the authoritative transmitted artifact, its SHA-256 upgrades the stored integrity fingerprint, and the export is logged immutably.

Returns application/xml as a file download.

StatusMeaning
200UBL XML returned as attachment.
400invalid_invoice — generated XML failed structural validation. Response includes issues array.
422not_exportable — invoice lacks captured line items (e.g. seeded demo records).
curl https://invoice.staple.jp/api/invoices/inv-01jxx.../peppol \
  -H "Authorization: Bearer $TOKEN" \
  -o invoice.xml

Verify invoice integrity

POST/api/invoices/{id}/verifyBearer token or session cookie

電子帳簿保存法 真実性 check for issued invoices. If a transmitted artifact (UBL/PDF) was persisted via the Peppol export, re-fetches and re-hashes it; otherwise recomputes the canonical snapshot hash. Compares to the stored fingerprint and logs the run immutably.

curl -X POST https://invoice.staple.jp/api/invoices/inv-01jxx.../verify \
  -H "Authorization: Bearer $TOKEN"
{
  "ok": true,
  "expected": "e3b0c44298fc1c14...",
  "actual":   "e3b0c44298fc1c14...",
  "match": true
}

Forward a bill by email

Every organisation has a dedicated inbound address — forward or BCC a vendor bill to it and it lands in your Inbox, no API call or login required. Find your address on the Inbox screen under “Forward bills by email.”

Address format: <org-id>@bill.staple.jp (lowercased)

Each PDF, JPEG, or PNG attachment — plus Peppol / JP PINT UBL XML — runs through the same OCR pipeline as a browser upload and lands as a real bill with status: "ai-review". Nothing is auto-approved: every email-ingested bill still needs a human to confirm it, exactly like a dragged-in file. An email with multiple attachments creates one bill per attachment.

Duplicate protection

Byte-identical re-deliveries (a webhook retry, an accidental double-forward) are skipped automatically via a content-hash check, before OCR ever runs. Bills sharing a vendor and document number are flagged as a possible duplicate for review, same as any other ingestion path.

Limits

ConstraintDetail
File size4.5MB per attachment. Larger images are compressed automatically before OCR; oversized PDFs are skipped.
File typesPDF, JPEG, PNG, and Peppol/JP PINT UBL XML. Other attachment types are silently skipped, not a hard failure for the whole email.
SenderNot restricted to a pre-registered address — a bill’s real sender is the vendor’s own billing system. A sender domain that doesn’t match the resolved vendor’s known domain gets an informational flag in review, not a block.

Errors

All error responses return JSON with an error field. HTTP status codes follow standard conventions.

StatusErrorCause
401unauthorized:no-session · unauthorized:no-org · unauthorized:invalid-tokenMissing, invalid, or revoked Bearer token — or no session cookie.
400invalid_bodyRequest body failed schema validation. The response includes an issues field with the full error detail.
404not_foundDocument does not exist or belongs to a different organisation.
400invalid_invoicePeppol export: generated UBL failed structural validation. Response includes an issues array.
422not_exportablePeppol export: invoice cannot be exported (missing line items).

MCP server

The Staple Invoice MCP server runs in-process as a stateless Streamable-HTTP server. Connect any MCP-compatible AI client to read and write invoice data from within your AI workflow.

MCP server URL: https://invoice.staple.jp/api/mcp

Connect from Claude Code

claude mcp add staple-invoice --transport http \
  https://invoice.staple.jp/api/mcp \
  --header "Authorization: Bearer $TOKEN"

Connect from Claude Desktop or claude.ai

These clients only accept a Name and URL — no custom header field. Pass the token as a query parameter instead:

Name: Staple Invoice
URL:  https://invoice.staple.jp/api/mcp?token=<your-token>

Test with MCP Inspector

npx @modelcontextprotocol/inspector
# → Transport: Streamable HTTP
# → URL: http://localhost:3000/api/mcp
# → Headers: Authorization: Bearer <token>

Available tools

19 tools across reads and safe writes. No deletes exposed via MCP, no email sending.

Read tools

ToolDescription
bill_listList received (AP) bills, newest first. Optionally filtered by status.
bill_getFetch a single AP bill by ID, including all extracted fields and line items.
bill_activityGet the full audit-trail activity log for a received bill.
invoice_listList all sent (AR) invoices for the org, newest first.
invoice_getFetch a single invoice by ID.
invoice_peppolGet the Peppol / JP PINT UBL XML export of an invoice.
vendor_searchSearch or list vendors (payee and payer counterparties) in the organisation's directory.
vendor_getFetch a single vendor by ID.
vendor_rollupAggregate AP totals and bill counts for a vendor.
space_listList the org's spaces — cost centers / departments used to allocate invoices.
draft_listList AR invoice drafts.
draft_getFetch a single draft by ID.
draft_next_numberGet the next suggested invoice number for a new draft.
report_summaryFinancial summary — AP/AR counts and totals by status, plus outstanding and paid amounts on each side.

Write tools

ToolDescription
bill_createCreate a new AP bill record with vendor linking and AI categorisation.
bill_updateUpdate fields or change the status of a received bill (e.g. approve, mark paid).
vendor_createCreate a new vendor in the payee directory.
vendor_updatePatch fields on an existing vendor. Only supplied fields change.
draft_upsertCreate or update an AR invoice draft.
Read tools return only committeddocuments. OCR’d invoices still in browser triage (not yet promoted to the database) are not visible via MCP until the user approves them in the app.