Skip to main content
Mark Invoice as Paid API

Authentication

All requests require an API key in the request headers. Headers:
x-idempotency-key is required on this endpoint, unlike most other write APIs where it is optional. This endpoint records a payment, so a retried request without a fresh key risks applying the same payment twice. Generate a new UUID (or similar unique value) per logical payment attempt, and reuse the same key only when retrying that exact attempt.
The permission required on your API key is Payment with the Create action enabled.

Request

Content-Type: application/json

Body Parameters

Resource Object

Each entry in resources represents one invoice payment:
Only invoices in APPROVED state can be marked as paid. Invoices in any other state will be rejected — see Error Responses.

Sync vs. Async Processing

  • Batches of up to 100 invoices are processed synchronously — the response contains a per-invoice outcome for every item in resources.
  • Batches larger than 100 invoices are processed asynchronously. The response immediately returns status: "PENDING" with a bulkActionSlug. Poll the Batch Status API with that slug to track progress.
Only one asynchronous invoice mark-as-paid batch can run per organization at a time — this applies across both this API and Pazy’s internal web app. If a batch (started via either) is still processing, a new async batch request returns a 409 MAP_BATCH_IN_PROGRESS error. Synchronous (≤100 item) requests are not affected by this restriction.

Accounting Sync Behavior

Payments recorded via this API are never automatically pushed to your connected accounting platform (Tally, Zoho Books, Oracle Fusion, etc.) — there’s no way for an external caller to supply the ledger/account mapping such a sync would need. Each resulting payment record’s accounting sync state is always SKIPPED. If you need the payment reflected in your accounting platform, sync it through your platform’s own existing mechanism.

Code Examples

Success Response

HTTP Status: 200 OK

Synchronous Response (≤ 100 invoices)

Result Object

Result Statuses

One resource failing does not stop the others — every entry in resources is attempted independently, and each gets its own result. If every resource in the batch ends in ERROR or SKIPPED, the response is instead sent as 422 with ok: false (see Error Responses), even though the payload shape is otherwise identical.

Response Example — synchronous, mixed outcomes

Asynchronous Response (> 100 invoices)

Response Example — asynchronous

Error Responses

Missing Idempotency Key

HTTP Status: 400 Bad Request

Duplicate Idempotency Key

If the same x-idempotency-key is reused for a repeat request within 5 minutes of the original, the request is rejected before any processing happens. Note this error uses a different response shape than the rest of this API: HTTP Status: 409 Conflict

Validation Errors

HTTP Status: 400 Bad Request

Batch Already In Progress

HTTP Status: 409 Conflict

Authentication Errors

HTTP Status: 401 Unauthorized

Permission Errors

HTTP Status: 403 Forbidden

All Resources Failed or Skipped

HTTP Status: 422 Unprocessable Entity

Best Practices

  • Always send a unique x-idempotency-key per payment attempt — reuse it only when retrying the exact same attempt (e.g. after a timeout), never for a genuinely new payment
  • Check every entry in data.results rather than assuming the whole batch succeeded — a 200 response can still contain individual ERROR/SKIPPED entries
  • To record a partial payment, send an amount less than the invoice’s remaining due — you can call this API again later with the remaining balance
  • For batches over 100 invoices, store the returned bulkActionSlug and poll the Batch Status API rather than assuming completion
  • Since only one async batch runs per organization at a time (shared with the web app), avoid submitting large batches back-to-back — wait for the previous one to finish
  • Use the id value returned by the Invoice List or Invoice Details APIs as the slug for each resource — it’s a stable identifier, not a numeric database ID