1. Direct debit
API
English
  • Español
  • English
  • Introduction
    • Kambia API
    • Credentials
    • Authentication
    • Verification
      POST
  • Services
    • Code catalog
    • Payout
      • Notifications
      • Create payout
      • Get payout
    • Direct debit
      • How it works
      • Authorization template
      • Notifications
      • Affiliation
        POST
      • Charge
        POST
  1. Direct debit

Notifications

Kambia notifies your webhook of how the bank answered your enrollments and your charges, as soon as it gets the response, and of what each person decided on their authorization.

How it is sent#

Method: POST
Content-Type: application/json
Signature header: x-kambia-signature (see below).
You get one notification per bank response, with all your enrollments (affiliations), all your charges (charges) or the account changes (changes) from that response. Consent notices arrive one per person.

Setup#

Send Kambia your webhook URL to register it. It is the same for sandbox and production.
If your webhook needs its own header (for example, a token), tell us and Kambia sends it with every notification.
Reply with a 2xx status within 6 seconds. If there is no reply, or it returns 5xx, 408 or 429, Kambia retries: three attempts in total, then it is not resent. Any other 4xx is not retried.

Charge notification#

It arrives with event: "autodebit.charge_results":
{
    "event": "autodebit.charge_results",
    "batch_id": "3c30bf81-509a-4c21-9c73-78f4f802ea9f",
    "merchant_id": "123",
    "processed_at": "2026-10-01T21:15:00.000Z",
    "charges": [
        {
            "document_number": "12345678",
            "full_name": "JUAN PEREZ",
            "amount": "150.50",
            "fecha_cobro": "20261001",
            "bank_code": "002",
            "status": "SUCCESS",
            "codigo_operacion": "KAM-20261001-ABC_12345678",
            "voucher_url": "https://api.kambia.app/v1/autodebit/123/charge-voucher/20261001/ABC_12345678"
        },
        {
            "document_number": "87654321",
            "full_name": "MARIA LOPEZ",
            "amount": "250.00",
            "fecha_cobro": "20261001",
            "bank_code": "002",
            "status": "NO_BALANCE",
            "codigo_operacion": "KAM-20261001-ABC_87654321"
        }
    ]
}
FieldDescription
document_numberDocument you enrolled the person with.
full_nameAccount holder's name.
amountAmount in soles processed by the bank. It includes the S/ 20 fixed charge if you pass it on to the account holder.
fecha_cobroDate of the charge attempt, as YYYYMMDD.
bank_codeBank of the charged account (3-digit code, as in affiliation).
statusResult of the charge (see the next table).
codigo_operacionCode to locate the charge if the account holder files a complaint.
voucher_urlOnly on SUCCESS: address of the charge voucher (see below).

Charge statuses#

statusDescription
SUCCESSThe bank collected the charge.
NO_BALANCEThe account had no balance. The bank tries again on the following business days; if it collects, another notification with SUCCESS arrives for the same person.
REJECTEDThe bank rejected the charge.

Enrollment notification#

It arrives with event: "autodebit.affiliation_results" when the bank answers your enrollments:
{
    "event": "autodebit.affiliation_results",
    "batch_id": "6f1d2c3a-8b4e-4f5a-9c7d-2e1f0a9b8c7d",
    "merchant_id": "123",
    "processed_at": "2026-10-01T21:15:00.000Z",
    "affiliations": [
        { "document_number": "12345678", "status": "ACCEPTED", "bank_code": "002", "account_last4": "8901" },
        { "document_number": "87654321", "status": "REJECTED", "reason": "CTA.NO ES DE CLIENTE", "bank_code": "002", "account_last4": "4321" }
    ]
}
statusDescription
ACCEPTEDThe bank accepted the enrollment: you can charge now.
REJECTEDThe bank did not accept it; reason says why. Fix the account and send affiliation again.
UNSUBSCRIBEDThe person is no longer enrolled: they can no longer be charged.
If account_change is true, the answer is to an account change: with REJECTED, the previous account keeps being charged.
Each enrollment includes bank_code and account_last4: the bank and the last 4 digits of the account the bank answered about.

Consent notice#

Arrives with event: "autodebit.consent" when a person decides on the authorization link (see How it works):
{
    "event": "autodebit.consent",
    "merchant_id": "123",
    "consent_id": "3f2c6d1a-8b4e-4f5a-9c7d-2e1f0a9b8c7d",
    "document_number": "12345678",
    "status": "ACCEPTED",
    "decided_at": "2026-10-06T15:04:05.000Z"
}
statusDescription
ACCEPTEDThe person authorized direct debit.
DECLINEDThe person did not authorize it.

Account change notice#

Arrives with event: "autodebit.account_change" when a person's charge account ends its window 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 (see How it works).
{
    "event": "autodebit.account_change",
    "batch_id": "b6a1c2d3-4e5f-4a7b-8c9d-0e1f2a3b4c5d",
    "merchant_id": "123",
    "processed_at": "2026-10-09T14:31:05.000Z",
    "changes": [
        {
            "document_number": "12345678",
            "full_name": "JUAN PEREZ",
            "from": { "bank_code": "002", "account_last4": "1001" },
            "to": { "bank_code": "002", "account_last4": "2002" },
            "reason": "la cuenta de cobro terminó su ventana sin saldo: Kambia pidió probar esta otra cuenta guardada",
            "requested_at": "2026-10-09T14:31:04.000Z"
        }
    ]
}
Until the bank accepts the change, charges keep going to the previous account. Whatever you send afterwards with account_action (replace, add or remove) takes precedence over this change. reason comes in Spanish.

Verifying the signature#

1.
Take the body exactly as received (the JSON string).
2.
Build the string to sign: merchant_id + body, with no separator.
3.
Compute HMAC-SHA256 with your merchant_secret and compare the hex result with the x-kambia-signature header.
If they don't match, the notification is not valid.

Voucher#

voucher_url is a Kambia API address: request it with GET and the authentication headers. For a GET, sign merchant_id + timestamp, with no body. The response has in data.url a link to the voucher image, valid for 1 hour, and in data.codigo_operacion the charge code.

Sandbox#

In sandbox, notifications arrive when you simulate the bank's response (see How it works), with "test": true so you don't mistake them for real ones.
Modified at 2026-10-06 15:03:29
Previous
Authorization template
Next
Affiliation
Built with