Skip to main content

Introduction

The Collection Flow v1 API programmatically exposes everything the dashboard does in the collection operation: customers, charges, collection rules, agreements, disputes, tasks, imports, and webhooks.

For AI agents

This documentation is optimized for LLMs: the full Markdown index lives at /llms.txt and the API contract at /openapi/openapi-v1-en.yaml (-pt and -es variants in the same directory). Prefer those sources over scraping the HTML.

Format

The API accepts and returns JSON only (UTF-8). Send Content-Type: application/json on every request with a body.

Field typeFormat
FieldscamelCase in responses and request bodies (dueDate, documentNumber)
DatesISO 8601 in UTC. E.g.: 2026-07-23T12:00:00.000Z
Monetary amountsReturned as decimal strings ("1500.00") to avoid precision loss; accepted as numbers in requests
List filtersQuery string in snake_case (due_date_from, person_id) — see Pagination and filters

Custom fields (customData)

The core resources (people, charges, agreements, tasks, interactions) accept a free-form JSON object in the customData field, for storing your own data alongside the resource (your ERP's IDs, internal flags...). On disputes, the equivalent field is named customMetadata. Limits, the same everywhere:

  • 64 KB of serialized payload, at most;
  • 16 levels of nesting, at most;
  • the keys __proto__, constructor and prototype are rejected.

Violations respond 400 with code: "VALIDATION_ERROR" and the reason in details. On updates, the default behavior is replace: the object you send replaces the stored one entirely (and null clears the field). To merge instead of replacing, send customDataMode: "merge" in the update body — nested objects are deep-merged; scalars, arrays and null overwrite the key.

Conventions

ConventionDescription
:idPath variable that must be replaced in the URL.
...Response content truncated for readability.
$DUNNING_TOKENYour API key. To test from the command line, export it: export DUNNING_TOKEN=xxxxxxxxxxxxxxxxxxxxxxxx and paste the documentation's commands into your terminal.

Error envelope

Every error responds with a stable envelope — a human-readable message, a machine-stable code (and details when useful):

{
"message": "Permissão insuficiente",
"code": "FORBIDDEN"
}

Always branch on code (VALIDATION_ERROR, UNAUTHORIZED, FORBIDDEN, NOT_FOUND, CONFLICT, IDEMPOTENCY_KEY_REUSED, RATE_LIMITED, INTERNAL_ERROR...) — the message text can change without notice.

Response codes

The API uses standard HTTP status codes:

CodeDescription
200 OKSuccessful request with a response body.
201 CreatedResource created successfully.
204 No ContentSuccessful request, no response body.
400 Bad RequestMalformed request — invalid JSON, invalid idempotency header.
401 UnauthorizedAPI key missing, invalid, revoked, or expired.
403 ForbiddenKey lacks the required scope, or the resource is admin-only and not exposed via API.
404 Not FoundResource or route does not exist (or belongs to another organization).
409 ConflictState conflict — X-Idempotency-Key reuse, invalid transition.
422 Unprocessable EntityWell-formed request whose data fails business validation.
429 Too Many RequestsRate limit exceeded — wait for Retry-After.
5xxServer error — see below for how to retry.

5xx errors and retries

500, 502, 503, and 504 indicate a failure on our side, almost always transient. Your integration should:

  1. Retry with exponential backoff (e.g.: 1s, 2s, 4s, 8s...) and a cap on attempts — never in a tight loop.
  2. Use X-Idempotency-Key on mutations — the retry returns the original response instead of duplicating the operation.
  3. Treat network timeouts as 5xx: not getting a response doesn't mean the operation didn't run; idempotency resolves the ambiguity.

On 429, wait the number of seconds in the Retry-After header before the next attempt.

Next steps