Skip to main content

Payables

7 operations under /v1/payables (GET POST): parameters, status codes, refusal bodies, and the same request in curl, HTTP, Python and TypeScript.

29 min read
View MarkdownEdit on GitHub

Base URL: https://api.codespar.dev

Every operation below requires a Bearer token. See Authentication.

GET /v1/payables

GEThttps://api.codespar.dev/v1/payables

List payables

This project's payables, each in the same shape GET /v1/payables/{payableId} returns plus due_date_effective (the due date rolled forward to the next bank business day), ordered by PRINTED due date ascending, then by creation, then by id; payables with no due date come last. That order agrees with due_date_effective except between a boleto and a Pix charge around the last business day of the year: a boleto due that day is effectively due on the first business day of January, a Pix charge is not extended, so the boleto can be listed first although it is effectively due later. Order by due_date_effective where that matters. Filter by status (one or several, comma-separated); there is no date filter. Page with before: pass the previous page's next_before as it was returned, and stop when it is null. The cursor is opaque and carries no tenant, so a cursor from another project pages this project's payables and reveals nothing. Payables of other projects and organizations are never listed. Reading never re-runs a check or changes a status.

Scope: payables:read.

Query parameters

NameTypeRequiredDescription
beforestringnoThe next_before of the previous page, as it was returned. Opaque.
limitintegernoPage size, 1..200. Default 50.
statusstringnoOne status or several, comma-separated (NEEDS_REVIEW,READY). Absent: every status.

Responses

StatusBodyDescription
200objectOK
400objectA filter, the limit or the cursor is not valid.

Response 200

FieldTypeRequiredDescription
next_beforestring,nullyesPass as before for the next page; null on the last page.
payablesarray of objectyes—
Example request
curl -X GET https://api.codespar.dev/v1/payables \
  -H "Authorization: Bearer $CODESPAR_API_KEY"
GET /v1/payables HTTP/1.1
Host: api.codespar.dev
Authorization: Bearer $CODESPAR_API_KEY
import os
import requests

res = requests.get(
    "https://api.codespar.dev/v1/payables",
    headers={"Authorization": f"Bearer {os.environ['CODESPAR_API_KEY']}"},
)
res.raise_for_status()
data = res.json()
const res = await fetch("https://api.codespar.dev/v1/payables", {
  method: "GET",
  headers: {
    Authorization: `Bearer ${process.env.CODESPAR_API_KEY}`,
  },
});

const data = await res.json();
const result = await cs.api.get("/v1/payables");
Example response 200
application/json
{
  "payables": [
    {
      "schema_version": "payable.v1",
      "doc_type": "invoice",
      "attribution": {
        "channel": "upload",
        "credential_id": "credential_0000000000000000",
        "connection_id": "conn_0000000000000000",
        "actor": "string"
      },
      "document_hash": "string",
      "supplier": {
        "document": {
          "value": "string",
          "from": "parser_local",
          "evidence": {
            "page": 0,
            "excerpt": "string",
            "verification": "verified"
          },
          "confidence": 0
        },
        "name": {
          "value": "string",
          "from": "parser_local",
          "evidence": {
            "page": 0,
            "excerpt": "string",
            "verification": "verified"
          },
          "confidence": 0
        }
      },
      "recipient": {
        "document": {
          "value": "string",
          "from": "parser_local",
          "evidence": {
            "page": 0,
            "excerpt": "string",
            "verification": "verified"
          },
          "confidence": 0
        },
        "name": {
          "value": "string",
          "from": "parser_local",
          "evidence": {
            "page": 0,
            "excerpt": "string",
            "verification": "verified"
          },
          "confidence": 0
        }
      },
      "invoice_number": {
        "value": "string",
        "from": "parser_local",
        "evidence": {
          "page": 0,
          "excerpt": "string",
          "verification": "verified"
        },
        "confidence": 0
      },
      "serie": {
        "value": "string",
        "from": "parser_local",
        "evidence": {
          "page": 0,
          "excerpt": "string",
          "verification": "verified"
        },
        "confidence": 0
      },
      "issue_date": {
        "value": "string",
        "from": "parser_local",
        "evidence": {
          "page": 0,
          "excerpt": "string",
          "verification": "verified"
        },
        "confidence": 0
      },
      "due_date": {
        "value": "string",
        "from": "parser_local",
        "evidence": {
          "page": 0,
          "excerpt": "string",
          "verification": "verified"
        },
        "confidence": 0
      },
      "items": [
        {
          "description": {
            "value": "string",
            "from": "parser_local",
            "evidence": {
              "page": 0,
              "excerpt": "string",
              "verification": "verified"
            },
            "confidence": 0
          },
          "quantity": {
            "value": 1000,
            "from": "parser_local",
            "evidence": {
              "page": 0,
              "excerpt": "string",
              "verification": "verified"
            },
            "confidence": 0
          },
          "unit_amount_minor": {
            "value": 1000,
            "from": "parser_local",
            "evidence": {
              "page": 0,
              "excerpt": "string",
              "verification": "verified"
            },
            "confidence": 0
          },
          "total_amount_minor": {
            "value": 1000,
            "from": "parser_local",
            "evidence": {
              "page": 0,
              "excerpt": "string",
              "verification": "verified"
            },
            "confidence": 0
          }
        }
      ],
      "totals": {
        "subtotal_minor": {
          "value": 1000,
          "from": "parser_local",
          "evidence": {
            "page": 0,
            "excerpt": "string",
            "verification": "verified"
          },
          "confidence": 0
        },
        "discount_minor": {
          "value": 1000,
          "from": "parser_local",
          "evidence": {
            "page": 0,
            "excerpt": "string",
            "verification": "verified"
          },
          "confidence": 0
        },
        "tax_relief_deducted_minor": {
          "value": 1000,
          "from": "parser_local",
          "evidence": {
            "page": 0,
            "excerpt": "string",
            "verification": "verified"
          },
          "confidence": 0
        },
        "freight_minor": {
          "value": 1000,
          "from": "parser_local",
          "evidence": {
            "page": 0,
            "excerpt": "string",
            "verification": "verified"
          },
          "confidence": 0
        },
        "insurance_minor": {
          "value": 1000,
          "from": "parser_local",
          "evidence": {
            "page": 0,
            "excerpt": "string",
            "verification": "verified"
          },
          "confidence": 0
        },
        "other_charges_minor": {
          "value": 1000,
          "from": "parser_local",
          "evidence": {
            "page": 0,
            "excerpt": "string",
            "verification": "verified"
          },
          "confidence": 0
        },
        "taxes_added_minor": {
          "value": 1000,
          "from": "parser_local",
          "evidence": {
            "page": 0,
            "excerpt": "string",
            "verification": "verified"
          },
          "confidence": 0
        },
        "taxes_included_minor": {
          "value": 1000,
          "from": "parser_local",
          "evidence": {
            "page": 0,
            "excerpt": "string",
            "verification": "verified"
          },
          "confidence": 0
        },
        "grand_total_minor": {
          "value": 1000,
          "from": "parser_local",
          "evidence": {
            "page": 0,
            "excerpt": "string",
            "verification": "verified"
          },
          "confidence": 0
        },
        "currency": {
          "value": "string",
          "from": "parser_local",
          "evidence": {
            "page": 0,
            "excerpt": "string",
            "verification": "verified"
          },
          "confidence": 0
        }
      },
      "carriers": {
        "boleto": "string",
        "br_code": "string",
        "nfe": "string"
      },
      "extraction": {
        "model": "string",
        "model_version": "string",
        "input_tokens": 0,
        "output_tokens": 0,
        "reasoning_tokens": 0
      },
      "payable_id": "payable_0000000000000000",
      "status": "RECEIVED",
      "rail_quote": {
        "beneficiary": {
          "value": "string",
          "from": "trilho"
        },
        "beneficiary_document_masked": {
          "value": "string",
          "from": "trilho"
        },
        "final_beneficiary": {
          "value": "string",
          "from": "trilho"
        },
        "final_beneficiary_document_masked": {
          "value": "string",
          "from": "trilho"
        },
        "amount_minor": {
          "value": 1000,
          "from": "trilho"
        },
        "discount_minor": {
          "value": 1000,
          "from": "trilho"
        },
        "interest_minor": {
          "value": 1000,
          "from": "trilho"
        },
        "fine_minor": {
          "value": 1000,
          "from": "trilho"
        },
        "due_date": {
          "value": "string",
          "from": "trilho"
        },
        "quoted_at": "2026-01-15T12:00:00.000Z"
      },
      "validation": {
        "carrier_check_digits": {
          "outcome": "ok",
          "detail": "string"
        },
        "document_check_digits": {
          "outcome": "ok",
          "detail": "string"
        },
        "nfe_key_consistency": {
          "outcome": "ok",
          "detail": "string"
        },
        "arithmetic": {
          "outcome": "ok",
          "detail": "string"
        },
        "duplicate_document": {
          "outcome": "ok",
          "detail": "string"
        },
        "amount_matches_rail": {
          "outcome": "ok",
          "detail": "string"
        },
        "beneficiary_document_matches_supplier": {
          "outcome": "ok",
          "detail": "string"
        },
        "due_date_state": {
          "outcome": "ok",
          "detail": "string"
        },
        "pix_key_owner_matches_supplier": {
          "outcome": "ok",
          "detail": "string"
        },
        "supplier_registry": {
          "outcome": "ok",
          "detail": "string"
        },
        "bank_details_changed": {
          "outcome": "ok",
          "detail": "string"
        }
      },
      "review": {
        "validation_status": "REJECTED",
        "review_by": [
          {
            "code": "string",
            "cause": "check_failed"
          }
        ],
        "rejected_by": [
          "string"
        ],
        "confirmed_by": [
          "string"
        ],
        "awaiting": [
          "string"
        ],
        "not_covered": [
          "string"
        ],
        "review_triggers": [
          "string"
        ],
        "resolutions": [
          {
            "code": "string",
            "resolution": "human_correction",
            "at": "string",
            "by": "string",
            "by_source": "verified_user_token",
            "fields": [
              "string"
            ],
            "confirmed_beneficiary_document": "string"
          }
        ]
      },
      "payment": {
        "state": "awaiting_approval",
        "approval_id": "approval_0000000000000000",
        "settled_against": "document_line",
        "document_amount_minor": 1000,
        "mandate_id": "mandate_0000000000000000",
        "attempt_id": "attempt_0000000000000000",
        "tries": 0,
        "amount_minor": 1000,
        "quote_hash": "string",
        "claimed_at": "string",
        "key_id": "key_0000000000000000",
        "via": "string",
        "executed_at": "string",
        "receipt_id": "receipt_0000000000000000",
        "transaction_id": "transaction_0000000000000000",
        "end_to_end_id": "endtoend_0000000000000000",
        "money_moved": true,
        "uncertain_code": "string",
        "hold_entry_id": "holdentry_0000000000000000",
        "last_refusal": {
          "code": "string",
          "attempt_id": "attempt_0000000000000000",
          "at": "string"
        }
      },
      "created_at": "string",
      "updated_at": "string",
      "due_date_effective": "string"
    }
  ],
  "next_before": "string"
}

POST /v1/payables

POSThttps://api.codespar.dev/v1/payables

Create a payable from a partner's record or a person's form

A payable is an obligation to pay somebody. This endpoint takes one as structured data: attribution.channel is structured for a partner system's record and manual for a form a person filled in. Both go through the same schema and the same deterministic checks, so the same payable sent through either channel ends in the same status with the same validation. A file (PDF or image) goes to POST /v1/payables/documents, which reads the payable out of it and enters the same pipeline; a multipart/form-data body sent HERE answers 415 payable_document_endpoint, and a JSON body claiming attribution.channel: "upload" is refused.

Every field carries its provenance in from. Amounts are integer centavos (*_minor). rail_quote is refused by name: the amount and the payee of a payment come from the rail, never from a request. attribution.credential_id is set to the API key the request authenticated with; a different value is refused.

The amount and the payee come from the rail, never from what was sent. amount_matches_rail, beneficiary_document_matches_supplier and due_date_state run against a consult of the boleto on the payable, and they block READY whether or not they answered. A consult that could not be made — no connected payment provider, a provider that did not answer — leaves them indisponivel and the payable NEEDS_REVIEW, named under review.review_by. pix_key_owner_matches_supplier is not consulted in this release and blocks a payable carrying a Pix BR Code with cause required_not_implemented. VALIDATING is never returned: nothing re-runs a validation yet, so a check with no answer goes to a person rather than waiting. due_date_state calls a payable overdue only after its EFFECTIVE due date: a due date on a weekend, a national bank holiday (Carnival Monday and Tuesday and Corpus Christi included) or, for a boleto, the last business day of the year is payable without charges on the next business day. State and municipal holidays are not considered.

Status. Two fields answer two questions. review.validation_status is what the checks alone say: REJECTED (a check that rejects failed), NEEDS_REVIEW (a check failed, or a required check has no answer it can have), VALIDATING (a required, implemented check did not answer and will be retried) or VALIDATED (every required check passed). status is what the payable may do: READY only from VALIDATED with no review trigger open, and NEEDS_REVIEW when a trigger is open. The trigger this API evaluates is new_supplier: this project has no executed payable for the supplier's document, or the payable names no supplier document. It is evaluated per project, never across projects.

Why things are in review. review.review_by lists each check that sends the payable to a person and its cause: check_failed, retries_exhausted or required_not_implemented. review.review_triggers lists the open triggers. review.not_covered lists checks that did not run and do not block READY in this release (supplier_registry, bank_details_changed).

What fails a check. A carrier that fails its own check digits (carrier_check_digits) or a duplicate (duplicate_document) is REJECTED and not stored. A document number with wrong check digits, an NF-e key that disagrees with the printed fields, or totals that do not add up (arithmetic, one centavo of tolerance per comparison) is check_failed. The total is composed the way an NF-e composes vNF: subtotal_minor minus discount_minor and tax_relief_deducted_minor, plus taxes_added_minor, freight_minor, insurance_minor and other_charges_minor. taxes_included_minor is informational and in no sum.

Duplicates. A payable is a duplicate when another payable of the SAME project that is open or already paid shares a duplicity axis with it: document_hash, the boleto (a 47- or 48-digit linha digitável and the 44-digit barcode it expands from are the same boleto), the Pix txid, the NF-e access key, or the supplier document together with invoice number and série. The answer is 409 payable_duplicate and nothing is stored; details.existing_payable_id names the payable that holds the axis. A payable in another project never collides and is never named.

