Direct debit has three steps: enroll the person with their account, send them charges and get the result.1. Enroll the person#
Send Affiliation with the person's or company's document and their account.Each record is one person or company (DNI, CE or RUC) with one account. You can send many in the same request.
You can add more accounts to the same person: send each one with account_action: "add" (or add_account: true), in the same request or another one. Their first account is the charge account and the others are saved. details shows the result of each record.
To see a person's accounts and the status of each one: GET /v1/autodebit/{merchant_id}/affiliations/{document_number} (each account with its bank_code, last 4 digits, whether it is the charge account, and its status).
Kambia sends the enrollment to the bank, and it stays pending until the bank accepts it.
When the bank answers, we notify your webhook whether it accepted or rejected the enrollment, and why (Notifications). 2. Send the charges#
Send Charge with the document_number and the amount.Charges go to the bank on the cut-off dates: send them before 4:00 p.m. (Lima time) on that date. The bank tries to collect from the next business day, for 3 business days. To get the dates in your calendar (Google, Outlook or Apple), subscribe to https://portal.kambia.app/api/debito-automatico/calendario.ics.
Only what you send on the cut-off date itself counts. On any other day, Charge answers 422 with code: "OUTSIDE_CUTOFF_DATE" and the next date in data.next_cutoff_date, and saves nothing: send the list on that date. A charge that didn't go out on one cut-off date isn't sent on its own at the next one: send it again. Sandbox accepts any day. Use the same document_number you enrolled the person with. Each charge goes to a single account: the charge account.
If the charge account ends its 3 days without funds and the person has another saved account at the same bank, Kambia asks the bank to switch to that other account for the next charges (one never tried goes first) and notifies you with autodebit.account_change (see Notifications). Kambia never debits two accounts at once. If the enrollment isn't ready by the cut-off date, that charge doesn't go out and you need to send it again. The response tells you in not_ready_to_send.
If you repeat a person in the same request, it comes back in duplicates. If you resend it with confirm: true and an idempotency_key, the amounts are added into a single charge.
3. Get the result#
Kambia notifies your webhook of each charge's result: collected, no balance or rejected. Details in Notifications.Changing the account#
To change the charge account, send Affiliation again with the new account and account_action: "replace" (or without the field). Until the bank accepts the change, the previous account keeps being debited. To remove an account, send it with account_action: "remove": if it is the charge account, the person is not charged until you choose another one. If the account is saved without changing the charge account, details tells you why in reason.Limits#
Up to 400 records per request (a request over 100 KB is rejected with 413) and 30 requests per minute.
Account holder's authorization#
Before enrolling a person you need their prior, express and written authorization for direct debit. You can request it through the API, or use your own contracts.Through the API#
1.
Send POST /v1/autodebit/{merchant_id}/consents with the person's data (the same as Affiliation; the account is optional):
{
"document": { "type": "1", "number": "12345678", "full_name": "Juan Perez" },
"bank_account": { "bank_code": "002", "account_type": "1", "account_number": "19112345678901" },
"contract_number": "PR-2026-001",
"return_url": "myapp://consent"
}
It returns 201 with consent_id and url:{
"status_code": 201,
"message": "Consent created",
"data": {
"consent_id": "3f2c6d1a-8b4e-4f5a-9c7d-2e1f0a9b8c7d",
"url": "https://api.kambia.app/v1/autorizar/3f2c6d1a-8b4e-4f5a-9c7d-2e1f0a9b8c7d",
"status": "PENDING",
"document_type": "1",
"document_number": "12345678",
"full_name": "Juan Perez",
"created_at": "2026-10-06T15:00:00.000Z",
"expires_at": "2026-10-13T15:00:00.000Z"
}
}
2.
Open url inside your app (or send it by message). The person reads the authorization and taps «Autorizo» (I authorize) or «No autorizo» (I don't), and Kambia stores it with its date, time, IP and device. The page is in Spanish. The link expires after 7 days; if it expires, request a new one. return_url (optional) is the button back to your app.
3.
We send you the result to your webhook (autodebit.consent, see Notifications). You can also check it with GET /v1/autodebit/{merchant_id}/consents/{consent_id}: PENDING, ACCEPTED, DECLINED, EXPIRED or REVOKED. 4.
If the person later unsubscribes in your app, send POST /v1/autodebit/{merchant_id}/affiliations/{document_number}/unsubscribe with body {}: they stop being charged, the cancellation goes to the bank and their authorizations become REVOKED.
With your own contracts#
If you prefer your own contracts, you obtain and keep the authorization yourself, and present it when the bank, an authority or Kambia asks for it.You can include this clause in your contracts. Account holders in Peru sign it in Spanish:CLÁUSULA [NÚMERO]: Débito Automático.-
EL (LA) PRESTATARIO(A) autoriza de manera expresa a [NOMBRE DE LA ENTIDAD], directamente o a través de los proveedores tecnológicos, operadores de cobro y/o empresas especializadas que contrate para tal efecto —incluyendo a KAMBIA S.A.C.—, a efectuar, en caso de mora, el débito automático de los montos vencidos, intereses moratorios y demás cargos generados por la mora, conforme al presente contrato, con cargo a sus cuentas en el Banco de Crédito del Perú (BCP) y en cualesquiera otras entidades del sistema financiero, así como a billeteras digitales y demás medios legales de pago o almacenamiento de dinero de los cuales sea titular, respetando los límites de protección de remuneraciones y fondos inembargables previstos por ley. Por cada débito ejecutado asumirá un cargo fijo de S/ 20.00 (veinte con 00/100 soles) por concepto de gestión operativa. Esta autorización se mantiene vigente hasta el cumplimiento total de las obligaciones del presente contrato, salvo comunicación escrita en contrario. Los garantes que suscriban el presente contrato otorgan esta misma autorización respecto de sus cuentas y medios de pago, hasta la cancelación total de la obligación garantizada.
CLAUSE [NUMBER]: Direct Debit.-
THE BORROWER expressly authorizes [NAME OF THE ENTITY], directly or through the technology providers, collection operators and/or specialized companies it engages for this purpose —including KAMBIA S.A.C.—, to carry out, in the event of default, the direct debit of overdue amounts, default interest and other charges generated by the default, in accordance with this contract, from their accounts at Banco de Crédito del Perú (BCP) and at any other entities of the financial system, as well as from digital wallets and other legal means of payment or money storage they hold, respecting the protection limits for wages and unseizable funds established by law. For each debit executed, they will bear a fixed charge of S/ 20.00 (twenty and 00/100 soles) for operational management. This authorization remains in force until all obligations under this contract are fully met, unless otherwise communicated in writing. Guarantors who sign this contract grant this same authorization with respect to their accounts and means of payment, until the guaranteed obligation is fully paid.
Testing in sandbox#
Use your same credentials with https://sandbox.kambia.app/v1. Nothing reaches the bank in sandbox.
To simulate the bank's response, send POST https://sandbox.kambia.app/v1/autodebit/{merchant_id}/sandbox/bank-response with body {}: it accepts your pending enrollments and answers your queued charges. Until you do, your charges come back in not_ready_to_send.
You choose the result with the amount's cents: .01 no balance (NO_BALANCE), .02 rejected (REJECTED) and anything else collected (SUCCESS). A document with no enrollment is rejected, as at the bank.
The notification reaches your webhook as in production, with "test": true. Each person gets one response per day; anything not answered comes back in not_answered with the reason.
Consent also works in sandbox: the link opens the same page and the notice arrives with "test": true.
Modified at 2026-10-19 05:40:49