---
title: "Bill a visit and read back what it was paid"
summary: "Ask Practor to invoice a visit your system sent, issue it and claim from the insurer in the same call, then read the claim's outcome and the payments back."
source: https://practor.app/en-za/help/security-and-integrations/bill-a-visit-and-read-back-what-it-was-paid
published: 2026-09-29T07:17:43.910Z
updated: 2026-10-01T18:08:42.864Z
category: "Security and integrations"
---

Once a visit is in Practor, one request turns it into an invoice, priced with the same rates and rules as one made by hand.

## Invoice a visit

`POST /api/v1/encounters/{encounterId}/bill`, with an `Idempotency-Key` header and a body saying what to do once the invoice is drafted:

```json
{ "issue": true, "submitClaim": true }
```

| Field | Effect |
| --- | --- |
| `issue` | `true` issues the invoice. Without it, the invoice is left as a draft for the practice to check |
| `submitClaim` | `true` submits it as a claim to the patient's insurer. Needs `issue` too |
| `coverageId` | The insurance to claim from. Left out, the patient's first medical insurance |
| `placeOfServiceCode` | The code for where the visit took place, for a claim that asks for it |

Billing needs the **Create** tick on **Invoices**. Issuing also needs the **Update** tick on **Invoices**, because it changes the invoice and tells the patient. Submitting a claim also needs the **Submit or verify** tick on **Claims**.

Send no body at all to draft the invoice and leave it for the practice, or to change its prices yourself before you issue it: [Change an invoice and claim it from your own system](/help/security-and-integrations/change-an-invoice-and-claim-it-from-your-own-system). The [invoice a visit](https://developers.practor.app/reference/encounters/encounter-bill) page has the body and the answer in full.

## Read the answer

The answer is a 201 with `"object": "bill_result"`:

| Field | What it holds |
| --- | --- |
| `invoice` | The invoice |
| `issued` | Whether the invoice was issued. `null` when you didn't ask |
| `issueSkippedReason` | Why it wasn't issued, when you asked and it wasn't |
| `claimQueued` | Whether the claim was queued. `null` when you didn't ask, or the invoice wasn't issued |
| `claimSkippedReason` | Why the claim wasn't queued |

Each reason uses the words the practice sees in Practor. The invoice is kept either way, as a draft if it couldn't be issued, so the practice can fix what's wrong and finish it.

| Status | Message | What to do |
| --- | --- | --- |
| 422 | A claim can only be submitted for an issued invoice. Send issue=true with submitClaim=true. | Add `issue` |
| 409 | This encounter is already billed on invoice ... | Read that invoice instead. The id varies |
| 422 | An encounter in status ... cannot be billed. | Only a finished visit can be billed. The status varies |
| 403 | This integration client does not have Update on Invoices. A practice owner can add it under Permissions. | Ask the practice to tick **Update** on **Invoices**, or send `issue` as `false` to leave a draft |
| 403 | This integration client does not have Submit on Claims. A practice owner can add it under Permissions. | Ask the practice to tick **Submit or verify** on **Claims** |
| 422 | The encounter has no billable procedures. | Send the visit again with its procedure codes |
| 429 | Too many encounters billed for this practice in the last minute. Slow down and retry. | Wait the `Retry-After` seconds, then retry with the same `Idempotency-Key` |

## Read an invoice

`GET /api/v1/invoices/{invoiceId}` gives the invoice, every field of it on the [read an invoice](https://developers.practor.app/reference/invoices/invoice-read) page. Amounts are whole numbers in the smallest unit of its `currency`, such as cents.

| Field | What it holds |
| --- | --- |
| `status` | Practor's own status: `draft`, `issued`, `amending`, `partially_paid`, `balanced`, `overdue`, `cancelled`, `written_off` or `entered_in_error` |
| `amountPaid` and `balanceDue` | What's been paid and what's left |
| `claimStatus` | Where the claim is, if one was submitted: `submitting`, `accepted`, `partially_accepted`, `rejected`, `reversing`, `reversed` or `reversal_failed`. `null` before then |
| `coverageId` and `encounterIds` | The insurance claimed against, and the visits billed |
| `lineItems` | Each line's code, quantity, prices, diagnoses, and in `pricingSource` where its price came from |

`GET /api/v1/invoices?encounterId={id}` or `?patientId={id}` finds invoices for one visit or one patient.

## Keep in step with changes

`GET /api/v1/invoices?updatedSince=2026-10-01T08:00:00Z` lists the invoices that changed after that moment, oldest first. While `hasMore` is `true`, send `nextCursor` back as `cursor`. Remember the last `updatedAt` you saw and ask from there next time.

Webhooks tell you without asking: [Get told when an invoice, claim or payment changes](/help/security-and-integrations/get-told-when-an-invoice-claim-or-payment-changes).

## Read the claim's outcome

`GET /api/v1/invoices/{invoiceId}/claim` gives the claim:

1. `outcome` is `queued`, `complete`, `partial` or `error`. A reversed claim also reads `complete`, so check `status` as well.
2. Each entry in `items` is an invoice line, numbered by `lineNumber`, with what was claimed in `submitted` and what the insurer will pay in `benefit`.
3. Each item lists its `rejections` and `warnings`, each with the insurer's code and reason.

Before a claim is submitted, the answer is a 404 that reads "No claim has been submitted for this invoice."

## Read the payments

`GET /api/v1/invoices/{invoiceId}/payments` lists each payment against the invoice, whether the patient paid or the insurer did. `method` says which, such as `medical_aid` or `card`.

## Related

- [Send patients and visits to Practor from your own system](/help/security-and-integrations/send-patients-and-visits-to-practor-from-your-own-system)
- [Change an invoice and claim it from your own system](/help/security-and-integrations/change-an-invoice-and-claim-it-from-your-own-system)
- [Integration API errors and limits](/help/security-and-integrations/integration-api-errors-and-limits)