Idempotency. Send an Idempotency-Key header to make a retry safe. The same key with the same body answers 200 with idempotent_replay: true and the payable as it is now, never a duplicate. The same key with a different body answers 409 idempotency_key_conflict. Without a key, a retry of a create that succeeded answers payable_duplicate naming the payable it created.

Scope: payables:write.

Request body

FieldTypeRequiredDescription
attributionobjectyes—
carriersobjectno—
doc_type"invoice" | "danfe_nfe" | "boleto" | "unknown"yes—
document_hashstringno—
due_dateobjectno—
extractionobjectno—
invoice_numberobjectno—
issue_dateobjectno—
itemsarray of objectno—
rail_quote—no—
recipientobjectno—
schema_version"payable.v1"yes—
serieobjectno—
supplierobjectyes—
totalsobjectyes—

Responses

StatusBodyDescription
200objectOK
201objectOK
400objectThe body did not match the schema, carried rail_quote, or the Idempotency-Key header is empty or longer than 255 characters. details.issues names paths and codes, never the values sent.
409objectpayable_duplicate: the payable is REJECTED as a duplicate and was not stored. details.axes names the axis, details.existing_payable_id the payable of this project that holds it, and details.validation the verdict. idempotency_key_conflict: the key was used with a different body.
415objectA multipart/form-data body was sent to the JSON endpoint. Send the file to POST /v1/payables/documents (details.endpoint).
422objectpayable_carrier_malformed: a carrier failed its own check digits, so the payable is REJECTED and was not stored; details.carriers names the carrier and the failure. payable_no_duplicate_key: the payable carries no duplicity axis. payable_channel_unsupported: a JSON body claimed upload. payable_attribution_mismatch: attribution.credential_id names another API key.
503objectThe key that protects supplier documents could not be read. Nothing was stored; retry later with the same Idempotency-Key.

Response 200

FieldTypeRequiredDescription
attributionobjectyes—
carriersobjectno—
created_atstringyesISO 8601 instant the payable was created.
doc_type"invoice" | "danfe_nfe" | "boleto" | "unknown"yes—
document_hashstringno—
due_dateobjectno—
extractionobjectno—
idempotent_replaybooleanyesTrue when this answer replays an earlier call made with the same Idempotency-Key.
invoice_numberobjectno—
issue_dateobjectno—
itemsarray of objectno—
payable_idstringyes—
paymentobject,nullyesWhat paying it did (ent#1587); null until a payment was attempted.
rail_quoteobjectno—
recipientobjectno—
reviewobjectyes—
schema_version"payable.v1"yes—
serieobjectno—
status"RECEIVED" | "EXTRACTING" | "EXTRACTED" | "VALIDATING" | "VALIDATED" | "NEEDS_REVIEW" | "READY" | "APPROVED" | "EXECUTED" | "REJECTED" | "FAILED_EXTRACTION" | "EXPIRED"yes—
supplierobjectyes—
totalsobjectyes—
updated_atstringyesISO 8601 instant of the last change to the payable.
validationobjectyes—
Example request
curl -X POST https://api.codespar.dev/v1/payables \
  -H "Authorization: Bearer $CODESPAR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
       "schema_version": "payable.v1",
       "doc_type": "invoice",
       "attribution": {
         "channel": "upload",
         "credential_id": "credential_0000000000000000",
         "connection_id": "conn_0000000000000000",
         "actor": "string"
       },
       "document_hash": "string",
       "supplier": {
         "document": {
           "value": "string",
           "from": "parser_local",
           "evidence": {
             "page": 0,
             "excerpt": "string",
             "verification": "verified"
           },
           "confidence": 0
         },
         "name": {
           "value": "string",
           "from": "parser_local",
           "evidence": {
             "page": 0,
             "excerpt": "string",
             "verification": "verified"
           },
           "confidence": 0
         }
       },
       "recipient": {
         "document": {
           "value": "string",
           "from": "parser_local",
           "evidence": {
             "page": 0,
             "excerpt": "string",
             "verification": "verified"
           },
           "confidence": 0
         },
         "name": {
           "value": "string",
           "from": "parser_local",
           "evidence": {
             "page": 0,
             "excerpt": "string",
             "verification": "verified"
           },
           "confidence": 0
         }
       },
       "invoice_number": {
         "value": "string",
         "from": "parser_local",
         "evidence": {
           "page": 0,
           "excerpt": "string",
           "verification": "verified"
         },
         "confidence": 0
       },
       "serie": {
         "value": "string",
         "from": "parser_local",
         "evidence": {
           "page": 0,
           "excerpt": "string",
           "verification": "verified"
         },
         "confidence": 0
       },
       "issue_date": {
         "value": "string",
         "from": "parser_local",
         "evidence": {
           "page": 0,
           "excerpt": "string",
           "verification": "verified"
         },
         "confidence": 0
       },
       "due_date": {
         "value": "string",
         "from": "parser_local",
         "evidence": {
           "page": 0,
           "excerpt": "string",
           "verification": "verified"
         },
         "confidence": 0
       },
       "items": [
         {
           "description": {
             "value": "string",
             "from": "parser_local",
             "evidence": {
               "page": 0,
               "excerpt": "string",
               "verification": "verified"
             },
             "confidence": 0
           },
           "quantity": {
             "value": 1000,
             "from": "parser_local",
             "evidence": {
               "page": 0,
               "excerpt": "string",
               "verification": "verified"
             },
             "confidence": 0
           },
           "unit_amount_minor": {
             "value": 1000,
             "from": "parser_local",
             "evidence": {
               "page": 0,
               "excerpt": "string",
               "verification": "verified"
             },
             "confidence": 0
           },
           "total_amount_minor": {
             "value": 1000,
             "from": "parser_local",
             "evidence": {
               "page": 0,
               "excerpt": "string",
               "verification": "verified"
             },
             "confidence": 0
           }
         }
       ],
       "totals": {
         "subtotal_minor": {
           "value": 1000,
           "from": "parser_local",
           "evidence": {
             "page": 0,
             "excerpt": "string",
             "verification": "verified"
           },
           "confidence": 0
         },
         "discount_minor": {
           "value": 1000,
           "from": "parser_local",
           "evidence": {
             "page": 0,
             "excerpt": "string",
             "verification": "verified"
           },
           "confidence": 0
         },
         "tax_relief_deducted_minor": {
           "value": 1000,
           "from": "parser_local",
           "evidence": {
             "page": 0,
             "excerpt": "string",
             "verification": "verified"
           },
           "confidence": 0
         },
         "freight_minor": {
           "value": 1000,
           "from": "parser_local",
           "evidence": {
             "page": 0,
             "excerpt": "string",
             "verification": "verified"
           },
           "confidence": 0
         },
         "insurance_minor": {
           "value": 1000,
           "from": "parser_local",
           "evidence": {
             "page": 0,
             "excerpt": "string",
             "verification": "verified"
           },
           "confidence": 0
         },
         "other_charges_minor": {
           "value": 1000,
           "from": "parser_local",
           "evidence": {
             "page": 0,
             "excerpt": "string",
             "verification": "verified"
           },
           "confidence": 0
         },
         "taxes_added_minor": {
           "value": 1000,
           "from": "parser_local",
           "evidence": {
             "page": 0,
             "excerpt": "string",
             "verification": "verified"
           },
           "confidence": 0
         },
         "taxes_included_minor": {
           "value": 1000,
           "from": "parser_local",
           "evidence": {
             "page": 0,
             "excerpt": "string",
             "verification": "verified"
           },
           "confidence": 0
         },
         "grand_total_minor": {
           "value": 1000,
           "from": "parser_local",
           "evidence": {
             "page": 0,
             "excerpt": "string",
             "verification": "verified"
           },
           "confidence": 0
         },
         "currency": {
           "value": "string",
           "from": "parser_local",
           "evidence": {
             "page": 0,
             "excerpt": "string",
             "verification": "verified"
           },
           "confidence": 0
         }
       },
       "carriers": {
         "boleto": "string",
         "br_code": "string",
         "nfe": "string"
       },
       "extraction": {
         "model": "string",
         "model_version": "string",
         "input_tokens": 0,
         "output_tokens": 0,
         "reasoning_tokens": 0
       }
     }'
POST /v1/payables HTTP/1.1
Host: api.codespar.dev
Authorization: Bearer $CODESPAR_API_KEY
Content-Type: application/json

{
  "schema_version": "payable.v1",
  "doc_type": "invoice",
  "attribution": {
    "channel": "upload",
    "credential_id": "credential_0000000000000000",
    "connection_id": "conn_0000000000000000",
    "actor": "string"
  },
  "document_hash": "string",
  "supplier": {
    "document": {
      "value": "string",
      "from": "parser_local",
      "evidence": {
        "page": 0,
        "excerpt": "string",
        "verification": "verified"
      },
      "confidence": 0
    },
    "name": {
      "value": "string",
      "from": "parser_local",
      "evidence": {
        "page": 0,
        "excerpt": "string",
        "verification": "verified"
      },
      "confidence": 0
    }
  },
  "recipient": {
    "document": {
      "value": "string",
      "from": "parser_local",
      "evidence": {
        "page": 0,
        "excerpt": "string",
        "verification": "verified"
      },
      "confidence": 0
    },
    "name": {
      "value": "string",
      "from": "parser_local",
      "evidence": {
        "page": 0,
        "excerpt": "string",
        "verification": "verified"
      },
      "confidence": 0
    }
  },
  "invoice_number": {
    "value": "string",
    "from": "parser_local",
    "evidence": {
      "page": 0,
      "excerpt": "string",
      "verification": "verified"
    },
    "confidence": 0
  },
  "serie": {
    "value": "string",
    "from": "parser_local",
    "evidence": {
      "page": 0,
      "excerpt": "string",
      "verification": "verified"
    },
    "confidence": 0
  },
  "issue_date": {
    "value": "string",
    "from": "parser_local",
    "evidence": {
      "page": 0,
      "excerpt": "string",
      "verification": "verified"
    },
    "confidence": 0
  },
  "due_date": {
    "value": "string",
    "from": "parser_local",
    "evidence": {
      "page": 0,
      "excerpt": "string",
      "verification": "verified"
    },
    "confidence": 0
  },
  "items": [
    {
      "description": {
        "value": "string",
        "from": "parser_local",
        "evidence": {
          "page": 0,
          "excerpt": "string",
          "verification": "verified"
        },
        "confidence": 0
      },
      "quantity": {
        "value": 1000,
        "from": "parser_local",
        "evidence": {
          "page": 0,
          "excerpt": "string",
          "verification": "verified"
        },
        "confidence": 0
      },
      "unit_amount_minor": {
        "value": 1000,
        "from": "parser_local",
        "evidence": {
          "page": 0,
          "excerpt": "string",
          "verification": "verified"
        },
        "confidence": 0
      },
      "total_amount_minor": {
        "value": 1000,
        "from": "parser_local",
        "evidence": {
          "page": 0,
          "excerpt": "string",
          "verification": "verified"
        },
        "confidence": 0
      }
    }
  ],
  "totals": {
    "subtotal_minor": {
      "value": 1000,
      "from": "parser_local",
      "evidence": {
        "page": 0,
        "excerpt": "string",
        "verification": "verified"
      },
      "confidence": 0
    },
    "discount_minor": {
      "value": 1000,
      "from": "parser_local",
      "evidence": {
        "page": 0,
        "excerpt": "string",
        "verification": "verified"
      },
      "confidence": 0
    },
    "tax_relief_deducted_minor": {
      "value": 1000,
      "from": "parser_local",
      "evidence": {
        "page": 0,
        "excerpt": "string",
        "verification": "verified"
      },
      "confidence": 0
    },
    "freight_minor": {
      "value": 1000,
      "from": "parser_local",
      "evidence": {
        "page": 0,
        "excerpt": "string",
        "verification": "verified"
      },
      "confidence": 0
    },
    "insurance_minor": {
      "value": 1000,
      "from": "parser_local",
      "evidence": {
        "page": 0,
        "excerpt": "string",
        "verification": "verified"
      },
      "confidence": 0
    },
    "other_charges_minor": {
      "value": 1000,
      "from": "parser_local",
      "evidence": {
        "page": 0,
        "excerpt": "string",
        "verification": "verified"
      },
      "confidence": 0
    },
    "taxes_added_minor": {
      "value": 1000,
      "from": "parser_local",
      "evidence": {
        "page": 0,
        "excerpt": "string",
        "verification": "verified"
      },
      "confidence": 0
    },
    "taxes_included_minor": {
      "value": 1000,
      "from": "parser_local",
      "evidence": {
        "page": 0,
        "excerpt": "string",
        "verification": "verified"
      },
      "confidence": 0
    },
    "grand_total_minor": {
      "value": 1000,
      "from": "parser_local",
      "evidence": {
        "page": 0,
        "excerpt": "string",
        "verification": "verified"
      },
      "confidence": 0
    },
    "currency": {
      "value": "string",
      "from": "parser_local",
      "evidence": {
        "page": 0,
        "excerpt": "string",
        "verification": "verified"
      },
      "confidence": 0
    }
  },
  "carriers": {
    "boleto": "string",
    "br_code": "string",
    "nfe": "string"
  },
  "extraction": {
    "model": "string",
    "model_version": "string",
    "input_tokens": 0,
    "output_tokens": 0,
    "reasoning_tokens": 0
  }
}
import os
import requests

