This is the page to read before you map anything. Almost every confused integration starts here: a document in Rivet is one record shared by two organizations, and a handful of its fields are answered from the point of view of whoever asked.
One record, two sides
When your customer issues you an invoice, there is not an invoice in their account and a copy of it in yours. There is one document on the connection between you. They issued it, so they see an Invoice numbered INV-0042. You received it, so you see a Bill numbered BILL-0042. Same record, same total, same id — different names, because that is what each side calls it.
{
"id": "6a5eed00000000000000d001",
"document_type": "invoice",
"direction": "received",
"label": "Bill",
"number": "BILL-0042",
"status": "due",
"display_status": "Due",
"phase": "approved",
"connection_id": "6a5eed00000000000000c001",
"issuer_org_id": "6a5eed0000000000000000b1",
"receiver_org_id": "6a5eed0000000000000000a1",
"currency": "USD",
"total": 1250,
"amount_paid": 0,
"balance_due": 1250,
"issued_at": "2026-08-01T00:00:00.000Z",
"due_at": "2026-08-31T00:00:00.000Z"
}{
"id": "6a5eed00000000000000d001",
"document_type": "invoice",
"direction": "issued",
"label": "Invoice",
"number": "INV-0042",
"status": "due",
"display_status": "Due",
"phase": "approved",
"connection_id": "6a5eed00000000000000c001",
"issuer_org_id": "6a5eed0000000000000000b1",
"receiver_org_id": "6a5eed0000000000000000a1",
"currency": "USD",
"total": 1250,
"amount_paid": 0,
"balance_due": 1250,
"issued_at": "2026-08-01T00:00:00.000Z",
"due_at": "2026-08-31T00:00:00.000Z"
}The two bodies differ in exactly direction, label, number. Everything else — the id, the connection, the totals, the dates — is byte-for-byte the same. The right-hand body is derived from the left by flipping only the fields the contract itself calls viewer-relative; it is not a second live read, and it is labelled that way.
Which fields are the viewer’s
The contract names them, and this list is read from it: direction, label, number, display_status, linked_system_number. Treat every other field as shared.
| Field | Type | Notes |
|---|---|---|
| direction* | string | issued — this organization created/sent it. received — the counterparty did.issued · received |
| label* | string | The name the app shows this organization (Invoice to the issuer, Bill to the receiver). |
| number* | string | null | The document number as this organization sees it (INV-0001 to the issuer, BILL-0001 to the receiver). |
| display_status* | string | The status in this organization's own vocabulary (its connected system's, if linked). |
| linked_system_number* | string | null | This organization's own connected-system number for the document, if synced. |
id — never on number. The id is the record. The number is a name one organization uses for it, and the other organization has a different one for the same thing.Direction is the pivot
direction: "issued"— your organization created and sent it. Your receivables live here.direction: "received"— the counterparty sent it to you. Your payables live here.
The same distinction drives the payments rollups: receivable is built from documents you issued, payable from documents you received. If a number looks inverted, check direction before you check arithmetic.
The party rule
You can read documents on connections your organization is a party to. That is the whole boundary. Ask for a document id on someone else’s connection and you get not_found — the same answer as an id that never existed.
curl "https://api.rivet.network/v1/documents/6a5eed00000000000000d001" \
-H "Authorization: Bearer rk_live_…"forbidden would confirm the document exists, which would leak the fact that two other organizations trade with each other. Nothing about another organization’s documents is ever acknowledged — including their existence.Listing documents
One list endpoint spans every connection you are a party to, newest first — the detail read above is the same record with its line items and the documents it was derived from.
curl "https://api.rivet.network/v1/documents?type=invoice&limit=2" \
-H "Authorization: Bearer rk_live_…"connection— one relationship at a time. The usual shape for a per-customer sync.type— invoice, purchase order, quote and the rest.status— statuses are per type, so pair it withtypefor a filter that means something.since/until— a window on the document date.
type=invoice returns invoices you issued and the ones you received, which you call bills. Narrow with direction in your own code after reading — the two sides are above.Keeping a copy in sync? updated_since and the cross-type phase filter live on their own page — see Filtering & polling.