> For the complete documentation index, see [llms.txt](https://developers.doku.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://developers.doku.com/accept-payments/direct-api/snap/integration-guide/kartu-kredit-indonesia-cepat-secure-kki-cpts/host-to-host-integration.md).

# Host to Host Integration

Integration Steps

Overview of integration process with KKI Integration

1. [Payment](#id-1.-payment)
2. [Refund](#id-2.-refund)

***

### 1. Payment&#x20;

Merchant can request for payment by requesting this API

**Payment Flow**

<figure><img src="/files/OTuzPPVMunh7c8pMjses" alt=""><figcaption><p>Flow Kartu Kredit Indonesia</p></figcaption></figure>

#### API Endpoint&#x20;

<table><thead><tr><th width="203">Environment</th><th>Endpoint</th></tr></thead><tbody><tr><td>HTTP Method</td><td>POST</td></tr><tr><td>API Sandbox</td><td><a href="https://api-sandbox.doku.com">https://api-sandbox.doku.com</a></td></tr><tr><td>API Production</td><td><a href="https://api.doku.com">https://api.doku.com</a></td></tr><tr><td>Path</td><td><code>.../direct-debit/core/v1/debit/payment-host-to-host</code></td></tr></tbody></table>

**Sample of Request Header, Request Body and Response Body**

Notes:&#x20;

Parameter with (\*) is mandatory&#x20;

Paramater without (\*) is optional/conditional

{% openapi src="/files/qm5oM9GTXh6IrjmmWXQJ" path="/direct-debit/core/v1/debit/payment-host-to-host" method="post" %}
[swagger-kki (4).yaml](https://3092822868-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FqCxtvLoJNNxvp4U7kLHd%2Fuploads%2FvBnh9ffjFDmKrWGM64YD%2Fswagger-kki%20\(4\).yaml?alt=media\&token=8001e4d2-6732-45f1-b7be-c3da736201b8)
{% endopenapi %}

{% openapi src="/files/VmP7VixcBA2P331kUYlm" path="/direct-debit/core/v1/debit/payment-host-to-host" method="post" %}
[swagger-kki (1).yaml](https://3092822868-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FqCxtvLoJNNxvp4U7kLHd%2Fuploads%2FWKLP4zm8UigYVzQ6Q1Mo%2Fswagger-kki%20\(1\).yaml?alt=media\&token=18ea8e23-c1ec-4802-9f13-6d61af9b1a01)
{% endopenapi %}

{% openapi src="/files/15iUcAdw58RNSz3TGIwj" path="/direct-debit/core/v1/debit/payment-host-to-host" method="post" %}
[swagger-kki (2).yaml](https://3092822868-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FqCxtvLoJNNxvp4U7kLHd%2Fuploads%2FlSnQawwXOA27dOCadsBI%2Fswagger-kki%20\(2\).yaml?alt=media\&token=80692911-7e98-4484-a5ab-61d809fc9e73)
{% endopenapi %}

{% openapi src="/files/1OhIldyr3zFFuVT7CKLZ" path="/direct-debit/core/v1/debit/payment-host-to-host" method="post" %}
[swagger-kki (3).yaml](https://3092822868-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FqCxtvLoJNNxvp4U7kLHd%2Fuploads%2FqNvMhQwNPFMRdMsMxmyd%2Fswagger-kki%20\(3\).yaml?alt=media\&token=f76e1d1b-8436-40ef-a9e2-88bffba5c4cd)
{% endopenapi %}

### 2. Binding

This endpoint is used to tokenize a customer's CPAN without charging any amount, compared to the payment with Tokenization API which need to charges some amount to the Customer.

## Card Binding (Card Registration)

> Registers a credit card for a customer under a merchant account.\
> \
> \*\*Flow:\*\*\
> 1\. Merchant submits the encrypted card data along with customer information.\
> 2\. The system decrypts the card data, validates it against the ALTO/KKI network, and creates an \`AcquirerToken\`.\
> 3\. On success, a \`redirectUrl\` is returned (when \`CHANNEL-ID: DH\`) pointing to the OTP verification page.\
> 4\. The customer completes OTP verification, which finalises the binding and issues a \`bankCardToken\`.\
> \
> \*\*Card Data Encryption:\*\*\
> Encrypt the \`CardDataPayload\` JSON object using AES-CBC with the merchant's \`sharedKey\`.\
> The resulting Base64-encoded ciphertext is submitted as the \`cardData\` field.<br>

```json
{"openapi":"3.0.3","info":{"title":"Direct Debit Core System - Card Binding (KARTU_KREDIT_INDONESIA)","version":"1.0.0"},"servers":[{"url":"https://api.doku.com","description":"Base URL"}],"security":[{"BearerAuth":[]}],"components":{"securitySchemes":{"BearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"JWT","description":"B2B access token obtained from the Get B2B Token API (`/authorization/v1/access-token/b2b`)"}},"schemas":{"CardBindingRequest":{"type":"object","description":"Request body for card binding (registration)","required":["cardData","custIdMerchant","additionalInfo"],"properties":{"partnerReferenceNo":{"type":"string","description":"Merchant's unique reference number for this binding request","maxLength":64},"cardData":{"type":"string","description":"AES-CBC encrypted JSON of the card data, Base64-encoded.\nEncrypt the `CardDataPayload` object using the merchant's `sharedKey` provided by DOKU.\nSee the `CardDataPayload` schema for the plaintext structure.\n"},"custIdMerchant":{"type":"string","description":"Merchant's unique identifier for the customer","maxLength":64,"pattern":"^[a-zA-Z0-9]+$"},"journeyId":{"type":"string","description":"Optional journey or session ID for tracking the binding flow end-to-end"},"phoneNo":{"type":"string","description":"Customer's phone number (used for OTP delivery during OTP verification step)"},"additionalInfo":{"$ref":"#/components/schemas/BindingAdditionalInfo"}}},"BindingAdditionalInfo":{"type":"object","description":"Additional information for the card binding request","required":["channel"],"properties":{"channel":{"type":"string","description":"Product channel. Must be `KARTU_KREDIT_INDONESIA` for this operation.","enum":["KARTU_KREDIT_INDONESIA"]},"customerName":{"type":"string","description":"Full name of the cardholder","maxLength":70},"email":{"type":"string","description":"Email address of the cardholder","format":"email","maxLength":254},"address":{"type":"string","description":"Cardholder's billing address","maxLength":255},"dateOfBirth":{"type":"string","description":"Cardholder's date of birth in `YYYYMMDD` format","pattern":"^\\d{8}$"},"idCard":{"type":"string","description":"National ID card number (KTP) of the cardholder"},"country":{"type":"string","description":"ISO 3166-1 alpha-2 country code of the cardholder","maxLength":2},"successRegistrationUrl":{"type":"string","description":"Merchant URL to redirect to after successful OTP verification"},"failedRegistrationUrl":{"type":"string","description":"Merchant URL to redirect to after failed OTP verification"}}},"CardBindingResponse":{"type":"object","description":"Response body for a successful card binding request","properties":{"responseCode":{"type":"string","description":"Response code: HTTP Status (3) + Service Code `01` (2) + Case Code (2).\nExample: `2000100` = HTTP 200 + service `01` + case `00` (Successful).\n"},"responseMessage":{"type":"string","description":"Human-readable response message"},"referenceNo":{"type":"string","description":"DOKU-generated reference number for this binding request"},"redirectUrl":{"type":"string","description":"URL for OTP verification page hosted by DOKU.\nOnly present when `CHANNEL-ID: DH`. Merchant must redirect the customer here\nto complete the binding via OTP entry.\n"},"bankCardToken":{"type":"string","description":"Reusable token representing the bound credit card.\nPresent only after OTP verification is successfully completed (final binding state).\nUse this token for subsequent payment requests.\n"},"chargeToken":{"type":"string","description":"Charge token from the ALTO network (from the decrypted card data), if applicable"},"additionalInfo":{"$ref":"#/components/schemas/BindingResponseAdditionalInfo"}}},"BindingResponseAdditionalInfo":{"type":"object","description":"Additional information in the binding response","properties":{"custIdMerchant":{"type":"string","description":"The merchant's customer ID echoed back from the request"},"status":{"type":"string","description":"Current binding status of the token:\n- `PENDING` — OTP verification not yet completed\n- `SUCCESS` — Binding fully completed\n- `FAILED` — Binding failed\n","enum":["PENDING","SUCCESS","FAILED"]},"authCode":{"type":"string","description":"Session ID / authentication code for the OTP verification step.\nUsed internally by the redirect URL (DH) or passed to the OTP verification API (H2H).\n"}}},"ErrorResponse":{"type":"object","description":"Standard error response body.\nResponse code format: HTTP Status (3) + Service Code `01` (2) + Case Code (2).\n\n| Case Code | Meaning                                              |\n|-----------|------------------------------------------------------|\n| `00`      | General / Format Error                               |\n| `01`      | Duplicate Transaction / Duplicate Token              |\n| `02`      | Invalid OTT / External Server Error                  |\n| `03`      | Suspected Fraud                                      |\n| `04`      | Exceeds Transaction Frequency Limit                  |\n| `05`      | Do Not Honor (declined by issuer)                    |\n| `08`      | Invalid Merchant / No Card Record                    |\n| `11`      | Invalid CPAN                                         |\n| `12`      | Transaction Not Permitted / OTT Expired              |\n| `13`      | Invalid Amount                                       |\n| `14`      | Insufficient Funds                                   |\n| `15`      | Transaction Not Permitted to Terminal                |\n","properties":{"responseCode":{"type":"string","description":"Error response code"},"responseMessage":{"type":"string","description":"Human-readable error message"}}}}},"paths":{"/direct-debit/core/v1/registration-card-bind":{"post":{"summary":"Card Binding (Card Registration)","description":"Registers a credit card for a customer under a merchant account.\n\n**Flow:**\n1. Merchant submits the encrypted card data along with customer information.\n2. The system decrypts the card data, validates it against the ALTO/KKI network, and creates an `AcquirerToken`.\n3. On success, a `redirectUrl` is returned (when `CHANNEL-ID: DH`) pointing to the OTP verification page.\n4. The customer completes OTP verification, which finalises the binding and issues a `bankCardToken`.\n\n**Card Data Encryption:**\nEncrypt the `CardDataPayload` JSON object using AES-CBC with the merchant's `sharedKey`.\nThe resulting Base64-encoded ciphertext is submitted as the `cardData` field.\n","operationId":"cardBindingKKI","tags":["Binding"],"parameters":[{"name":"X-PARTNER-ID","in":"header","required":true,"description":"Merchant's client ID registered with DOKU","schema":{"type":"string","maxLength":32}},{"name":"X-EXTERNAL-ID","in":"header","required":true,"description":"Unique reference ID for this request (per-day uniqueness required).\nUsed for idempotency and tracing.\n","schema":{"type":"string","maxLength":36}},{"name":"Authorization","in":"header","required":true,"description":"B2B access token obtained from the Get B2B Token API","schema":{"type":"string"}},{"name":"X-TIMESTAMP","in":"header","required":true,"description":"Request timestamp in ISO 8601 format (yyyy-MM-ddTHH:mm:ss+07:00)","schema":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}[+\\-]\\d{2}:\\d{2}$"}},{"name":"X-SIGNATURE","in":"header","required":true,"description":"HMAC-SHA512 asymmetric signature for request integrity verification","schema":{"type":"string"}},{"name":"CHANNEL-ID","in":"header","required":false,"description":"Channel identifier determining the post-registration redirect behaviour.\n- `DH` (Direct Hosting, default): returns a `redirectUrl` pointing to the DOKU-hosted OTP page.\n- `H2H` (Host-to-Host): no redirect; merchant handles the OTP flow independently.\n","schema":{"type":"string","enum":["DH","H2H"],"default":"DH"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CardBindingRequest"}}}},"responses":{"200":{"description":"Card binding request accepted. The customer must complete OTP verification\nto finalise the binding. Use `redirectUrl` (DH flow) or `additionalInfo.authCode`\n(H2H flow) to proceed.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CardBindingResponse"}}}},"202":{"description":"Request in progress (timeout from ALTO network; may still succeed asynchronously)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"400":{"description":"Bad request — missing or invalid fields","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Authentication failure — invalid token or card data decryption failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Forbidden — transaction not permitted or card restrictions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not found — merchant, card, or transaction record not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Conflict — duplicate transaction or duplicate token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error or external system malfunction","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}}}}
```

### 3. Unbinding

This endpoint is used to unbind a previously binded token  compared to the payment with Tokenization API which need to charges some amount to the Customer.

## Card Unbinding

> Deactivates a previously bound credit card token for a customer under a merchant account.\
> \
> \*\*Flow:\*\*\
> 1\. Merchant submits the \`tokenId\` (i.e., the \`bankCardToken\` from the binding response).\
> 2\. The system locates all active tokens for the card and marks them as \`PENDING\` for deactivation.\
> 3\. The unbinding is finalised asynchronously via the ALTO/KKI network.\
> 4\. A Kafka event is published for downstream systems.\
> \
> The \`tokenId\` is the raw token value for KKI (not Base64-decoded, unlike other channels).<br>

```json
{"openapi":"3.0.3","info":{"title":"Direct Debit Core System - Card Unbinding (KARTU_KREDIT_INDONESIA)","version":"1.0.0"},"servers":[{"url":"https://api.doku.com","description":"Base URL"}],"security":[{"BearerAuth":[]}],"components":{"securitySchemes":{"BearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"JWT","description":"B2B access token obtained from the Get B2B Token API (`/authorization/v1/access-token/b2b`)"}},"schemas":{"CardUnbindingRequest":{"type":"object","description":"Request body for card unbinding","required":["tokenId","additionalInfo"],"properties":{"tokenId":{"type":"string","description":"The token to be deactivated. This is the `bankCardToken` value returned\nin the binding response (or from the token list).\nFor KKI, this value is used as-is (no Base64 decoding is applied).\n"},"additionalInfo":{"$ref":"#/components/schemas/UnbindingAdditionalInfo"}}},"UnbindingAdditionalInfo":{"type":"object","description":"Additional information for the unbinding request","required":["channelId"],"properties":{"channelId":{"type":"string","description":"Product channel identifier. Must be `KARTU_KREDIT_INDONESIA` for this operation.","enum":["KARTU_KREDIT_INDONESIA"]}}},"CardUnbindingResponse":{"type":"object","description":"Response body for a successful card unbinding request","properties":{"responseCode":{"type":"string","description":"Response code: HTTP Status (3) + Service Code `05` (2) + Case Code (2).\nExample: `2000500` = HTTP 200 + service `05` + case `00` (Successful).\n"},"responseMessage":{"type":"string","description":"Human-readable response message"},"referenceNo":{"type":"string","description":"DOKU-generated reference number for this unbinding request"},"additionalInfo":{"$ref":"#/components/schemas/UnbindingResponseAdditionalInfo"}}},"UnbindingResponseAdditionalInfo":{"type":"object","description":"Additional information in the unbinding response","properties":{"custIdMerchant":{"type":"string","description":"The merchant's customer ID associated with the unbound token"},"status":{"type":"string","description":"Current token status after unbinding:\n- `PENDING` — Deactivation in progress (finalised asynchronously via ALTO network)\n- `SUCCESS` — Token fully deactivated\n","enum":["PENDING","SUCCESS"]},"redirectUrl":{"type":"string","description":"Redirect URL, if applicable for the unbinding flow"}}},"ErrorResponse":{"type":"object","description":"Standard error response body.\nResponse code format: HTTP Status (3) + Service Code `05` (2) + Case Code (2).\n\n| Case Code | Meaning                                              |\n|-----------|------------------------------------------------------|\n| `00`      | General / Format Error                               |\n| `01`      | Duplicate Transaction / Duplicate Token              |\n| `02`      | Invalid OTT / External Server Error                  |\n| `03`      | Suspected Fraud                                      |\n| `04`      | Exceeds Transaction Frequency Limit                  |\n| `05`      | Do Not Honor (declined by issuer)                    |\n| `08`      | Invalid Merchant / No Card Record                    |\n| `11`      | Invalid CPAN                                         |\n| `12`      | Transaction Not Permitted / OTT Expired              |\n| `13`      | Invalid Amount                                       |\n| `14`      | Insufficient Funds                                   |\n| `15`      | Transaction Not Permitted to Terminal                |\n","properties":{"responseCode":{"type":"string","description":"Error response code"},"responseMessage":{"type":"string","description":"Human-readable error message"}}}}},"paths":{"/direct-debit/core/v1/registration-card-unbind":{"post":{"summary":"Card Unbinding","description":"Deactivates a previously bound credit card token for a customer under a merchant account.\n\n**Flow:**\n1. Merchant submits the `tokenId` (i.e., the `bankCardToken` from the binding response).\n2. The system locates all active tokens for the card and marks them as `PENDING` for deactivation.\n3. The unbinding is finalised asynchronously via the ALTO/KKI network.\n4. A Kafka event is published for downstream systems.\n\nThe `tokenId` is the raw token value for KKI (not Base64-decoded, unlike other channels).\n","operationId":"cardUnbindingKKI","tags":["Unbinding"],"parameters":[{"name":"X-PARTNER-ID","in":"header","required":true,"description":"Merchant's client ID registered with DOKU","schema":{"type":"string","maxLength":32}},{"name":"X-EXTERNAL-ID","in":"header","required":true,"description":"Unique reference ID for this request (per-day uniqueness required)","schema":{"type":"string","maxLength":36}},{"name":"Authorization","in":"header","required":true,"description":"B2B access token obtained from the Get B2B Token API","schema":{"type":"string"}},{"name":"X-TIMESTAMP","in":"header","required":true,"description":"Request timestamp in ISO 8601 format (yyyy-MM-ddTHH:mm:ss+07:00)","schema":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}[+\\-]\\d{2}:\\d{2}$"}},{"name":"X-SIGNATURE","in":"header","required":true,"description":"HMAC-SHA512 asymmetric signature for request integrity verification","schema":{"type":"string"}},{"name":"X-IP-ADDRESS","in":"header","required":false,"description":"IP address of the end customer's device","schema":{"type":"string"}},{"name":"CHANNEL-ID","in":"header","required":false,"description":"Channel identifier. Defaults to `DH` (Direct Hosting).\n- `DH`: may return a `redirectUrl` for redirect-based unbinding flows.\n- `H2H`: host-to-host; returns a plain success response without redirect.\n","schema":{"type":"string","enum":["DH","H2H"],"default":"DH"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CardUnbindingRequest"}}}},"responses":{"200":{"description":"Unbinding request accepted. The token is now in `PENDING` deactivation state.\nFinal deactivation is completed asynchronously via the ALTO/KKI network.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CardUnbindingResponse"}}}},"400":{"description":"Bad request — missing or invalid fields","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Authentication failure — invalid B2B token or token not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Forbidden — transaction not permitted for the given card/account","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not found — active token not found for the given merchant and token ID","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}}}}
```

### 4. Refund

### Online Refund

This endpoint is used to create refund request for previous successful payment. Merchant can request a transaction refund to DOKU. Full refund and partial refund are available to be requested

**Online Refund Flow**

<figure><img src="/files/9uLyS7KXEgymVT5g2AfX" alt=""><figcaption><p>Online Refund Flow -  KKI Refund Flow</p></figcaption></figure>

#### API Endpoint&#x20;

<table><thead><tr><th width="215">Environment</th><th>Endpoint</th></tr></thead><tbody><tr><td>HTTP Method</td><td>POST</td></tr><tr><td>API Sandbox</td><td><a href="https://api-sandbox.doku.com">https://api-sandbox.doku.com</a></td></tr><tr><td>API Production</td><td><a href="https://api.doku.com">https://api.doku.com</a></td></tr><tr><td>Path</td><td><code>.../direct-debit/core/v1/debit/refund</code></td></tr></tbody></table>

**Sample of Request Header, Request Body and Response Body**

Notes:&#x20;

Parameter with (\*) is mandatory&#x20;

Paramater without (\*) is optional/conditional

{% openapi src="/files/rbGiMBn1DE6zRKEnCsnu" path="/direct-debit/core/v1/debit/refund" method="post" %}
[swagger-dd-allo.yaml](https://3092822868-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FqCxtvLoJNNxvp4U7kLHd%2Fuploads%2FVCYOKw46b3xQWjJlXHZ9%2Fswagger-dd-allo.yaml?alt=media\&token=a1acaa1a-720b-44cc-bd59-28c79392f3cd)
{% endopenapi %}