res = requests.post(
    "https://api.codespar.dev/v1/payables",
    headers={"Authorization": f"Bearer {os.environ['CODESPAR_API_KEY']}"},
    json={
      "schema_version": "payable.v1",
      "doc_type": "invoice",
      "attribution": {
        "channel": "upload",
        "credential_id": "credential_0000000000000000",
        "connection_id": "conn_0000000000000000",
        "actor": "string"
      },
      "document_hash": "string",
      "supplier": {
        "document": {
          "value": "string",
          "from": "parser_local",
          "evidence": {
            "page": 0,
            "excerpt": "string",
            "verification": "verified"
          },
          "confidence": 0
        },
        "name": {
          "value": "string",
          "from": "parser_local",
          "evidence": {
            "page": 0,
            "excerpt": "string",
            "verification": "verified"
          },
          "confidence": 0
        }
      },
      "recipient": {
        "document": {
          "value": "string",
          "from": "parser_local",
          "evidence": {
            "page": 0,
            "excerpt": "string",
            "verification": "verified"
          },
          "confidence": 0
        },
        "name": {
          "value": "string",
          "from": "parser_local",
          "evidence": {
            "page": 0,
            "excerpt": "string",
            "verification": "verified"
          },
          "confidence": 0
        }
      },
      "invoice_number": {
        "value": "string",
        "from": "parser_local",
        "evidence": {
          "page": 0,
          "excerpt": "string",
          "verification": "verified"
        },
        "confidence": 0
      },
      "serie": {
        "value": "string",
        "from": "parser_local",
        "evidence": {
          "page": 0,
          "excerpt": "string",
          "verification": "verified"
        },
        "confidence": 0
      },
      "issue_date": {
        "value": "string",
        "from": "parser_local",
        "evidence": {
          "page": 0,
          "excerpt": "string",
          "verification": "verified"
        },
        "confidence": 0
      },
      "due_date": {
        "value": "string",
        "from": "parser_local",
        "evidence": {
          "page": 0,
          "excerpt": "string",
          "verification": "verified"
        },
        "confidence": 0
      },
      "items": [
        {
          "description": {
            "value": "string",
            "from": "parser_local",
            "evidence": {
              "page": 0,
              "excerpt": "string",
              "verification": "verified"
            },
            "confidence": 0
          },
          "quantity": {
            "value": 1000,
            "from": "parser_local",
            "evidence": {
              "page": 0,
              "excerpt": "string",
              "verification": "verified"
            },
            "confidence": 0
          },
          "unit_amount_minor": {
            "value": 1000,
            "from": "parser_local",
            "evidence": {
              "page": 0,
              "excerpt": "string",
              "verification": "verified"
            },
            "confidence": 0
          },
          "total_amount_minor": {
            "value": 1000,
            "from": "parser_local",
            "evidence": {
              "page": 0,
              "excerpt": "string",
              "verification": "verified"
            },
            "confidence": 0
          }
        }
      ],
      "totals": {
        "subtotal_minor": {
          "value": 1000,
          "from": "parser_local",
          "evidence": {
            "page": 0,
            "excerpt": "string",
            "verification": "verified"
          },
          "confidence": 0
        },
        "discount_minor": {
          "value": 1000,
          "from": "parser_local",
          "evidence": {
            "page": 0,
            "excerpt": "string",
            "verification": "verified"
          },
          "confidence": 0
        },
        "tax_relief_deducted_minor": {
          "value": 1000,
          "from": "parser_local",
          "evidence": {
            "page": 0,
            "excerpt": "string",
            "verification": "verified"
          },
          "confidence": 0
        },
        "freight_minor": {
          "value": 1000,
          "from": "parser_local",
          "evidence": {
            "page": 0,
            "excerpt": "string",
            "verification": "verified"
          },
          "confidence": 0
        },
        "insurance_minor": {
          "value": 1000,
          "from": "parser_local",
          "evidence": {
            "page": 0,
            "excerpt": "string",
            "verification": "verified"
          },
          "confidence": 0
        },
        "other_charges_minor": {
          "value": 1000,
          "from": "parser_local",
          "evidence": {
            "page": 0,
            "excerpt": "string",
            "verification": "verified"
          },
          "confidence": 0
        },
        "taxes_added_minor": {
          "value": 1000,
          "from": "parser_local",
          "evidence": {
            "page": 0,
            "excerpt": "string",
            "verification": "verified"
          },
          "confidence": 0
        },
        "taxes_included_minor": {
          "value": 1000,
          "from": "parser_local",
          "evidence": {
            "page": 0,
            "excerpt": "string",
            "verification": "verified"
          },
          "confidence": 0
        },
        "grand_total_minor": {
          "value": 1000,
          "from": "parser_local",
          "evidence": {
            "page": 0,
            "excerpt": "string",
            "verification": "verified"
          },
          "confidence": 0
        },
        "currency": {
          "value": "string",
          "from": "parser_local",
          "evidence": {
            "page": 0,
            "excerpt": "string",
            "verification": "verified"
          },
          "confidence": 0
        }
      },
      "carriers": {
        "boleto": "string",
        "br_code": "string",
        "nfe": "string"
      },
      "extraction": {
        "model": "string",
        "model_version": "string",
        "input_tokens": 0,
        "output_tokens": 0,
        "reasoning_tokens": 0
      }
    },
)
res.raise_for_status()
data = res.json()
const res = await fetch("https://api.codespar.dev/v1/payables", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.CODESPAR_API_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    "schema_version": "payable.v1",
    "doc_type": "invoice",
    "attribution": {
      "channel": "upload",
      "credential_id": "credential_0000000000000000",
      "connection_id": "conn_0000000000000000",
      "actor": "string"
    },
    "document_hash": "string",
    "supplier": {
      "document": {
        "value": "string",
        "from": "parser_local",
        "evidence": {
          "page": 0,
          "excerpt": "string",
          "verification": "verified"
        },
        "confidence": 0
      },
      "name": {
        "value": "string",
        "from": "parser_local",
        "evidence": {
          "page": 0,
          "excerpt": "string",
          "verification": "verified"
        },
        "confidence": 0
      }
    },
    "recipient": {
      "document": {
        "value": "string",
        "from": "parser_local",
        "evidence": {
          "page": 0,
          "excerpt": "string",
          "verification": "verified"
        },
        "confidence": 0
      },
      "name": {
        "value": "string",
        "from": "parser_local",
        "evidence": {
          "page": 0,
          "excerpt": "string",
          "verification": "verified"
        },
        "confidence": 0
      }
    },
    "invoice_number": {
      "value": "string",
      "from": "parser_local",
      "evidence": {
        "page": 0,
        "excerpt": "string",
        "verification": "verified"
      },
      "confidence": 0
    },
    "serie": {
      "value": "string",
      "from": "parser_local",
      "evidence": {
        "page": 0,
        "excerpt": "string",
        "verification": "verified"
      },
      "confidence": 0
    },
    "issue_date": {
      "value": "string",
      "from": "parser_local",
      "evidence": {
        "page": 0,
        "excerpt": "string",
        "verification": "verified"
      },
      "confidence": 0
    },
    "due_date": {
      "value": "string",
      "from": "parser_local",
      "evidence": {
        "page": 0,
        "excerpt": "string",
        "verification": "verified"
      },
      "confidence": 0
    },
    "items": [
      {
        "description": {
          "value": "string",
          "from": "parser_local",
          "evidence": {
            "page": 0,
            "excerpt": "string",
            "verification": "verified"
          },
          "confidence": 0
        },
        "quantity": {
          "value": 1000,
          "from": "parser_local",
          "evidence": {
            "page": 0,
            "excerpt": "string",
            "verification": "verified"
          },
          "confidence": 0
        },
        "unit_amount_minor": {
          "value": 1000,
          "from": "parser_local",
          "evidence": {
            "page": 0,
            "excerpt": "string",
            "verification": "verified"
          },
          "confidence": 0
        },
        "total_amount_minor": {
          "value": 1000,
          "from": "parser_local",
          "evidence": {
            "page": 0,
            "excerpt": "string",
            "verification": "verified"
          },
          "confidence": 0
        }
      }
    ],
    "totals": {
      "subtotal_minor": {
        "value": 1000,
        "from": "parser_local",
        "evidence": {
          "page": 0,
          "excerpt": "string",
          "verification": "verified"
        },
        "confidence": 0
      },
      "discount_minor": {
        "value": 1000,
        "from": "parser_local",
        "evidence": {
          "page": 0,
          "excerpt": "string",
          "verification": "verified"
        },
        "confidence": 0
      },
      "tax_relief_deducted_minor": {
        "value": 1000,
        "from": "parser_local",
        "evidence": {
          "page": 0,
          "excerpt": "string",
          "verification": "verified"
        },
        "confidence": 0
      },
      "freight_minor": {
        "value": 1000,
        "from": "parser_local",
        "evidence": {
          "page": 0,
          "excerpt": "string",
          "verification": "verified"
        },
        "confidence": 0
      },
      "insurance_minor": {
        "value": 1000,
        "from": "parser_local",
        "evidence": {
          "page": 0,
          "excerpt": "string",
          "verification": "verified"
        },
        "confidence": 0
      },
      "other_charges_minor": {
        "value": 1000,
        "from": "parser_local",
        "evidence": {
          "page": 0,
          "excerpt": "string",
          "verification": "verified"
        },
        "confidence": 0
      },
      "taxes_added_minor": {
        "value": 1000,
        "from": "parser_local",
        "evidence": {
          "page": 0,
          "excerpt": "string",
          "verification": "verified"
        },
        "confidence": 0
      },
      "taxes_included_minor": {
        "value": 1000,
        "from": "parser_local",
        "evidence": {
          "page": 0,
          "excerpt": "string",
          "verification": "verified"
        },
        "confidence": 0
      },
      "grand_total_minor": {
        "value": 1000,
        "from": "parser_local",
        "evidence": {
          "page": 0,
          "excerpt": "string",
          "verification": "verified"
        },
        "confidence": 0
      },
      "currency": {
        "value": "string",
        "from": "parser_local",
        "evidence": {
          "page": 0,
          "excerpt": "string",
          "verification": "verified"
        },
        "confidence": 0
      }
    },
    "carriers": {
      "boleto": "string",
      "br_code": "string",
      "nfe": "string"
    },
    "extraction": {
      "model": "string",
      "model_version": "string",
      "input_tokens": 0,
      "output_tokens": 0,
      "reasoning_tokens": 0
    }
  }),
});

