---
title: "Integration API errors and limits"
summary: "Find the message the Practor API sent back to see what to fix. Retry a 429, a 500 or a timeout. Every other message says what to change."
source: https://practor.app/en-za/help/security-and-integrations/integration-api-errors-and-limits
published: 2026-09-29T07:17:43.925Z
updated: 2026-10-01T18:08:42.891Z
category: "Security and integrations"
---

When the Practor API refuses a request, the body is sent as `application/problem+json`:

```json
{
  "type": "https://developers.practor.app/guides/errors#validation-failed",
  "title": "Some fields are missing or wrong",
  "status": 422,
  "detail": "Fix the fields listed in errors and send it again.",
  "code": "validation_failed",
  "requestId": "x9k2m4p7q1w8e3r6t5y0u2i4",
  "errors": [
    { "field": "lastName", "code": "required", "message": "Send lastName." },
    { "field": "birthDate", "code": "invalid", "message": "birthDate must be a real date, written YYYY-MM-DD" }
  ]
}
```

Branch on `code`, which stays the same from release to release. `detail` is a sentence saying what went wrong. When fields failed their checks, `errors` lists every one Practor found, each with the `field` it's about, like `birthDate` or `procedures.1.code`. A field's `code` is `required` when you left it out and `invalid` when its value is wrong.

In the [API reference](https://developers.practor.app/reference), each request's page lists the statuses Practor can answer it with.

Every answer has an `X-Request-Id` header, refusals included, and a refusal repeats it as `requestId`. Keep it in your logs. The practice sees the same id on that request in its audit log, and it's the number to quote if you contact us.

## Fix a refused key or address

| Status | Message | What to do |
| --- | --- | --- |
| 401 | Send an integration key as "Authorization: Bearer <key>". | Add the header |
| 401 | The integration key is not valid. | Check you copied the whole key. If you did, ask the practice to look the request up in its audit log |
| 403 | The Integrations add-on is not active for this practice. | Ask the practice to switch integrations on |
| 403 | This integration client does not have Read on Invoices. A practice owner can add it under Permissions. | Ask the practice to tick that permission. The permission and the records named vary |

Practor gives the same answer for a key it doesn't know, one that was revoked or has expired, a client the practice suspended, and a call from an address the client isn't allowed to use. That way nobody holding an old key can learn which it is. The practice's audit log shows the reason against the request id.

## Fix a refused request

| Status | What it means |
| --- | --- |
| 400 | The body isn't JSON |
| 400 | A search parameter is missing or isn't in the form the search takes. `errors` names the parameter, like `patientId`, and the message shows the form to use |
| 400 | The `cursor` isn't one Practor sent. Send `nextCursor` exactly as it came, with the same filters |
| 404 | The record doesn't exist at this practice. A record at another practice answers the same way |
| 405 | The address doesn't take that method. A `PUT` to `/api/v1/patients`, for example, is refused with an `Allow` header naming `POST` |
| 409 | The record clashes with one that exists, such as a second patient with your patient number. The message names the one that's there |
| 413 | The body is over 256 KB |
| 415 | Send the body as application/json. |
| 422 | The body is valid JSON but Practor can't accept it: a missing field, an unknown code, a plan that doesn't exist. `errors` says where |
| 500 | Something went wrong on our side. Quote the `requestId` if you contact us |

A 400, 404, 405 or 422, or a 409 about a clashing record, fails the same way if you send it again unchanged. Fix what the message says first.

Practor checks the key and the client's permission before the method, so a `PUT` to `/api/v1/patients` with a revoked key gets the 401, not the 405.

## Retry safely

Retry a 429, a 500 or a timeout. A retried `POST` keeps its `Idempotency-Key`, as [Send patients and visits to Practor from your own system](/help/security-and-integrations/send-patients-and-visits-to-practor-from-your-own-system) explains.

| Status | Message | What to do |
| --- | --- | --- |
| 400 | Send an Idempotency-Key header (up to 255 characters) with every create, so a retry cannot create the record twice. | Add the header to every `POST` |
| 409 | A request with this Idempotency-Key is still being processed. Retry shortly. | Wait a few seconds, then retry |
| 422 | This Idempotency-Key was already used with a different request body. | Use a new key for each new record |

Practor remembers a key for 24 hours.

## Stay inside the limits

| Limit | What happens past it |
| --- | --- |
| 600 requests a minute, per integration client | A 429 that reads "Too many requests for this integration client. Slow down and retry.", for a minute |
| 30 visits billed a minute, per practice, across all its clients | A 429 that reads "Too many encounters billed for this practice in the last minute. Slow down and retry." Billing is refused the same way if Practor can't count, so a 429 here is always safe to retry |
| 30 claims submitted, resubmitted or reversed a minute, per practice | A 429 that reads "Too many claims sent for this practice in the last minute. Slow down and retry." |
| 30 checks of a patient's cover a minute, per practice, counting the practice's own | A 429 that reads "Too many insurance checks for this practice in the last minute. Slow down and retry." |
| 30 requests from one address refused for their key, their client or their address, in 10 minutes | Further refused requests from that address get a 429 that reads "Too many refused requests from this address. Try again later.", for 10 minutes. A working key from that address carries on |
| 50 results a page, for invoices, a patient's visits, plans, code systems and their codes, unless you set `limit` up to 100 | While `hasMore` is `true`, send `nextCursor` back as `cursor` for the next page |

Once your key and permission are accepted, the answer carries `X-RateLimit-Limit`, `X-RateLimit-Remaining` and `X-RateLimit-Reset`. On a billing or claim request they count the practice's limit for those. A 429 adds `Retry-After`, in seconds. Wait that long before the next request.

If one of the practice's keys is refused more than 20 times in 10 minutes, the practice gets a notification naming the key, once a day at most.

## 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)
- [Connect your own software to Practor](/help/security-and-integrations/connect-your-own-software-to-practor)
