Browse the manual

Prepare invoices and confirm issue

Exact invoice inputs, draft previews and the human approval required before issuance.

On this page

For: developers connecting an HTTP or MCP client. Start with Agent API and AI clients.

AI is optional. You confirm invoice issuance in Pepper.

Draft fields

Create and preview require customer_id, currency_code, issue_date, due_date and line_items. Use an active permitted customer and a supported currency.

Dates use YYYY-MM-DD. The due date cannot precede the issue date.

Optional fields are language, notes and reference. Notes allow 5,000 characters; reference allows 100. Language uses a supported code.

Update also requires the current integer lock_version and an editable invoice. Every draft write sends the full header and line set.

Line field Format and limit
description Required text, 1,000 characters
quantity Required positive string, dot decimal, at most 4 decimal places
unit_price Required unsigned minor-unit string, at most 18 digits; no separators or leading zeros except 0
unit Optional text, 20 characters
discount_type Optional percent or amount
discount_value Required when a discount type exists; unsigned string
tax_rate_id Optional ID of an existing active tax rate

For percent, discount_value uses basis points: 1000 means 10%. For amount, it uses the invoice currency's minor units.

Ask a permitted person for the intended tax rate ID. These tools cannot create rates or decide your tax treatment.

Money is exact. A price of "10001" means EUR 100.01, USD 100.01, JPY 10,001 or BHD 10.001.

PHP selects the currency scale and calculates totals. Send money as JSON strings. Do not send floats or numeric money values.

Do not submit totals, status, creator, document type, bank details, legal fields or frozen tax snapshots. Unknown draft fields fail validation.

Example: preview then save

Use a customer ID from the customer endpoint. This example uses no tax rate. Confirm the correct treatment before issuing.

{
  "customer_id": "<permitted-customer-ulid>",
  "currency_code": "USD",
  "issue_date": "2026-10-08",
  "due_date": "2026-11-08",
  "reference": "Northwind October",
  "line_items": [
    {"description": "Website design for October", "quantity": "1.25", "unit_price": "10001"}
  ]
}
  1. POST the JSON to /api/v1/documents/preview.
  2. Check data.grand_total of "12501", or USD 125.01.
  3. POST the JSON to /api/v1/drafts with Idempotency-Key: northwind-october-1.
  4. Open the returned data.href.
  5. Review the saved draft in Made with Pepper.

For an update, PUT the full JSON with the latest lock_version to /api/v1/drafts/{id}. Use a new key for that operation.

MCP uses documents_preview, followed by drafts_create. Add idempotency_key to the draft call's arguments.

Issue after approval

These three tools need invoices:execute and the delegated user's invoices.finalize permission. They handle one invoice at a time.

Execution also rechecks invoices.manage in the issue action. A custom role needs both invoice permissions and access to that invoice.

For version 0, the preparation body is {"lock_version": 0}. Use the draft's actual version.

  1. Read the saved draft and its latest lock_version.
  2. Create a JSON body with that lock_version.
  3. POST the body to /api/v1/documents/{id}/issue-approvals with a new Idempotency-Key.
  4. Show the returned data.review_url to the delegated person.
  5. Retain data.approval_id and data.nonce for execution.
  6. Read /api/v1/approvals/{approval_id} for the decision.
  7. If its status is approved, execute the request within its window.

For execution, POST {"nonce": "<returned-nonce>"} to /api/v1/approvals/{approval_id}/execute. Send a new Idempotency-Key header.

MCP uses documents_issue_prepare, approvals_get and documents_issue. Their id is the document ID for preparation and approval ID afterward.

The preparation response has HTTP 202. It includes the customer, dates, exact totals and expiry. It does not issue anything.

Only the delegated person can click Approve issue or Reject in the app. Another staff member cannot approve through the review link.

Approval lasts 10 minutes from preparation. The decision does not restart the window. approved permits execution; executed confirms issuance.

Execution assigns the next invoice number and freezes the invoice. It sends no email and records no payment.

The result includes the issued document and number. Treat only that result or the issued record as proof of issuance.

A changed draft, expired request, revoked connection or lost permission can prevent execution. Prepare a new request when the previous one is stale.

An identical retry of executed approval returns its stored result. It must use the same connection, nonce and execute key.

E-invoice readiness refusal

Required e-invoice readiness also applies after you approve issuance. An unready document remains a draft.

HTTP returns 422 with error.code: einvoice_not_ready. MCP returns isError: true and the same error in structuredContent.

error.problems names each input and includes a fix link only when the delegated person can open it. No invoice number is used.

Need help with the product?

Contact support