const data = await res.json();
const r = await cs.api.response("post", "/v1/payables", {
  body: {
    schema_version: "payable.v1",
    doc_type: "invoice",
    attribution: {
      channel: "upload",
      credential_id: "credential_0000000000000000",
      connection_id: "conn_0000000000000000",
      actor: "string"
    },
    document_hash: "string",
    supplier: {
      document: {
        value: "string",
        from: "parser_local",
        evidence: {
          page: 0,
          excerpt: "string",
          verification: "verified"
        },
        confidence: 0
      },
      name: {
        value: "string",
        from: "parser_local",
        evidence: {
          page: 0,
          excerpt: "string",
          verification: "verified"
        },
        confidence: 0
      }
    },
    recipient: {
      document: {
        value: "string",
        from: "parser_local",
        evidence: {
          page: 0,
          excerpt: "string",
          verification: "verified"
        },
        confidence: 0
      },
      name: {
        value: "string",
        from: "parser_local",
        evidence: {
          page: 0,
          excerpt: "string",
          verification: "verified"
        },
        confidence: 0
      }
    },
    invoice_number: {
      value: "string",
      from: "parser_local",
      evidence: {
        page: 0,
        excerpt: "string",
        verification: "verified"
      },
      confidence: 0
    },
    serie: {
      value: "string",
      from: "parser_local",
      evidence: {
        page: 0,
        excerpt: "string",
        verification: "verified"
      },
      confidence: 0
    },
    issue_date: {
      value: "string",
      from: "parser_local",
      evidence: {
        page: 0,
        excerpt: "string",
        verification: "verified"
      },
      confidence: 0
    },
    due_date: {
      value: "string",
      from: "parser_local",
      evidence: {
        page: 0,
        excerpt: "string",
        verification: "verified"
      },
      confidence: 0
    },
    items: [
      {
        description: {
          value: "string",
          from: "parser_local",
          evidence: {
            page: 0,
            excerpt: "string",
            verification: "verified"
          },
          confidence: 0
        },
        quantity: {
          value: 1000,
          from: "parser_local",
          evidence: {
            page: 0,
            excerpt: "string",
            verification: "verified"
          },
          confidence: 0
        },
        unit_amount_minor: {
          value: 1000,
          from: "parser_local",
          evidence: {
            page: 0,
            excerpt: "string",
            verification: "verified"
          },
          confidence: 0
        },
        total_amount_minor: {
          value: 1000,
          from: "parser_local",
          evidence: {
            page: 0,
            excerpt: "string",
            verification: "verified"
          },
          confidence: 0
        }
      }
    ],
    totals: {
      subtotal_minor: {
        value: 1000,
        from: "parser_local",
        evidence: {
          page: 0,
          excerpt: "string",
          verification: "verified"
        },
        confidence: 0
      },
      discount_minor: {
        value: 1000,
        from: "parser_local",
        evidence: {
          page: 0,
          excerpt: "string",
          verification: "verified"
        },
        confidence: 0
      },
      tax_relief_deducted_minor: {
        value: 1000,
        from: "parser_local",
        evidence: {
          page: 0,
          excerpt: "string",
          verification: "verified"
        },
        confidence: 0
      },
      freight_minor: {
        value: 1000,
        from: "parser_local",
        evidence: {
          page: 0,
          excerpt: "string",
          verification: "verified"
        },
        confidence: 0
      },
      insurance_minor: {
        value: 1000,
        from: "parser_local",
        evidence: {
          page: 0,
          excerpt: "string",
          verification: "verified"
        },
        confidence: 0
      },
      other_charges_minor: {
        value: 1000,
        from: "parser_local",
        evidence: {
          page: 0,
          excerpt: "string",
          verification: "verified"
        },
        confidence: 0
      },
      taxes_added_minor: {
        value: 1000,
        from: "parser_local",
        evidence: {
          page: 0,
          excerpt: "string",
          verification: "verified"
        },
        confidence: 0
      },
      taxes_included_minor: {
        value: 1000,
        from: "parser_local",
        evidence: {
          page: 0,
          excerpt: "string",
          verification: "verified"
        },
        confidence: 0
      },
      grand_total_minor: {
        value: 1000,
        from: "parser_local",
        evidence: {
          page: 0,
          excerpt: "string",
          verification: "verified"
        },
        confidence: 0
      },
      currency: {
        value: "string",
        from: "parser_local",
        evidence: {
          page: 0,
          excerpt: "string",
          verification: "verified"
        },
        confidence: 0
      }
    },
    carriers: {
      boleto: "string",
      br_code: "string",
      nfe: "string"
    },
    extraction: {
      model: "string",
      model_version: "string",
      input_tokens: 0,
      output_tokens: 0,
      reasoning_tokens: 0
    }
  }
});
// r.status is one of the documented statuses (200, 422),
// each with its own body shape in r.data; nothing here throws on 422.
if (r.ok) {
  console.log(r.data);
}
Example response 200
application/json
{
  "schema_version": "payable.v1",
  "doc_type": "invoice",
  "attribution": {
    "channel": "upload",
    "credential_id": "credential_0000000000000000",
    "connection_id": "conn_0000000000000000",
    "actor": "string"
  },
  "document_hash": "string",
  "supplier": {
    "document": {
      "value": "string",
      "from": "parser_local",
      "evidence": {
        "page": 0,
        "excerpt": "string",
        "verification": "verified"
      },
      "confidence": 0
    },
    "name": {
      "value": "string",
      "from": "parser_local",
      "evidence": {
        "page": 0,
        "excerpt": "string",
        "verification": "verified"
      },
      "confidence": 0
    }
  },
  "recipient": {
    "document": {
      "value": "string",
      "from": "parser_local",
      "evidence": {
        "page": 0,
        "excerpt": "string",
        "verification": "verified"
      },
      "confidence": 0
    },
    "name": {
      "value": "string",
      "from": "parser_local",
      "evidence": {
        "page": 0,
        "excerpt": "string",
        "verification": "verified"
      },
      "confidence": 0
    }
  },
  "invoice_number": {
    "value": "string",
    "from": "parser_local",
    "evidence": {
      "page": 0,
      "excerpt": "string",
      "verification": "verified"
    },
    "confidence": 0
  },
  "serie": {
    "value": "string",
    "from": "parser_local",
    "evidence": {
      "page": 0,
      "excerpt": "string",
      "verification": "verified"
    },
    "confidence": 0
  },
  "issue_date": {
    "value": "string",
    "from": "parser_local",
    "evidence": {
      "page": 0,
      "excerpt": "string",
      "verification": "verified"
    },
    "confidence": 0
  },
  "due_date": {
    "value": "string",
    "from": "parser_local",
    "evidence": {
      "page": 0,
      "excerpt": "string",
      "verification": "verified"
    },
    "confidence": 0
  },
  "items": [
    {
      "description": {
        "value": "string",
        "from": "parser_local",
        "evidence": {
          "page": 0,
          "excerpt": "string",
          "verification": "verified"
        },
        "confidence": 0
      },
      "quantity": {
        "value": 1000,
        "from": "parser_local",
        "evidence": {
          "page": 0,
          "excerpt": "string",
          "verification": "verified"
        },
        "confidence": 0
      },
      "unit_amount_minor": {
        "value": 1000,
        "from": "parser_local",
        "evidence": {
          "page": 0,
          "excerpt": "string",
          "verification": "verified"
        },
        "confidence": 0
      },
      "total_amount_minor": {
        "value": 1000,
        "from": "parser_local",
        "evidence": {
          "page": 0,
          "excerpt": "string",
          "verification": "verified"
        },
        "confidence": 0
      }
    }
  ],
  "totals": {
    "subtotal_minor": {
      "value": 1000,
      "from": "parser_local",
      "evidence": {
        "page": 0,
        "excerpt": "string",
        "verification": "verified"
      },
      "confidence": 0
    },
    "discount_minor": {
      "value": 1000,
      "from": "parser_local",
      "evidence": {
        "page": 0,
        "excerpt": "string",
        "verification": "verified"
      },
      "confidence": 0
    },
    "tax_relief_deducted_minor": {
      "value": 1000,
      "from": "parser_local",
      "evidence": {
        "page": 0,
        "excerpt": "string",
        "verification": "verified"
      },
      "confidence": 0
    },
    "freight_minor": {
      "value": 1000,
      "from": "parser_local",
      "evidence": {
        "page": 0,
        "excerpt": "string",
        "verification": "verified"
      },
      "confidence": 0
    },
    "insurance_minor": {
      "value": 1000,
      "from": "parser_local",
      "evidence": {
        "page": 0,
        "excerpt": "string",
        "verification": "verified"
      },
      "confidence": 0
    },
    "other_charges_minor": {
      "value": 1000,
      "from": "parser_local",
      "evidence": {
        "page": 0,
        "excerpt": "string",
        "verification": "verified"
      },
      "confidence": 0
    },
    "taxes_added_minor": {
      "value": 1000,
      "from": "parser_local",
      "evidence": {
        "page": 0,
        "excerpt": "string",
        "verification": "verified"
      },
      "confidence": 0
    },
    "taxes_included_minor": {
      "value": 1000,
      "from": "parser_local",
      "evidence": {
        "page": 0,
        "excerpt": "string",
        "verification": "verified"
      },
      "confidence": 0
    },
    "grand_total_minor": {
      "value": 1000,
      "from": "parser_local",
      "evidence": {
        "page": 0,
        "excerpt": "string",
        "verification": "verified"
      },
      "confidence": 0
    },
    "currency": {
      "value": "string",
      "from": "parser_local",
      "evidence": {
        "page": 0,
        "excerpt": "string",
        "verification": "verified"
      },
      "confidence": 0
    }
  },
  "carriers": {
    "boleto": "string",
    "br_code": "string",
    "nfe": "string"
  },
  "extraction": {
    "model": "string",
    "model_version": "string",
    "input_tokens": 0,
    "output_tokens": 0,
    "reasoning_tokens": 0
  },
  "payable_id": "payable_0000000000000000",
  "status": "RECEIVED",
  "rail_quote": {
    "beneficiary": {
      "value": "string",
      "from": "trilho"
    },
    "beneficiary_document_masked": {
      "value": "string",
      "from": "trilho"
    },
    "final_beneficiary": {
      "value": "string",
      "from": "trilho"
    },
    "final_beneficiary_document_masked": {
      "value": "string",
      "from": "trilho"
    },
    "amount_minor": {
      "value": 1000,
      "from": "trilho"
    },
    "discount_minor": {
      "value": 1000,
      "from": "trilho"
    },
    "interest_minor": {
      "value": 1000,
      "from": "trilho"
    },
    "fine_minor": {
      "value": 1000,
      "from": "trilho"
    },
    "due_date": {
      "value": "string",
      "from": "trilho"
    },
    "quoted_at": "2026-01-15T12:00:00.000Z"
  },
  "validation": {
    "carrier_check_digits": {
      "outcome": "ok",
      "detail": "string"
    },
    "document_check_digits": {
      "outcome": "ok",
      "detail": "string"
    },
    "nfe_key_consistency": {
      "outcome": "ok",
      "detail": "string"
    },
    "arithmetic": {
      "outcome": "ok",
      "detail": "string"
    },
    "duplicate_document": {
      "outcome": "ok",
      "detail": "string"
    },
    "amount_matches_rail": {
      "outcome": "ok",
      "detail": "string"
    },
    "beneficiary_document_matches_supplier": {
      "outcome": "ok",
      "detail": "string"
    },
    "due_date_state": {
      "outcome": "ok",
      "detail": "string"
    },
    "pix_key_owner_matches_supplier": {
      "outcome": "ok",
      "detail": "string"
    },
    "supplier_registry": {
      "outcome": "ok",
      "detail": "string"
    },
    "bank_details_changed": {
      "outcome": "ok",
      "detail": "string"
    }
  },
  "review": {
    "validation_status": "REJECTED",
    "review_by": [
      {
        "code": "string",
        "cause": "check_failed"
      }
    ],
    "rejected_by": [
      "string"
    ],
    "confirmed_by": [
      "string"
    ],
    "awaiting": [
      "string"
    ],
    "not_covered": [
      "string"
    ],
    "review_triggers": [
      "string"
    ],
    "resolutions": [
      {
        "code": "string",
        "resolution": "human_correction",
        "at": "string",
        "by": "string",
        "by_source": "verified_user_token",
        "fields": [
          "string"
        ],
        "confirmed_beneficiary_document": "string"
      }
    ]
  },
  "payment": {
    "state": "awaiting_approval",
    "approval_id": "approval_0000000000000000",
    "settled_against": "document_line",
    "document_amount_minor": 1000,
    "mandate_id": "mandate_0000000000000000",
    "attempt_id": "attempt_0000000000000000",
    "tries": 0,
    "amount_minor": 1000,
    "quote_hash": "string",
    "claimed_at": "string",
    "key_id": "key_0000000000000000",
    "via": "string",
    "executed_at": "string",
    "receipt_id": "receipt_0000000000000000",
    "transaction_id": "transaction_0000000000000000",
    "end_to_end_id": "endtoend_0000000000000000",
    "money_moved": true,
    "uncertain_code": "string",
    "hold_entry_id": "holdentry_0000000000000000",
    "last_refusal": {
      "code": "string",
      "attempt_id": "attempt_0000000000000000",
      "at": "string"
    }
  },
  "created_at": "string",
  "updated_at": "string",
  "idempotent_replay": true
}

GET /v1/payables/counts

GEThttps://api.codespar.dev/v1/payables/counts

Count the payables waiting for a person

How many of this project's payables are NEEDS_REVIEW and how many are READY, and how many unpaid open ones fall due in the rest of this week. due_this_week counts READY and APPROVED payables (an APPROVED payment is claimed or awaiting an approval and has not paid yet) whose EFFECTIVE due date is from today to Sunday of the current São Paulo week, inclusive (the day taken in America/Sao_Paulo; weeks run Monday to Sunday). The effective due date is the printed one rolled forward to the next bank business day, the day until which the bill is payable without charges: a boleto due last Saturday is due this Monday. Due today is in it; an effective due date before today is overdue and is not. NEEDS_REVIEW is not in due_this_week, and a payable with no due date never is.

overdue counts the same READY and APPROVED set whose effective due date is before today.

Scope: payables:read.

Responses

StatusBodyDescription
200objectOK

Response 200

FieldTypeRequiredDescription
due_this_weekintegeryesUnpaid open payables (READY and APPROVED) whose EFFECTIVE due date (due_date_effective) is from today to Sunday of the current São Paulo week, inclusive. Due today is in it; an effective due date before today is overdue and is not; NEEDS_REVIEW is not in it.
needs_reviewintegeryesPayables in NEEDS_REVIEW.
overdueintegeryesThe same unpaid open payables (READY and APPROVED) whose EFFECTIVE due date is before today in São Paulo. A printed date before today that rolls forward to today is not overdue; NEEDS_REVIEW is not in it.
readyintegeryesPayables in READY.
Example request
curl -X GET https://api.codespar.dev/v1/payables/counts \
  -H "Authorization: Bearer $CODESPAR_API_KEY"
GET /v1/payables/counts HTTP/1.1
Host: api.codespar.dev
Authorization: Bearer $CODESPAR_API_KEY
import os
import requests

res = requests.get(
    "https://api.codespar.dev/v1/payables/counts",
    headers={"Authorization": f"Bearer {os.environ['CODESPAR_API_KEY']}"},
)
res.raise_for_status()
data = res.json()
const res = await fetch("https://api.codespar.dev/v1/payables/counts", {
  method: "GET",
  headers: {
    Authorization: `Bearer ${process.env.CODESPAR_API_KEY}`,
  },
});

const data = await res.json();
const result = await cs.api.get("/v1/payables/counts");
Example response 200
application/json
{
  "needs_review": 0,
  "ready": 0,
  "due_this_week": 0,
  "overdue": 0
}

POST /v1/payables/documents

POSThttps://api.codespar.dev/v1/payables/documents

Create a payable from an uploaded document (PDF or image)

The file goes in the multipart field document (PDF, PNG, JPEG or WEBP by its bytes; the declared type is not consulted), an optional text field actor names the person who uploaded it, and the payable is READ from the document: attribution.channel is upload, every field carries from: "modelo", a page and a literal excerpt, and extraction names the model and its token counts. From there it enters the same pipeline as POST /v1/payables — the same schema, the same deterministic checks, the same duplicate axes, the same statuses — and answers the same 200/201 shape. A JSON body sent here answers 415 payable_document_required.

Upload (multipart). The door is behind a deployment switch: while it is off every upload answers 503 payable_extraction_disabled and nothing is read or stored. The file is checked before any reader sees it — real type by magic bytes (415 payable_document_type_unsupported; HEIC is detected and named but not accepted), at most 10 MB (413 payable_document_too_large), at most 10 pages (422 payable_document_too_many_pages), no JavaScript, embedded files, forms or launch actions (422 payable_document_active_content; refused, not stripped, so the hash on the payable is the hash of the bytes sent), and it must open (422 payable_document_unreadable, details.reason encrypted or malformed). The SHA-256 of the file is document_hash, computed before anything else: a file an open or paid payable of this project already holds answers 409 payable_duplicate on the document_hash axis without being read again. The original file is NOT kept; re-extraction is re-upload.

The reader's citations are checked against the PDF's text layer (§7): each field's evidence.verification is verified, moved (the excerpt is on another page) or unverifiable (an image, or a PDF with no text layer — a scan). moved and unverifiable on a critical field open the critical_field_without_evidence review trigger; an excerpt that is in NO page of a critical field refuses the whole document, 422 payable_evidence_fabricated, and nothing is stored. A reader that did not find enough for the schema answers 422 payable_extraction_incomplete naming the missing paths. A reader that did not answer after a bounded retry answers 502 payable_extraction_unavailable (retriable, nothing stored; the original is not kept, so there is no failed row to resume); a reader that declined the document answers 422 payable_extraction_refused. Nothing of the document's content reaches a log, an audit event or an error body: the trail carries the hash, the model, the token counts and the verdict counts.

The amount and the payee come from the rail, never from what was sent. amount_matches_rail, beneficiary_document_matches_supplier and due_date_state run against a consult of the boleto on the payable, and they block READY whether or not they answered. A consult that could not be made — no connected payment provider, a provider that did not answer — leaves them indisponivel and the payable NEEDS_REVIEW, named under review.review_by. pix_key_owner_matches_supplier is not consulted in this release and blocks a payable carrying a Pix BR Code with cause required_not_implemented. VALIDATING is never returned: nothing re-runs a validation yet, so a check with no answer goes to a person rather than waiting. due_date_state calls a payable overdue only after its EFFECTIVE due date: a due date on a weekend, a national bank holiday (Carnival Monday and Tuesday and Corpus Christi included) or, for a boleto, the last business day of the year is payable without charges on the next business day. State and municipal holidays are not considered.

