# 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 %}


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://developers.doku.com/accept-payments/direct-api/snap/integration-guide/kartu-kredit-indonesia-cepat-secure-kki-cpts/host-to-host-integration.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
