También en markdown y en OpenAPI.
Referencia de la API de Makatea
Generada del OpenAPI de producción (versión
2026-09-23). URL base:https://makatea.ai/api. Las descripciones de rutas y campos vienen del spec, en inglés. Las guías en español están en https://makatea.ai/desarrolladores.
Introducción
The Makatea API lets your system create members and billing orders, register payments, and
receive events. Every response carries Makatea-API-Version: 2026-09-23 and an
X-Request-Id (send your own to correlate logs).
Authentication
Create an API key in Makatea → Settings → API. Send it in either header:
Authorization: Bearer mk_live_…
X-API-Key: mk_live_…
Keys have scopes: read (GET) and write (everything else). A session JWT from the Makatea app
is also accepted in Authorization (legacy). Missing or invalid credentials → 401; a key
without the needed scope → 403 insufficient_scope.
Responses
Success always has the same shape, for single objects and for lists:
{"data": {…} }
{"data": [ … ], "pagination": {"limit": 100, "has_more": true, "next_cursor": "eyJm…"}}
Errors always look like this:
{"error": {"code": "validation_error", "message": "amount must be a positive number", "request_id": "…"}}
| Status | Meaning |
|---|---|
| 400 | Malformed request: invalid JSON, unknown query parameter (unknown_parameter lists the allowed ones), bad cursor |
| 401 | Missing/invalid credentials |
| 403 | Key lacks the scope |
| 404 | Not found (also unknown routes: route_not_found) |
| 405 | Route exists with another method |
| 409 | Conflict with the current state (already paid, duplicate external_ref, opted out, …) |
| 413 | Body or document too large |
| 422 | Validation error, or an Idempotency-Key reused with a different body |
| 429 | Rate limit exceeded (see Retry-After) |
| 5xx | Our fault; safe to retry with the same Idempotency-Key |
Pagination and sync
Lists accept limit (default 100, max 500) and cursor. Pass the next_cursor you received to
get the next page, keeping the same filters; stop when has_more is false. offset still
works for compatibility but can skip rows while data changes. Add count=true to get
pagination.total (slower).
To mirror data into your system, call the list with updated_since=<last sync instant>: results come
ordered by updated_at ascending, so you can page with the cursor and store the updated_at of the
last row as your next checkpoint.
Idempotency
Send Idempotency-Key: <unique string> on any POST/PUT/PATCH/DELETE. Retrying with the same key and
the same body returns the original response (with header Idempotent-Replayed: true) instead of
acting twice. The same key with a different body is 422 idempotency_key_reused; while the first
request is still running, 409 idempotency_in_progress. Keys are kept 24 hours.
Webhooks
Register an https endpoint (POST /v1/webhook-endpoints) with the event types you want (or *).
The response includes the signing secret (whsec_…) only once. Each event is POSTed as:
{"id": "<event id>", "type": "payment.received", "created_at": "…", "data": {…}}
with headers Makatea-Event-Id, Makatea-Event-Type and
Makatea-Signature: t=<unix seconds>,v1=<hex HMAC-SHA256(secret, "<t>.<raw body>")>
Verify by recomputing the HMAC over t + "." + raw body and comparing in constant time; reject
timestamps older than 5 minutes. Answer 2xx within 10 seconds. Otherwise we retry after 1 min, 5 min,
30 min, 2 h, 6 h and 24 h; after 8 failed attempts the delivery is failed (you can retry it with
POST /v1/webhook-deliveries/{id}/retry). Deliveries can arrive more than once or out of order: use
the event id to de-duplicate.
Event types: member.created, member.updated, billing_order.created, billing_order.updated, billing_order.paid, billing_order.cancelled, payment.received, payment.voided, promise.created, promise.kept, promise.broken, message.sent, message.received. *.updated events carry
{"object": {…}, "previous_attributes": {…}}. Records created by CSV imports do not emit events.
Limits
600 requests per minute per API key (per organization for session JWTs). Every response includes
X-RateLimit-Limit, X-RateLimit-Remaining and X-RateLimit-Reset (unix seconds). Over the limit →
429 with Retry-After. Request bodies up to 21 MB; documents up to 15 MB.
Status
GET /v1/status (no key) says whether the service and its database answer.
Índice de rutas
- Status
- Members
- Promises
- Credit
- Messages
- Documents
- Billing orders
- Payments
- Credits (loans)
- Webhooks
- Operations
Status
GET /v1/status
Service status (no authentication).
Checks that the database answers. Returns 503 when it does not.
Respuestas
200OK ·data: Status
Members
GET /v1/members
List members.
Parámetros
| Nombre | En | Tipo | Obligatorio | Descripción |
|---|---|---|---|---|
state | query | string: contact, active, at_risk, delinquent, dormant, churned | ||
q | query | string | Search in name or phone. | |
external_ref | query | string | Exact match on your own identifier. | |
updated_since | query | string (date-time) | Only records changed at or after this instant (ISO-8601). Switches ordering to updated_at ascending, so you can resume a sync with the last next_cursor. | |
limit | query | integer | ||
cursor | query | string | next_cursor from the previous page. | |
offset | query | integer | Legacy; prefer cursor. | |
count | query | boolean | Include pagination.total. |
Respuestas
200OK ·data: array de Member401Missing or invalid credentials429Rate limit exceeded
POST /v1/members
Create a member.
Two members may share a phone number. external_ref is unique per organization (409 if reused).
Acepta Idempotency-Key.
Cuerpo (JSON)
| Campo | Tipo | Obligatorio | Descripción |
|---|---|---|---|
full_name | string | sí | |
phone_e164 | string | Ejemplo: "+5215512345678". | |
email | string | ||
state | string: contact, active, at_risk, delinquent, dormant, churned | Por omisión: "active". | |
external_ref | string | Your identifier for this member. | |
identity | object | Free-form attributes (used as template variables). | |
tags | array de string | ||
notes | string | ||
customer_since | string (date) | When the member became your customer (not when it entered Makatea). Not in the future. | |
do_not_contact | boolean | Never send this member any message. Requires do_not_contact_reason. Por omisión: false. | |
do_not_contact_reason | string |
Respuestas
201OK ·data: Member401Missing or invalid credentials422Validation error429Rate limit exceeded
GET /v1/members/{id}
Get a member (with billing orders and recent interactions).
Parámetros
| Nombre | En | Tipo | Obligatorio | Descripción |
|---|---|---|---|---|
id | path | string (uuid) | sí |
Respuestas
200OK ·data: Member401Missing or invalid credentials404Not found429Rate limit exceeded
PUT /v1/members/{id}
Update a member.
Only the fields you send are changed.
Parámetros
| Nombre | En | Tipo | Obligatorio | Descripción |
|---|---|---|---|---|
id | path | string (uuid) | sí |
Acepta Idempotency-Key.
Cuerpo (JSON)
| Campo | Tipo | Obligatorio | Descripción |
|---|---|---|---|
full_name | string | ||
phone_e164 | string | ||
email | string, nullable | ||
state | string: contact, active, at_risk, delinquent, dormant, churned | ||
external_ref | string, nullable | ||
identity | object | ||
tags | array de string | ||
notes | string, nullable | ||
customer_since | string (date), nullable | Not in the future. null clears it. | |
do_not_contact | boolean | true requires do_not_contact_reason (sent now or already on file); false clears the reason. Pending messages are withdrawn when it turns on. | |
do_not_contact_reason | string | Can be sent alone to change the reason of a member already marked. |
Respuestas
200OK ·data: Member401Missing or invalid credentials404Not found422Validation error429Rate limit exceeded
PATCH /v1/members/{id}
Update a member (partial).
Only the fields you send are changed.
Parámetros
| Nombre | En | Tipo | Obligatorio | Descripción |
|---|---|---|---|---|
id | path | string (uuid) | sí |
Acepta Idempotency-Key.
Cuerpo (JSON)
| Campo | Tipo | Obligatorio | Descripción |
|---|---|---|---|
full_name | string | ||
phone_e164 | string | ||
email | string, nullable | ||
state | string: contact, active, at_risk, delinquent, dormant, churned | ||
external_ref | string, nullable | ||
identity | object | ||
tags | array de string | ||
notes | string, nullable | ||
customer_since | string (date), nullable | Not in the future. null clears it. | |
do_not_contact | boolean | true requires do_not_contact_reason (sent now or already on file); false clears the reason. Pending messages are withdrawn when it turns on. | |
do_not_contact_reason | string | Can be sent alone to change the reason of a member already marked. |
Respuestas
200OK ·data: Member401Missing or invalid credentials404Not found422Validation error429Rate limit exceeded
DELETE /v1/members/{id}
Soft-delete a member (state becomes churned).
Parámetros
| Nombre | En | Tipo | Obligatorio | Descripción |
|---|---|---|---|---|
id | path | string (uuid) | sí |
Acepta Idempotency-Key.
Respuestas
200OK ·data: Member401Missing or invalid credentials404Not found429Rate limit exceeded
Promises
GET /v1/members/{id}/promises
Current promise and history.
Parámetros
| Nombre | En | Tipo | Obligatorio | Descripción |
|---|---|---|---|---|
id | path | string (uuid) | sí |
Respuestas
200OK ·data: PromiseState401Missing or invalid credentials404Not found429Rate limit exceeded
POST /v1/members/{id}/promises
Record a payment promise.
Pauses collection messages until the promised date (one reminder survives). Replaces any active promise. When the date passes the promise becomes kept or broken (webhooks promise.kept / promise.broken).
Parámetros
| Nombre | En | Tipo | Obligatorio | Descripción |
|---|---|---|---|---|
id | path | string (uuid) | sí |
Acepta Idempotency-Key.
Cuerpo (JSON)
| Campo | Tipo | Obligatorio | Descripción |
|---|---|---|---|
promised_date | string (date) | sí | |
amount | number |
Respuestas
201OK ·data: PromiseState401Missing or invalid credentials404Not found422Validation error429Rate limit exceeded
DELETE /v1/members/{id}/promises/current
Cancel the active promise.
Marks it cancelled (kept in history) and re-schedules collection for the member's open orders. 409 if there is no active promise.
Parámetros
| Nombre | En | Tipo | Obligatorio | Descripción |
|---|---|---|---|---|
id | path | string (uuid) | sí |
Acepta Idempotency-Key.
Respuestas
200OK ·data: PromiseState401Missing or invalid credentials404Not found429Rate limit exceeded
Credit
GET /v1/members/{id}/credit
Credit balance and its ledger.
Parámetros
| Nombre | En | Tipo | Obligatorio | Descripción |
|---|---|---|---|---|
id | path | string (uuid) | sí |
Respuestas
200OK ·data: Credit401Missing or invalid credentials404Not found429Rate limit exceeded
POST /v1/members/{id}/credit/apply
Apply the credit balance to open orders (oldest first).
Parámetros
| Nombre | En | Tipo | Obligatorio | Descripción |
|---|---|---|---|---|
id | path | string (uuid) | sí |
Acepta Idempotency-Key.
Respuestas
200OK ·data: CreditApplied401Missing or invalid credentials404Not found429Rate limit exceeded
Messages
GET /v1/members/{id}/conversation
Messages exchanged with a member (newest first).
Parámetros
| Nombre | En | Tipo | Obligatorio | Descripción |
|---|---|---|---|---|
id | path | string (uuid) | sí | |
channel | query | string: whatsapp, sms, email | ||
limit | query | integer | ||
cursor | query | string | next_cursor from the previous page. | |
offset | query | integer | Legacy; prefer cursor. | |
count | query | boolean | Include pagination.total. |
Respuestas
200OK ·data: array de Interaction401Missing or invalid credentials404Not found429Rate limit exceeded
POST /v1/messages
Send a message to a member.
With text: sent right away through the organization's line (WhatsApp or SMS) — status: sent.
With template_id: queued for the sending engine, which renders the template variables — status: queued (any channel, including email).
Respects opt-outs (409 opted_out), the organization's kill switch (409 comms_disabled) and its send window (409 outside_send_window, text only; queued messages wait for the window).
Organizations in simulation mode record the message but nothing leaves (status: simulated).
Acepta Idempotency-Key.
Cuerpo (JSON)
| Campo | Tipo | Obligatorio | Descripción |
|---|---|---|---|
member_id | string (uuid) | sí | |
channel | string: whatsapp, sms, email | Por omisión: "whatsapp". | |
text | string | ||
template_id | string (uuid) |
Respuestas
202OK ·data: MessageResult401Missing or invalid credentials422Validation error429Rate limit exceeded
POST /v1/conversations/import
Import conversation history (messages that happened outside Makatea).
Up to 20,000 rows per call. Idempotent by external_id (or by member + time + direction + text). Imported messages trigger nothing: no auto-replies, no notices, no webhooks. dry_run validates without writing. Members are matched by member_external_ref, or by phone when exactly one member has it.
Acepta Idempotency-Key.
Cuerpo (JSON)
| Campo | Tipo | Obligatorio | Descripción |
|---|---|---|---|
dry_run | boolean | ||
rows | array de object |
Cada elemento de rows:
| Campo | Tipo | Obligatorio | Descripción |
|---|---|---|---|
member_external_ref | string | ||
phone | string | ||
occurred_at | string (date-time) | sí | |
direction | string: inbound, outbound | sí | |
channel | string: whatsapp, email, sms | sí | |
body | string | sí | |
subject | string | ||
external_id | string |
Respuestas
200OK ·data: ConversationImportResult401Missing or invalid credentials422Validation error429Rate limit exceeded
Documents
GET /v1/members/{id}/documents
List a member's documents (with temporary download URLs, valid 1 hour).
Parámetros
| Nombre | En | Tipo | Obligatorio | Descripción |
|---|---|---|---|---|
id | path | string (uuid) | sí | |
external_ref | query | string | Exact match on your own identifier. |
Respuestas
200OK ·data: array de Document401Missing or invalid credentials404Not found429Rate limit exceeded
POST /v1/members/{id}/documents
Attach a document to a member.
Send the file inline (content_base64) or a public https url the server downloads. Max 15 MB. With external_ref, repeating the call returns the existing document (200) instead of uploading twice.
Parámetros
| Nombre | En | Tipo | Obligatorio | Descripción |
|---|---|---|---|---|
id | path | string (uuid) | sí |
Acepta Idempotency-Key.
Cuerpo (JSON)
| Campo | Tipo | Obligatorio | Descripción |
|---|---|---|---|
name | string | sí | |
mime_type | string | ||
content_base64 | string (byte) | ||
url | string (uri) | ||
external_ref | string | ||
type | string: ine_frontal, ine_reverso, comprobante, otro | Por omisión: "otro". | |
description | string |
Respuestas
201OK ·data: Document401Missing or invalid credentials404Not found422Validation error429Rate limit exceeded
DELETE /v1/members/{id}/documents/{document_id}
Delete a document (file and record).
Parámetros
| Nombre | En | Tipo | Obligatorio | Descripción |
|---|---|---|---|---|
id | path | string (uuid) | sí | |
document_id | path | string (uuid) | sí |
Acepta Idempotency-Key.
Respuestas
200OK ·data: Deleted401Missing or invalid credentials404Not found429Rate limit exceeded
Billing orders
GET /v1/billing-orders
List billing orders.
Default order: due_date ascending. With updated_since: updated_at ascending.
Parámetros
| Nombre | En | Tipo | Obligatorio | Descripción |
|---|---|---|---|---|
status | query | string: pending, overdue, paid, cancelled | ||
member_id | query | string (uuid) | ||
external_ref | query | string | Exact match on your own identifier. | |
updated_since | query | string (date-time) | Only records changed at or after this instant (ISO-8601). Switches ordering to updated_at ascending, so you can resume a sync with the last next_cursor. | |
credit_id | query | string (uuid) | Only the installments of this credit. | |
due_from | query | string (date) | ||
due_to | query | string (date) | ||
limit | query | integer | ||
cursor | query | string | next_cursor from the previous page. | |
offset | query | integer | Legacy; prefer cursor. | |
count | query | boolean | Include pagination.total. |
Respuestas
200OK ·data: array de BillingOrder401Missing or invalid credentials429Rate limit exceeded
POST /v1/billing-orders
Create a billing order.
Acepta Idempotency-Key.
Cuerpo (JSON)
| Campo | Tipo | Obligatorio | Descripción |
|---|---|---|---|
member_id | string (uuid) | sí | |
amount | number | sí | |
currency | string | Por omisión: "MXN". | |
due_date | string (date) | sí | |
period_label | string | ||
external_ref | string | Unique per organization. | |
notes | string | ||
capital_portion | number, nullable | Principal part of this installment. Send together with interest_portion (both null removes the breakdown). capital + interest ≤ amount; the rest of amount is the collectible late fee and, beyond it, «other charges». | |
interest_portion | number, nullable | Interest part of this installment (include commissions you consider interest). | |
credit_id | string (uuid), nullable | Credit (loan) this installment belongs to; must be of the same member. null detaches it. |
Respuestas
201OK ·data: BillingOrder401Missing or invalid credentials422Validation error429Rate limit exceeded
GET /v1/billing-orders/{id}
Get a billing order.
Parámetros
| Nombre | En | Tipo | Obligatorio | Descripción |
|---|---|---|---|---|
id | path | string (uuid) | sí |
Respuestas
200OK ·data: BillingOrder401Missing or invalid credentials404Not found429Rate limit exceeded
PATCH /v1/billing-orders/{id}
Update a billing order (move the date, change the amount, …).
Moving due_date re-schedules its collection messages. Raising amount above what was paid re-opens a paid order; lowering it to what is covered marks it paid. late_fee sets the accumulated late fee (absolute). capital_portion/interest_portion set the breakdown (also on paid orders: it is history) and re-apply the order's payments. Cancelled orders cannot be edited (409).
Parámetros
| Nombre | En | Tipo | Obligatorio | Descripción |
|---|---|---|---|---|
id | path | string (uuid) | sí |
Acepta Idempotency-Key.
Cuerpo (JSON)
| Campo | Tipo | Obligatorio | Descripción |
|---|---|---|---|
due_date | string (date) | ||
amount | number | ||
period_label | string, nullable | ||
late_fee | number | ||
external_ref | string, nullable | ||
notes | string, nullable | ||
member_id | string (uuid) | Move the order (with its payments) to another member of the organization. | |
capital_portion | number, nullable | Principal part of this installment. Send together with interest_portion (both null removes the breakdown). capital + interest ≤ amount; the rest of amount is the collectible late fee and, beyond it, «other charges». | |
interest_portion | number, nullable | Interest part of this installment (include commissions you consider interest). | |
credit_id | string (uuid), nullable | Credit (loan) this installment belongs to; must be of the same member. null detaches it. |
Respuestas
200OK ·data: BillingOrder401Missing or invalid credentials404Not found422Validation error429Rate limit exceeded
DELETE /v1/billing-orders/{id}
Cancel a billing order (409 if already paid).
Optional reason (query ?reason= or JSON body {"reason": …}, max 500 chars) is stored as cancel_reason — e.g. «consolidated into another account». Cancelling an already cancelled order with a reason updates the reason.
Parámetros
| Nombre | En | Tipo | Obligatorio | Descripción |
|---|---|---|---|---|
id | path | string (uuid) | sí | |
reason | query | string | Why the order is cancelled (stored as cancel_reason). |
Acepta Idempotency-Key.
Cuerpo (JSON)
| Campo | Tipo | Obligatorio | Descripción |
|---|---|---|---|
reason | string |
Respuestas
200OK ·data: BillingOrder401Missing or invalid credentials404Not found422Validation error429Rate limit exceeded
POST /v1/billing-orders/{id}/forgive
Forgive (condone) part or all of the balance.
Forgiven money is not a payment: it does not appear in /v1/payments. Without amount, forgives the whole balance and the order becomes paid. On orders with a breakdown the forgiveness takes, of what is still owed, late fee first, then interest, then other charges and principal last (forgiven_now_breakdown; forgiven principal is a loss).
Parámetros
| Nombre | En | Tipo | Obligatorio | Descripción |
|---|---|---|---|---|
id | path | string (uuid) | sí |
Acepta Idempotency-Key.
Cuerpo (JSON)
| Campo | Tipo | Obligatorio | Descripción |
|---|---|---|---|
amount | number | ||
reason | string |
Respuestas
200OK ·data: BillingOrder401Missing or invalid credentials404Not found422Validation error429Rate limit exceeded
POST /v1/billing-orders/{id}/late-fees
Add a late fee to an order.
Adds to late_fee and fires the late_fee_applied notice if the organization configured one. With collectible: true the fee is also added to amount (it becomes owed; a paid order re-opens). When omitted, the organization's moratorio_cobrable setting decides (default: informational only).
Parámetros
| Nombre | En | Tipo | Obligatorio | Descripción |
|---|---|---|---|---|
id | path | string (uuid) | sí |
Acepta Idempotency-Key.
Cuerpo (JSON)
| Campo | Tipo | Obligatorio | Descripción |
|---|---|---|---|
amount | number | sí | |
collectible | boolean |
Respuestas
201OK ·data: BillingOrder401Missing or invalid credentials404Not found422Validation error429Rate limit exceeded
POST /v1/billing-orders/{id}/payment-link
Create (or reuse) a payment link with the organization's payment provider.
Parámetros
| Nombre | En | Tipo | Obligatorio | Descripción |
|---|---|---|---|---|
id | path | string (uuid) | sí |
Acepta Idempotency-Key.
Respuestas
200OK ·data: PaymentLink401Missing or invalid credentials404Not found429Rate limit exceeded
Payments
POST /v1/billing-orders/{id}/pay
Settle the whole remaining balance.
Registers one payment for exactly the remaining balance. For partial or historical payments use POST /v1/billing-orders/{id}/payments.
Parámetros
| Nombre | En | Tipo | Obligatorio | Descripción |
|---|---|---|---|---|
id | path | string (uuid) | sí |
Acepta Idempotency-Key.
Cuerpo (JSON)
| Campo | Tipo | Obligatorio | Descripción |
|---|---|---|---|
method | string | Por omisión: "external". | |
type | string | Old name of method. | |
reference | string | ||
notes | string | ||
paid_at | string | When the money was received. Defaults to now. A date without time (2026-09-22) means that day in the organization's timezone (organizations.timezone): today → now, any other day → 12:00 local that day, so it never shifts to the previous day. A date and time without offset (2026-09-22T23:30) is that wall-clock time in the organization's timezone. A full ISO-8601 timestamp with Z or an offset is taken as is. Cannot be in the future. Ejemplo: "2026-09-22". |
Respuestas
200OK ·data: PaymentResult401Missing or invalid credentials404Not found422Validation error429Rate limit exceeded
POST /v1/billing-orders/{id}/payments
Register a payment (partial, historical date, overpayment policy).
excess decides what happens when amount is larger than the balance: reject (default) answers 422 amount_exceeds_balance; credit applies the excess to the member's next open orders (oldest first) and keeps the rest as credit balance.
Parámetros
| Nombre | En | Tipo | Obligatorio | Descripción |
|---|---|---|---|---|
id | path | string (uuid) | sí |
Acepta Idempotency-Key.
Cuerpo (JSON)
| Campo | Tipo | Obligatorio | Descripción |
|---|---|---|---|
amount | number | sí | |
paid_at | string | When the money was received. Defaults to now. A date without time (2026-09-22) means that day in the organization's timezone (organizations.timezone): today → now, any other day → 12:00 local that day, so it never shifts to the previous day. A date and time without offset (2026-09-22T23:30) is that wall-clock time in the organization's timezone. A full ISO-8601 timestamp with Z or an offset is taken as is. Cannot be in the future. Ejemplo: "2026-09-22". | |
method | string | Ejemplo: "transfer". | |
reference | string | ||
notes | string | ||
excess | string: reject, credit | Por omisión: "reject". |
Respuestas
201OK ·data: PaymentResult401Missing or invalid credentials404Not found422Validation error429Rate limit exceeded
GET /v1/payments
List payments (the ledger).
Every money movement: payments (kind: payment) and reversals of voided payments (kind: reversal, negative amount). allocation says how each entry was applied to its installment (principal, interest, late fee, other charges, unassigned; null when the installment has no breakdown); a reversal carries exactly the same figures, negative. paid_at is when the money was received (it can be in the past); recorded_at is when the entry reached Makatea — created_since/updated_since and the ordering use recorded_at, so a back-dated payment registered today still shows up in your next sync. The ledger is append-only, so updated_since is an alias of created_since. Default order: newest first; with a *_since filter: oldest first.
Parámetros
| Nombre | En | Tipo | Obligatorio | Descripción |
|---|---|---|---|---|
member_id | query | string (uuid) | ||
billing_order_id | query | string (uuid) | ||
created_since | query | string (date-time) | Only records created at or after this instant (ISO-8601). Ordering becomes created_at ascending. | |
updated_since | query | string (date-time) | Only records changed at or after this instant (ISO-8601). Switches ordering to updated_at ascending, so you can resume a sync with the last next_cursor. | |
limit | query | integer | ||
cursor | query | string | next_cursor from the previous page. | |
offset | query | integer | Legacy; prefer cursor. | |
count | query | boolean | Include pagination.total. |
Respuestas
200OK ·data: array de Payment401Missing or invalid credentials429Rate limit exceeded
GET /v1/payments/{id}
Get a payment.
Parámetros
| Nombre | En | Tipo | Obligatorio | Descripción |
|---|---|---|---|---|
id | path | string (uuid) | sí |
Respuestas
200OK ·data: Payment401Missing or invalid credentials404Not found429Rate limit exceeded
POST /v1/payments/{id}/void
Void a payment.
Writes a reversal (negative) entry, lowers the order's amount_paid and re-opens it if needed. 409 already_voided the second time.
Parámetros
| Nombre | En | Tipo | Obligatorio | Descripción |
|---|---|---|---|---|
id | path | string (uuid) | sí |
Acepta Idempotency-Key.
Cuerpo (JSON)
| Campo | Tipo | Obligatorio | Descripción |
|---|---|---|---|
reason | string |
Respuestas
200OK ·data: Payment401Missing or invalid credentials404Not found422Validation error429Rate limit exceeded
Credits (loans)
GET /v1/credits
List credits (loans) with their principal, what came back and what is owed.
Each credit groups the installments of one loan (external_ref = your folio) and carries its principal. totals are to date: capital_recovered/interest_collected/late_fee_collected = what the payment ledger applied to its installments (voided payments net out); capital_outstanding/interest_outstanding = of its open installments with breakdown; balance = amount − paid − forgiven of its open installments; paid_without_ledger = paid amounts imported as history, with no ledger entry. Default order: start_date descending; with updated_since: updated_at ascending.
Parámetros
| Nombre | En | Tipo | Obligatorio | Descripción |
|---|---|---|---|---|
member_id | query | string (uuid) | ||
external_ref | query | string | Exact match on your own identifier. | |
updated_since | query | string (date-time) | Only records changed at or after this instant (ISO-8601). Switches ordering to updated_at ascending, so you can resume a sync with the last next_cursor. | |
status | query | string: active, liquidated, cancelled | ||
limit | query | integer | ||
cursor | query | string | next_cursor from the previous page. | |
offset | query | integer | Legacy; prefer cursor. | |
count | query | boolean | Include pagination.total. |
Respuestas
200OK ·data: array de Loan401Missing or invalid credentials429Rate limit exceeded
POST /v1/credits
Create a credit (loan) and attach its installments.
external_ref (your folio) is unique per organization: reusing it is 409. Installments are attached by id or by their external_ref; they must belong to the same member (422 credit_member_mismatch). start_date is when the money was lent: it decides in which period the principal counts as «placed».
Acepta Idempotency-Key.
Cuerpo (JSON)
| Campo | Tipo | Obligatorio | Descripción |
|---|---|---|---|
member_id | string (uuid) | sí | |
external_ref | string | Your folio / contract number. Unique per organization. | |
principal | number | sí | Money lent (capital prestado). |
start_date | string (date) | sí | Date the money was lent. |
total_amount | number | Total the member will pay (principal + interest), if you have it. | |
periods | integer | ||
frequency | string: weekly, biweekly, monthly, daily, other | ||
notes | string | ||
billing_order_ids | array de string (uuid) | ||
billing_order_external_refs | array de string |
Respuestas
201OK ·data: LoanDetail401Missing or invalid credentials422Validation error429Rate limit exceeded
GET /v1/credits/{id}
Get a credit with its installments and their breakdown.
Parámetros
| Nombre | En | Tipo | Obligatorio | Descripción |
|---|---|---|---|---|
id | path | string (uuid) | sí |
Respuestas
200OK ·data: LoanDetail401Missing or invalid credentials404Not found429Rate limit exceeded
PATCH /v1/credits/{id}
Update a credit, attach or detach installments.
Only the fields you send change. status can be set to cancelled (the principal stops counting as placed) or back to active; liquidated is computed from its installments.
Parámetros
| Nombre | En | Tipo | Obligatorio | Descripción |
|---|---|---|---|---|
id | path | string (uuid) | sí |
Acepta Idempotency-Key.
Cuerpo (JSON)
| Campo | Tipo | Obligatorio | Descripción |
|---|---|---|---|
external_ref | string, nullable | ||
principal | number | ||
start_date | string (date) | ||
total_amount | number, nullable | ||
periods | integer, nullable | ||
frequency | string: weekly, biweekly, monthly, daily, other, nullable | ||
notes | string, nullable | ||
status | string: active, cancelled | ||
add_billing_order_ids | array de string (uuid) | ||
add_billing_order_external_refs | array de string | ||
remove_billing_order_ids | array de string (uuid) |
Respuestas
200OK ·data: LoanDetail401Missing or invalid credentials404Not found422Validation error429Rate limit exceeded
GET /v1/settings/payment-allocation
How payments are split between late fee, interest and principal.
Respuestas
200OK ·data: AllocationRule401Missing or invalid credentials429Rate limit exceeded
PUT /v1/settings/payment-allocation
Change the payment allocation rule.
moratorio_interes_capital (default: late fee, then interest, then other charges, then principal), proporcional (each payment split in proportion to what is owed of each part) or al_liquidar (a partial payment stays «unassigned» until the installment is settled; the settling payment recognizes all of its principal and interest on its date). The rule is fixed on each installment when its breakdown is loaded; with apply_existing: true every installment with breakdown is re-applied with the new rule (past figures change).
Acepta Idempotency-Key.
Cuerpo (JSON)
| Campo | Tipo | Obligatorio | Descripción |
|---|---|---|---|
rule | string: moratorio_interes_capital, proporcional, al_liquidar | sí | |
apply_existing | boolean | Por omisión: false. |
Respuestas
200OK ·data: AllocationRule401Missing or invalid credentials422Validation error429Rate limit exceeded
Webhooks
GET /v1/webhook-endpoints
List webhook endpoints.
Respuestas
200OK ·data: array de WebhookEndpoint401Missing or invalid credentials429Rate limit exceeded
POST /v1/webhook-endpoints
Register a webhook endpoint (the signing secret is returned only here).
Acepta Idempotency-Key.
Cuerpo (JSON)
| Campo | Tipo | Obligatorio | Descripción |
|---|---|---|---|
url | string (uri) | sí | https only; private/internal hosts are rejected. |
events | array de string: *, member.created, member.updated, billing_order.created, billing_order.updated, billing_order.paid, billing_order.cancelled, payment.received, payment.voided, promise.created, promise.kept, promise.broken, message.sent, message.received | sí | |
description | string |
Respuestas
201OK ·data: WebhookEndpointCreated401Missing or invalid credentials422Validation error429Rate limit exceeded
DELETE /v1/webhook-endpoints/{id}
Delete a webhook endpoint (its pending deliveries are dropped).
Parámetros
| Nombre | En | Tipo | Obligatorio | Descripción |
|---|---|---|---|---|
id | path | string (uuid) | sí |
Acepta Idempotency-Key.
Respuestas
200OK ·data: Deleted401Missing or invalid credentials404Not found429Rate limit exceeded
GET /v1/webhook-events
List emitted events (newest first).
Events are recorded only while the organization has at least one active endpoint subscribed to that type.
Parámetros
| Nombre | En | Tipo | Obligatorio | Descripción |
|---|---|---|---|---|
type | query | string | ||
created_since | query | string (date-time) | Only records created at or after this instant (ISO-8601). Ordering becomes created_at ascending. | |
limit | query | integer | ||
cursor | query | string | next_cursor from the previous page. | |
offset | query | integer | Legacy; prefer cursor. | |
count | query | boolean | Include pagination.total. |
Respuestas
200OK ·data: array de WebhookEvent401Missing or invalid credentials429Rate limit exceeded
GET /v1/webhook-deliveries
List delivery attempts (newest first).
Parámetros
| Nombre | En | Tipo | Obligatorio | Descripción |
|---|---|---|---|---|
status | query | string: pending, delivered, failed | ||
event_id | query | string (uuid) | ||
endpoint_id | query | string (uuid) | ||
limit | query | integer | ||
cursor | query | string | next_cursor from the previous page. | |
offset | query | integer | Legacy; prefer cursor. | |
count | query | boolean | Include pagination.total. |
Respuestas
200OK ·data: array de WebhookDelivery401Missing or invalid credentials429Rate limit exceeded
POST /v1/webhook-deliveries/{id}/retry
Retry a delivery now (pending or failed).
Parámetros
| Nombre | En | Tipo | Obligatorio | Descripción |
|---|---|---|---|---|
id | path | string (uuid) | sí |
Acepta Idempotency-Key.
Respuestas
200OK ·data: WebhookDelivery401Missing or invalid credentials404Not found429Rate limit exceeded
Operations
GET /v1/sequence-runs
List scheduled/sent collection messages (newest scheduled first).
Parámetros
| Nombre | En | Tipo | Obligatorio | Descripción |
|---|---|---|---|---|
state | query | string | ||
member_id | query | string (uuid) | ||
limit | query | integer | ||
cursor | query | string | next_cursor from the previous page. | |
offset | query | integer | Legacy; prefer cursor. | |
count | query | boolean | Include pagination.total. |
Respuestas
200OK ·data: array de SequenceRun401Missing or invalid credentials429Rate limit exceeded
GET /v1/flows
List the organization's flows.
Respuestas
200OK ·data: array de Flow401Missing or invalid credentials429Rate limit exceeded
GET /v1/templates
List the organization's active templates.
Respuestas
200OK ·data: array de Template401Missing or invalid credentials429Rate limit exceeded
GET /v1/stats
Dashboard numbers — the same figures the app's Panel shows.
Every money figure comes from the same database function the app uses (org_metricas_cobranza), so the API and the Panel never disagree. metrics has the full set for the period (from/to, default: 1st of the current month to today, in the org's timezone): collected = money that came in by payment date (voided payments, credit-balance applications and future-dated rows excluded), overdue/upcoming = real balance (amount − paid − forgiven) of open installments due before / on-or-after today, aging by days late (1-9, 10-30, 31-60, 60+), collection_rate = of what came due in the period up to today, the share already paid. metrics.capital_profit splits the same period into principal and profit: placed (principal lent, by credit start_date), collected.capital|interest|late_fee|other|unassigned|no_breakdown|to_credit_balance (they add up exactly to collected.total, the same «collected» as above), profit = interest + late fee collected with its margin over what was collected with a breakdown, outstanding principal and interest (current / overdue) of open installments, and forgiven split into principal (a loss), interest, late fee and other. coverage.status is none when no installment has a breakdown: then every figure is 0 and no_breakdown carries the money. portfolio and members keep their old shape.
Parámetros
| Nombre | En | Tipo | Obligatorio | Descripción |
|---|---|---|---|---|
from | query | string (date) | Period start (YYYY-MM-DD). Default: 1st of the current month. | |
to | query | string (date) | Period end (YYYY-MM-DD). Default: today (org timezone). |
Respuestas
200OK ·data: Stats401Missing or invalid credentials429Rate limit exceeded
Objetos
Error
| Campo | Tipo | Obligatorio | Descripción |
|---|---|---|---|
error | object |
Pagination
| Campo | Tipo | Obligatorio | Descripción |
|---|---|---|---|
limit | integer | ||
has_more | boolean | ||
next_cursor | string, nullable | ||
offset | integer | Only when paging with offset. | |
total | integer | Only with count=true. |
Status
| Campo | Tipo | Obligatorio | Descripción |
|---|---|---|---|
status | string: ok, degraded | ||
database | string | ||
database_latency_ms | integer | ||
api_version | string | ||
time | string (date-time) |
Member
| Campo | Tipo | Obligatorio | Descripción |
|---|---|---|---|
id | string (uuid) | ||
external_ref | string, nullable | ||
full_name | string | ||
phone_e164 | string, nullable | ||
email | string, nullable | ||
state | string | ||
identity | object | ||
tags | array de string | ||
notes | string, nullable | ||
payment_reference | string, nullable | ||
segment_id | string, nullable | ||
promised_date | string (date), nullable | ||
promise_status | string | ||
promised_amount | number, nullable | ||
promise_registered_at | string (date-time), nullable | ||
credit_balance | number | ||
do_not_contact | boolean | Never message this member (withdraws anything queued). | |
do_not_contact_reason | string, nullable | ||
customer_since | string (date), nullable | When it became your customer; created_at is when it entered Makatea. | |
import_batch_id | string (uuid), nullable | ||
created_at | string (date-time) | ||
updated_at | string (date-time) |
BillingOrder
| Campo | Tipo | Obligatorio | Descripción |
|---|---|---|---|
id | string (uuid) | ||
member_id | string (uuid) | ||
external_ref | string, nullable | ||
amount | number | ||
amount_paid | number | ||
amount_forgiven | number | ||
late_fee | number | ||
balance | number | amount − amount_paid − amount_forgiven (late fees are reported apart). | |
currency | string | ||
due_date | string (date) | ||
period_label | string, nullable | ||
status | string: pending, overdue, paid, cancelled | ||
paid_at | string (date-time), nullable | ||
paid_via | string, nullable | ||
notes | string, nullable | ||
forgiven_at | string (date-time), nullable | ||
forgiven_reason | string, nullable | ||
cancel_reason | string, nullable | Why it was cancelled (DELETE …?reason=). | |
created_at | string (date-time) | ||
updated_at | string (date-time) | ||
credit_id | string (uuid), nullable | Credit (loan) it belongs to. | |
capital_portion | number, nullable | Principal part of the installment (null = no breakdown). | |
interest_portion | number, nullable | Interest part of the installment. | |
breakdown | object, nullable | null when the installment has no breakdown (figures are never invented). |
Payment
| Campo | Tipo | Obligatorio | Descripción |
|---|---|---|---|
id | string (uuid) | ||
billing_order_id | string (uuid) | ||
member_id | string (uuid) | ||
amount | number | ||
kind | string: payment, reversal | ||
method | string, nullable | ||
reference | string, nullable | ||
notes | string, nullable | ||
voids_payment_id | string (uuid), nullable | ||
voided | boolean | ||
paid_at | string (date-time) | When the money was received. | |
created_at | string (date-time) | ||
recorded_at | string (date-time) | When the entry was recorded in Makatea. | |
allocation | object, nullable | How this entry was applied to its installment. Adds up to amount. unassigned = beyond the installment's parts or, with rule al_liquidar, a partial payment not yet recognized (the settling payment then carries it negative). null when the installment has no breakdown. |
PaymentResult
| Campo | Tipo | Obligatorio | Descripción |
|---|---|---|---|
order_id | string (uuid) | ||
amount_paid | number | ||
status | string | ||
fully_paid | boolean | ||
excess_applied_to_other_orders | number | ||
credit_added | number | ||
already_applied | boolean | ||
payment | Payment | ||
order | BillingOrder |
PromiseState
| Campo | Tipo | Obligatorio | Descripción |
|---|---|---|---|
member_id | string (uuid) | ||
status | string: none, active, kept, broken, cancelled | ||
current | object, nullable | ||
history | array de object |
Credit
| Campo | Tipo | Obligatorio | Descripción |
|---|---|---|---|
member_id | string (uuid) | ||
credit_balance | number | ||
ledger | array de object |
CreditApplied
| Campo | Tipo | Obligatorio | Descripción |
|---|---|---|---|
member_id | string (uuid) | ||
applied | number | ||
credit_balance | number |
Interaction
| Campo | Tipo | Obligatorio | Descripción |
|---|---|---|---|
id | string (uuid) | ||
channel | string | ||
direction | string: inbound, outbound | ||
text | string, nullable | ||
attachment | string, nullable | ||
classification | string, nullable | ||
sequence_run_id | string (uuid), nullable | ||
simulated | boolean | ||
occurred_at | string (date-time) |
MessageResult
| Campo | Tipo | Obligatorio | Descripción |
|---|---|---|---|
id | string (uuid) | ||
object | string: interaction, sequence_run | ||
status | string: sent, simulated, queued, queued_simulated | ||
channel | string | ||
member_id | string (uuid) |
ConversationImportResult
| Campo | Tipo | Obligatorio | Descripción |
|---|---|---|---|
inserted | integer | ||
skipped_duplicates | integer | ||
unmatched | array de object | ||
errors | array de object |
Document
| Campo | Tipo | Obligatorio | Descripción |
|---|---|---|---|
id | string (uuid) | ||
member_id | string (uuid) | ||
name | string | ||
type | string | ||
mime_type | string | ||
size | integer | ||
external_ref | string, nullable | ||
description | string, nullable | ||
storage_path | string | ||
download_url | string, nullable | Signed URL, valid 1 hour. | |
download_url_expires_at | string (date-time), nullable | ||
created_at | string (date-time) |
Deleted
| Campo | Tipo | Obligatorio | Descripción |
|---|---|---|---|
id | string (uuid) | ||
deleted | boolean |
PaymentLink
object
WebhookEndpoint
| Campo | Tipo | Obligatorio | Descripción |
|---|---|---|---|
id | string (uuid) | ||
url | string | ||
events | array de string | ||
active | boolean | ||
description | string, nullable | ||
created_at | string (date-time) | ||
updated_at | string (date-time) |
WebhookEndpointCreated
object
WebhookEvent
| Campo | Tipo | Obligatorio | Descripción |
|---|---|---|---|
id | string (uuid) | ||
type | string: member.created, member.updated, billing_order.created, billing_order.updated, billing_order.paid, billing_order.cancelled, payment.received, payment.voided, promise.created, promise.kept, promise.broken, message.sent, message.received | ||
created_at | string (date-time) | ||
data | object |
WebhookDelivery
| Campo | Tipo | Obligatorio | Descripción |
|---|---|---|---|
id | string (uuid) | ||
event_id | string (uuid) | ||
event_type | string | ||
endpoint_id | string (uuid) | ||
status | string: pending, delivered, failed | ||
attempts | integer | ||
next_attempt_at | string (date-time), nullable | ||
last_status | integer, nullable | ||
last_error | string, nullable | ||
created_at | string (date-time) | ||
delivered_at | string (date-time), nullable |
SequenceRun
| Campo | Tipo | Obligatorio | Descripción |
|---|---|---|---|
id | string (uuid) | ||
member_id | string (uuid) | ||
billing_order_id | string (uuid), nullable | ||
template_id | string (uuid) | ||
state | string | ||
channel | string | ||
scheduled_at | string (date-time) | ||
outcome | string, nullable | ||
attempts | integer |
Flow
| Campo | Tipo | Obligatorio | Descripción |
|---|---|---|---|
id | string (uuid) | ||
name | string | ||
status | string | ||
steps | integer |
Template
| Campo | Tipo | Obligatorio | Descripción |
|---|---|---|---|
id | string (uuid) | ||
name | string | ||
channel | string | ||
trigger_type | string | ||
version | integer | ||
subject | string, nullable |
Stats
object
Loan
| Campo | Tipo | Obligatorio | Descripción |
|---|---|---|---|
id | string (uuid) | ||
member_id | string (uuid) | ||
member_name | string, nullable | ||
external_ref | string, nullable | Your folio. | |
principal | number | Money lent. | |
total_amount | number, nullable | ||
periods | integer, nullable | ||
frequency | string, nullable | ||
start_date | string (date) | Date the money was lent. | |
status | string: active, liquidated, cancelled | ||
notes | string, nullable | ||
created_at | string (date-time) | ||
updated_at | string (date-time) | ||
totals | object |
LoanDetail
object
AllocationRule
| Campo | Tipo | Obligatorio | Descripción |
|---|---|---|---|
rule | string | ||
rules | array de string | ||
orders_reapplied | integer |