Status. Two fields answer two questions. review.validation_status is what the checks alone say: REJECTED (a check that rejects failed), NEEDS_REVIEW (a check failed, or a required check has no answer it can have), VALIDATING (a required, implemented check did not answer and will be retried) or VALIDATED (every required check passed). status is what the payable may do: READY only from VALIDATED with no review trigger open, and NEEDS_REVIEW when a trigger is open. The trigger this API evaluates is new_supplier: this project has no executed payable for the supplier's document, or the payable names no supplier document. It is evaluated per project, never across projects.

Why things are in review. review.review_by lists each check that sends the payable to a person and its cause: check_failed, retries_exhausted or required_not_implemented. review.review_triggers lists the open triggers. review.not_covered lists checks that did not run and do not block READY in this release (supplier_registry, bank_details_changed).

Idempotency. Send an Idempotency-Key header to make a retry safe. The same key with the same file answers 200 with idempotent_replay: true; the same key with a different file answers 409 idempotency_key_conflict. Both are checked before the reader runs, so a retry never spends a model call.

Scope: payables:write.

Responses

StatusBodyDescription
200objectOK
201objectOK
400objectThe multipart field document is absent or empty (payable_document_required), the actor field is out of shape or the multipart body could not be read (invalid_body), or the Idempotency-Key header is empty or longer than 255 characters.
409objectpayable_duplicate: an open or paid payable of this project already holds this file's document_hash (refused before the reader runs; no details.validation) or shares a carrier with what was read. idempotency_key_conflict: the key was used with a different file.
413objectThe uploaded file exceeds 10 MB. Nothing was read or stored.
415objectpayable_document_type_unsupported: the file is not a PDF, PNG, JPEG or WEBP by its bytes; details.detected names what it is when known (image/heic is detected and not accepted). payable_document_required: the body was not multipart/form-data at all.
422objectThe PDF has more than 10 pages (payable_document_too_many_pages), carries active content (payable_document_active_content, details.found), or cannot be opened (payable_document_unreadable, details.reason); the reader cited, for a critical field, a passage in no page (payable_evidence_fabricated, details.fields); the reader found too little (payable_extraction_incomplete, details.issues); the reader declined the document (payable_extraction_refused); or a carrier it read fails its check digits (payable_carrier_malformed). None of these stores anything.
502objectpayable_extraction_unavailable: the reader did not answer usably after a bounded retry (details.attempts); nothing was stored; retry later with the same Idempotency-Key. payable_extraction_failed: the extraction request was refused for a reason on our side; not fixable by retrying.
503objectpayable_extraction_disabled: the document door is switched off on this deployment; send the payable as JSON (structured or manual). payable_extractor_unconfigured: the door is on with no reader behind it; a deployment fault, not retriable. vault_unavailable: the key that protects supplier documents could not be read; retry later with the same Idempotency-Key.

Response 200

FieldTypeRequiredDescription
attributionobjectyes—
carriersobjectno—
created_atstringyesISO 8601 instant the payable was created.
doc_type"invoice" | "danfe_nfe" | "boleto" | "unknown"yes—
document_hashstringno—
due_dateobjectno—
extractionobjectno—
idempotent_replaybooleanyesTrue when this answer replays an earlier call made with the same Idempotency-Key.
invoice_numberobjectno—
issue_dateobjectno—
itemsarray of objectno—
payable_idstringyes—
paymentobject,nullyesWhat paying it did (ent#1587); null until a payment was attempted.
rail_quoteobjectno—
recipientobjectno—
reviewobjectyes—
schema_version"payable.v1"yes—
serieobjectno—
status"RECEIVED" | "EXTRACTING" | "EXTRACTED" | "VALIDATING" | "VALIDATED" | "NEEDS_REVIEW" | "READY" | "APPROVED" | "EXECUTED" | "REJECTED" | "FAILED_EXTRACTION" | "EXPIRED"yes—
supplierobjectyes—
totalsobjectyes—
updated_atstringyesISO 8601 instant of the last change to the payable.
validationobjectyes—
Example request
curl -X POST https://api.codespar.dev/v1/payables/documents \
  -H "Authorization: Bearer $CODESPAR_API_KEY"
POST /v1/payables/documents HTTP/1.1
Host: api.codespar.dev
Authorization: Bearer $CODESPAR_API_KEY
import os
import requests

res = requests.post(
    "https://api.codespar.dev/v1/payables/documents",
    headers={"Authorization": f"Bearer {os.environ['CODESPAR_API_KEY']}"},
)
res.raise_for_status()
data = res.json()
const res = await fetch("https://api.codespar.dev/v1/payables/documents", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.CODESPAR_API_KEY}`,
  },
});

const data = await res.json();
const r = await cs.api.response("post", "/v1/payables/documents", {
  body: {
    document: "string",
    actor: "string"
  }
});
// r.status is one of the documented statuses (200, 422),
// each with its own body shape in r.data; nothing here throws on 422.
if (r.ok) {
  console.log(r.data);
}
Example response 200
application/json
{
  "schema_version": "payable.v1",
  "doc_type": "invoice",
  "attribution": {
    "channel": "upload",
    "credential_id": "credential_0000000000000000",
    "connection_id": "conn_0000000000000000",
    "actor": "string"
  },
  "document_hash": "string",
  "supplier": {
    "document": {
      "value": "string",
      "from": "parser_local",
      "evidence": {
        "page": 0,
        "excerpt": "string",
        "verification": "verified"
      },
      "confidence": 0
    },
    "name": {
      "value": "string",
      "from": "parser_local",
      "evidence": {
        "page": 0,
        "excerpt": "string",
        "verification": "verified"
      },
      "confidence": 0
    }
  },
  "recipient": {
    "document": {
      "value": "string",
      "from": "parser_local",
      "evidence": {
        "page": 0,
        "excerpt": "string",
        "verification": "verified"
      },
      "confidence": 0
    },
    "name": {
      "value": "string",
      "from": "parser_local",
      "evidence": {
        "page": 0,
        "excerpt": "string",
        "verification": "verified"
      },
      "confidence": 0
    }
  },
  "invoice_number": {
    "value": "string",
    "from": "parser_local",
    "evidence": {
      "page": 0,
      "excerpt": "string",
      "verification": "verified"
    },
    "confidence": 0
  },
  "serie": {
    "value": "string",
    "from": "parser_local",
    "evidence": {
      "page": 0,
      "excerpt": "string",
      "verification": "verified"
    },
    "confidence": 0
  },
  "issue_date": {
    "value": "string",
    "from": "parser_local",
    "evidence": {
      "page": 0,
      "excerpt": "string",
      "verification": "verified"
    },
    "confidence": 0
  },
  "due_date": {
    "value": "string",
    "from": "parser_local",
    "evidence": {
      "page": 0,
      "excerpt": "string",
      "verification": "verified"
    },
    "confidence": 0
  },
  "items": [
    {
      "description": {
        "value": "string",
        "from": "parser_local",
        "evidence": {
          "page": 0,
          "excerpt": "string",
          "verification": "verified"
        },
        "confidence": 0
      },
      "quantity": {
        "value": 1000,
        "from": "parser_local",
        "evidence": {
          "page": 0,
          "excerpt": "string",
          "verification": "verified"
        },
        "confidence": 0
      },
      "unit_amount_minor": {
        "value": 1000,
        "from": "parser_local",
        "evidence": {
          "page": 0,
          "excerpt": "string",
          "verification": "verified"
        },
        "confidence": 0
      },
      "total_amount_minor": {
        "value": 1000,
        "from": "parser_local",
        "evidence": {
          "page": 0,
          "excerpt": "string",
          "verification": "verified"
        },
        "confidence": 0
      }
    }
  ],
  "totals": {
    "subtotal_minor": {
      "value": 1000,
      "from": "parser_local",
      "evidence": {
        "page": 0,
        "excerpt": "string",
        "verification": "verified"
      },
      "confidence": 0
    },
    "discount_minor": {
      "value": 1000,
      "from": "parser_local",
      "evidence": {
        "page": 0,
        "excerpt": "string",
        "verification": "verified"
      },
      "confidence": 0
    },
    "tax_relief_deducted_minor": {
      "value": 1000,
      "from": "parser_local",
      "evidence": {
        "page": 0,
        "excerpt": "string",
        "verification": "verified"
      },
      "confidence": 0
    },
    "freight_minor": {
      "value": 1000,
      "from": "parser_local",
      "evidence": {
        "page": 0,
        "excerpt": "string",
        "verification": "verified"
      },
      "confidence": 0
    },
    "insurance_minor": {
      "value": 1000,
      "from": "parser_local",
      "evidence": {
        "page": 0,
        "excerpt": "string",
        "verification": "verified"
      },
      "confidence": 0
    },
    "other_charges_minor": {
      "value": 1000,
      "from": "parser_local",
      "evidence": {
        "page": 0,
        "excerpt": "string",
        "verification": "verified"
      },
      "confidence": 0
    },
    "taxes_added_minor": {
      "value": 1000,
      "from": "parser_local",
      "evidence": {
        "page": 0,
        "excerpt": "string",
        "verification": "verified"
      },
      "confidence": 0
    },
    "taxes_included_minor": {
      "value": 1000,
      "from": "parser_local",
      "evidence": {
        "page": 0,
        "excerpt": "string",
        "verification": "verified"
      },
      "confidence": 0
    },
    "grand_total_minor": {
      "value": 1000,
      "from": "parser_local",
      "evidence": {
        "page": 0,
        "excerpt": "string",
        "verification": "verified"
      },
      "confidence": 0
    },
    "currency": {
      "value": "string",
      "from": "parser_local",
      "evidence": {
        "page": 0,
        "excerpt": "string",
        "verification": "verified"
      },
      "confidence": 0
    }
  },
  "carriers": {
    "boleto": "string",
    "br_code": "string",
    "nfe": "string"
  },
  "extraction": {
    "model": "string",
    "model_version": "string",
    "input_tokens": 0,
    "output_tokens": 0,
    "reasoning_tokens": 0
  },
  "payable_id": "payable_0000000000000000",
  "status": "RECEIVED",
  "rail_quote": {
    "beneficiary": {
      "value": "string",
      "from": "trilho"
    },
    "beneficiary_document_masked": {
      "value": "string",
      "from": "trilho"
    },
    "final_beneficiary": {
      "value": "string",
      "from": "trilho"
    },
    "final_beneficiary_document_masked": {
      "value": "string",
      "from": "trilho"
    },
    "amount_minor": {
      "value": 1000,
      "from": "trilho"
    },
    "discount_minor": {
      "value": 1000,
      "from": "trilho"
    },
    "interest_minor": {
      "value": 1000,
      "from": "trilho"
    },
    "fine_minor": {
      "value": 1000,
      "from": "trilho"
    },
    "due_date": {
      "value": "string",
      "from": "trilho"
    },
    "quoted_at": "2026-01-15T12:00:00.000Z"
  },
  "validation": {
    "carrier_check_digits": {
      "outcome": "ok",
      "detail": "string"
    },
    "document_check_digits": {
      "outcome": "ok",
      "detail": "string"
    },
    "nfe_key_consistency": {
      "outcome": "ok",
      "detail": "string"
    },
    "arithmetic": {
      "outcome": "ok",
      "detail": "string"
    },
    "duplicate_document": {
      "outcome": "ok",
      "detail": "string"
    },
    "amount_matches_rail": {
      "outcome": "ok",
      "detail": "string"
    },
    "beneficiary_document_matches_supplier": {
      "outcome": "ok",
      "detail": "string"
    },
    "due_date_state": {
      "outcome": "ok",
      "detail": "string"
    },
    "pix_key_owner_matches_supplier": {
      "outcome": "ok",
      "detail": "string"
    },
    "supplier_registry": {
      "outcome": "ok",
      "detail": "string"
    },
    "bank_details_changed": {
      "outcome": "ok",
      "detail": "string"
    }
  },
  "review": {
    "validation_status": "REJECTED",
    "review_by": [
      {
        "code": "string",
        "cause": "check_failed"
      }
    ],
    "rejected_by": [
      "string"
    ],
    "confirmed_by": [
      "string"
    ],
    "awaiting": [
      "string"
    ],
    "not_covered": [
      "string"
    ],
    "review_triggers": [
      "string"
    ],
    "resolutions": [
      {
        "code": "string",
        "resolution": "human_correction",
        "at": "string",
        "by": "string",
        "by_source": "verified_user_token",
        "fields": [
          "string"
        ],
        "confirmed_beneficiary_document": "string"
      }
    ]
  },
  "payment": {
    "state": "awaiting_approval",
    "approval_id": "approval_0000000000000000",
    "settled_against": "document_line",
    "document_amount_minor": 1000,
    "mandate_id": "mandate_0000000000000000",
    "attempt_id": "attempt_0000000000000000",
    "tries": 0,
    "amount_minor": 1000,
    "quote_hash": "string",
    "claimed_at": "string",
    "key_id": "key_0000000000000000",
    "via": "string",
    "executed_at": "string",
    "receipt_id": "receipt_0000000000000000",
    "transaction_id": "transaction_0000000000000000",
    "end_to_end_id": "endtoend_0000000000000000",
    "money_moved": true,
    "uncertain_code": "string",
    "hold_entry_id": "holdentry_0000000000000000",
    "last_refusal": {
      "code": "string",
      "attempt_id": "attempt_0000000000000000",
      "at": "string"
    }
  },
  "created_at": "string",
  "updated_at": "string",
  "idempotent_replay": true
}

GET /v1/payables/{payableId}

GEThttps://api.codespar.dev/v1/payables/{payableId}

Read a payable

The payable, its status, the outcome of every check in validation, and why it has that status in review. Reading never re-runs a check or changes the status. The amount and the payee come from the rail, never from what was sent. amount_matches_rail, beneficiary_document_matches_supplier and due_date_state run against a consult of the boleto on the payable, and they block READY whether or not they answered. A consult that could not be made — no connected payment provider, a provider that did not answer — leaves them indisponivel and the payable NEEDS_REVIEW, named under review.review_by. pix_key_owner_matches_supplier is not consulted in this release and blocks a payable carrying a Pix BR Code with cause required_not_implemented. VALIDATING is never returned: nothing re-runs a validation yet, so a check with no answer goes to a person rather than waiting. due_date_state calls a payable overdue only after its EFFECTIVE due date: a due date on a weekend, a national bank holiday (Carnival Monday and Tuesday and Corpus Christi included) or, for a boleto, the last business day of the year is payable without charges on the next business day. State and municipal holidays are not considered.

Status. Two fields answer two questions. review.validation_status is what the checks alone say: REJECTED (a check that rejects failed), NEEDS_REVIEW (a check failed, or a required check has no answer it can have), VALIDATING (a required, implemented check did not answer and will be retried) or VALIDATED (every required check passed). status is what the payable may do: READY only from VALIDATED with no review trigger open, and NEEDS_REVIEW when a trigger is open. The trigger this API evaluates is new_supplier: this project has no executed payable for the supplier's document, or the payable names no supplier document. It is evaluated per project, never across projects.

Why things are in review. review.review_by lists each check that sends the payable to a person and its cause: check_failed, retries_exhausted or required_not_implemented. review.review_triggers lists the open triggers. review.not_covered lists checks that did not run and do not block READY in this release (supplier_registry, bank_details_changed).

A payable of another project, of another organization and an id that is not a payable id all answer the same 404.

Scope: payables:read.

Path parameters

NameTypeRequiredDescription
payableIdstringyespbl_ followed by 16 characters.

Responses

StatusBodyDescription
200objectOK
404objectNo payable with this id in this project.

Response 200

FieldTypeRequiredDescription
attributionobjectyes—
carriersobjectno—
created_atstringyesISO 8601 instant the payable was created.
doc_type"invoice" | "danfe_nfe" | "boleto" | "unknown"yes—
document_hashstringno—
due_dateobjectno—
extractionobjectno—
invoice_numberobjectno—
issue_dateobjectno—
itemsarray of objectno—
payable_idstringyes—
paymentobject,nullyesWhat paying it did (ent#1587); null until a payment was attempted.
rail_quoteobjectno—
recipientobjectno—
reviewobjectyes—
schema_version"payable.v1"yes—
serieobjectno—
status"RECEIVED" | "EXTRACTING" | "EXTRACTED" | "VALIDATING" | "VALIDATED" | "NEEDS_REVIEW" | "READY" | "APPROVED" | "EXECUTED" | "REJECTED" | "FAILED_EXTRACTION" | "EXPIRED"yes—
supplierobjectyes—
totalsobjectyes—
updated_atstringyesISO 8601 instant of the last change to the payable.
validationobjectyes—
Example request
curl -X GET https://api.codespar.dev/v1/payables/{payableId} \
  -H "Authorization: Bearer $CODESPAR_API_KEY"
GET /v1/payables/{payableId} HTTP/1.1
Host: api.codespar.dev
Authorization: Bearer $CODESPAR_API_KEY
import os
import requests

res = requests.get(
    "https://api.codespar.dev/v1/payables/{payableId}",
    headers={"Authorization": f"Bearer {os.environ['CODESPAR_API_KEY']}"},
)
res.raise_for_status()
data = res.json()
const res = await fetch("https://api.codespar.dev/v1/payables/{payableId}", {
  method: "GET",
  headers: {
    Authorization: `Bearer ${process.env.CODESPAR_API_KEY}`,
  },
});

const data = await res.json();
const result = await cs.api.get("/v1/payables/{payableId}", {
  path: {
    payableId: "payable_0000000000000000"
  }
});
Example response 200
application/json
{
  "schema_version": "payable.v1",
  "doc_type": "invoice",
  "attribution": {
    "channel": "upload",
    "credential_id": "credential_0000000000000000",
    "connection_id": "conn_0000000000000000",
    "actor": "string"
  },
  "document_hash": "string",
  "supplier": {
    "document": {
      "value": "string",
      "from": "parser_local",
      "evidence": {
        "page": 0,
        "excerpt": "string",
        "verification": "verified"
      },
      "confidence": 0
    },
    "name": {
      "value": "string",
      "from": "parser_local",
      "evidence": {
        "page": 0,
        "excerpt": "string",
        "verification": "verified"
      },
      "confidence": 0
    }
  },
  "recipient": {
    "document": {
      "value": "string",
      "from": "parser_local",
      "evidence": {
        "page": 0,
        "excerpt": "string",
        "verification": "verified"
      },
      "confidence": 0
    },
    "name": {
      "value": "string",
      "from": "parser_local",
      "evidence": {
        "page": 0,
        "excerpt": "string",
        "verification": "verified"
      },
      "confidence": 0
    }
  },
  "invoice_number": {
    "value": "string",
    "from": "parser_local",
    "evidence": {
      "page": 0,
      "excerpt": "string",
      "verification": "verified"
    },
    "confidence": 0
  },
  "serie": {
    "value": "string",
    "from": "parser_local",
    "evidence": {
      "page": 0,
      "excerpt": "string",
      "verification": "verified"
    },
    "confidence": 0
  },
  "issue_date": {
    "value": "string",
    "from": "parser_local",
    "evidence": {
      "page": 0,
      "excerpt": "string",
      "verification": "verified"
    },
    "confidence": 0
  },
  "due_date": {
    "value": "string",
    "from": "parser_local",
    "evidence": {
      "page": 0,
      "excerpt": "string",
      "verification": "verified"
    },
    "confidence": 0
  },
  "items": [
    {
      "description": {
        "value": "string",
        "from": "parser_local",
        "evidence": {
          "page": 0,
          "excerpt": "string",
          "verification": "verified"
        },
        "confidence": 0
      },
      "quantity": {
        "value": 1000,
        "from": "parser_local",
        "evidence": {
          "page": 0,
          "excerpt": "string",
          "verification": "verified"
        },
        "confidence": 0
      },
      "unit_amount_minor": {
        "value": 1000,
        "from": "parser_local",
        "evidence": {
          "page": 0,
          "excerpt": "string",
          "verification": "verified"
        },
        "confidence": 0
      },
      "total_amount_minor": {
        "value": 1000,
        "from": "parser_local",
        "evidence": {
          "page": 0,
          "excerpt": "string",
          "verification": "verified"
        },
        "confidence": 0
      }
    }
  ],
  "totals": {
    "subtotal_minor": {
      "value": 1000,
      "from": "parser_local",
      "evidence": {
        "page": 0,
        "excerpt": "string",
        "verification": "verified"
      },
      "confidence": 0
    },
    "discount_minor": {
      "value": 1000,
      "from": "parser_local",
      "evidence": {
        "page": 0,
        "excerpt": "string",
        "verification": "verified"
      },
      "confidence": 0
    },
    "tax_relief_deducted_minor": {
      "value": 1000,
      "from": "parser_local",
      "evidence": {
        "page": 0,
        "excerpt": "string",
        "verification": "verified"
      },
      "confidence": 0
    },
    "freight_minor": {
      "value": 1000,
      "from": "parser_local",
      "evidence": {
        "page": 0,
        "excerpt": "string",
        "verification": "verified"
      },
      "confidence": 0
    },
    "insurance_minor": {
      "value": 1000,
      "from": "parser_local",
      "evidence": {
        "page": 0,
        "excerpt": "string",
        "verification": "verified"
      },
      "confidence": 0
    },
    "other_charges_minor": {
      "value": 1000,
      "from": "parser_local",
      "evidence": {
        "page": 0,
        "excerpt": "string",
        "verification": "verified"
      },
      "confidence": 0
    },
    "taxes_added_minor": {
      "value": 1000,
      "from": "parser_local",
      "evidence": {
        "page": 0,
        "excerpt": "string",
        "verification": "verified"
      },
      "confidence": 0
    },
    "taxes_included_minor": {
      "value": 1000,
      "from": "parser_local",
      "evidence": {
        "page": 0,
        "excerpt": "string",
        "verification": "verified"
      },
      "confidence": 0
    },
    "grand_total_minor": {
      "value": 1000,
      "from": "parser_local",
      "evidence": {
        "page": 0,
        "excerpt": "string",
        "verification": "verified"
      },
      "confidence": 0
    },
    "currency": {
      "value": "string",
      "from": "parser_local",
      "evidence": {
        "page": 0,
        "excerpt": "string",
        "verification": "verified"
      },
      "confidence": 0
    }
  },
  "carriers": {
    "boleto": "string",
    "br_code": "string",
    "nfe": "string"
  },
  "extraction": {
    "model": "string",
    "model_version": "string",
    "input_tokens": 0,
    "output_tokens": 0,
    "reasoning_tokens": 0
  },
  "payable_id": "payable_0000000000000000",
  "status": "RECEIVED",
  "rail_quote": {
    "beneficiary": {
      "value": "string",
      "from": "trilho"
    },
    "beneficiary_document_masked": {
      "value": "string",
      "from": "trilho"
    },
    "final_beneficiary": {
      "value": "string",
      "from": "trilho"
    },
    "final_beneficiary_document_masked": {
      "value": "string",
      "from": "trilho"
    },
    "amount_minor": {
      "value": 1000,
      "from": "trilho"
    },
    "discount_minor": {
      "value": 1000,
      "from": "trilho"
    },
    "interest_minor": {
      "value": 1000,
      "from": "trilho"
    },
    "fine_minor": {
      "value": 1000,
      "from": "trilho"
    },
    "due_date": {
      "value": "string",
      "from": "trilho"
    },
    "quoted_at": "2026-01-15T12:00:00.000Z"
  },
  "validation": {
    "carrier_check_digits": {
      "outcome": "ok",
      "detail": "string"
    },
    "document_check_digits": {
      "outcome": "ok",
      "detail": "string"
    },
    "nfe_key_consistency": {
      "outcome": "ok",
      "detail": "string"
    },
    "arithmetic": {
      "outcome": "ok",
      "detail": "string"
    },
    "duplicate_document": {
      "outcome": "ok",
      "detail": "string"
    },
    "amount_matches_rail": {
      "outcome": "ok",
      "detail": "string"
    },
    "beneficiary_document_matches_supplier": {
      "outcome": "ok",
      "detail": "string"
    },
    "due_date_state": {
      "outcome": "ok",
      "detail": "string"
    },
    "pix_key_owner_matches_supplier": {
      "outcome": "ok",
      "detail": "string"
    },
    "supplier_registry": {
      "outcome": "ok",
      "detail": "string"
    },
    "bank_details_changed": {
      "outcome": "ok",
      "detail": "string"
    }
  },
  "review": {
    "validation_status": "REJECTED",
    "review_by": [
      {
        "code": "string",
        "cause": "check_failed"
      }
    ],
    "rejected_by": [
      "string"
    ],
    "confirmed_by": [
      "string"
    ],
    "awaiting": [
      "string"
    ],
    "not_covered": [
      "string"
    ],
    "review_triggers": [
      "string"
    ],
    "resolutions": [
      {
        "code": "string",
        "resolution": "human_correction",
        "at": "string",
        "by": "string",
        "by_source": "verified_user_token",
        "fields": [
          "string"
        ],
        "confirmed_beneficiary_document": "string"
      }
    ]
  },
  "payment": {
    "state": "awaiting_approval",
    "approval_id": "approval_0000000000000000",
    "settled_against": "document_line",
    "document_amount_minor": 1000,
    "mandate_id": "mandate_0000000000000000",
    "attempt_id": "attempt_0000000000000000",
    "tries": 0,
    "amount_minor": 1000,
    "quote_hash": "string",
    "claimed_at": "string",
    "key_id": "key_0000000000000000",
    "via": "string",
    "executed_at": "string",
    "receipt_id": "receipt_0000000000000000",
    "transaction_id": "transaction_0000000000000000",
    "end_to_end_id": "endtoend_0000000000000000",
    "money_moved": true,
    "uncertain_code": "string",
    "hold_entry_id": "holdentry_0000000000000000",
    "last_refusal": {
      "code": "string",
      "attempt_id": "attempt_0000000000000000",
      "at": "string"
    }
  },
  "created_at": "string",
  "updated_at": "string"
}

POST /v1/payables/{payableId}/pay

POSThttps://api.codespar.dev/v1/payables/{payableId}/pay
Moves money

Pays a `READY` payable through the governed consumer-payment cycle

Pay a payable under a consumer mandate

Pays a READY payable through the governed consumer-payment cycle — mandate HMAC verification, policy, cap under lock, hold, dispatch with uncertainty classification and a sealed receipt — and moves it to EXECUTED. Only a boleto is paid in this wave.

The rail is consulted again first. The stored quote may have aged, so the eleven checks re-run over a fresh consult, with the review's confirmations standing. If that verdict no longer allows paying, nothing is dispatched: the payable goes back to NEEDS_REVIEW with the new verdict and the call answers payable_quote_diverged. READY is derived from a verdict, never assumed from the row.

The attempt id is derived, from the payable id and the fresh quote (payment.attempt_id). The same quote is the same attempt — a retry lands on the same hold, the same provider anchor and the same receipt — and a different quote is a different attempt, which is why the payable leaves READY before money moves.

What the outcome does to the payable. Success: EXECUTED, payment.state = executed, with receipt_id, transaction_id and end_to_end_id; the response also carries receipt. A refusal that provably moved no money (policy, cap, allowlist, funds, boleto_amount_mismatch): the payable is READY again with payment.last_refusal. A dispatch whose outcome is unknown (psp_dispatch_uncertain, psp_attempt_uncertain, payable_dispatch_unknown): the payable stays APPROVED with payment.state = uncertain, pinned for reconciliation — do not resubmit it, under this payable or another; a later call answers payable_payment_uncertain.

The receipt carries the document hash. Its delivery proof is a merchant_document_ref of kind payable whose reference is payable:<id>;sha256:<document_hash> (the hash part only when the payable has one), covered by the receipt's chain: document → mandate → payment → receipt verifies offline.

A policy approval holds the payable. When the durable policy engine routes the spend to a person (403 policy_denied with approval_id), the payable leaves READY under that approval (payment.state = awaiting_approval, payment.approval_id); /pay answers payable_payment_pending_approval until it is decided. The approved execution pays the attempt and records the outcome on the payable; a denied or expired approval is released by the next /pay, which asks the gate again.

Test projects settle the sandbox fixture. A boleto in a test project is settled against Celcoin's sandbox fixture, not the document's line (spec §18): payment.settled_against = sandbox_fixture, payment.document_amount_minor keeps what the document quoted, and the receipt's delivery reference ends in ;settled_against:sandbox_fixture. Live projects are untouched.

Scope: payables:pay. The mandate must be one of this organization's consumers' and its merchant_allowlist must name the boleto's digitable line.

Path parameters

NameTypeRequiredDescription
payableIdstringyespbl_ followed by 16 characters.

Request body

FieldTypeRequiredDescription
mandate_idstringyes—

Responses

StatusBodyDescription
200objectOK
400objectThe body did not match the pay schema.
403objectpolicy_denied: the durable policy engine refused (reason, ruleId; approval_id when it routed the spend to a person — once approved, the same attempt is paid and a later call to this route records it). payee_not_allowed: the mandate's allowlist does not name the boleto.
404objectnot_found: no payable with this id in this project. mandate_not_found: no consumer mandate with this id in this organization.
409objectpayable_not_payable: not READY; details.status says what it is. payable_already_paid: EXECUTED; details.receipt_id. payable_payment_in_flight: a dispatch is running. payable_payment_uncertain: a dispatch outcome is unknown and the payable is pinned — do not resubmit. payable_payment_pending_approval: a person is deciding the policy approval (details.approval_id). payable_quote_diverged: the fresh verdict no longer allows paying; the payable is back in NEEDS_REVIEW and details.review says why. payable_payment_conflict: the row moved while this payment was planned; read it again. boleto_amount_mismatch: the provider's true amount moved between the fresh quote and the confirm; nothing paid, the payable is READY.
422objectpayable_rail_unsupported: no boleto carrier to pay by. insufficient_funds and the mandate cap codes carry their usual consumer-payment meanings; the payable is READY again. per_tx_cap_exceeded: the payable's amount is above the mandate's per-transaction cap; a boleto is refused, never routed to approval. details carries amount_minor and per_tx_cap_minor (integer strings in the mandate's own unit: minor for a v1 mandate, currency-native for unit_version: 2) and currency, beside payable_status and the message "<amount> > <cap>".
502objectThe dispatch did not answer cleanly. psp_dispatch_uncertain / payable_dispatch_unknown: the outcome is unknown, the payable is APPROVED with payment.state = uncertain and held for reconciliation — do not resubmit. psp_dispatch_failed: the provider refused and nothing moved; the payable is READY. payable_cycle_threw: the cycle failed before any provider debit; nothing moved, the payable is READY, retry.
503objectvault_unavailable: the key that protects supplier documents could not be read. policy_engine_error: the policy engine could not evaluate; refused, nothing dispatched. payable_sandbox_fixture_unavailable: test project, the sandbox settlement consult did not answer; nothing dispatched, retry.

Response 200

FieldTypeRequiredDescription
attributionobjectyes—
carriersobjectno—
created_atstringyesISO 8601 instant the payable was created.
doc_type"invoice" | "danfe_nfe" | "boleto" | "unknown"yes—
document_hashstringno—
due_dateobjectno—
extractionobjectno—
invoice_numberobjectno—
issue_dateobjectno—
itemsarray of objectno—
payable_idstringyes—
paymentobject,nullyesWhat paying it did (ent#1587); null until a payment was attempted.
rail_quoteobjectno—
receiptobject,nullyesThe sealed Control Record receipt; null when no consumer secret could sign one.
recipientobjectno—
reviewobjectyes—
schema_version"payable.v1"yes—
serieobjectno—
status"RECEIVED" | "EXTRACTING" | "EXTRACTED" | "VALIDATING" | "VALIDATED" | "NEEDS_REVIEW" | "READY" | "APPROVED" | "EXECUTED" | "REJECTED" | "FAILED_EXTRACTION" | "EXPIRED"yes—
supplierobjectyes—
totalsobjectyes—
updated_atstringyesISO 8601 instant of the last change to the payable.
validationobjectyes—
Example request
curl -X POST https://api.codespar.dev/v1/payables/{payableId}/pay \
  -H "Authorization: Bearer $CODESPAR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
       "mandate_id": "mandate_0000000000000000"
     }'
POST /v1/payables/{payableId}/pay HTTP/1.1
Host: api.codespar.dev
Authorization: Bearer $CODESPAR_API_KEY
Content-Type: application/json

{
  "mandate_id": "mandate_0000000000000000"
}
import os
import requests

res = requests.post(
    "https://api.codespar.dev/v1/payables/{payableId}/pay",
    headers={"Authorization": f"Bearer {os.environ['CODESPAR_API_KEY']}"},
    json={
      "mandate_id": "mandate_0000000000000000"
    },
)
res.raise_for_status()
data = res.json()
const res = await fetch("https://api.codespar.dev/v1/payables/{payableId}/pay", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.CODESPAR_API_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    "mandate_id": "mandate_0000000000000000"
  }),
});

const data = await res.json();
const r = await cs.api.response("post", "/v1/payables/{payableId}/pay", {
  path: {
    payableId: "payable_0000000000000000"
  },
  body: {
    mandate_id: "mandate_0000000000000000"
  }
});
// r.status is one of the documented statuses (200, 403, 422),
// each with its own body shape in r.data; nothing here throws on 403.
if (r.ok) {
  console.log(r.data);
}
Example response 200
application/json
{
  "schema_version": "payable.v1",
  "doc_type": "invoice",
  "attribution": {
    "channel": "upload",
    "credential_id": "credential_0000000000000000",
    "connection_id": "conn_0000000000000000",
    "actor": "string"
  },
  "document_hash": "string",
  "supplier": {
    "document": {
      "value": "string",
      "from": "parser_local",
      "evidence": {
        "page": 0,
        "excerpt": "string",
        "verification": "verified"
      },
      "confidence": 0
    },
    "name": {
      "value": "string",
      "from": "parser_local",
      "evidence": {
        "page": 0,
        "excerpt": "string",
        "verification": "verified"
      },
      "confidence": 0
    }
  },
  "recipient": {
    "document": {
      "value": "string",
      "from": "parser_local",
      "evidence": {
        "page": 0,
        "excerpt": "string",
        "verification": "verified"
      },
      "confidence": 0
    },
    "name": {
      "value": "string",
      "from": "parser_local",
      "evidence": {
        "page": 0,
        "excerpt": "string",
        "verification": "verified"
      },
      "confidence": 0
    }
  },
  "invoice_number": {
    "value": "string",
    "from": "parser_local",
    "evidence": {
      "page": 0,
      "excerpt": "string",
      "verification": "verified"
    },
    "confidence": 0
  },
  "serie": {
    "value": "string",
    "from": "parser_local",
    "evidence": {
      "page": 0,
      "excerpt": "string",
      "verification": "verified"
    },
    "confidence": 0
  },
  "issue_date": {
    "value": "string",
    "from": "parser_local",
    "evidence": {
      "page": 0,
      "excerpt": "string",
      "verification": "verified"
    },
    "confidence": 0
  },
  "due_date": {
    "value": "string",
    "from": "parser_local",
    "evidence": {
      "page": 0,
      "excerpt": "string",
      "verification": "verified"
    },
    "confidence": 0
  },
  "items": [
    {
      "description": {
        "value": "string",
        "from": "parser_local",
        "evidence": {
          "page": 0,
          "excerpt": "string",
          "verification": "verified"
        },
        "confidence": 0
      },
      "quantity": {
        "value": 1000,
        "from": "parser_local",
        "evidence": {
          "page": 0,
          "excerpt": "string",
          "verification": "verified"
        },
        "confidence": 0
      },
      "unit_amount_minor": {
        "value": 1000,
        "from": "parser_local",
        "evidence": {
          "page": 0,
          "excerpt": "string",
          "verification": "verified"
        },
        "confidence": 0
      },
      "total_amount_minor": {
        "value": 1000,
        "from": "parser_local",
        "evidence": {
          "page": 0,
          "excerpt": "string",
          "verification": "verified"
        },
        "confidence": 0
      }
    }
  ],
  "totals": {
    "subtotal_minor": {
      "value": 1000,
      "from": "parser_local",
      "evidence": {
        "page": 0,
        "excerpt": "string",
        "verification": "verified"
      },
      "confidence": 0
    },
    "discount_minor": {
      "value": 1000,
      "from": "parser_local",
      "evidence": {
        "page": 0,
        "excerpt": "string",
        "verification": "verified"
      },
      "confidence": 0
    },
    "tax_relief_deducted_minor": {
      "value": 1000,
      "from": "parser_local",
      "evidence": {
        "page": 0,
        "excerpt": "string",
        "verification": "verified"
      },
      "confidence": 0
    },
    "freight_minor": {
      "value": 1000,
      "from": "parser_local",
      "evidence": {
        "page": 0,
        "excerpt": "string",
        "verification": "verified"
      },
      "confidence": 0
    },
    "insurance_minor": {
      "value": 1000,
      "from": "parser_local",
      "evidence": {
        "page": 0,
        "excerpt": "string",
        "verification": "verified"
      },
      "confidence": 0
    },
    "other_charges_minor": {
      "value": 1000,
      "from": "parser_local",
      "evidence": {
        "page": 0,
        "excerpt": "string",
        "verification": "verified"
      },
      "confidence": 0
    },
    "taxes_added_minor": {
      "value": 1000,
      "from": "parser_local",
      "evidence": {
        "page": 0,
        "excerpt": "string",
        "verification": "verified"
      },
      "confidence": 0
    },
    "taxes_included_minor": {
      "value": 1000,
      "from": "parser_local",
      "evidence": {
        "page": 0,
        "excerpt": "string",
        "verification": "verified"
      },
      "confidence": 0
    },
    "grand_total_minor": {
      "value": 1000,
      "from": "parser_local",
      "evidence": {
        "page": 0,
        "excerpt": "string",
        "verification": "verified"
      },
      "confidence": 0
    },
    "currency": {
      "value": "string",
      "from": "parser_local",
      "evidence": {
        "page": 0,
        "excerpt": "string",
        "verification": "verified"
      },
      "confidence": 0
    }
  },
  "carriers": {
    "boleto": "string",
    "br_code": "string",
    "nfe": "string"
  },
  "extraction": {
    "model": "string",
    "model_version": "string",
    "input_tokens": 0,
    "output_tokens": 0,
    "reasoning_tokens": 0
  },
  "payable_id": "payable_0000000000000000",
  "status": "RECEIVED",
  "rail_quote": {
    "beneficiary": {
      "value": "string",
      "from": "trilho"
    },
    "beneficiary_document_masked": {
      "value": "string",
      "from": "trilho"
    },
    "final_beneficiary": {
      "value": "string",
      "from": "trilho"
    },
    "final_beneficiary_document_masked": {
      "value": "string",
      "from": "trilho"
    },
    "amount_minor": {
      "value": 1000,
      "from": "trilho"
    },
    "discount_minor": {
      "value": 1000,
      "from": "trilho"
    },
    "interest_minor": {
      "value": 1000,
      "from": "trilho"
    },
    "fine_minor": {
      "value": 1000,
      "from": "trilho"
    },
    "due_date": {
      "value": "string",
      "from": "trilho"
    },
    "quoted_at": "2026-01-15T12:00:00.000Z"
  },
  "validation": {
    "carrier_check_digits": {
      "outcome": "ok",
      "detail": "string"
    },
    "document_check_digits": {
      "outcome": "ok",
      "detail": "string"
    },
    "nfe_key_consistency": {
      "outcome": "ok",
      "detail": "string"
    },
    "arithmetic": {
      "outcome": "ok",
      "detail": "string"
    },
    "duplicate_document": {
      "outcome": "ok",
      "detail": "string"
    },
    "amount_matches_rail": {
      "outcome": "ok",
      "detail": "string"
    },
    "beneficiary_document_matches_supplier": {
      "outcome": "ok",
      "detail": "string"
    },
    "due_date_state": {
      "outcome": "ok",
      "detail": "string"
    },
    "pix_key_owner_matches_supplier": {
      "outcome": "ok",
      "detail": "string"
    },
    "supplier_registry": {
      "outcome": "ok",
      "detail": "string"
    },
    "bank_details_changed": {
      "outcome": "ok",
      "detail": "string"
    }
  },
  "review": {
    "validation_status": "REJECTED",
    "review_by": [
      {
        "code": "string",
        "cause": "check_failed"
      }
    ],
    "rejected_by": [
      "string"
    ],
    "confirmed_by": [
      "string"
    ],
    "awaiting": [
      "string"
    ],
    "not_covered": [
      "string"
    ],
    "review_triggers": [
      "string"
    ],
    "resolutions": [
      {
        "code": "string",
        "resolution": "human_correction",
        "at": "string",
        "by": "string",
        "by_source": "verified_user_token",
        "fields": [
          "string"
        ],
        "confirmed_beneficiary_document": "string"
      }
    ]
  },
  "payment": {
    "state": "awaiting_approval",
    "approval_id": "approval_0000000000000000",
    "settled_against": "document_line",
    "document_amount_minor": 1000,
    "mandate_id": "mandate_0000000000000000",
    "attempt_id": "attempt_0000000000000000",
    "tries": 0,
    "amount_minor": 1000,
    "quote_hash": "string",
    "claimed_at": "string",
    "key_id": "key_0000000000000000",
    "via": "string",
    "executed_at": "string",
    "receipt_id": "receipt_0000000000000000",
    "transaction_id": "transaction_0000000000000000",
    "end_to_end_id": "endtoend_0000000000000000",
    "money_moved": true,
    "uncertain_code": "string",
    "hold_entry_id": "holdentry_0000000000000000",
    "last_refusal": {
      "code": "string",
      "attempt_id": "attempt_0000000000000000",
      "at": "string"
    }
  },
  "created_at": "string",
  "updated_at": "string",
  "receipt": {
    "id": "obj_0000000000000000",
    "state": "paid",
    "chain": "string",
    "exceptions": [
      {
        "code": "string",
        "detail": "string",
        "at": "string"
      }
    ]
  }
}

POST /v1/payables/{payableId}/review

POSThttps://api.codespar.dev/v1/payables/{payableId}/review

Complete the review of a payable

A person records what they decided about a payable that is NEEDS_REVIEW, and the payable comes out READY or REJECTED. There is no third outcome and no partial review: a call that leaves anything blocking is refused and writes nothing, so resolve every item of review in one call.

Who may review. A verified human. Forward the reviewer's Clerk session token in x-codespar-user-token on a service-auth request; that user must be an admin of the organization. Any other credential, a project API key or an OAuth token, is refused (bearer_token_cannot_decide) even with a user token: a key or token proves which service is calling, never which person confirmed, and the audit event names the person.

The ordinary review is an empty one. resolutions: [] releases a payable that no check failed and that only a review trigger holds — typically new_supplier, a supplier this project has never paid. The person is still recorded as the author.

One resolution per failed check. Each names a code that is currently needs_review and one of the resolutions that code admits: the two rejecting codes (carrier_check_digits, duplicate_document) admit none, the three payee codes (beneficiary_document_matches_supplier, pix_key_owner_matches_supplier, bank_details_changed) admit reject or confirm_rail_beneficiary, and every other code admits human_correction or reject. A refused resolution lists what its code admits in details.allowed. A check that produced no answer (indisponivel) has no finding to resolve and is refused (payable_check_did_not_run) — a check that never ran is not a check that passed.

  • human_correction carries corrections, each naming a field and its corrected value. The value is stored with provenance pessoa; evidence and confidence of the previous value are dropped. The correction is then RE-CHECKED: the payable is validated again, the rail is consulted again, and the resolution holds only if the check now passes. It is refused otherwise (payable_correction_did_not_resolve).
  • confirm_rail_beneficiary is the only resolution for a payee that differs from the rail's, because editing the extracted field would turn a forged beneficiary into corrected data. It carries confirmed_beneficiary_document: the rail's beneficiary, masked. If it is absent or is not who the rail names now, the call is refused with payable_rail_beneficiary_unconfirmed and details.rail_beneficiary_document_masked tells you who that is — send it back verbatim to confirm.
  • reject ends the payable, and is sent alone. It is a decision about the payable, not the resolution of a check, so it is accepted whatever state the checks are in — a check that produced no answer included; the code it names only has to be one that admits reject.

What a correction may touch. issue_date, due_date, recipient.document, recipient.name and the totals.* fields, and only when the payable already carries them. Everything that is a duplicity axis (document_hash, the carriers, supplier.document, invoice_number, serie) is outside, because it is a canonical column the duplicate check runs on, and supplier.* is outside for the payee reason above. A misread carrier or supplier document is re-entered as a new payable, not patched.

Scope: payables:write.

Path parameters

NameTypeRequiredDescription
payableIdstringyespbl_ followed by 16 characters.

Request body

FieldTypeRequiredDescription
resolutionsarray of objectno—

Responses

StatusBodyDescription
200objectOK
400objectThe body did not match the review schema.
403objectThe reviewer was not established. bearer_token_cannot_decide: the credential is not service auth (a project API key or an OAuth token), which cannot review. user_token_required: no token was forwarded. user_token_invalid: the token did not verify — mint a fresh one. user_token_identity_mismatch: x-codespar-user names somebody else. insufficient_role: that user is not an admin of the organization.
404objectNo payable with this id in this project.
409objectNothing was written. payable_not_reviewable: the payable is not NEEDS_REVIEW. payable_correction_did_not_resolve: the corrections were applied and details.code still does not pass. payable_rail_beneficiary_unconfirmed: the confirmation named nobody, or not who the rail names now; details.rail_beneficiary_document_masked names who. payable_review_incomplete: something still blocks the payable; details.review says what. payable_review_conflict: the payable changed while this review was being decided.
422objectThe review itself is malformed. payable_check_not_in_review: that check did not fail. payable_check_did_not_run: that check produced no answer. payable_resolution_not_allowed: that check does not admit that resolution; details.allowed lists what it does. payable_resolution_repeated: one code, one resolution. payable_resolution_conflict: a rejection resolves nothing else. payable_field_not_correctable: that field is not corrected in a review, or the payable does not carry it. payable_correction_invalid: the corrected payable no longer matches the schema.
503objectvault_unavailable: the key that protects supplier documents could not be read. user_token_verification_unconfigured: this deployment cannot verify a reviewer's token. Nothing was written either way.

Response 200

FieldTypeRequiredDescription
attributionobjectyes—
carriersobjectno—
created_atstringyesISO 8601 instant the payable was created.
doc_type"invoice" | "danfe_nfe" | "boleto" | "unknown"yes—
document_hashstringno—
due_dateobjectno—
extractionobjectno—
invoice_numberobjectno—
issue_dateobjectno—
itemsarray of objectno—
payable_idstringyes—
paymentobject,nullyesWhat paying it did (ent#1587); null until a payment was attempted.
rail_quoteobjectno—
recipientobjectno—
reviewobjectyes—
schema_version"payable.v1"yes—
serieobjectno—
status"RECEIVED" | "EXTRACTING" | "EXTRACTED" | "VALIDATING" | "VALIDATED" | "NEEDS_REVIEW" | "READY" | "APPROVED" | "EXECUTED" | "REJECTED" | "FAILED_EXTRACTION" | "EXPIRED"yes—
supplierobjectyes—
totalsobjectyes—
updated_atstringyesISO 8601 instant of the last change to the payable.
validationobjectyes—
Example request
curl -X POST https://api.codespar.dev/v1/payables/{payableId}/review \
  -H "Authorization: Bearer $CODESPAR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
       "resolutions": []
     }'
POST /v1/payables/{payableId}/review HTTP/1.1
Host: api.codespar.dev
Authorization: Bearer $CODESPAR_API_KEY
Content-Type: application/json

{
  "resolutions": []
}
import os
import requests

res = requests.post(
    "https://api.codespar.dev/v1/payables/{payableId}/review",
    headers={"Authorization": f"Bearer {os.environ['CODESPAR_API_KEY']}"},
    json={
      "resolutions": []
    },
)
res.raise_for_status()
data = res.json()
const res = await fetch("https://api.codespar.dev/v1/payables/{payableId}/review", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.CODESPAR_API_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    "resolutions": []
  }),
});

const data = await res.json();
const r = await cs.api.response("post", "/v1/payables/{payableId}/review", {
  path: {
    payableId: "payable_0000000000000000"
  },
  body: {
    resolutions: []
  }
});
// r.status is one of the documented statuses (200, 403, 422),
// each with its own body shape in r.data; nothing here throws on 403.
if (r.ok) {
  console.log(r.data);
}
Example response 200
application/json
{
  "schema_version": "payable.v1",
  "doc_type": "invoice",
  "attribution": {
    "channel": "upload",
    "credential_id": "credential_0000000000000000",
    "connection_id": "conn_0000000000000000",
    "actor": "string"
  },
  "document_hash": "string",
  "supplier": {
    "document": {
      "value": "string",
      "from": "parser_local",
      "evidence": {
        "page": 0,
        "excerpt": "string",
        "verification": "verified"
      },
      "confidence": 0
    },
    "name": {
      "value": "string",
      "from": "parser_local",
      "evidence": {
        "page": 0,
        "excerpt": "string",
        "verification": "verified"
      },
      "confidence": 0
    }
  },
  "recipient": {
    "document": {
      "value": "string",
      "from": "parser_local",
      "evidence": {
        "page": 0,
        "excerpt": "string",
        "verification": "verified"
      },
      "confidence": 0
    },
    "name": {
      "value": "string",
      "from": "parser_local",
      "evidence": {
        "page": 0,
        "excerpt": "string",
        "verification": "verified"
      },
      "confidence": 0
    }
  },
  "invoice_number": {
    "value": "string",
    "from": "parser_local",
    "evidence": {
      "page": 0,
      "excerpt": "string",
      "verification": "verified"
    },
    "confidence": 0
  },
  "serie": {
    "value": "string",
    "from": "parser_local",
    "evidence": {
      "page": 0,
      "excerpt": "string",
      "verification": "verified"
    },
    "confidence": 0
  },
  "issue_date": {
    "value": "string",
    "from": "parser_local",
    "evidence": {
      "page": 0,
      "excerpt": "string",
      "verification": "verified"
    },
    "confidence": 0
  },
  "due_date": {
    "value": "string",
    "from": "parser_local",
    "evidence": {
      "page": 0,
      "excerpt": "string",
      "verification": "verified"
    },
    "confidence": 0
  },
  "items": [
    {
      "description": {
        "value": "string",
        "from": "parser_local",
        "evidence": {
          "page": 0,
          "excerpt": "string",
          "verification": "verified"
        },
        "confidence": 0
      },
      "quantity": {
        "value": 1000,
        "from": "parser_local",
        "evidence": {
          "page": 0,
          "excerpt": "string",
          "verification": "verified"
        },
        "confidence": 0
      },
      "unit_amount_minor": {
        "value": 1000,
        "from": "parser_local",
        "evidence": {
          "page": 0,
          "excerpt": "string",
          "verification": "verified"
        },
        "confidence": 0
      },
      "total_amount_minor": {
        "value": 1000,
        "from": "parser_local",
        "evidence": {
          "page": 0,
          "excerpt": "string",
          "verification": "verified"
        },
        "confidence": 0
      }
    }
  ],
  "totals": {
    "subtotal_minor": {
      "value": 1000,
      "from": "parser_local",
      "evidence": {
        "page": 0,
        "excerpt": "string",
        "verification": "verified"
      },
      "confidence": 0
    },
    "discount_minor": {
      "value": 1000,
      "from": "parser_local",
      "evidence": {
        "page": 0,
        "excerpt": "string",
        "verification": "verified"
      },
      "confidence": 0
    },
    "tax_relief_deducted_minor": {
      "value": 1000,
      "from": "parser_local",
      "evidence": {
        "page": 0,
        "excerpt": "string",
        "verification": "verified"
      },
      "confidence": 0
    },
    "freight_minor": {
      "value": 1000,
      "from": "parser_local",
      "evidence": {
        "page": 0,
        "excerpt": "string",
        "verification": "verified"
      },
      "confidence": 0
    },
    "insurance_minor": {
      "value": 1000,
      "from": "parser_local",
      "evidence": {
        "page": 0,
        "excerpt": "string",
        "verification": "verified"
      },
      "confidence": 0
    },
    "other_charges_minor": {
      "value": 1000,
      "from": "parser_local",
      "evidence": {
        "page": 0,
        "excerpt": "string",
        "verification": "verified"
      },
      "confidence": 0
    },
    "taxes_added_minor": {
      "value": 1000,
      "from": "parser_local",
      "evidence": {
        "page": 0,
        "excerpt": "string",
        "verification": "verified"
      },
      "confidence": 0
    },
    "taxes_included_minor": {
      "value": 1000,
      "from": "parser_local",
      "evidence": {
        "page": 0,
        "excerpt": "string",
        "verification": "verified"
      },
      "confidence": 0
    },
    "grand_total_minor": {
      "value": 1000,
      "from": "parser_local",
      "evidence": {
        "page": 0,
        "excerpt": "string",
        "verification": "verified"
      },
      "confidence": 0
    },
    "currency": {
      "value": "string",
      "from": "parser_local",
      "evidence": {
        "page": 0,
        "excerpt": "string",
        "verification": "verified"
      },
      "confidence": 0
    }
  },
  "carriers": {
    "boleto": "string",
    "br_code": "string",
    "nfe": "string"
  },
  "extraction": {
    "model": "string",
    "model_version": "string",
    "input_tokens": 0,
    "output_tokens": 0,
    "reasoning_tokens": 0
  },
  "payable_id": "payable_0000000000000000",
  "status": "RECEIVED",
  "rail_quote": {
    "beneficiary": {
      "value": "string",
      "from": "trilho"
    },
    "beneficiary_document_masked": {
      "value": "string",
      "from": "trilho"
    },
    "final_beneficiary": {
      "value": "string",
      "from": "trilho"
    },
    "final_beneficiary_document_masked": {
      "value": "string",
      "from": "trilho"
    },
    "amount_minor": {
      "value": 1000,
      "from": "trilho"
    },
    "discount_minor": {
      "value": 1000,
      "from": "trilho"
    },
    "interest_minor": {
      "value": 1000,
      "from": "trilho"
    },
    "fine_minor": {
      "value": 1000,
      "from": "trilho"
    },
    "due_date": {
      "value": "string",
      "from": "trilho"
    },
    "quoted_at": "2026-01-15T12:00:00.000Z"
  },
  "validation": {
    "carrier_check_digits": {
      "outcome": "ok",
      "detail": "string"
    },
    "document_check_digits": {
      "outcome": "ok",
      "detail": "string"
    },
    "nfe_key_consistency": {
      "outcome": "ok",
      "detail": "string"
    },
    "arithmetic": {
      "outcome": "ok",
      "detail": "string"
    },
    "duplicate_document": {
      "outcome": "ok",
      "detail": "string"
    },
    "amount_matches_rail": {
      "outcome": "ok",
      "detail": "string"
    },
    "beneficiary_document_matches_supplier": {
      "outcome": "ok",
      "detail": "string"
    },
    "due_date_state": {
      "outcome": "ok",
      "detail": "string"
    },
    "pix_key_owner_matches_supplier": {
      "outcome": "ok",
      "detail": "string"
    },
    "supplier_registry": {
      "outcome": "ok",
      "detail": "string"
    },
    "bank_details_changed": {
      "outcome": "ok",
      "detail": "string"
    }
  },
  "review": {
    "validation_status": "REJECTED",
    "review_by": [
      {
        "code": "string",
        "cause": "check_failed"
      }
    ],
    "rejected_by": [
      "string"
    ],
    "confirmed_by": [
      "string"
    ],
    "awaiting": [
      "string"
    ],
    "not_covered": [
      "string"
    ],
    "review_triggers": [
      "string"
    ],
    "resolutions": [
      {
        "code": "string",
        "resolution": "human_correction",
        "at": "string",
        "by": "string",
        "by_source": "verified_user_token",
        "fields": [
          "string"
        ],
        "confirmed_beneficiary_document": "string"
      }
    ]
  },
  "payment": {
    "state": "awaiting_approval",
    "approval_id": "approval_0000000000000000",
    "settled_against": "document_line",
    "document_amount_minor": 1000,
    "mandate_id": "mandate_0000000000000000",
    "attempt_id": "attempt_0000000000000000",
    "tries": 0,
    "amount_minor": 1000,
    "quote_hash": "string",
    "claimed_at": "string",
    "key_id": "key_0000000000000000",
    "via": "string",
    "executed_at": "string",
    "receipt_id": "receipt_0000000000000000",
    "transaction_id": "transaction_0000000000000000",
    "end_to_end_id": "endtoend_0000000000000000",
    "money_moved": true,
    "uncertain_code": "string",
    "hold_entry_id": "holdentry_0000000000000000",
    "last_refusal": {
      "code": "string",
      "attempt_id": "attempt_0000000000000000",
      "at": "string"
    }
  },
  "created_at": "string",
  "updated_at": "string"
}
Payables | CodeSpar