NAV undefined
undefined
bash php java

Introduction

Welcome! Here at Xendit, our mission is to provide payments infrastructure that helps you succeed. We help with both the money in (accepting payments) and money out (disbursing payments). Use cases range from platform business to eCommerce, SaaS, and everything else in between.

The Xendit API is organized around REST. Our API has predictable, resource-oriented URLs, and uses HTTP response codes to indicate API errors. We use built-in HTTP features and HTTP verbs, which are understood by off-the-shelf HTTP clients. JSON is returned by all API responses, including errors.

Learn our APIs with Postman

To make it easier to get familiar with our APIs, we've published a Postman Collection so that you can see examples of all of Xendit APIs in one place. See our Postman Guide to get started!

Authentication

To successfully authenticate with Xendit's APIs, you must authenticate your secret API key using Basic Auth. You can obtain your API keys in Dashboard. For example if your API key is

xnd_development_P4qDfOss0OCpl8RtKrROHjaQYNCk9dN5lSfk+R1l9Wbe+rSiCwZ3jw==

Select Basic Auth authentication. Input secret API key in username and leave the password empty

Basic Auth format
{{username}}:{{password}}

Following the format (with colon)
xnd_development_P4qDfOss0OCpl8RtKrROHjaQYNCk9dN5lSfk+R1l9Wbe+rSiCwZ3jw==:

Encode Basic Auth format above into Base64 format

eG5kX2RldmVsb3BtZW50X1A0cURmT3NzME9DcGw4UnRLclJPSGphUVlOQ2s5ZE41bFNmaytSMWw5V2JlK3JTaUN3WjNqdz09Og==

Include Base64 encoded value in HTTP(s) header

Authorization: Basic eG5kX2RldmVsb3BtZW50X1A0cURmT3NzME9DcGw4UnRLclJPSGphUVlOQ2s5ZE41bFNmaytSMWw5V2JlK3JTaUN3WjNqdz09Og==

Xendit API is organized around REST to make it cleaner and easier to understand. All our API responses return JSON. To let you explore our APIs, make sure that you have registered an account. You can obtain and manage your API keys in API Keys Settings. We provide you API keys for both the test and live environments.

To authenticate your account, you have to include your secret API key in the request which can be accessed in Xendit Dashboard. Here are the steps to authenticate your account:

  1. Generate secret API key
  2. Obtain your secret API key from Dashboard
  3. Select Basic Access Authentication or BASIC AUTH authentication
  4. BASIC AUTH format will be {{username}}:{{password}}
  5. Input Secret API key as username and leave the password empty. Make sure to include : at the end
  6. Encode the value above into Base64 format
  7. Include the base64 encoded into Authorization header

All the API requests should be made over HTTPS instead of HTTP (all calls made over plain HTTP will fail). All requests made in the test environment will never hit the banking networks and will not cost you anything. Your API keys should be kept private so do not share your secret API keys. Learn more about API key here

Libraries / SDKs

Xendit has official libraries for different programming languages and mobile platforms. We are continuously developing more libraries and plugins. If you have implemented your own library or an example that you would like to share, send us a link to your code and we'll be happy to add it to the list!

Node.js

Install via npm

npm install xendit-node

See the source on Github

Node.js library is a server-side library that helps you to integrate Xendit easily using Node.js.

List of Supported Product

  1. Credit/debit cards
  2. eWallets
  3. Cardless Credit
  4. Bank Transfer via Virtual Accounts
  5. Retail Outlets
  6. Invoices
  7. Recurring Payments
  8. Payouts
  9. Disbursements
  10. Batch Disbursements

Installation

You can install our Node.js library using npm npm install xendit-node or check out the source on Github

PHP

Download PHP package here

https://packagist.org/packages/xendit/xendit-php-clients

PHP library is a client that is created on top of PHP so it is easier for you to integrate with us to accept payments via our supported payment channels.

Currently PHP library supports:

  1. Bank Transfer via Virtual Accounts
  2. Credit/debit cards
  3. XenInvoice
  4. Disbursements

Here are the steps to use Xendit PHP library:

  1. Download PHP package here
  2. Include XenditPHPClient.php in your code
  3. Create XenditPHPClient object with secret API key as parameter
  4. Require XenditPHPClient.php in your code

Java

Install Xendit in your Java code

Maven

<dependency>
  <groupId>com.xendit</groupId>
  <artifactId>xendit-java-lib</artifactId>
  <version>1.0.0</version>
  <type>pom</type>
</dependency>

Gradle

compile 'com.xendit:xendit-java-lib:1.0.0'

Import Xendit Library

import com.xendit.Xendit; 
import com.xendit.exception.XenditException; 
import com.xendit.model.AvailableBank; 
import com.xendit.model.VirtualAccount;

Xendit Java library (Gradle and Maven) installation is easy and simple. For more detail about the steps, refer to the right section

  1. Add Xendit dependency in your Java code
  2. Import Xendit library
  3. Obtain your API keys in Dashboard to start using Xendit Java library APIs.

Our current Java Library supports Virtual Accounts APIs.

Android

Download Xendit Android SDK

https://github.com/xendit/xendit-sdk-android

Android SDK helps you to process digital payments using Xendit with features as follow:

  1. Tokenize credit/debit cards with single-use token
  2. Tokenize credit/debit cards with multiple-use token
  3. Authenticate credit/debit card transactions

iOS

Download Xendit iOS SDK

https://github.com/xendit/xendit-sdk-ios

iOS SDK helps you to process digital payments using Xendit with features as follow:

  1. Tokenize credit/debit cards with single-use token
  2. Tokenize credit/debit cards with multiple-use token
  3. Authenticate credit/debit card transactions

Errors

Your Xendit integration might have to deal with errors at some point when making API requests to Xendit. These errors fall into a few major categories:

The right approach and idempotency semantics to use for handling errors depend on the type of error being handled.

HTTP Status Code

Xendit uses conventional HTTP response codes to indicate the success or failure of an API request. In general: Codes in the 2xx range indicate success. Codes in the 4xx range indicate an error that failed given the information provided (e.g., a required parameter was omitted, a charge failed, etc). Codes in the 5xx range indicate an error with Xendit's servers (these are rare).

Status Code Description
200 - OK Everything worked as expected
400 - Bad Request The request was unacceptable, often due to missing a required parameter
401 - Unauthorized No valid API key provided
403 - Forbidden The API key doesn't have permissions to perform the request
404 - Not Found The requested resources doesn't exist
500 - Server Errors Something went wrong on Xendit's end (These are rare)

Error Code

Below are some of most common errors across all our endpoints. Specific errors are located under each endpoint.

Error Code Description
API_VALIDATION_ERROR Invalid request errors arise when your request has invalid parameters
INVALID_API_KEY No valid API key provided
REQUEST_FORBIDDEN_ERROR
The API key doesn't have permissions to perform the request
SERVER_ERROR API errors cover any other type of problem (e.g. a temporary problem with Xendit's servers), and are extremely uncommon

Error Handling

Safely retry requests with idempotency

A key part of web API design is the idea of idempotency, defined as being able to apply the same operation multiple times without changing the result beyond the first try. Because a certain amount of intermittent failure is to be expected, clients need a way of reconciling failed requests with a server, and idempotency provides a mechanism for that.

The Xendit API guarantees the idempotency of GET requests, so it's always safe to retry them. Including an idempotency key makes POST and PATCH request idempotent, which prompts the API to do the bookkeeping required to prevent duplicate operations. For example, if a request to create disbursements does not respond due to network connection error, you can retry the request with the same idempotency key to guarantee that no more than one disbursement is created.

Idempotency keys are sent in the x-idempotency-key header, and you should use them for all POST requests to Xendit's API whenever supported. A few common strategies for generating idempotency keys are:

A response that's being replayed from the server because it had already executed previously can be identified by the error code DUPLICATE_TRANSACTION_ERROR

Content errors

Content errros are the result of the contents of an API request being invalid and return a 4xx error code. Integrations should correct the original request and try again. Depending of the type of user error, it may be possible to handle the problem programmatically.

For a POST operation using an idempotency key, as long as an API method began execution, Xendit's API servers will cache the results of the request regardless of what they were. A request that returns a 400 will send back the same 400 if followed by a new request with the same idempotency key. A fresh idempotency key should be generated when modifying the original request to get a successful result. The safest strategy where 4xx errors are concerned is to always generate a new idempotency key.

Network errors

Network errors are the result of connectivity problems between client and server and tend to manifest as low-level errors like socket or timeout exceptions.

This class of errors is where the value of idempotency keys and request retries is most obvious. When intermittent problems occur, clients are usually left in a state where they don't know whether or not the server received the request. To get a definitive answer, they should retry such requests with the same idempotency keys and the same parameters until they're able to receive a result from the server. Sending the same idempotency with different parameters will produce an error indicating that the new request didn't match the original.

Server errors

Server errors are the result of a server-side problem and return a 5xx error code. These errors are the most difficult to handle, so we try to ensure that they happen as infrequently as possible.

As with the errors, retrying them with the same idempotency key will usually produce the same result. The request can be retried with a new idempotency key, but we'd advice against it because it's possible for the original one to have produced side effects.

The result of a 500 request should be treated as indeterminate. The exact nature of any retroactive changes in the system depend heavily on the type of request. For example, if creating a disbursement returns a 500 error but we detect that the information has gone out to a payment network, we'll try to roll it forward and send callback after it has been completed. If not, we'll try to roll it back. However, ideal results under these circumstances are not guaranteed, and requests resulting in a 500 error may proeduce user-visible side effects.

Integration that want to maximize robustness must configure callback handlers that are capable of receiving events that have never been seen in an API response.

Callback

Xendit uses callback to notify your application any time an event happens on your account. Set up callback for events that Xendit doesn't already notify you of, like when a disbursement has been completed, a Virtual Account has been created and paid, or your invoice has expired.

Setup

You need to provide an endpoint in your system to receive callback from us. The callback notification will be sent over POST request to your callback URL that you have set. Setup your callback URL in Callback settings. You can use a tool like ngrok to make your endpoint available for receiving callback during testing.

Delivery Attempts and Retries

Understand how to view delivery attempts and retry logic when callback events aren't acknowledged

View events

When viewing information about a specific event through the Dashboard's Callback tab, you can check how many times Xendit attempted to send an event to the endpoint. This shows the latest response from your endpoint, a list of all attempted callback, and the respective HTTP status codes Xendit received.

Retry logic

Xendit attempts to deliver your callback three times and will stop retrying until we have received response from your server or there is still no response yet.

Receive callback statistics via email

You can also receive summary of your callback statistics (number of success and failed callback) via email every 6 hours. You can enable this feature in Email Recipient settings

Event Handling

Handling callback events correctly is crucial to making sure your integration's business logic works as expected

Acknowledge events immediately

If your callback script performs complex logic, or makes network calls, it's possible that the script would time out before Xendit sees its complete execution. Ideally, your callback handler code (acknowledging receipt of an event by returning a 2xx status code) is separate of any other logic you do for that event.

Handle duplicate events

Callback endpoints might occasionally receive the same event more than once. We advise you to guard against duplicated event receipts by making your event processing idempotent. One way of doing this is logging the events you've processed, and then not processing already-logged events.

Order of events

Xendit does not guarantee delivery of events in the order in which they are generated. Your endpoint should not expect delivery of these events in this order and should handle this accordingly. You can also use the API to fetch any missing objects.

Security

Keeping your endpoints secure is critical to protecting your customers' information. Xendit provides several ways for you to verify events are coming from Xendit in a secure manner.

Receive events with an HTTPS server

If you use an HTTPS URL for your callback endpoint, Xendit will validate that the connection to your server is secure before sending your callback data. For this to work, your server must be correctly configured to support HTTPS with a valid server certificate.

Verify events are sent from Xendit

Xendit can optionally sign the callback events it sends to your endpoints. We do so by including a token in each event's x-callback-token header. This allows you to verify that the events were sent by Xendit, not by a third party.

Header Parameter Description
x-callback-token
string Your Xendit unique callback token to verify the origin of the callback

Before you can verify tokens, you need to retrieve your callback token from Dashboard's Callback settings. Each secret is unique to each environments.

Balances

Get Balance

Endpoint: Get Balance

GET https://api.xendit.co/balance?account_type={account_type}

Balance is like your wallet since it will tell you how much money is available to you on Xendit. You can retrieve it to see the current balance on your Xendit cash account. Your balance is debited on any money out transaction, e.g. when performing disbursements or Xendit fees are charged. Your balance is credited when money comes into your account, e.g. invoices are paid or you deposit funds.

Get Balance Request

Example Get Balance Request

curl https://api.xendit.co/balance -X GET \
-u xnd_development_O46JfOtygef9kMNsK+ZPGT+ZZ9b3ooF4w3Dn+R1k+2fT/7GlCAN3jg==:
<?php
  require 'vendor/autoload.php';

  $options['secret_api_key'] = 'xnd_development_P4qDfOss0OCpl8RtKrROHjaQYNCk9dN5lSfk+R1l9Wbe+rSiCwZ3jw==';

  $xenditPHPClient = new XenditClient\XenditPHPClient($options);

  $response = $xenditPHPClient->getBalance();
  print_r($response);
?>
import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.client.Entity;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.MediaType;

Client client = ClientBuilder.newClient();
Response response = client.target("https://api.xendit.co/balance")
  .request(MediaType.APPLICATION_JSON_TYPE)
  .header("Authorization", "Basic eG5kX2RldmVsb3BtZW50X1A0cURmT3NzME9DcGw4UnRLclJPSGphUVlOQ2s5ZE41bFNmaytSMWw5V2JlK3JTaUN3WjNqdz09Og==")
  .get();

System.out.println("status: " + response.getStatus());
System.out.println("headers: " + response.getHeaders());
System.out.println("body:" + response.readEntity(String.class));

Get Balance allows you to retrieve the balance of your cash and pending balance. Some use cases include: deciding when you may need to withdraw funds, and determining if you have funds to disburse

Query Parameter Description
account_type
optional
default: CASH
string The selected balance type

available values: CASH, HOLDING, TAX

Get Balance Response

Example Get Balance Response

{
  "balance": 1241231
}
Parameter Description
balance The balance remaining in your cash account

Credit Cards

Create Token

Javascript Function: createToken

Xendit.card.createToken(tokenData, function (err, data) {
    if (err) {
        //Define error handling
    }

    if (data.status === 'VERIFIED') {
        // Handle success
    } else if (data.status === 'IN_REVIEW') {
        // Handle authentication (3DS)
    } else if (data.status === 'FAILED') {
        // Handle failure
    }
});

Tokenization is the process where card details (account number and expiration date) are securely collected on the client-side, so that sensitive card data is never passed through your systems. Tokens are then used to Charge Cards.

Example tokenData object

{        
    "amount": "10000",        
    "card_number": "4000000000000002",        
    "card_exp_month": "12",        
    "card_exp_year": "2017",        
    "card_cvn": "123",
    "is_multiple_use": false,
    "should_authenticate": true
}

Example Tokenization Response

{
    "id": "586f0ba2ab70de5d2b409e0d",
    "authentication_id": "598c3e5a8c62078a5108f661",
    "masked_card_number": "400000XXXXXX0002",
    "status": "IN_REVIEW",
    "payer_authentication_url": "https://api.xendit.co/credit_card_tokens/586f0ba2ab70de5d2b409e0d/authentication_redirect?api_key=xnd_public_development_key"
}

Tokens can be created for single or multiple use. If you plan to save a card for future use, set is_multiple_use to true.

See our Tokenization Sample for an example implementation.

Single Use Tokens

For single-use tokens, authentication is performed by default, and so the amount field is also required. If optional authentication is enabled on your account, it can be bypassed by setting should_authenticate to false.

Multiple Use Tokens

When tokenizing a card for multi-use, the amount field is not required as it is instead specified during Authentication. See Create Authentication for more details.

Tokenization Request (Money-in write permission)

Parameter Description
amount
optional
string The charge amount. Only required for single use tokens with bundled authentication.
card_number
required
string Card number
card_exp_month
required
string Card expiration month
card_exp_year
required
string Card expiration year
card_cvn
optional
string Card CVN/CVC code
Note: Only used for single-use tokens
is_multiple_use
optional
default: false
boolean Whether or not to save token for multiple use
should_authenticate
optional
default: true
boolean Whether or not to bundle authentication with tokenization.
xenditResponseHandler
required
function The response handler function is called after tokenization is attempted, to receive errors and tokenization response

Tokenization Response

Parameter Description
id
required
string The token ID. This will be used later to Charge the funds from the credit card
authentication_id
optional
string Included if authentication was bundled for single use token.
masked_card_number
required
string The first 6 digits and last 4 digits of the tokenized card.
status
required
string Tokenization status. See Tokenization Statuses
payer_authentication_url
optional
string If status is IN_REVIEW, this contains the URL to the page for users to authenticate themselves using 3DS
failure_reason
optional
string If status is FAILED, this describes the failure. See Tokenization Failure Reasons.

Tokenization Statuses

Status Description
IN_REVIEW The customer must authenticate their identity. Xendit provides a URL which you should navigate your users to for easily performing 3DS.
VERIFIED The customer successfully authenticated their identity. Therefore, it is safe to send the token to your backend for charging.
FAILED Tokenization can fail for many reasons. See Tokenization Failure Reasons.

Tokenization Failure Reasons

Failure Reason Description
AUTHENTICATION_FAILED This status means the customer tried to authenticate using 3DS but did not successfully complete the authentication.

Tokenization Errors

Error Code Description
API_VALIDATION_ERROR
400
Inputs are failing validation. The errors field contains details about which fields are violating validation.
INVALID_JSON_FORMAT
400
The request body is not valid JSON.
ACCOUNT_NUMBER_INVALID_ERROR
400
Credit card number is invalid.
VALIDATION_ERROR
400
Data was passed in an incorrect format.
BRAND_NOT_SUPPORTED_ERROR
400
Card brand is not supported. Ask user to try a Visa/Mastercard.
CREDIT_CARD_DATA_ERROR
400
Invalid data was sent to the credit card processor.
AUTHENTICATION_REQUIRED_ERROR
400
A valid authentication_id was not included in the request, and your account is not configured for optional authentication. Include a valid authentication_id or contact us if you would like to enable optional authentication.
REQUEST_FORBIDDEN_ERROR
403
API key in use does not have necessary permissions to perform the request. Please assign proper permissions for the key. Learn more here
VERIFICATION_TIMEOUT_ERROR
408
The credit card network timed out when trying to tokenize the card.
TEMPORARY_SERVICE_ERROR
503
There was a problem with the credit card network, which prevents tokenization.
CONNECTION_ERROR Error connecting to our server. Try again and if the error persists, try with another device/network.
TOKENIZATION_ERROR General error. Try again or try with a different card.

Create Authentication

Javascript Function: createAuthentication

Xendit.card.createAuthentication(authenticationData, function (err, data) {
    if (err) {
        //Define error handling
    }

    if (data.status === 'VERIFIED') {
        // Handle success
    } else if (data.status === 'IN_REVIEW') {
        // Handle authentication (3DS)
    } else if (data.status === 'FAILED') {
        // Handle failure
    }
});

To authenticate a token, use the Xendit.card.createAuthentication function in Xendit.js. This function accepts an authenticationData object and returns an authentication_id which can be used to authenticate a charge. For more details on creating a charge, see Create Charge.

See our Authentication Sample for an example implementation.

Example authenticationData object

{        
    "amount": "10000",        
    "token_id": "58e2096018b815f555c8a524"
}

Example Authentication Response

{
    "id": "58e2097218b815f555c8a526",
    "status": "VERIFIED"
}

Authentication Request

Parameter Description
amount
required
string Authentication amount
token_id
required
string Token to authenticate
xenditResponseHandler
required
function Response handler, called after authentication attempt to handle errors and response.

Authentication Response

Parameter Description
id
required
string Authentication ID to be used with Token ID when charging a card
status
required
string Authentication status. See Tokenization Statuses
payer_authentication_url
optional
string If status is IN_REVIEW, this contains the URL for authenticating users with 3DS
failure_reason
optional
string If status is FAILED, this describes the failure. See Tokenization Failure Reasons.

Create Authorization

Definition: Create authorization

POST https://api.xendit.co/credit_card_charges

Example Create Authorization Request

curl -X POST \
  https://api.xendit.co/credit_card_charges \
  -u xnd_development_OYiAfOR3gbOunJU4frcaHmLCYNLy8oQuknDm+R1r9G3S/byhDAB+gA==: \
  -H 'content-type: application/json' \
  -d '{
      "token_id" : "598d5d0e51e0870d44c61534",
      "external_id": "postman-charge-1502436817",
      "amount": 140000,
      "authentication_id":"598d5d0f51e0870d44c61535",
      "card_cvn":"123",
      "capture":false
    }'
<?php
  require 'vendor/autoload.php';

  $options['secret_api_key'] = 'xnd_development_P4qDfOss0OCpl8RtKrROHjaQYNCk9dN5lSfk+R1l9Wbe+rSiCwZ3jw==';

  $xenditPHPClient = new XenditClient\XenditPHPClient($options);

  $external_id = 'sample-external-id-1475459775872';
  $token_id = 'sample-token-id-1475459775872';
  $amount = 140000;
  $authentication_id = '58e2097218b815f555c8a526';
  $capture = false;

  $response = $xenditPHPClient->captureCreditCardPayment($external_id, $token_id, $amount);
  print_r($response);
?>

Example Create Authorization Response

{
    "created": "2017-08-11T07:33:14.442Z",
    "status": "AUTHORIZED",
    "business_id": "5850e55d8d9791bd40096364",
    "authorized_amount": 140000,
    "external_id": "postman-charge-1502436793",
    "merchant_id": "xendit",
    "merchant_reference_code": "598d5d0d51e0870d44c61533",
    "card_type": "CREDIT",
    "masked_card_number": "400000XXXXXX0002",
    "charge_type": "SINGLE_USE_TOKEN",
    "card_brand": "VISA",
    "bank_reconciliation_id": "5132390610356134503009",
    "eci": "05",
    "id": "598d5dba51e0870d44c61539"
}

You can do authorization using create charge endpoint. Just capture field as false, and you will receive an authorized charge response.

Example Zero Amount Authorization Request

curl -X POST \
  https://api.xendit.co/credit_card_charges \
  -u xnd_development_OYiAfOR3gbOunJU4frcaHmLCYNLy8oQuknDm+R1r9G3S/byhDAB+gA==: \
  -H 'content-type: application/json' \
  -d '{
      "token_id" : "598d5d0e51e0870d44c61534",
      "external_id": "postman-charge-1502436817",
      "amount": 0,
      "authentication_id":"598d5d0f51e0870d44c61535",
      "card_cvn":"123"
    }'
<?php
  require 'vendor/autoload.php';

  $options['secret_api_key'] = 'xnd_development_P4qDfOss0OCpl8RtKrROHjaQYNCk9dN5lSfk+R1l9Wbe+rSiCwZ3jw==';

  $xenditPHPClient = new XenditClient\XenditPHPClient($options);

  $external_id = 'sample-external-id-1475459775872';
  $token_id = 'sample-token-id-1475459775872';
  $amount = 0;
  $authentication_id = '58e2097218b815f555c8a526';

  $response = $xenditPHPClient->captureCreditCardPayment($external_id, $token_id, $amount);
  print_r($response);
?>

Example Zero Amount Authorization Response

{
    "created": "2017-08-11T07:33:14.442Z",
    "status": "AUTHORIZED",
    "business_id": "5850e55d8d9791bd40096364",
    "authorized_amount": 0,
    "external_id": "postman-charge-1502436793",
    "merchant_id": "xendit",
    "merchant_reference_code": "598d5d0d51e0870d44c61533",
    "card_type": "CREDIT",
    "masked_card_number": "400000XXXXXX0002",
    "charge_type": "SINGLE_USE_TOKEN",
    "card_brand": "VISA",
    "bank_reconciliation_id": "5132390610356134503009",
    "eci": "05",
    "id": "598d5dba51e0870d44c61539"
}

Zero Amount Authorization

You can also do zero amount authorization amount using create charge endpoint. Just put 0 for amount field, and you will receive and authorized charge response.

To be able to do zero amount authorization, your account must have card processor that has zero amount authorization compatibility.
Please contact us to set up zero amount compatible card processor for your account. You can always use development environment to try zero amount authorization feature.

Reverse Authorization

Definition: Reversing Authorized Charge

POST https://api.xendit.co/credit_card_charges/:charge_id/auth_reversal

Example Reverse Authorization

curl -X POST \
  https://api.xendit.co/credit_card_charges/:charge_id/auth_reversal \
  -u xnd_development_OYiAfOR3gbOunJU4frcaHmLCYNLy8oQuknDm+R1r9G3S/byhDAB+gA==: \
  -d '{
    "external_id": "postman-charge-1502436817",
    }'

Example of request body

{        
    "external_id": "postman-charge-1502436817",
}

Example of Reverse Autherization Response

{
    "created": "2018-06-21T11:37:51.436Z",
    "credit_card_charge_id": "5b2b8e024ec5ad6463cdc594",
    "external_id": "postman-charge-1502436817",
    "business_id": "5ae9216707ce36df1060c309",
    "amount": 5000,
    "status": "SUCCEEDED",
    "id": "5b2b8e0f4ec5ad6463cdc597"
}

This API provides reversing charge when the charge has AUTHORIZED status and hasn't yet captured.

Reverse Authorization Fields

Parameter Description
external_id
required
string Charge reference

Reverse Autherization Response

Parameter Description
external_id
required
string Unique Identifier for your Reversed Charge reference
business_id
required
string The ID of your business in Xendit.
merchant_id
required
string Your merchant ID used for processing credit cards with the bank
merchant_reference_code
required
string An ID used to reconcile transactions with the bank.
masked_card_number
required
string Masked card number. The first 6 digits are the BIN (Bank Identification Number).
charge_type
required
string Types of charges. See Charge types.
card_brand
required
string Card scheme (VISA, MASTERCARD,...)
authorized_amount
required
number The amount that've been authorized for this charge.
status
required
string Status of the charge. See Charge Statuses.
created
required
string An ISO timestamp that tracks when the charge was made.

Stasus

Recommendation Description
SUCCEEDED
Reverse Authorization scenario is success
FAILED
Reverse Authorization is failed with detailed failure reason

Reverse Authorization Errors

Error Code Description
API_VALIDATION_ERROR
400
Inputs are failing validation. The errors field contains details about which fields are violating validation.
CHARGE_ALREADY_REVERSED_ERROR
400
Charge already reversed
CHARGE_ALREADY_CAPTURED_ERROR
400
Charge already captured
CHARGE_FAILED_ERROR
400
Charge already captured
TEMPORARY_SERVICE_ERROR
400
Charge already captured
REQUEST_FORBIDDEN_ERROR
403
API key in use does not have necessary permissions to perform the request. Please assign proper permissions for the key. Learn more here
CREDIT_CARD_CHARGE_NOT_FOUND_ERROR
404
credit_card_charge_id not found

Create Charge

Definition: Create Charge

POST https://api.xendit.co/credit_card_charges

Example Charge Request

curl -X POST \
  https://api.xendit.co/credit_card_charges \
  -u xnd_development_OYiAfOR3gbOunJU4frcaHmLCYNLy8oQuknDm+R1r9G3S/byhDAB+gA==: \
  -H 'content-type: application/json' \
  -d '{
      "token_id" : "598d5d0e51e0870d44c61534",
      "external_id": "postman-charge-1502436817",
      "amount": 15000,
      "authentication_id":"598d5d0f51e0870d44c61535",
      "card_cvn":"123",
      "descriptor":"My new store"
    }'
<?php
  require 'vendor/autoload.php';

  $options['secret_api_key'] = 'xnd_development_P4qDfOss0OCpl8RtKrROHjaQYNCk9dN5lSfk+R1l9Wbe+rSiCwZ3jw==';

  $xenditPHPClient = new XenditClient\XenditPHPClient($options);

  $external_id = 'sample-external-id-1475459775872';
  $token_id = 'sample-token-id-1475459775872';
  $amount = 17000;
  $authentication_id = '58e2097218b815f555c8a526';

  $response = $xenditPHPClient->captureCreditCardPayment($external_id, $token_id, $amount);
  print_r($response);
?>

Example Charge Response

{
    "created": "2017-08-11T07:33:14.442Z",
    "status": "CAPTURED",
    "business_id": "5850e55d8d9791bd40096364",
    "authorized_amount": 15000,
    "external_id": "postman-charge-1502436793",
    "merchant_id": "xendit",
    "merchant_reference_code": "598d5d0d51e0870d44c61533",
    "card_type": "CREDIT",
    "masked_card_number": "400000XXXXXX0002",
    "charge_type": "SINGLE_USE_TOKEN",
    "card_brand": "VISA",
    "bank_reconciliation_id": "5132390610356134503009",
    "eci": "05",
    "capture_amount": 15000,
    "descriptor": "My new store",
    "id": "598d5dba51e0870d44c61539"
}

Example Authorization Response

{
    "created": "2017-08-11T07:43:39.563Z",
    "status": "AUTHORIZED",
    "business_id": "5850e55d8d9791bd40096364",
    "authorized_amount": 15000,
    "external_id": "postman-authorize-1502437417",
    "merchant_id": "xendit",
    "merchant_reference_code": "598d5ffb51e0870d44c6153a",
    "card_type": "CREDIT",
    "masked_card_number": "400000XXXXXX0002",
    "charge_type": "SINGLE_USE_TOKEN",
    "card_brand": "VISA",
    "bank_reconciliation_id": "5132390610356134503009",
    "eci": "05",
    "descriptor": "My new store",
    "id": "598d602b51e0870d44c6153d"
}

Once you have a token, that token can be used to charge a card.

Charge Request

Parameter Description
token_id
required
string The token ID used to charge the card.
external_id
required
string A unique identifier of your choice. Max 64 characters.
amount
required
number The charge amount
authentication_id
optional
string Authentication ID for authenticating charge. Optional only if charge was already authenticated with a single-use token, or if optional authentication is enabled for your account.
card_cvn
optional
string 3 or 4 digit CVN (CVC) code. Optional but highly recommended. Required for cards issued in Europe.
capture
optional
default: true
boolean Whether or not to capture immediately. Set to false to issue an authorization (hold funds) only, to be captured later with the capture endpoint.
Note: Authorizations expire in 7 days.
descriptor
optional
string Spesific descriptor to define merchant's identity

Charge Response

Parameter Description
created
required
string An ISO timestamp that tracks when the charge was made.
status
required
string Status of the charge. See Charge Statuses.
business_id
required
string The ID of your business in Xendit.
authorized_amount
required
number The amount that've been authorized for this charge.
external_id
required
string A unique identifier of your choice.
merchant_id
required
string Your merchant ID used for processing credit cards with the bank.
merchant_reference_code
required
string An ID used to reconcile transactions with the bank.
card_type
required
string Type of card (CREDIT or DEBIT)
masked_card_number
required
string Masked card number. The first 6 digits are the BIN (Bank Identification Number).
charge_type
required
string Types of charges. See Charge types.
card_brand
required
string Card scheme (VISA, MASTERCARD,...)
bank_reconciliation_id
required
string ID of the transaction that can be reconciled with bank
eci
optional
string Status of 3DS authentication. See ECI codes.
capture_amount
optional
number The amount that've been captured for this charge. Can be up to authorized_amount.
id
required
string ID of the charge captured.
descriptor
required
string Description which already inputted by merchant when creating a charge.
failure_reason
optional
string If status is FAILED, this describes the failure. See Charge Failure Reasons.

Charge Statuses

Status Description
CAPTURED Charge is successfully captured and the funds will be settled according to the settlement schedule.
AUTHORIZED Charge is successfully authorized.
REVERSED Charge is sucessfully reversed.
FAILED Charge failed. See Charge Failure Reasons

Charge Failure Reasons

Failure Reason Description
EXPIRED_CARD The card you are trying to capture is expired. Ask your customer for a different card
CARD_DECLINED The card you are trying to capture has been declined by the bank. Ask your customer for a different card
INSUFFICIENT_BALANCE The card you are trying to capture does not have enough balance to complete the capture
STOLEN_CARD The card you are trying to capture has been marked as stolen. Ask your customer for a different card
INACTIVE_CARD The card you are trying to capture is inactive. Ask your customer for a different card
INVALID_CVN The cvn that being submitted is not correct.
PROCESSOR_ERROR The charge failed because there's an integration issue between card processor and the bank. Contact us if you encounter this issue.
BIN_BLOCK The cards' BIN has been blocked by request from the Bank.

Charge Errors

Error Code Description
API_VALIDATION_ERROR
400
Inputs are failing validation. The errors field contains details about which fields are violating validation.
INVALID_JSON_FORMAT
400
The request body is not valid JSON.
TOKEN_ALREADY_USED_ERROR
400
The single-use token ID has already been used in a charge.
AUTHENTICATION_ALREADY_USED_ERROR
400
The authentication ID has already been used in a charge.
INVALID_TOKEN_ID_ERROR
400
The token ID format is invalid.
INVALID_CVN_LENGTH_ERROR
400
The length of CVN is invalid. For AMEX card, CVN length must be 4 digit and for the others card type it must be 3.
AUTHENTICATION_ID_MISSING_ERROR
400
Authentication ID is required for this charge.
AMOUNT_GREATER_THAN_AUTHENTICATED_ERROR
400
Charge amount was greater than what was authenticated.
INVALID_AUTHENTICATION_ID_ERROR
400
The authentication ID format is invalid.
REQUEST_FORBIDDEN_ERROR
403
API key in use does not have necessary permissions to perform the request. Please assign proper permissions for the key. Learn more here
TOKEN_NOT_FOUND_ERROR
404
The token ID was not found in the system.
AUTHENTICATION_NOT_FOUND_ERROR
404
Authenticated token with given authentication ID is not found.

Charge Types

Status Description
SINGLE_USE_TOKEN Charge created with single-use token
MULTIPLE_USE_TOKEN Charge created with multiple-use token
RECURRING Charge a recurring charge in a subscription

ECI Codes

ECI Description
1 Incomplete authentication (MasterCard)
2 Successful authentication (MasterCard)
5 Successful authentication (Visa, AMEX, JCB, Diners Club)
6 Authentication attempted (Visa, AMEX, JCB, Diners Club)
7 Unable to Authenticate

Capture Charge

Definition: Capture Charge

POST https://api.xendit.co/credit_card_charges/:credit_card_charge_id/capture

Example Capture Charge Request

curl https://api.xendit.co/credit_card_charges/5877255293ff67900c6aa64e/capture \
    -X POST \
    -u xnd_development_OYiAfOR3gbOunJU4frcaHmLCYNLy8oQuknDm+R1r9G3S/byhDAB+gA==: \
    -d amount=15000

Example Capture Charge Response

{
  "created": "2017-08-08T04:49:08.815Z",
  "status": "CAPTURED",
  "business_id": "5848fdf860053555135587e7",
  "authorized_amount": 10000,
  "external_id": "test-pre-auth",
  "merchant_id": "xendit",
  "merchant_reference_code": "598942aabb91a4ec309e9a35",
  "card_type": "CREDIT",
  "masked_card_number": "400000XXXXXX0002",
  "charge_type": "SINGLE_USE_TOKEN",
  "card_brand": "VISA",
  "bank_reconciliation_id": "5132390610356134503009",
  "capture_amount": 9900,
  "descriptor": "My new store",
  "id": "598942c4bb91a4ec309e9a37"
}

Capturing a charge only needed if you do pre-authorization by specifying capture to false in create charge request. You can capture a charge with amount different than authorized amount as long as it's less than authorized amount. Response for this endpoint is the same as create charge response

Capture Charge Request

Query Parameter Description
credit_card_charge_id
required
string Charge ID of authorization
Body Parameter Description
amount
required
string Amount to be captured. Can be up to amount of authorization but not more

Capture Charge Errors

Error Code Description
API_VALIDATION_ERROR
400
Inputs are failing validation. The errors field contains details about which fields are violating validation.
INVALID_JSON_FORMAT
400
The request body is not valid JSON.
AMOUNT_GREATER_THAN_AUTHORIZED_ERROR
400
Capture amount is larger than authorized amount
INVALID_CHARGE_STATUS_ERROR
400
Charge status is not AUTHORIZED
REQUEST_FORBIDDEN_ERROR
403
API key in use does not have necessary permissions to perform the request. Please assign proper permissions for the key. Learn more here
CREDIT_CARD_CHARGE_NOT_FOUND_ERROR
404
credit_card_charge_id not found

Get Charge

Definition: Get Charge

GET https://api.xendit.co/credit_card_charges/:credit_card_charge_id

Example Get Charge Request

curl https://api.xendit.co/credit_card_charges/5877255293ff67900c6aa64e \
    -X GET \
    -u xnd_development_OYiAfOR3gbOunJU4frcaHmLCYNLy8oQuknDm+R1r9G3S/byhDAB+gA==:

Example Get Charge Response

{
  "created": "2017-08-08T04:49:08.815Z",
  "status": "CAPTURED",
  "business_id": "5848fdf860053555135587e7",
  "authorized_amount": 10000,
  "external_id": "test-pre-auth",
  "merchant_id": "xendit",
  "merchant_reference_code": "598942aabb91a4ec309e9a35",
  "card_type": "CREDIT",
  "masked_card_number": "400000XXXXXX0002",
  "charge_type": "SINGLE_USE_TOKEN",
  "card_brand": "VISA",
  "bank_reconciliation_id": "5132390610356134503009",
  "capture_amount": 9900,
  "descriptor": "My new store",
  "id": "598942c4bb91a4ec309e9a37"
}

This is endpoint to get a charge object. You need to specify the charge_id. Response for this endpoint is the same as create charge response

Get Charge Request

Query Parameter Description
credit_card_charge_id
required
string Charge ID of the payment that have been authorized

Get Charge Errors

Error Code Description
API_VALIDATION_ERROR
400
Inputs are failing validation. The errors field contains details about which fields are violating validation.
REQUEST_FORBIDDEN_ERROR
403
API key in use does not have necessary permissions to perform the request. Please assign proper permissions for the key. Learn more here
CREDIT_CARD_CHARGE_NOT_FOUND_ERROR
404
credit_card_charge_id not found

Create Refund

Definition: Create Refund

POST https://api.xendit.co/credit_card_charges/:credit_card_charge_id/refunds

Example Refund Request

curl https://api.xendit.co/credit_card_charges/5877255293ff67900c6aa64e/refunds \
    -X POST \
    -u xnd_development_O46JfOtygef9kMNsK+ZPGT+ZZ9b3ooF4w3Dn+R1k+2fT/7GlCAN3jg==: \
    -H "X-IDEMPOTENCY-KEY: unique-id-12345" \
    -d amount=15000
    -d external_id=unique-external-id
<?php
  require 'vendor/autoload.php';

  $options['secret_api_key'] = 'xnd_development_P4qDfOss0OCpl8RtKrROHjaQYNCk9dN5lSfk+R1l9Wbe+rSiCwZ3jw==';

  $xenditPHPClient = new XenditClient\XenditPHPClient($options);

  $credit_card_charge_id = '5877255293ff67900c6aa64e';
  $amount = 15000;
  $external_id = 'unique-external-id';

  $response = $xenditPHPClient->issueCreditCardRefund($credit_card_charge_id, $amount, $external_id);
  print_r($response);
?>

Example Refund Response

{
  "updated": "2017-04-21T04:05:09.755Z",
  "created": "2017-04-21T04:05:04.936Z",
  "credit_card_charge_id": "58f89041780d51ed097896c5",
  "user_id": "57c5aa7a36e3b6a709b6e148",
  "amount": 15000,
  "external_id": "unique-external-id",
  "status": "PENDING",
  "fee_refund_amount": 150,
  "id": "58f984f09d1b74bc08506c34"
}

The Refund API accepts two parameters, amount and external_id. The charge ID, which is returned after a successful charge, must be used in request URL per the definition. Several refund calls can be made, so long as the total amount refunded is not greater than the total charge amount. For every refund request you will receive a PENDING refund.

Note: Idempotency can be achieved by sending a header with the key X-IDEMPOTENCY-KEY.

Refund Request

Header Parameter Description
X-IDEMPOTENCY-KEY
optional
string A unique key to prevent processing duplicate requests. Must be unique across test & live mode
Body Parameter Description
credit_card_charge_id
required
string Charge ID of the payment that will be refunded (you can see this in credit card details in dashboard)
amount
required
string The amount to be refunded
external_id
required
string A unique identifier of your choice. Max 64 characters.

Refund Response

Parameter Description
updated
required
string An ISO timestamp that tracks when the last time refund was updated
created
required
string An ISO timestamp that tracks when the refund was made
credit_card_charge_id
required
string The charge ID, used to unique identify every charge.
user_id
required
string Your ID in xendit system
amount
required
number Amount of the refund
external_id
required
string Unique identifier that you provide in the request
status
required
string Status of the refund. See Refund Statuses
failure_reason
required
string If the status is failed, this is describe the reason. See Refund Failure Reasons
fee_refund_amount
required
number Amount of fee refunded (proportional to the refund amount)
id
required
string Unique ID referencing the refund request

Refund Statuses

Status Description
SUCCEEDED Refund succeeded
FAILED Refund failed

Refund Errors

Error Code Description
API_VALIDATION_ERROR
400
Inputs are failing validation. The errors field contains details about which fields are violating validation.
INVALID_JSON_FORMAT
400
The request body is not valid JSON.
REFUND_AMOUNT_EXCEEDED_ERROR
400
Refunded amount would exceed total charge
DUPLICATE_REFUND_ERROR
400
external_id has already been used
REQUEST_FORBIDDEN_ERROR
403
API key in use does not have necessary permissions to perform the request. Please assign proper permissions for the key. Learn more here
CREDIT_CARD_CHARGE_NOT_FOUND_ERROR
404
credit_card_charge_id not found

Refund Failure Reason

Failure Reason Description
INSUFFICIENT_BALANCE Insufficient balance to create refund
REFUND_FAILED Request for refund is rejected by processor

eWallets

Create Payment

Create Payment Request

Endpoint: Create Ewallet Payment

POST https://api.xendit.co/ewallets

Example: Create Ewallet Payment Request

OVO:

curl https://api.xendit.co/ewallets -X POST \
   -u xnd_development_O46JfOtygef9kMNsK+ZPGT+ZZ9b3ooF4w3Dn+R1k+2fT/7GlCAN3jg==: \
   -d external_id='ovo-ewallet' \
   -d amount=1000 \
   -d phone='08123123123'\
   -d ewallet_type='OVO'
  <?php
      $url = 'https://api.xendit.co/ewallets';
      $apiKey = 'xnd_development_O46JfOtygef9kMNsK+ZPGT+ZZ9b3ooF4w3Dn+R1k+2fT/7GlCAN3jg==:';
      $headers = [];
      $headers[] = 'Content-Type: application/json';
      $data = [
          'external_id' => 'ovo-ewallet',
          'amount' => 1000,
          'phone' => '08123123123',
          'ewallet_type' => 'OVO'
      ];

      $curl = curl_init();

      $payload = json_encode($data);
      curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
      curl_setopt($curl, CURLOPT_USERPWD, $apiKey.":");
      curl_setopt($curl, CURLOPT_URL, $url);
      curl_setopt($curl, CURLOPT_POST, true);
      curl_setopt($curl, CURLOPT_POSTFIELDS, $payload);
      curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);

      $result = curl_exec($curl);
      echo $result;

DANA:

curl https://api.xendit.co/ewallets -X POST \
  -u xnd_development_O46JfOtygef9kMNsK+ZPGT+ZZ9b3ooF4w3Dn+R1k+2fT/7GlCAN3jg==: \
  -d external_id = 'dana-ewallet' \
  -d amount = 1001 \
  -d expiration_date = '2020-02-20T00:00:00.000Z' \
  -d callback_url = 'https://my-shop.com/callbacks' \
  -d redirect_url = 'https://my-shop.com/home' \
  -d ewallet_type = 'DANA'
  <?php
      $url = 'https://api.xendit.co/ewallets';
      $apiKey = 'xnd_development_O46JfOtygef9kMNsK+ZPGT+ZZ9b3ooF4w3Dn+R1k+2fT/7GlCAN3jg==:';
      $headers = [];
      $headers[] = 'Content-Type: application/json';
      $data = [
          'external_id' => 'dana-ewallet',
          'amount' => 1001,
          'expiration_date' => '2020-02-20T00:00:00.000Z',
          'callback_url' => 'https://my-shop.com/callbacks',
          'redirect_url' => 'https://my-shop.com/home',
          'ewallet_type' => 'DANA'
      ];

      $curl = curl_init();

      $payload = json_encode($data);
      curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
      curl_setopt($curl, CURLOPT_USERPWD, $apiKey.":");
      curl_setopt($curl, CURLOPT_URL, $url);
      curl_setopt($curl, CURLOPT_POST, true);
      curl_setopt($curl, CURLOPT_POSTFIELDS, $payload);
      curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);

      $result = curl_exec($curl);
      echo $result;

LINKAJA:

curl https://api.xendit.co/ewallets -X POST \
  -u xnd_development_O46JfOtygef9kMNsK+ZPGT+ZZ9b3ooF4w3Dn+R1k+2fT/7GlCAN3jg==: \
  --header 'content-type: application/json' \
  --data '{
    "external_id": "linkaja-ewallet",
    "phone": "081245671234",
    "amount": 300000,
    "items": [
        {
            "id": "123123",
            "name": "Phone Case",
            "price": 100000,
            "quantity": 1
        },
    {
            "id": "345678",
            "name": "Powerbank",
            "price": 200000,
            "quantity": 1
        }
    ],
    "callback_url": "https://yourwebsite.com/callback",
    "redirect_url": "https://yourwebsite.com/order/123",
    "ewallet_type": "LINKAJA",
}'
<?php
  $url = 'https://api.xendit.co/ewallets';
  $apiKey = 'xnd_development_O46JfOtygef9kMNsK+ZPGT+ZZ9b3ooF4w3Dn+R1k+2fT/7GlCAN3jg==:';
  $headers = [];
  $headers[] = 'Content-Type: application/json';

  $item_1 = new stdClass();
  $item_1->id = "123123";
  $item_1->name = "Phone Case";
  $item_1->price = 100000;
  $item_1->quantity = 1;

  $item_2 = new stdClass();
  $item_2->id = "345678";
  $item_2->name = "Powerbank";
  $item_2->price = 200000;
  $item_2->quantity = 1;

  $data = [
    'external_id' => 'linkaja-ewallet',
    'amount' => 300000,
    'items' => [ $item_1, $item_2 ]
    'callback_url' => 'https://yourwebsite.com/callbacks',
    'redirect_url' => 'https://yourwebsite.com/order/123',
    'ewallet_type' => 'LINKAJA',
  ];

  $curl = curl_init();

  $payload = json_encode($data);
  curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
  curl_setopt($curl, CURLOPT_USERPWD, $apiKey.":");
  curl_setopt($curl, CURLOPT_URL, $url);
  curl_setopt($curl, CURLOPT_POST, true);
  curl_setopt($curl, CURLOPT_POSTFIELDS, $payload);
  curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);

  $result = curl_exec($curl);
  echo $result;

Example: Create Ewallet Payment Success Response

OVO:

{
  transaction_date: "2019-04-07T01:35:46.658Z",
  amount: 1000,
  external_id: "ovo-ewallet",
  ewallet_type: "OVO",
  business_id: "12121212"
}
{
  transaction_date: "2019-04-07T01:35:46.658Z",
  amount: 1000,
  external_id: "ovo-ewallet",
  ewallet_type: "OVO",
  business_id: "12121212"
}

DANA:

{
  external_id: "dana-ewallet",
  checkout_url: "https://dana.id/m/portal/cashier/checkout?id=5d34079d51a9ed12c78a78d3",
  amount: 1000,
  ewallet_type: "DANA"
}
{
  external_id: "dana-ewallet",
  checkout_url: "https://dana.id/m/portal/cashier/checkout?id=5d34079d51a9ed12c78a78d3",
  amount: 1000,
  ewallet_type: "DANA"
}

LINKAJA:

{
  "checkout_url": "https://ewallet-linkaja-dev.xendit.co/checkouts/b0c464ab-dcdc-4426-9255-759a9450c9d2",
  "transaction_date": "2019-10-25T08:42:54.308Z",
  "amount": 300000,
  "external_id": "linkaja-ewallet",
  "ewallet_type": "LINKAJA"
}
{
  "checkout_url": "https://ewallet-linkaja-dev.xendit.co/checkouts/b0c464ab-dcdc-4426-9255-759a9450c9d2",
  "transaction_date": "2019-10-25T08:42:54.308Z",
  "amount": 300000,
  "external_id": "linkaja-ewallet",
  "ewallet_type": "LINKAJA"
}

Example: Create Ewallet Payment Error Response

OVO:

{
  error_code: 'USER_DID_NOT_AUTHORIZE_THE_PAYMENT',
  message: 'Payment was not authorized',
}
{
  error_code: 'USER_DID_NOT_AUTHORIZE_THE_PAYMENT',
  message: 'Payment was not authorized',
}

DANA:

{
  error_code: 'DUPLICATE_ERROR',
  message: 'Transaction with this external_id is already exist',
}
{
  error_code: 'DUPLICATE_ERROR',
  message: 'Transaction with this external_id is already exist',
}

LINKAJA:

{
  error_code: 'DUPLICATE_ERROR',
  message: 'Transaction with this external_id is already exist',
}
{
  error_code: 'DUPLICATE_ERROR',
  message: 'Transaction with this external_id is already exist',
}

OVO

Parameter Description
external_id
required
string An ID of your choice. Often it is unique identifier like a phone number, email or transaction ID.
Note: Only alphanumeric characters allowed.
Note: Maximum length allowed is 1000 characters.
amount
required
number Amount end-customer will pay.
Note: minimum amount is 1 IDR and maximum is 10,000,000 IDR
phone
required
string Phone number of end-customer (e.g. 08123123123)
Note: End-customer must have an active ewallet account registered to Indonesian phone number prior to payment request.
ewallet_type
required
string ewallet_type must be in capital letters - 'OVO'

DANA

Parameter Description
external_id
required
string An ID of your choice. Often it is unique identifier like a phone number, email or transaction ID. Maximum length allowed is 1000 characters.
amount
required
number Amount end-customer will pay.
Note: minimum amount is 1 IDR and maximum is 10,000,000 IDR
expiration_date
optional
string End-customer cannot complete the payment past the expiration date
Note: The default is 24 hours if not specified.
callback_url
required
string The URL to receive the callback after payment made by end-customer
redirect_url
required
string The URL to redirect to after payment made by end-customer
ewallet_type
required
string ewallet_type must be in capital letters - 'DANA'

LINKAJA

Parameter Description
external_id
required
string An ID of your choice. Often it is unique identifier like a phone number, email or transaction ID. Maximum length allowed is 1000 characters.
phone
required
string Phone number of end-customer (e.g. 08123123123)
Note: End-customer must have an active ewallet account registered to Indonesian phone number prior to payment request.
amount
required
number Amount end-customer will pay.
Note: minimum amount is 100 IDR and maximum is 10,000,000 IDR
items
required
array of item object List of items / products.
item object
required
item object Details of an item, it should contains: id [string], name [string], price [number], quantity [number]
callback_url
required
string The URL to receive the callback after payment made by end-customer
redirect_url
required
string The URL to redirect to after payment made by end-customer
ewallet_type
required
string ewallet_type must be in capital letters - 'LINKAJA'

Errors

OVO

Error Code Description
API_VALIDATION_ERROR
422
There is invalid input in one of the required request fields.
USER_DID_NOT_AUTHORIZE_THE_PAYMENT
400
User did not authorize the payment request within time limit.
USER_DECLINED_THE_TRANSACTION
400
User declined the payment request.
PHONE_NUMBER_NOT_REGISTERED
400
Phone number the user tried to pay is not registered
EXTERNAL_ERROR
400
There is an error on ewallet provider side. Please contact our support for further assistance.
SENDING_TRANSACTION_ERROR
400
We cannot send the transaction. Please contact our support for further assistance.
EWALLET_APP_UNREACHABLE
400
The ewallet provider/server can't reach the user ewallet app/phone. Common cases are the ewallet app is uninstalled.
DUPLICATE_PAYMENT
400
The payment with the same external_id has already been made before.
EWALLET_TYPE_NOT_SUPPORTED
422
Your requested ewallet_type is not supported yet
REQUEST_FORBIDDEN_ERROR
403
API key in use does not have necessary permissions to perform the request. Please assign proper permissions for the key. Learn more here

DANA

Error Code Description
API_VALIDATION_ERROR
422
There is invalid input in one of the required request fields.
DUPLICATE_PAYMENT
400
The payment with the same external_id has already been made before.
EWALLET_TYPE_NOT_SUPPORTED
422
Your requested ewallet_type is not supported yet
REQUEST_FORBIDDEN_ERROR
403
API key in use does not have necessary permissions to perform the request. Please assign proper permissions for the key. Learn more here

LINKAJA

Error Code Description
API_VALIDATION_ERROR
422
There is invalid input in one of the required request fields.
GENERATE_CHECKOUT_TOKEN_ERROR
422
An error occured when generating the checkout_url.
API_VALIDATION_ERROR
400
Some field are missing or you don't specify the value with the correct type or length.
DUPLICATE_PAYMENT
400
The payment with the same external_id has already been made before.
EWALLET_TYPE_NOT_SUPPORTED
422
Your requested ewallet_type is not supported yet
REQUEST_FORBIDDEN_ERROR
403
API key in use does not have necessary permissions to perform the request. Please assign proper permissions for the key. Learn more here

Get Payment Status

Endpoint: Get Ewallet Payment Status

GET https://api.xendit.co/ewallets?external_id={external_id}&ewallet_type={ewallet_type}

Example: Check Ewallet Payment Status Request

OVO, DANA, LINKAJA

curl 'https://api.xendit.co/ewallets?external_id=ovo-ewallet&ewallet_type=OVO' \
   -X GET \
   -u xnd_development_O46JfOtygef9kMNsK+ZPGT+ZZ9b3ooF4w3Dn+R1k+2fT/7GlCAN3jg:
  <?php
      $url = 'https://api.xendit.co/ewallets';
      $apiKey = 'xnd_development_O46JfOtygef9kMNsK+ZPGT+ZZ9b3ooF4w3Dn+R1k+2fT/7GlCAN3jg==:';
      $headers = [];
      $headers[] = 'Content-Type: application/json';

      $externalId = 'ovo-ewallet';
      $ewalletType = 'OVO';

      $urlWithParams = $url . '?external_id=' . $externalId . '&ewallet_type=' . $ewalletType;

      $curl = curl_init();

      curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
      curl_setopt($curl, CURLOPT_USERPWD, $apiKey.":");
      curl_setopt($curl, CURLOPT_URL, $urlWithParams);
      curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);

      $result = curl_exec($curl);
      echo $result;

Example: Check Ewallet Payment Status Success Responses

OVO

{
  amount: 10000,
  business_id: 'business123',
  ewallet_type: 'OVO',
  external_id: 'ovo-payment',
  status: 'COMPLETED',
  transaction_date: '2020-01-14T11:48:47.903Z'
}
{
  amount: 10000,
  business_id: 'business123',
  ewallet_type: 'OVO',
  external_id: 'ovo-payment',
  status: 'COMPLETED',
  transaction_date: '2020-01-14T11:48:47.903Z'
}

DANA

{
  amount: 10000,
  business_id: 'business123',
  checkout_url: 'https://example.com/checkout',
  external_id: 'dana-payment-23',
  expiration_date: '2020-01-14T11:48:47.903Z',
  status: 'PAID'
}
{
  amount: 10000,
  business_id: 'business123',
  checkout_url: 'https://example.com/checkout',
  external_id: 'dana-payment-23',
  expiration_date: '2020-01-14T11:48:47.903Z',
  status: 'PAID'
}

LINKAJA - COMPLETED or FAILED

{
  amount: 10000,
  business_id: 'business123',
  external_id: 'linkaja-payment-23',
  payment_timestamp: '2020-01-14T11:48:47.903Z',
  status: 'COMPLETED'
}
{
  amount: 10000,
  business_id: 'business123',
  external_id: 'linkaja-payment-23',
  payment_timestamp: '2020-01-14T11:48:47.903Z',
  status: 'COMPLETED'
}

LINKAJA - PENDING or EXPIRED

{
  amount: 10000,
  business_id: 'business123',
  checkout_url: 'https://example.com/checkout',
  expired_at: '2020-01-14T11:48:47.903Z',
  external_id: 'linkaja-payment-23',
  status: 'PENDING'
}
{
  amount: 10000,
  business_id: 'business123',
  checkout_url: 'https://example.com/checkout',
  expired_at: '2020-01-14T11:48:47.903Z',
  external_id: 'linkaja-payment-23',
  status: 'PENDING'
}

Example: Check Ewallet Payment Status Error Response

{
  error_code: 'PAYMENT_NOT_FOUND_ERROR',
  message: 'Payment not found',
}
{
  error_code: 'PAYMENT_NOT_FOUND_ERROR',
  message: 'Payment not found',
}

This endpoint is used to get payment status of an single payment. You need to specify the external_id and ewallet_type.

Get Payment Status

Parameter Description
external_id
required
string An ID of your choice. Often it is unique identifier like a phone number, email or transaction ID. Maximum length allowed is 1000 characters.
ewallet_type
required
string ewallet_type must be in capital letters
Supported ewallet types: 'OVO', 'DANA', 'LINKAJA'

Get Payment Status - OVO Responses

Status Description
COMPLETED Payment transaction for specified external_id is successfully
PENDING Payment transaction for specified external_id is awaiting approval by OVO user
FAILED Payment transaction for specified external_id has failed and is not completed (e.g. user did not complete the payment process or payment session timed out)

Get Payment Status - DANA Responses

Status Description
PAID Payment transaction for specified external_id is successfully
PENDING Payment transaction for specified external_id is awaiting approval by DANA user
FAILED Payment creation for specified external_id failed with DANA
EXPIRED Payment transaction URL for specified external_id has expired (e.g. user did not access payment link or complete the payment process)

Get Payment Status - LinkAja Responses

Status Description
COMPLETED Payment transaction specified external_id is successfully
PENDING Payment transaction for specified external_id is awaiting approval by LinkAja user
FAILED Payment creation for specified external_id failed with LinkAja
EXPIRED Payment transaction URL for specified external_id has expired (e.g. user did not access payment link or complete the payment process)

Errors

Error Code Description
PAYMENT_NOT_FOUND_ERROR
404
Payment not found
REQUEST_FORBIDDEN_ERROR
403
API key in use does not have necessary permissions to perform the request. Please assign proper permissions for the key. Learn more here

Payment Status Callback

You need to provide an endpoint in your system to receive payment callback notification from our system. You will receive the callback when end-customer completed the payment for DANA or LINKAJA. The payment callback notification will be sent as POST request to the "callback_url" that you specified on the create payment request. Note: Please give this notification a response back with status 200 so we know that our notification is received.

Example Payment Status Callback

DANA

{
  external_id: "dana-ewallet",
  amount: 1001,
  business_id: "12121212",
  payment_status: "PAID",
  transaction_date: "2019-04-07T01:35:46.658Z",
  callback_authentication_token: "MuaJALKJSDK12LASHD123kSAKSDHzjahwUWjkasJSDSA12KSNAK21n=="
}
{
  external_id: "dana-ewallet",
  amount: 1001,
  business_id: "12121212",
  payment_status: "PAID",
  transaction_date: "2019-04-07T01:35:46.658Z",
  callback_authentication_token: "MuaJALKJSDK12LASHD123kSAKSDHzjahwUWjkasJSDSA12KSNAK21n=="
}

LINKAJA

{
  "external_id": "linkaja-ewallet",
  "amount": 300000,
  "items": [
    {
      "id": "123123",
      "name": "Phone Case",
      "price": 100000,
      "quantity": 1
    },
    {
      "id": "345678",
      "name": "Powerbank",
      "price": 200000,
      "quantity": 1
    }
  ],
  "status": "SUCCESS_COMPLETED",
  "ewallet_type": "LINKAJA",
  "callback_authentication_token": "MuaJALKJSDK12LASHD123kSAKSDHzjahwUWjkasJSDSA12KSNAK21n=="
}
{
  "external_id": "linkaja-ewallet",
  "amount": 300000,
  "items": [
    {
      "id": "123123",
      "name": "Phone Case",
      "price": 100000,
      "quantity": 1
    },
    {
      "id": "345678",
      "name": "Powerbank",
      "price": 200000,
      "quantity": 1
    }
  ],
  "status": "SUCCESS_COMPLETED",
  "ewallet_type": "LINKAJA",
  "callback_authentication_token": "MuaJALKJSDK12LASHD123kSAKSDHzjahwUWjkasJSDSA12KSNAK21n=="
}

DANA

Parameter Description
external_id string Your transaction identifier that you specified in on the Generate Checkout URL request.
amount string The amount of transaction
business_id string Your business_id that registered on our system.
payment_status string The status of payment.
Notes: The statuses are: EXPIRED and PAID.
transaction_date string The time that of payment was made
callback_authentication_token string Your Callback Verfication API Key that you can found on your Xendit Dashboard. You need to verify if this had the same value.

LINKAJA

Parameter Description
external_id string Your transaction identifier that you specified in on the Generate Checkout URL request.
amount string The amount of transaction
items array of item object List of items / products.
item object item object Details of an item, it should contains: id [string], name [string], price [number], quantity [number]
status string The status of payment.
Notes: The statuses are: FAILED and SUCCESS_COMPLETED
ewallet_type string The type of ewallet that you specified when creating the payment request.
Supported ewallet types: OVO, DANA, LINKAJA
callback_authentication_token string Your Callback Verfication API Key that you can found on your Xendit Dashboard. You need to verify if this had the same value.

Cardless Credit

Create Payment / Generate Checkout URL

Generate Checkout URL

Example: Generate Checkout URL

curl https://api.xendit.co/cardless-credit -X POST \
  -u xnd_development_O46JfOtygef9kMNsK+ZPGT+ZZ9b3ooF4w3Dn+R1k+2fT/7GlCAN3jg==: \
  --header 'content-type: application/json' \
  --data '{
    "cardless_credit_type": "KREDIVO",
    "external_id": "test-cardless-credit-01",
    "amount": 800000,
    "payment_type": "3_months",
    "items": [
      {
        "id": "123123",
        "name": "Phone Case",
        "price": 200000,
        "type": "Smartphone",
        "url": "http://example.com/phone/phone_case",
        "quantity": 2
      },
      {
        "id": "234567",
        "name": "Bluetooth Headset",
        "price": 400000,
        "type": "Audio",
        "url": "http://example.com/phone/bluetooth_headset",
        "quantity": 1
      }
    ],
    "customer_details": {
      "first_name": "customer first name",
      "last_name": "customer last name",
      "email": "customer@yourwebsite.com",
      "phone": "081513114262"
    },
    "shipping_address": {
      "first_name": "first name",
      "last_name": "last name",
      "address": "Jalan Teknologi No. 12",
      "city": "Jakarta",
      "postal_code": "12345",
      "phone": "081513114262",
      "country_code": "IDN"
    },
    "redirect_url": "https://example.com",
    "callback_url": "http://example.com/callback-cardless-credit"
  }'
<?php
  $url = 'https://api.xendit.co/cardless-credit';
  $apiKey = 'xnd_development_O46JfOtygef9kMNsK+ZPGT+ZZ9b3ooF4w3Dn+R1k+2fT/7GlCAN3jg==:';
  $headers = [];
  $headers[] = 'Content-Type: application/json';

  $item_1 = new stdClass();
  $item_1->id = "123123";
  $item_1->name = "Phone Case";
  $item_1->price = 200000;
  $item_1->type = "Smartphone";
  $item_1->url = "http://example.com/phone/phone_case";
  $item_1->quantity = 2;

  $item_2 = new stdClass();
  $item_2->id = "234567";
  $item_2->name = "Bluetooth Headset";
  $item_2->price = 400000;
  $item_2->type = "Audio";
  $item_2->url = "http://example.com/phone/bluetooth_headset";
  $item_2->quantity = 1;

  $customer_details = new stdClass();
  $customer_details->first_name = "customer first name";
  $customer_details->last_name = "customer last name";
  $customer_details->email = "customer@email.com";
  $customer_details->phone = "081513114262";

  $shipping_address = new stdClass();
  $shipping_address->first_name = "first name";
  $shipping_address->last_name = "last name";
  $shipping_address->address = "Jalan Teknologi No. 12";
  $shipping_address->city = "Jakarta";
  $shipping_address->postal_code = "12345";
  $shipping_address->phone = "081513114262";
  $shipping_address->country_code = "IDN";

  $data = [
      "cardless_credit_type" => "KREDIVO",
      "external_id" => "test-cardless-credit-01",
      "amount" => 800000,
      "payment_type" => "3_months",
      "items" => [ $item_1, $item_2 ],
      "customer_details" => $customer_details,
      "shipping_address" => $shipping_address,
      "redirect_url" => "https://example.com",
      "callback_url" => "http://example.com/callback-cardless-credit"
  ];

  $curl = curl_init();

  $payload = json_encode($data);
  curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
  curl_setopt($curl, CURLOPT_USERPWD, $apiKey.":");
  curl_setopt($curl, CURLOPT_URL, $url);
  curl_setopt($curl, CURLOPT_POST, true);
  curl_setopt($curl, CURLOPT_POSTFIELDS, $payload);
  curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);

  $result = curl_exec($curl);
  echo $result;

Example: Generate Checkout URL Success Response

{
  "redirect_url": "https://sandbox.kredivo.com/kredivo/v2/signin?tk=fKhTeBntLW3Zyu23+GQ6s+RQaMMRtQ6YdZA1bnbTszt9WXcph/B4+j8nuPlV599Rfkv85FAYuE21Suajpm45tEMZqjZIdqnSgIPlt7T5gJk=",
  "transaction_id": "66403e84-c8da-4af4-8d30-d17e95522f43",
  "order_id": "123456-test-cardless-credit-01",
  "external_id": "test-cardless-credit-01",
  "cardless_credit_type": "KREDIVO"
}
{
  "redirect_url": "https://sandbox.kredivo.com/kredivo/v2/signin?tk=fKhTeBntLW3Zyu23+GQ6s+RQaMMRtQ6YdZA1bnbTszt9WXcph/B4+j8nuPlV599Rfkv85FAYuE21Suajpm45tEMZqjZIdqnSgIPlt7T5gJk=",
  "transaction_id": "66403e84-c8da-4af4-8d30-d17e95522f43",
  "order_id": "5d353767d2c80e33ddc2d252-test-cardless-credit-01",
  "external_id": "test-cardless-credit-01",
  "cardless_credit_type": "KREDIVO"
}

Example: Generate Checkout URL error response

{
  error_code: 'API_VALIDATION_ERROR',
  message: '[fieldName] is required',
}
{
  error_code: 'DUPLICATE_PAYMENT_ERROR',
  message: 'Checkout URL with the same external_id has been created before.',
}
{
  error_code: 'API_VALIDATION_ERROR',
  message: '[fieldName] is required',
}
{
  error_code: 'DUPLICATE_PAYMENT_ERROR',
  message: 'Checkout URL with the same external_id has been created before.',
}
Parameter Description
cardless_credit_type
required
string The type of cardless-credit to be paid. Must be in capital letters.
Supported Cardless Credit types: KREDIVO
external_id
required
string An ID of your choice. Often it is unique identifier like a phone number, email or transaction ID. Maximum length allowed is 1000 characters.
amount
required
number Amount end customer will pay.
Note: minimum amount is 1 IDR
payment_type
required
string The type of installment, you can choose between: "30_days", "3_months", "6_months" and "12_months".
items
required
array of item object List of items / products.
item object
required
item object Details of an item, it should contains: id [string], name [string], price [number], type [string], url [string], quantity [number]
customer_details
required
object Details of the customer, it should contains: first_name [string], last_name [string], email [string], phone [string]
shipping_address
required
object Details of the shipping address, it should contains: first_name [string], last_name [string], address [string], city [string], postal_code [string], phone [string], country_code [string]
redirect_url
required
string After end-customer complete the checkout they will be redirected to the url that you specify in this field. You can put your transaction details page or your home page.
callback_url
required
string We will send callback to this address when the customer completes the payment proccess.

Errors

Error Code Description
MERCHANT_NOT_FOUND
422
You are not registered yet to use this payment method.
GENERATE_CHECKOUT_URL_ERROR
422
Your request did not meet the requirement or there is a problem in the Kredivo / Partner server.
DUPLICATE_PAYMENT_ERROR
422
Checkout URL with the same external_id has been created before.
REQUEST_FORBIDDEN_ERROR
403
API key in use does not have necessary permissions to perform the request. Please assign proper permissions for the key. Learn more here

Payment Callback Notification

Receive Payment Callback Notification

You need to provide an endpoint in your system to receive payment callback notification from our system. We will send the payment callback notification when the end-customer completes the payment on the Checkout page.

The payment callback notification will be sent as POST request to the "callback_url" that you sepecified on the Generate Checkout URL request.

Example: Payment Callback Notification Request

{
  "external_id": "test-cardless-credit-01",
  "order_id": "75191237c81273jajsh7291c-test-cardless-credit-01",
  "transaction_id": "ashd7129-sh82-a9ks-js82-asj82912bajs",
  "amount": 800000,
  "transaction_status": "settlement",
  "payment_type": "3_months",
  "items": [
    {
      "id": "123123",
      "name": "Phone Case",
      "price": 200000,
      "type": "Smartphone",
      "url": "http://example.com/phone/phone_case",
      "quantity": 2
    },
    {
      "id": "234567",
      "name": "Bluetooth Headset",
      "price": 400000,
      "type": "Audio",
      "url": "http://example.com/audio/bluetooth_headset",
      "quantity": 1
    }
  ],
  "customer_details": {
      "first_name": "customer first name",
      "last_name": "customer last name",
      "email": "customer@yourwebsite.com",
      "phone": "081513114262"
    },
    "shipping_address": {
      "first_name": "first name",
      "last_name": "last name",
      "address": "Jalan Teknologi No. 12",
      "city": "Jakarta",
      "postal_code": "12345",
      "phone": "081513114262",
      "country_code": "IDN"
    },
  "cardless_credit_type": "KREDIVO",
  "callback_authentication_token": "MuaJALKJSDK12LASHD123kSAKSDHzjahwUWjkasJSDSA12KSNAK21n=="
}
Parameter Description
external_id string Your transaction identifier that you specified in on the Generate Checkout URL request.
order_id string Unique Identifier that we gave to the cardless credit payment partner.
transaction_id string Transaction ID given by Cardless Credit partner.
transaction_status string Transaction status, the value is:
settlement: Transaction is successful
pending: End-User has not completed the transaction
deny: Transaction has been denied by our Cardless Credit Partner
cancel: Transaction has been cancelled
expire: End-User did not complete transaction in 24 hours, thus transaction is expired
payment_type string the type of installment.
amount number Amount that you specified in on the Generate Checkout URL request.
items array of item List of items / products that you specified in on the Generate Checkout URL request.
item object
item detail Details of an item, it should contains: id [string], name [string], price [number], type [string], url [string], quantity [number]
customer_details object Details of the customer, it should contains: first_name [string], last_name [string], email [string], phone [string]
shipping_address object Details of the shipping address, it should contains: first_name [string], last_name [string], address [string], city [string], postal_code [string], phone [string], country_code [string]
cardless_credit_type string The type of cardless-credit.
Supported Cardless Credit types: KREDIVO
callback_authentication_token string Your Callback Verfication API Key that you can found on your Xendit Dashboard. You need to verify if this had the same value.

Virtual Accounts

Create Fixed Virtual Account

Endpoint: Create Fixed Virtual Account

POST https://api.xendit.co/callback_virtual_accounts

Fixed Virtual Accounts are dedicated virtual accounts under a name you choose, e.g. 'YourCompany - Becca Salim'. You will receive a callback each time this fixed virtual account is paid.

For production environments, activate the Fixed Virtual Account Range from the dashboard by going to Dashboard > Settings > Configuration > Fixed Virtual Accounts, and clicking the "Activate!" button. The Fixed VA range will be set and activated instantly. In development environments, the development VA range is assigned right away. Read more about fixed virtual accounts.

Looking for your virtual accounts to be tied to a transaction rather than a user? Use our invoices API.

Create Fixed Virtual Account Request

Example Create Fixed Virtual Accounts Request

curl https://api.xendit.co/callback_virtual_accounts -X POST \
   -u xnd_development_O46JfOtygef9kMNsK+ZPGT+ZZ9b3ooF4w3Dn+R1k+2fT/7GlCAN3jg==: \
   -d external_id=demo_virtual_account_1475459775872 \
   -d bank_code=BNI \
   -d name='Rika Sutanto'
<?php
  require 'vendor/autoload.php';

  $options['secret_api_key'] = 'xnd_development_P4qDfOss0OCpl8RtKrROHjaQYNCk9dN5lSfk+R1l9Wbe+rSiCwZ3jw==';

  $xenditPHPClient = new XenditClient\XenditPHPClient($options);

  $external_id = 'demo_1475459775872';
  $bank_code = 'BNI';
  $name = 'Rika Sutanto';

  $response = $xenditPHPClient->createCallbackVirtualAccount($external_id, $bank_code, $name);
  print_r($response);
?>
import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.client.Entity;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.MediaType;

Client client = ClientBuilder.newClient();
Entity payload = Entity.json("{  'external_id': 'user_1212412312',  'bank_code': 'BNI',  'name': 'William Sutanto'}");
Response response = client.target("https://api.xendit.co/callback_virtual_accounts")
  .request(MediaType.APPLICATION_JSON_TYPE)
  .header("Authorization", "Basic eG5kX2RldmVsb3BtZW50X1A0cURmT3NzME9DcGw4UnRLclJPSGphUVlOQ2s5ZE41bFNmaytSMWw5V2JlK3JTaUN3WjNqdz09Og==")
  .post(payload);

System.out.println("status: " + response.getStatus());
System.out.println("headers: " + response.getHeaders());
System.out.println("body:" + response.readEntity(String.class));
Parameter Description
external_id
required
string An ID of your choice. Often it is unique identifier like a phone number, email or transaction ID. Maximum length allowed is 1000 characters. Note: External IDs cannot be changed once set
bank_code
required
string Bank code of the virtual account you want to create
Note: We highly recommend you redirect customers to pay into BNI Virtual Account for interbank transfers
name
required
string Name of user/virtual account, - this will be displayed in the bank's user interface, e.g. ATM confirmation screens. Note that this field can only contain letters and spaces and has no length restriction (though the banks will truncate as per their limitations)
virtual_account_number
optional
string The virtual account number you want to assign. If you do not send one, one will be picked at random
Note: Please do not include the merchant code
suggested_amount
optional
number The suggested amount you want to assign.
Note: Suggested amounts is only supported for Mandiri and BRI
is_closed
optional
boolean When set to true, the virtual account will be closed and will only accept the amount specified in expected_amount
expected_amount
optional
number The amount that the virtual account will expect if is_closed is set to true
expiration_date
optional
ISO Date The time when the virtual account will be expired
is_single_use
optional
boolean When set to true, the virtual account will be inactive after it is paid
description
optional
string The virtual account description. This field is only supported for BRI

Create Fixed Virtual Account Response

Example Create Fixed Virtual Account Response

{
   "owner_id":"57b4e5181473eeb61c11f9b9",
   "external_id":"demo-1475804036622",
   "bank_code":"BNI",
   "merchant_code":"8808",
   "name":"Rika Sutanto",
   "account_number":"88082548",
   "is_closed": false,
   "id":"57f6fbf26b9f064272622aa6",
   "is_single_use": true,
   "status": "ACTIVE"
}
Parameter Description
owner_id Your user ID
external_id An ID of your choice which you provided upon request
bank_code Bank code for the relevant bank, e.g. BNI
merchant_code 5-digit merchant prefix to the full virtual account number
name Name for the fixed virtual account
account_number Complete virtual account number (including prefix). This is what a user will need to enter into an ATM or their Internet/mobile banking.
suggested_amount OPTIONAL suggested amount for created fixed virtual account
is_closed Value that determines whether a virtual account is closed or not
expected_amount OPTIONAL the amount that is expected when is_closed is true
id Unique ID for the fixed virtual account. Can be used to create invoices linked to the FVA.
is_single_use Value that determines whether a virtual account will be inactive after it is paid
status Status of fixed virtual account that defines if it’s pending, inactive, or active. Status is pending if virtual account creation request has been sent and request is being processed by the bank. Status is inactive either because it is a paid single use fixed virtual account or it is already expired. If status is active it is ready to be used by the end user.
description OPTIONAL description of the virtual account which will be displayed during payment. Only supported for BRI virtual accounts.

Create Fixed Virtual Account Errors

Error Code Description
API_VALIDATION_ERROR
400
Inputs are failing validation. The errors field contains details about which fields are violating validation.
INVALID_JSON_FORMAT
400
The request body is not a valid JSON format.
VIRTUAL_ACCOUNT_NUMBER_OUTSIDE_RANGE
400
The virtual account number you want is outside your range.
BANK_NOT_SUPPORTED_ERROR
400
The bank code is not currently supported.
EXPIRATION_DATE_NOT_SUPPORTED_ERROR
400
Custom expiration date for the fixed virtual account is not currently supported.
EXPIRATION_DATE_INVALID_ERROR
400
Invalid custom expiration date because it's earlier than current time.
SUGGESTED_AMOUNT_NOT_SUPPORTED_ERROR
400
The suggested amount for the fixed virtual account is not currently supported.
EXPECTED_AMOUNT_REQUIRED_ERROR
400
The expected amount is required when is_closed is set to true.
CLOSED_VA_NOT_SUPPORTED_ERROR
400
The closed option for this virtual account is not currently supported.
DUPLICATE_CALLBACK_VIRTUAL_ACCOUNT_ERROR
400
The account number that you want to create is already exist
MINIMUM_EXPECTED_AMOUNT_ERROR
400
The minimum expected amount is Rp.1 for BNI, BRI and MANDIRI
MAXIMUM_EXPECTED_AMOUNT_ERROR
400
The maximum expected amount is Rp.50,000,000,000 for BNI, BRI and MANDIRI
CALLBACK_VIRTUAL_ACCOUNT_NAME_NOT_ALLOWED_ERROR
400
The name cannot contain bank or institution name
DESCRIPTION_NOT_SUPPORTED_ERROR
400
Description field is only supported for BRI
REQUEST_FORBIDDEN_ERROR
403
API key in use does not have necessary permissions to perform the request. Please assign proper permissions for the key. Learn more here

Get Virtual Account Banks

Endpoint: Get Virtual Account Available Banks

GET https://api.xendit.co/available_virtual_account_banks

Example Get Virtual Account Banks Request

curl https://api.xendit.co/available_virtual_account_banks -X GET \
   -u xnd_development_O46JfOtygef9kMNsK+ZPGT+ZZ9b3ooF4w3Dn+R1k+2fT/7GlCAN3jg==:
<?php
  require 'vendor/autoload.php';

  $options['secret_api_key'] = 'xnd_development_P4qDfOss0OCpl8RtKrROHjaQYNCk9dN5lSfk+R1l9Wbe+rSiCwZ3jw==';

  $xenditPHPClient = new XenditClient\XenditPHPClient($options);

  $response = $xenditPHPClient->getVirtualAccountBanks();
  print_r($response);
?>

import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.client.Entity;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.MediaType;

Client client = ClientBuilder.newClient();
Response response = client.target("https://api.xendit.co/available_virtual_account_banks")
  .request(MediaType.APPLICATION_JSON_TYPE)
  .header("Authorization", "Basic eG5kX2RldmVsb3BtZW50X1A0cURmT3NzME9DcGw4UnRLclJPSGphUVlOQ2s5ZE41bFNmaytSMWw5V2JlK3JTaUN3WjNqdz09Og==")
  .get();

System.out.println("status: " + response.getStatus());
System.out.println("headers: " + response.getHeaders());
System.out.println("body:" + response.readEntity(String.class));

Get Virtual Account Banks Response

Example Get Virtual Account Banks Response

{
  "name": "Bank Negara Indonesia",
  "code": "BNI"
}
Parameter Description
name Full name of the bank
code Code of the bank, relevant during creation of virtual accounts

Get Fixed Virtual Account

Endpoint: Get Fixed Virtual Account

GET https://api.xendit.co/callback_virtual_accounts/:id

Example Get Fixed Virtual Account Request

curl https://api.xendit.co/callback_virtual_accounts/:id -X GET \
  -u xnd_development_O46JfOtygef9kMNsK+ZPGT+ZZ9b3ooF4w3Dn+R1k+2fT/7GlCAN3jg==:

Sometime, you need to know the detail for your fixed virtual account. This endpoint can be used to get the latest details from your fixed virtual account

Get Fixed Virtual Account Request

Parameter Description
id
required
string ID of the fixed virtual account to retrieve

Get Fixed Virtual Account Response

Example Get Fixed Virtual Account Response

{
    "owner_id": "58cd618ba0464eb64acdb246",
    "external_id": "fixed-va-1507867286",
    "bank_code": "BRI",
    "merchant_code": "26215",
    "name": "Steve Wozniak",
    "account_number": "262151000393993",
    "is_single_use": false,
    "status": "ACTIVE",
    "expiration_date": "2048-10-12T17:00:00.000Z",
    "is_closed": false,
    "id": "59e03a976fab8b1850fdf347"
}
Parameter Description
owner_id ID of the business that own the fixed virtual account
external_id An ID of your choice which you provided upon virtual account creation
bank_code Bank code of the virtual account number
merchant_code 4 or 5-digit merchant prefix to the full virtual account number
name Name of the virtual account
account_number Account number of the virtual account
expiration_date Expiration date of the virtual account
is_closed Flag that define the fixed virtual account is close or open
id ID of the fixed virtual account
is_single_use Flag that define the fixed virtual account is single use or multiple use
status Status of fixed virtual account that defines if it’s active or inactive. Status is inactive either because it is a paid single use fixed virtual account or it is already expired.

Get Fixed Virtual Account Errors

Error Code Description
REQUEST_FORBIDDEN_ERROR
403
API key in use does not have necessary permissions to perform the request. Please assign proper permissions for the key. Learn more here
CALLBACK_VIRTUAL_ACCOUNT_NOT_FOUND_ERROR
404
Could not find callback virtual account.

Update Fixed Virtual Account

Endpoint: Update Fixed Virtual Account (FVA)

PATCH https://api.xendit.co/callback_virtual_accounts/:id

Fixed Virtual Account is adaptable, and can be customized to fit your needs. Therefore, we provide you this endpoint to easily update your fixed virtual account as you like. You can update multiple use VAs as well as active single use VAs, though inactive single use VAs cannot be updated.

Note: Closed virtual accounts can not be changed to open virtual accounts, and vice versa.

Update Fixed Virtual Account Request

Parameter Description
suggested_amount
optional
number suggested amount you want to assign
expected_amount
optional
number The amount that the virtual account will expect if is_closed is set to true
expiration_date
optional
ISO Date The time when the virtual account will be expired. You can set it to be days in the past to expire virtual account immediately
is_single_use
optional
boolean When set to true, the virtual account will be inactive after it is paid
description
optional
string Virtual account description shown to end user during payment

Update Fixed Virtual Account Response

Example Update Fixed Virtual Account Response

{
   "owner_id":"57b4e5181473eeb61c11f9b9",
   "external_id":"demo-1475804036622",
   "bank_code":"BNI",
   "merchant_code":"8808",
   "name":"Rika Sutanto",
   "account_number":"88082548",
   "suggested_amount":50000,
   "is_closed": false,
   "id":"57f6fbf26b9f064272622aa6",
   "is_single_use": true,
   "status": "ACTIVE"
}
Parameter Description
owner_id Your user ID
external_id An ID of your choice which you provided upon virtual account creation
bank_code Bank code for the relevant bank, e.g. BNI
merchant_code 5-digit merchant prefix to the full virtual account number
name Name for the fixed virtual account
account_number Complete virtual account number (including prefix). This is what a user will need to enter into an ATM or their Internet/mobile banking.
suggested_amount Suggested amount of updated fixed virtual account
id Unique ID for the fixed virtual account. Can be used to create invoices linked to the FVA.
is_closed value that determines whether a virtual account is closed or not
expected_amount OPTIONAL the amount that is expected when is_closed is true
is_single_use value that determines whether a virtual account will be inactive after it is paid
status Status of fixed virtual account that defines if it’s pending or inactive. Status is inactive either because it is a paid single use fixed virtual account or it is already expired.
description OPTIONAL description of the virtual account which will be displayed during payment. Only supported for BRI virtual accounts.

Update Fixed Virtual Account Errors

Error Code Description
API_VALIDATION_ERROR
400
Inputs are failing validation. The errors field contains details about which fields are violating validation.
INVALID_JSON_FORMAT
400
The request body is not a valid JSON format.
VIRTUAL_ACCOUNT_NUMBER_OUTSIDE_RANGE
400
The virtual account number you want is outside your range.
BANK_NOT_SUPPORTED_ERROR
400
The bank code is not currently supported.
SUGGESTED_AMOUNT_NOT_SUPPORTED_ERROR
400
The suggested amount for the fixed virtual account is not currently supported.
EXPECTED_AMOUNT_REQUIRED_ERROR
400
The expected amount is required when is_closed is set to true.
CLOSED_VA_NOT_SUPPORTED_ERROR
400
The closed option for this virtual account is not currently supported.
INACTIVE_VIRTUAL_ACCOUNT_ERROR
400
Account number that you want to update is inactive.
MINIMUM_EXPECTED_AMOUNT_ERROR
400
The expected amount can only be more than zero
MAXIMUM_EXPECTED_AMOUNT_ERROR
400
The expected amount can only be less than Rp.1000000000
DESCRIPTION_NOT_SUPPORTED_ERROR
400
Description field is only supported for BRI
REQUEST_FORBIDDEN_ERROR
403
API key in use does not have necessary permissions to perform the request. Please assign proper permissions for the key. Learn more here

Fixed Virtual Account Callback

Endpoint: Fixed Virtual Account Callback

POST https://yourcompany.com/virtual_account_paid_callback_url
import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.client.Entity;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.MediaType;

Client client = ClientBuilder.newClient();
Entity payload = Entity.json("{
    id: '57fb4e076fa3fa296b7f5a97',
    payment_id: 'demo-1476087608948_1476087303080',
    callback_virtual_account_id: '57fb4df9af86ce19778ad359',
    owner_id: '57b4e5181473eeb61c11f9b9',
    external_id: 'demo-1476087608948',
    account_number: '1547',
    bank_code: 'BNI',
    amount: 99000,
    transaction_timestamp: '2016-10-10T08:15:03.080Z',
    merchant_code: '8808',
    updated: '2016-10-10T08:15:03.404Z',
    created: '2016-10-10T08:15:03.404Z'
}");
Response response = client.target("https://api.xendit.co/virtual_account_paid_callback_url")
  .request(MediaType.APPLICATION_JSON_TYPE)
  .header("X-CALLBACK-TOKEN", "MuaJALKJSDK12LASHD123kSAKSDHzjahwUWjkasJSDSA12KSNAK21n==")
  .post(payload);

System.out.println("status: " + response.getStatus());
System.out.println("headers: " + response.getHeaders());
System.out.println("body:" + response.readEntity(String.class));

When someone pays into your fixed virtual account, our callback APIs will hit your URL that you already set in dashboard. Our callback API will also hit your URL upon fixed virtual account creations and updates. Please see Create Fixed Virtual Accounts for more details. For further information about callbacks please read these docs.

This example is only used to show the body parameters that send from Xendit APIs to your callback URL and cannot be tested in here. If you want to test this callback request, use the test feature in dashboard or go to Settings > Developers > Callbacks.

Fixed Virtual Account Payment Callback Request

Example Fixed Virtual Account Payment Callback Request

curl --include \
     --request POST \
     --header "Content-Type: application/json" \
     --header "X-CALLBACK-TOKEN: MuaJALKJSDK12LASHD123kSAKSDHzjahwUWjkasJSDSA12KSNAK21n==" \
     --data-binary "{
    id: \"57fb4e076fa3fa296b7f5a97\",
    payment_id: \"demo-1476087608948_1476087303080\",
    callback_virtual_account_id: \"57fb4df9af86ce19778ad359\",
    owner_id: \"57b4e5181473eeb61c11f9b9\",
    external_id: \"demo-1476087608948\",
    account_number: \"1547\",
    bank_code: \"BNI\",
    amount: 99000,
    transaction_timestamp: \"2016-10-10T08:15:03.080Z\",
    merchant_code: \"8808\",
    updated: \"2016-10-10T08:15:03.404Z\",
    created: \"2016-10-10T08:15:03.404Z\"
}" \
'https://api.xendit.co/virtual_account_paid_callback_url'
Parameter Description
payment_id Our internal system’s payment ID
callback_virtual_account_id The id field value from the response when the fixed virtual account was created. See Create Fixed Virtual Accounts
owner_id Your user ID
external_id An ID of your choice which you provided upon virtual account creation
account_number This is the virtual account number (excluding the prefix). This works just like a bank account and is what a user will need to enter in their internet banking/ATM to send funds.
bank_code Bank code for the relevant bank, e.g. BNI
amount Nominal amount to transfer
merchant_code The merchant code will be the prefix for the virtual account number, e.g 01234 your_number
id ID of fixed virtual account payment

Fixed Virtual Account Creation / Update Callback Request

Example Fixed Virtual Account Creation / Update Callback Request

curl --include \
     --request POST \
     --header "Content-Type: application/json" \
     --header "X-CALLBACK-TOKEN: MuaJALKJSDK12LASHD123kSAKSDHzjahwUWjkasJSDSA12KSNAK21n==" \
     --data-binary "{
    id: \"57fb4e076fa3fa296b7f5a97\",
    owner_id: \"5824128aa6f9f9b648be9d76\",
    external_id: \"fixed-va-1487156410\",
    merchant_code: \"88608\",
    account_number: \"886081000123456\",
    bank_code: \"MANDIRI\",
    name: \"John Doe\",
    is_closed: false,    
    is_single_use: false,
    status: \"ACTIVE\",
    expiration_date: \"2048-02-15T11:01:52.722Z\",
    updated: \"2016-10-10T08:15:03.404Z\",
    created: \"2016-10-10T08:15:03.404Z\"
}" \
'https://api.xendit.co/virtual_account_created_callback_url'
Parameter Description
owner_id Your user ID
external_id An ID of your choice which you provided upon request
bank_code Bank code for the relevant bank, e.g. MANDIRI
merchant_code 5-digit merchant prefix to the full virtual account number
name Name for the fixed virtual account
account_number Complete virtual account number (including prefix). This is what a user will need to enter into an ATM or their Internet/mobile banking.
suggested_amount OPTIONAL suggested amount for created fixed virtual account
is_closed value that determines whether a virtual account is closed or not
expected_amount OPTIONAL the amount that is expected when is_closed is true
id Unique ID for the fixed virtual account. Can be used to create invoices linked to the FVA.
is_single_use value that determines whether a virtual account will be inactive after it is paid
status Status of fixed virtual account.

Fixed Virtual Account Callback Errors

Note that in the case where we don't get a successful response from your servers on the first try, we will retry 2 times more with a 30 second delay between each retry. After 3 failures, we get internal alerts that a callback has failed. Our team will then contact you to resolve the issue.

Get Fixed Virtual Account Payment

Endpoint: Get Fixed Virtual Account Payment

GET https://api.xendit.co/callback_virtual_account_payments/payment_id={payment_id}

Example Get Fixed Virtual Account Payment Request

curl https://api.xendit.co/callback_virtual_account_payments/payment_id={payment_id} -X GET \
    -u xnd_development_O46JfOtygef9kMNsK+ZPGT+ZZ9b3ooF4w3Dn+R1k+2fT/7GlCAN3jg==:

When you receive our callback in your URL, you can verify that the callback you receive is coming from us.

Get Fixed Virtual Account Payment Request

Parameter Description
payment_id
required
string ID of the payment to retrieve

Get Fixed Virtual Account Payment Response

Example Get Fixed Virtual Account Payment Response

{
    "id": "598d91b1191029596846047f",
    "payment_id": "1502450097080",
    "callback_virtual_account_id": "598d5f71bf64853820c49a18",
    "external_id": "demo-1502437214715",
    "merchant_code": "77517",
    "account_number": "1000016980",
    "bank_code": "BNI",
    "amount": 5000,
    "transaction_timestamp": "2017-08-11T11:14:57.080Z"
}
Parameter Description
id ID of the fixed virtual account payment
payment_id Our internal system’s payment ID
callback_virtual_account_id ID of the fixed virtual account payment that was paid
external_id External ID on the fixed virtual account payment
merchant_code 5-digit merchant prefix to the full virtual account number
account_number Account number of the virtual account
bank_code Bank code of the virtual account number
amount Amount that was paid to this virtual account payment
transaction_timestamp Date time that the fixed virtual account was paid

Get Fixed Virtual Account Payment Errors

Error Code Description
REQUEST_FORBIDDEN_ERROR
403
API key in use does not have necessary permissions to perform the request. Please assign proper permissions for the key. Learn more here
CALLBACK_VIRTUAL_ACCOUNT_PAYMENT_NOT_FOUND_ERROR
404
Could not find callback virtual account payment by payment id.

Retail Outlets

Create Fixed Payment Code

Endpoint: Create Fixed Payment Code (FPC)

POST https://api.xendit.co/fixed_payment_code

One way for your customer to pay through Retail Outlets is by providing them Fixed Payment Code. Fixed payment code is a dedicated payment code under a name you choose, e.g. 'YourCompany - Becca Salim'. You will receive a callback each time this fixed payment code is paid.

Create Fixed Payment Code Request

Example Create Fixed Payment Code Request

curl https://api.xendit.co/fixed_payment_code -X POST \
   -u xnd_development_O46JfOtygef9kMNsK+ZPGT+ZZ9b3ooF4w3Dn+R1k+2fT/7GlCAN3jg==: \
   -d external_id=demo_fixed_payment_code_123 \
   -d retail_outlet_name=ALFAMART \
   -d name='Rika Sutanto' \
   -d expected_amount=10000
Parameter Description
external_id
required
string An ID of your choice. Often it is unique identifier like a phone number, email or transaction ID. Maximum length allowed is 1000 characters.
retail_outlet_name
required
string Name of the fixed payment code you want to create
name
required
string Name of user - this might be used by the Retail Outlets cashier to validate the end user
expected_amount
required
number The amount that is expected to be paid by end customer
payment_code
optional
string The fixed payment code that you want to assign. If you do not send one, one will be picked at random
expiration_date
optional
ISO Date The time when the fixed payment code will be expired
is_single_use
optional
boolean When set to true, the fixed payment code will be inactive after it is paid

Create Fixed Payment Code Response

Example Create Fixed Payment Code Response

{
    "owner_id": "5b614aa8e79f9214007244d4",
    "external_id": "123",
    "retail_outlet_name": "ALFAMART",
    "prefix": "TEST",
    "name": "Rika Sutanto",
    "payment_code": "TEST123456",
    "type": "USER",
    "expected_amount": 10000,
    "is_single_use": true,
    "expiration_date": "2049-07-31T17:00:00.000Z",
    "id": "5b61881e6cc2770f00117f73"
}
Parameter Description
owner_id Your user ID
external_id An ID of your choice which you provided upon request
retail_outlet_name Name of the Retail Outlets, e.g. ALFAMART or INDOMARET
prefix 3-6 characters that differentiate your fixed payment code from the others
name Name for the fixed payment code
payment_code Complete fixed payment code (including prefix). This is what a user will need to tell Retail Outlets cashier
expected_amount The amount that is expected to be paid by end customer
is_single_use Value that determines whether a fixed payment code will be inactive after it is paid or not
expiration_date The time when the fixed payment code will be expired
id Unique ID for the fixed payment code

Create Fixed Payment Code Errors

Error Code Description
API_VALIDATION_ERROR
400
Inputs are failing validation. The errors field contains details about which fields are violating validation.
INVALID_JSON_FORMAT
400
The request body is not a valid JSON format.
PAYMENT_CODE_OUTSIDE_RANGE
400
The fixed payment code you want is outside your range.
RETAIL_OUTLET_NOT_SUPPORTED_ERROR
400
The Retail Outlets is not currently supported.
DUPLICATE_PAYMENT_CODE_ERROR
400
The payment code that you want to create is already exist
EXPIRATION_DATE_INVALID_ERROR
400
Invalid custom expiration date because it's earlier than current time.
MINIMUM_EXPECTED_AMOUNT_ERROR
400
The expected amount can only be more than or equal Rp 10,0000
MAXIMUM_EXPECTED_AMOUNT_ERROR
400
The expected amount can only be less than or equal Rp 5,000,000
REQUEST_FORBIDDEN_ERROR
403
API key in use does not have necessary permissions to perform the request. Please assign proper permissions for the key. Learn more here

Update Fixed Payment Code

Endpoint: Update Fixed Payment Code (FPC)

PATCH https://api.xendit.co/fixed_payment_code/{fixed_payment_code_id}

Fixed Payment Code is so adaptable, and it's all based on your needs. Therefore, we provide you this endpoint to easily update your fixed payment code as you like.

Update Fixed Payment Code Request

Example Create Fixed Payment Code Request

curl https://api.xendit.co/fixed_payment_code/{fixed_payment_code_id} -X PATCH \
   -u xnd_development_O46JfOtygef9kMNsK+ZPGT+ZZ9b3ooF4w3Dn+R1k+2fT/7GlCAN3jg==: \
   -d expected_amount=20000
   -d name='Joe Contini'
Parameter Description
name
optional
string Name for the fixed payment code
expected_amount
optional
number The amount that is expected to be paid by end customer
expiration_date
optional
ISO Date The time when the fixed payment code will be expired. You can set it to be days in the past to expire fixed payment code immediately

Update Fixed Payment Code Response

Example Update Fixed Payment Code Response

{
    "owner_id": "5b614aa8e79f9214007244d4",
    "external_id": "123",
    "retail_outlet_name": "ALFAMART",
    "prefix": "TEST",
    "name": "Joe Contini",
    "payment_code": "TEST123456",
    "type": "USER",
    "expected_amount": 20000,
    "is_single_use": true,
    "expiration_date": "2049-07-31T17:00:00.000Z",
    "id": "5b61881e6cc2770f00117f73"
}
Parameter Description
owner_id Your user ID
external_id An ID of your choice which you provided upon request
retail_outlet_name Name of the Retail Outlets, e.g. ALFAMART or INDOMARET
prefix 3-6 characters that differentiate your fixed payment code from the others
name Name for the fixed payment code
payment_code Complete fixed payment code (including prefix). This is what a user will need to tell Retail Outlets cashier
expected_amount The amount that is expected to be paid by end customer
is_single_use Value that determines whether a fixed payment code will be inactive after it is paid or not
expiration_date The time when the fixed payment code will be expired
id Unique ID for the fixed payment code

Update Fixed Payment Code Errors

Error Code Description
API_VALIDATION_ERROR
400
Inputs are failing validation. The errors field contains details about which fields are violating validation.
INVALID_JSON_FORMAT
400
The request body is not a valid JSON format.
PAYMENT_CODE_OUTSIDE_RANGE
400
The fixed payment code you want is outside your range.
INACTIVE_FIXED_PAYMENT_CODE_ERROR
400
Account number that you want to update is inactive.
MINIMUM_EXPECTED_AMOUNT_ERROR
400
The expected amount can only be more than or equal Rp 10,000
MAXIMUM_EXPECTED_AMOUNT_ERROR
400
The expected amount can only be less than or equal Rp 5,000,000
REQUEST_FORBIDDEN_ERROR
403
API key in use does not have necessary permissions to perform the request. Please assign proper permissions for the key. Learn more here

Get Fixed Payment Code

Endpoint: Get Fixed Payment Code

GET https://api.xendit.co/fixed_payment_code/{fixed_payment_code_id}

Example Get Fixed Payment Code Request

curl https://api.xendit.co/fixed_payment_code/{fixed_payment_code_id} -X GET \
  -u xnd_development_O46JfOtygef9kMNsK+ZPGT+ZZ9b3ooF4w3Dn+R1k+2fT/7GlCAN3jg==:

Sometimes, you need to know the detail for your fixed payment code. This endpoint can be used to get the latest details from your fixed payment code

Get Fixed Payment Code Request

Parameter Description
fixed_payment_code_id
required
string ID of the fixed payment code to retrieve

Get Fixed Payment Code Response

Example Get Fixed Payment Code Response

{
    "owner_id": "5b614aa8e79f9214007244d4",
    "external_id": "123",
    "retail_outlet_name": "INDOMARET",
    "prefix": "TEST",
    "name": "Joe Contini",
    "payment_code": "TEST123456",
    "type": "USER",
    "expected_amount": 20000,
    "is_single_use": true,
    "expiration_date": "2049-07-31T17:00:00.000Z",
    "id": "5b61881e6cc2770f00117f73"
}
Parameter Description
owner_id Your user ID
external_id An ID of your choice which you provided upon request
retail_outlet_name Name for the relevant Retail Outlets, e.g. ALFAMART or INDOMARET
prefix 3-6 characters that differentiate your fixed payment code from the others
name Name for the fixed payment code
payment_code Complete fixed payment code (including prefix). This is what a user will need to tell Retail Outlets cashier
expected_amount The amount that is expected to be paid by end customer
is_single_use Value that determines whether a fixed payment code will be inactive after it is paid or not
expiration_date The time when the fixed payment code will be expired
id Unique ID for the fixed payment code

Get Fixed Payment Code Errors

Error Code Description
REQUEST_FORBIDDEN_ERROR
403
API key in use does not have necessary permissions to perform the request. Please assign proper permissions for the key. Learn more here
FIXED_PAYMENT_CODE_NOT_FOUND_ERROR
404
Could not find fixed payment code.

Fixed Payment Code Callback

Endpoint: Fixed Payment Code Callback

POST https://yourcompany.com/fixed_payment_code_paid_callback_url

When someone pays into your fixed payment code, our callback APIs will hit your URL that you already set in dashboard.

This example is only used to show the body parameters that send from Xendit APIs to your callback URL and cannot be tested in here. If you want to test this callback request, use the test feature in dashboard and go to Settings > Developers > Callbacks.

Fixed Payment Code Payment Callback Request

Example Fixed Payment Code Payment Callback Request

curl --include \
     --request POST \
     --header "Content-Type: application/json" \
     --header "X-CALLBACK-TOKEN: MuaJALKJSDK12LASHD123kSAKSDHzjahwUWjkasJSDSA12KSNAK21n==" \
     --data-binary "{
    fixed_payment_code_payment_id: \"5b61ffc470f7f3470165e7b3\",
    owner_id: \"5b614aa8e79f9214007244d4\",
    fixed_payment_code_id: \"5b61f49e6cc2770f00117f82\",
    payment_id:\"1533149124896\",
    external_id: \"123\",
    payment_code: \"TEST123456\",
    prefix: \"TEST\",
    retail_outlet_name: 'INDOMARET',
    amount: 20000,
    name: 'Joe Contini',
    transaction_timestamp: \"2018-07-31T08:15:03.080Z\",
    updated: \"2016-10-10T08:15:03.404Z\",
    created: \"2016-10-10T08:15:03.404Z\"
}" \
'https://api.xendit.co/fixed_payment_code_paid_callback_url'
Parameter Description
fixed_payment_code_payment_id Unique ID for the fixed payment code payment
owner_id Your user ID
fixed_payment_code_id Unique ID for the fixed payment code
payment_id Our internal system’s payment ID that can be used as payment reference
external_id An ID of your choice which you provided upon fixed payment code creation
payment_code Complete fixed payment code (including prefix). This is what a user will need to tell Retail Outlets cashier
prefix 3-6 characters that differentiate your fixed payment code from the others
retail_outlet_name Name for the relevant Retail Outlets, e.g. ALFAMART or INDOMARET
amount Nominal amount that is paid
name Name for the fixed payment code
transaction_timestamp Date time that the fixed payment code was paid

Fixed Payment Code Callback Errors

Note that in the case where we don't get a successful response from your servers on the first try, we will retry 2 times more with a 30 second delay between each retry. After 3 failures, we get internal alerts that a callback has failed. Our team will then contact you to resolve the issue.

Invoices

Create Invoice

Endpoint: Create Invoice

POST https://api.xendit.co/v2/invoices

Invoices allow you to quickly create a form for users to pay with any of our payment methods. When payment is complete, a callback is made regardless of the payment method used.

Learn more about invoices in our documentation

Create Invoice Request

Example Create Invoice Request

curl https://api.xendit.co/v2/invoices -X POST \
   -u xnd_development_O46JfOtygef9kMNsK+ZPGT+ZZ9b3ooF4w3Dn+R1k+2fT/7GlCAN3jg==: \
   -d external_id=demo_1475801962607 \
   -d payer_email=sample_email@xendit.co \
   -d description='Trip to Bali' \
   -d amount=230000
<?php
  require 'vendor/autoload.php';

  $options['secret_api_key'] = 'xnd_development_P4qDfOss0OCpl8RtKrROHjaQYNCk9dN5lSfk+R1l9Wbe+rSiCwZ3jw==';

  $xenditPHPClient = new XenditClient\XenditPHPClient($options);

  $external_id = 'demo_1475801962607';
  $amount = 230000;
  $payer_email = 'sample_email@xendit.co';
  $description = 'Trip to Bali';

  $response = $xenditPHPClient->createInvoice($external_id, $amount, $payer_email, $description);
  print_r($response);
?>
import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.client.Entity;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.MediaType;

Client client = ClientBuilder.newClient();
Entity payload = Entity.json("{  'external_id': 'invoice_123124123',  'amount': 500000,  'payer_email': 'payer@test.com',  'description': 'Invoice #123124123 for Nike shoes',  'should_exclude_taxes': false,  'should_exclude_fees': false}");
Response response = client.target("https://api.xendit.co/v2/invoices")
  .request(MediaType.APPLICATION_JSON_TYPE)
  .header("Authorization", "Basic eG5kX2RldmVsb3BtZW50X1A0cURmT3NzME9DcGw4UnRLclJPSGphUVlOQ2s5ZE41bFNmaytSMWw5V2JlK3JTaUN3WjNqdz09Og==")
  .post(payload);

System.out.println("status: " + response.getStatus());
System.out.println("headers: " + response.getHeaders());
System.out.println("body:" + response.readEntity(String.class));


Parameter Description
external_id
required
string ID of your choice (typically the unique identifier of an invoice in your system)
payer_email
required
string Email of the end user you're charging
description
required
string Description of the invoice
amount
required
number Amount on the invoice. The minimum amount to create an invoice is 10000.
should_send_email
optional

default: false
boolean Specify should the end user get email when invoice is created, paid, or expired; or not
callback_virtual_account_id
optional
string To allow payment via Fixed Virtual Account, pass in the id field value from the response when the fixed virtual account was created. See Create Fixed Virtual Accounts
invoice_duration
optional
number duration of time that end user have in order to pay the invoice before it's expired (in Second)
success_redirect_url
optional
string url that end user will be redirected to upon successful invoice payment.
example : https://yourcompany.com/example_item/10/success_page
failure_redirect_url
optional
string url that end user will be redirected to upon expiration of this invoice.
example : https://yourcompany.com/example_item/10/failed_checkout
payment_methods
optional
array of strings choices of payment channels that is available in your account. leave this field empty if all payment channel is expected to be available in this particular invoice.
example : ["BCA", "BRI", "MANDIRI", "BNI",
"PERMATA", "ALFAMART", "CREDIT_CARD",
"OVO"]
mid_label
optional
string MID label that you have when you are using credit card payment and have acquiring bank.
currency
optional
string Currency of the amount that you created
example : "IDR"
fixed_va
optional

default: false
boolean Input this parameter as true to enable one VA number for Your end customers.

Create Invoice Response

Example Create Invoice Response

{
  "id": "579c8d61f23fa4ca35e52da4",
  "user_id": "5781d19b2e2385880609791c",
  "external_id": "invoice_123124123",
  "status": "PENDING",
  "merchant_name": "Xendit",
  "merchant_profile_picture_url": "https://xnd-companies.s3.amazonaws.com/prod/1493610897264_473.png",
  "amount": 50000,
  "payer_email": "lanny@xendit.co",
  "description": "This is a description",
  "invoice_url": "https://invoice.xendit.co/web/invoices/595b6248c763ac05592e3eb4",
  "expiry_date": "2016-08-01T11:20:01.017Z",
  "available_banks": [
   {
            "bank_code": "MANDIRI",
            "collection_type": "POOL",
            "bank_account_number": "8860810000525",
            "transfer_amount": 50000,
            "bank_branch": "Virtual Account",
            "account_holder_name": "LANSUR13",
            "identity_amount": 0
        },
        {
            "bank_code": "BRI",
            "collection_type": "POOL",
            "bank_account_number": "2621510002426",
            "transfer_amount": 50000,
            "bank_branch": "Virtual Account",
            "account_holder_name": "LANSUR13",
            "identity_amount": 0
        },
        {
            "bank_code": "BNI",
            "collection_type": "POOL",
            "bank_account_number": "880810000689",
            "transfer_amount": 50000,
            "bank_branch": "Virtual Account",
            "account_holder_name": "LANSUR13",
            "identity_amount": 0
        }
  ],
  "available_retail_outlets": [
      {
          "retail_outlet_name": "ALFAMART",
          "payment_code": "ALFA123456",
          "transfer_amount": 54000
      }
  ],
  "should_exclude_credit_card": false,
  "should_send_email": false,
  "created": "2017-06-12T14:00:00.306Z",
  "updated": "2017-06-12T14:00:00.306Z",
  "mid_label": "test-mid",
  "currency": "IDR",
  "fixed_va":true
}
Parameter Description
id An invoice ID generated by Xendit
user_id Your Xendit Business ID
external_id The invoice ID in your server, that can be used to reconcile between you and Xendit
status PENDING the invoice has yet to be paid
merchant_name The name of your company or website
merchant_profile_picture_url The URL to profile picture of your company
amount Nominal amount for the invoice
payer_email Email of the payer, we get this information from your API call
description Description for the invoice, we get this information from your API call
invoice_url Public URL for this invoice, it’s there in case you want to use our UI
expiry_date ISO date and time that the invoice expires. Default is 24 hours.
available_banks Available payment methods through banks as per your config
bank_code BCA / MANDIRI / BNI / BRI / PERMATA
collection_type POOL type is nonfixed virtual account
bank_account_number Bank account number for users to pay into
transfer_amount Amount the user should transfer
bank_branch Bank account type
account_holder_name Bank account holder name
available_retail_outlets Available payment methods through retail outlet as per your config
retail_outlet_name Name of the retail outlet
payment_code Unique code that you use to pay in retail outlet
transfer_amount Amount the user should transfer
transfer_amount Amount the user should transfer
should_exclude_credit_card A flag showing if credit card should be excluded in invoice UI or not
should_send_email A flag showing should payer get email when invoice is created, paid, or expired; or not
created An ISO timestamp that tracks when the invoice was created
updated An ISO timestamp that tracks when the invoice was updated
mid_label MID label that you have when you are using credit card payment and have acquiring bank. You will get this response when you add this parameter when create invoice through API
currency Currency of the amount that you created. You will get this response when you add this parameter when create invoice through API
fixed_va Input this parameter as true to enable one VA number for Your end customers.

Create Invoice Errors

Error Code Description
API_VALIDATION_ERROR
400
Inputs are failing validation. The errors field contains details about which fields are violating validation.
INVALID_JSON_FORMAT
400
The request body is not a valid JSON format.
MINIMAL_TRANSFER_AMOUNT_ERROR
400
Could not create invoice because amount is below Rp10000.
MAXIMUM_TRANSFER_AMOUNT_ERROR
400
Could not create invoice because amount is above Rp1000000000. If you are configured with Retail Outlets, then amount cannot be more than Rp5000000
NO_COLLECTION_METHODS_ERROR
400
Your account has no payment methods configured (virtual account, credit card). Please contact support and we will set this up for you.
UNAVAILABLE_PAYMENT_METHOD_ERROR
400
The payment method choices did not match with the available one on this business.
REQUEST_FORBIDDEN_ERROR
403
API key in use does not have necessary permissions to perform the request. Please assign proper permissions for the key. Learn more here
UNIQUE_ACCOUNT_NUMBER_UNAVAILABLE_ERROR
404
There is no available virtual account in your non-fixed virtual account range.
CALLBACK_VIRTUAL_ACCOUNT_NOT_FOUND_ERROR
404
Fixed virtual account id that you've specified not found
AVAILABLE_PAYMENT_CODE_NOT_FOUND_ERROR
404
There is no available payment code in your retail outlet range.

Get Invoice

Endpoint: Get an Invoice

GET https://api.xendit.co/v2/invoices/{invoice_id}

Get Invoice Request

Example Get Invoice Request

curl https://api.xendit.co/v2/invoices/{invoice_id} -X GET \
    -u xnd_development_O46JfOtygef9kMNsK+ZPGT+ZZ9b3ooF4w3Dn+R1k+2fT/7GlCAN3jg==:
<?php
  require 'vendor/autoload.php';

  $options['secret_api_key'] = 'xnd_development_P4qDfOss0OCpl8RtKrROHjaQYNCk9dN5lSfk+R1l9Wbe+rSiCwZ3jw==';

  $xenditPHPClient = new XenditClient\XenditPHPClient($options);

  $invoice_id = '587cc7b4863f2b462beb31f6';

  $response = $xenditPHPClient->getInvoice($invoice_id);
  print_r($response);
?>
import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.client.Entity;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.MediaType;

Client client = ClientBuilder.newClient();
Response response = client.target("https://api.xendit.co/v2/invoices/{invoice_id}")
  .request(MediaType.APPLICATION_JSON_TYPE)
  .header("Authorization", "Basic eG5kX2RldmVsb3BtZW50X1A0cURmT3NzME9DcGw4UnRLclJPSGphUVlOQ2s5ZE41bFNmaytSMWw5V2JlK3JTaUN3WjNqdz09Og==")
  .get();

System.out.println("status: " + response.getStatus());
System.out.println("headers: " + response.getHeaders());
System.out.println("body:" + response.readEntity(String.class));
Query Parameter Description
invoice_id
required
string ID of the invoice to retrieve

Get Invoice Response

Example Get Invoice Response

{
  "id": "579c8d61f23fa4ca35e52da4",
  "user_id": "5781d19b2e2385880609791c",
  "external_id": "invoice_123124123",
  "status": "PENDING",
  "merchant_name": "Xendit",
  "merchant_profile_picture_url": "https://xnd-companies.s3.amazonaws.com/prod/1493610897264_473.png",
  "amount": 50000,
  "payer_email": "lanny@xendit.co",
  "description": "This is a description",
  "invoice_url": "https://invoice.xendit.co/web/invoices/595b6248c763ac05592e3eb4",
  "expiry_date": "2016-08-01T11:20:01.017Z",
  "available_banks": [
    {
            "bank_code": "MANDIRI",
            "collection_type": "POOL",
            "bank_account_number": "8860810000525",
            "transfer_amount": 50000,
            "bank_branch": "Virtual Account",
            "account_holder_name": "LANSUR13",
            "identity_amount": 0
        },
        {
            "bank_code": "BRI",
            "collection_type": "POOL",
            "bank_account_number": "2621510002426",
            "transfer_amount": 50000,
            "bank_branch": "Virtual Account",
            "account_holder_name": "LANSUR13",
            "identity_amount": 0
        },
        {
            "bank_code": "BNI",
            "collection_type": "POOL",
            "bank_account_number": "880810000689",
            "transfer_amount": 50000,
            "bank_branch": "Virtual Account",
            "account_holder_name": "LANSUR13",
            "identity_amount": 0
        }
  ],
  "available_retail_outlets": [
      {
          "retail_outlet_name": "ALFAMART",
          "payment_code": "ALFA123456",
          "transfer_amount": 54000
      }
  ],
  "should_exclude_credit_card": false,
  "should_send_email": false,
  "created": "2017-06-12T14:00:00.306Z",
  "updated": "2017-06-12T14:00:00.306Z",
  "mid_label": "test-mid",
  "currency": "IDR",
  "paid_at": "2017-06-13T11:00:00.306Z",
  "credit_card_charge_id": "579c8d61f23fa4ca35e52eas",
  "payment_method": "BANK_TRANSFER",
  "payment_channel": "BCA",
  "payment_destination": "10002233222294375",
  "success_redirect_url": "www.xendit.co",
  "failure_redirect_url": "www.xendit.co",
  "fixed_va":true
}



Parameter Description
id An invoice ID generated by Xendit
user_id Your Xendit Business ID
external_id The invoice ID in your server, that can be used to reconcile between you and Xendit
status PENDING the invoice has yet to be paid
PAID the invoice has successfully been paid
SETTLED the amount of paid invoice has been settled to cash balance
EXPIRED the invoice has been expired
merchant_name The name of your company or website
merchant_profile_picture_url The URL to profile picture of your company
amount Nominal amount for the invoice
payer_email Email of the payer, we get this information from your API call
description Description for the invoice, we get this information from your API call
invoice_url Public URL for this invoice, it’s there in case you want to use our UI
expiry_date ISO date and time that the invoice expires. Default is 24 hours.
available_banks Available payment methods through banks as per your config
bank_code BCA / MANDIRI / BNI / BRI / PERMATA
collection_type POOL type is nonfixed virtual account
bank_account_number Bank account number for users to pay into
transfer_amount Amount the user should transfer
bank_branch Bank account type
account_holder_name Bank account holder name
available_retail_outlets
Available payment methods through retail outlet as per your config
retail_outlet_name Name of the retail outlet
payment_code Unique code that you use to pay in retail outlet
transfer_amount Amount the user should transfer
should_exclude_credit_card

A flag showing if credit card should be excluded in invoice UI or not

should_send_email

A flag showing should payer get email when invoice is created, paid, or expired; or not

updated

An ISO timestamp that tracks when the invoice was updated

created

An ISO timestamp that tracks when the invoice was created

mid_label MID label that you have when you are using credit card payment and have acquiring bank. You will get this response when you add this parameter when create invoice through API
currency Currency of the amount that you created. You will get this response when you add this parameter when create invoice through API
success_redirect_url URL that end user will be redirected to upon successful invoice payment. You will get this response when you add this parameter when create invoice through API
failure_redirect_url URL that end user will be redirected to upon expiration of this invoice. You will get this response when you add this parameter when create invoice through API
paid_at Date time data when your customer pay the invoice. You will get this response when your invoice is paid
credit_card_charge_id Credit card charge ID when your customer pay the invoice with credit card. You will get this response when your invoice is paid with Credit Card
payment_method Payment method that is used when a customer pays the invoice. You will get this response when your invoice is paid
Example : ["BANK_TRANSFER", "CREDIT_CARD", "RETAIL_OUTLET",
"EWALLET"]
payment_channel The payment channel used when a customer pays the invoice. You will get this response when your invoice is paid
Example : ["BCA", "BRI", "MANDIRI",
"BNI", "PERMATA", "ALFAMART",
"OVO", "CREDIT_CARD"]
payment_destination Virtual Account number or Retail Outlet payment code used to pay the invoice (will not be shown for cards and e-wallet payments). You will get this response when your invoice is paid
fixed_va Input this parameter as true to enable one VA number for Your end customers.

Get Invoice Errors

Error Code Description
INVALID_JSON_FORMAT
400
The request body is not a valid JSON format.
REQUEST_FORBIDDEN_ERROR
403
API key in use does not have necessary permissions to perform the request. Please assign proper permissions for the key. Learn more here
INVOICE_NOT_FOUND_ERROR
404
Could not find invoice by id.

Expire Invoice

Endpoint: Expire Invoice

POST https://api.xendit.co/invoices/{invoice_id}/expire!

You can cancel an already created invoice by expiring it immediately using this endpoint.

Note:

  1. Expiring invoice will close available payment methods: Pool Virtual Account, Retail Outlet, and Credit Card, but not Fixed Virtual Account.
  2. Expiring invoice which linked to Fixed Virtual Account will only unlink the Fixed Virtual Account's relation to the invoice, so further payments to this Fixed Virtual Account will be detected as Fixed Virtual Account payment instead of invoice payment. To expire Fixed Virtual Account, change the expiration_date using Update Fixed Virtual Account Endpoint

Expire Invoice Request

Example Expire Invoice Request

curl https://api.xendit.co/invoices/{invoice_id}/expire! -X POST \
   -u xnd_development_O46JfOtygef9kMNsK+ZPGT+ZZ9b3ooF4w3Dn+R1k+2fT/7GlCAN3jg==:
Parameter Description
invoice_id
required
string ID of the invoice to be expired / canceled

Expire Invoice Response

Example Expire Invoice Response

{
  "id": "579c8d61f23fa4ca35e52da4",
  "user_id": "5781d19b2e2385880609791c",
  "external_id": "invoice_123124123",
  "status": "EXPIRED",
  "merchant_name": "Xendit",
  "merchant_profile_picture_url": "https://xnd-companies.s3.amazonaws.com/prod/1493610897264_473.png",
  "amount": 50000,
  "payer_email": "albert@xendit.co",
  "description": "This is a description",
  "invoice_url": "https://invoice.xendit.co/web/invoices/595b6248c763ac05592e3eb4",
  "expiry_date": "2016-08-01T11:20:01.017Z",
  "available_banks": [
    {
      "bank_code": "BCA",
      "collection_type": "POOL",
      "bank_account_number": 1000008,
      "transfer_amount": 54000
    },
    {
      "bank_code": "MANDIRI",
      "collection_type": "POOL",
      "bank_account_number": 1000009,
      "transfer_amount": 54000
    }
  ],
  "available_retail_outlets": [
      {
          "retail_outlet_name": "ALFAMART",
          "payment_code": "ALFA123456",
          "transfer_amount": 54000
      }
  ],
  "should_exclude_credit_card": false,
  "should_send_email": false,
  "created": "2017-06-12T14:00:00.306Z",
  "updated": "2017-06-12T14:00:00.306Z"
}
Parameter Description
id An invoice ID generated by Xendit
user_id Your Xendit Business ID
external_id The invoice ID in your server, that can be used to reconcile between you and Xendit
status EXPIRED the invoice has been expired
merchant_name The name of your company or website
merchant_profile_picture_url The URL to profile picture of your company
amount Nominal amount for the invoice
payer_email Email of the payer, we get this information from your API call
description Description for the invoice, we get this information from your API call
invoice_url Public URL for this invoice, it’s there in case you want to use our UI
expiry_date ISO date and time that the invoice expires. Default is 24 hours.
available_banks Available payment methods through banks as per your config
bank_code BCA / MANDIRI / BNI / BRI / PERMATA
collection_type POOL type is nonfixed virtual account
bank_account_number Bank account number for users to pay into
transfer_amount Amount the user should transfer
bank_branch Bank account type
account_holder_name Bank account holder name
available_retail_outlets
Available payment methods through retail outlet as per your config
retail_outlet_name Name of the retail outlet
payment_code Unique code that you use to pay in retail outlet
transfer_amount Amount the user should transfer
should_exclude_credit_card

A flag showing if credit card should be excluded in invoice UI or not

should_send_email

A flag showing should payer get email when invoice is created, paid, or expired; or not

updated

An ISO timestamp that tracks when the invoice was updated

created

An ISO timestamp that tracks when the invoice was created

Expire Invoice Errors

Error Code Description
INVALID_JSON_FORMAT
400
The request body is not a valid JSON format.
REQUEST_FORBIDDEN_ERROR
403
API key in use does not have necessary permissions to perform the request. Please assign proper permissions for the key. Learn more here
INVOICE_NOT_FOUND_ERROR
404
Could not find invoice by id.

List All Invoices

Endpoint: List Invoice

GET https://api.xendit.co/v2/invoices

You can list all invoices, or list the invoices for a specific updated time. The invoices are returned sorted by updated date, with the most recently updated invoices appearing first.

List Invoice Request

Example List Invoice Request

curl https://api.xendit.co/v2/invoices?limit=3&statuses=["SETTLED","EXPIRED"]&last_invoice_id=5ca186e407f3b83e34176eac&client_types=["DASHBOARD","API_GATEWAY"]&after=2016-02-24T23:48:36.697Z&before=2020-02-24T23:48:36.697Z -X GET \
   -u xnd_development_O46JfOtygef9kMNsK+ZPGT+ZZ9b3ooF4w3Dn+R1k+2fT/7GlCAN3jg==:

Example List Invoice Response

[
    {
        "id": "5c65be6880a55b02867b2b6f",
        "external_id": "627",
        "user_id": "5bbe23e1c901a730130f5b15",
        "status": "EXPIRED",
        "merchant_name": "Your Business Name",
        "merchant_profile_picture_url": "https://xnd-companies.s3.amazonaws.com/prod/1545257692599_408.jpg",
        "amount": 838838,
        "payer_email": "Dudi@xendit.co",
        "description": "Your description1",
        "expiry_date": "2018-02-24T23:48:36.697Z",
        "invoice_url": "https://invoice-staging.xendit.co/web/invoices/5c65be6880a55b02867b2b6f",
        "available_banks": [
            {
                "bank_code": "MANDIRI",
                "collection_type": "POOL",
                "bank_account_number": "8860838034047",
                "transfer_amount": 838838,
                "bank_branch": "Virtual Account",
                "account_holder_name": "YOUR BUSINESS NAME",
                "identity_amount": 0
            },
            {
                "bank_code": "BRI",
                "collection_type": "POOL",
                "bank_account_number": "2621545817176",
                "transfer_amount": 838838,
                "bank_branch": "Virtual Account",
                "account_holder_name": "YOUR BUSINESS NAME",
                "identity_amount": 0
            },
            {
                "bank_code": "BNI",
                "collection_type": "POOL",
                "bank_account_number": "880845676187",
                "transfer_amount": 838838,
                "bank_branch": "Virtual Account",
                "account_holder_name": "YOUR BUSINESS NAME",
                "identity_amount": 0
            }
        ],
        "available_ewallets": [],
        "should_exclude_credit_card": false,
        "should_send_email": false,
        "created": "2018-02-14T23:48:56.907Z",
        "updated": "2018-02-24T23:49:03.296Z"
    },
    {
        "id": "5c6398b710a54b0c867b2b52",
        "external_id": "1242",
        "user_id": "5bbe23e1c901a730130f5b15",
        "status": "SETTLED",
        "merchant_name": "Your Business Name",
        "merchant_profile_picture_url": "https://xnd-companies.s3.amazonaws.com/prod/1545257692599_408.jpg",
        "amount": 67888,
        "paid_amount": 67888,
        "bank_code": "MANDIRI",
        "payer_email": "Budi@xendit.co",
        "description": "Your description2 testing",
        "expiry_date": "2019-02-24T16:34:24.341Z",
        "invoice_url": "https://invoice-staging.xendit.co/web/invoices/5c6398b710a54b0c867b2b52",
        "available_banks": [
            {
                "bank_code": "MANDIRI",
                "collection_type": "POOL",
                "bank_account_number": "8860838033759",
                "transfer_amount": 67888,
                "bank_branch": "Virtual Account",
                "account_holder_name": "YOUR BUSINESS NAME",
                "identity_amount": 0
            },
            {
                "bank_code": "BRI",
                "collection_type": "POOL",
                "bank_account_number": "2621545816888",
                "transfer_amount": 67888,
                "bank_branch": "Virtual Account",
                "account_holder_name": "YOUR BUSINESS NAME",
                "identity_amount": 0
            },
            {
                "bank_code": "BNI",
                "collection_type": "POOL",
                "bank_account_number": "880845675899",
                "transfer_amount": 67888,
                "bank_branch": "Virtual Account",
                "account_holder_name": "YOUR BUSINESS NAME",
                "identity_amount": 0
            }
        ],
        "available_ewallets": [],
        "should_exclude_credit_card": false,
        "adjusted_received_amount": 62938,
        "should_send_email": false,
        "created": "2019-02-14T16:35:03.573Z",
        "updated": "2019-02-22T04:33:14.806Z"
    }
]
Parameter Description
statuses
optional
array of strings Indicates the status of the invoices that will be available in the list.
It contains PENDING, PAID, SETTLED, EXPIRED
limit
optional

default: 10
number A limit on the number of invoice objects to be returned.
Limit can range between 1 and 100.
created_after
optional
string (ISO 8601) Return invoices where the created field is greater than this value
created_before
optional
string (ISO 8601) Return invoices where the created field is less than this value.
both created_after and created_before field should be used in the same time for the filter to take effect
paid_after
optional
string (ISO 8601) Return invoices where the paid_at field is greater than this value
paid_before
optional
string (ISO 8601) Return invoices where the paid_at field is less than this value
both paid_after and paid_before field should be used in the same time for the filter to take effect
expired_after
optional
string (ISO 8601) Return invoices where the expiry_date field is greater than this value
expired_before
optional
string (ISO 8601) Return invoices where the expiry_date field is less than this value
both expired_after and expired_before field should be used in the same time for the filter to take effect
last_invoice_id
optional
string A cursor for use in pagination.
last_invoice_id is an invoice ID that defines your starting point for the list. For instance, if you make a list request and receive 10 objects, starting with obj_bar, your subsequent call can include last_invoice_id=obj_bar in order to fetch the previous page of the list.
client_types
optional
array of strings Indicates the method used to create the invoice. It contains:
API_GATEWAY Invoice created via create invoice API
DASHBOARD Invoice created via dashboard
INTEGRATION Invoice created via 3rd party integration such as Shopify and Woocommerce
ON_DEMAND Invoice created via On Demand
RECURRING Invoice created via Recurring Payment
payment_channels
optional
array of strings Indicates the channels used to pay the invoice.
on_demand_link
optional
string The link for the specific on demand. If you input on_demand_link, it will return invoices that created from that specific on demand link.
recurring_payment_id
optional
string The recurring payment id for specific recurring payment, it will return invoices that created from that specific recurring payment id.

List Invoice Response

List Invoice Response

List invoice response will return array of get invoices response. Please refer get an invoice for more information.

List Invoice Errors

Error Code Description
API_VALIDATION_ERROR
400
Inputs are failing validation. The errors field contains details about which fields are violating validation.
REQUEST_FORBIDDEN_ERROR
403
API key in use does not have necessary permissions to perform the request. Please assign proper permissions for the key. Learn more here

Invoice Callback

Endpoint: Invoice Callback

POST https://yourcompany.com/invoice_callback_url
import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.client.Entity;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.MediaType;

Client client = ClientBuilder.newClient();
Entity payload = Entity.json("{
  adjusted_xendit_fee_amount: 19064,
  adjusted_received_amount: 1980000,
  payment_method: 'POOL',
  bank_code: 'MANDIRI',
  paid_amount: 1999064,
  updated: '2017-06-13T02:32:50.912Z',
  created: '2017-06-13T02:32:49.827Z',
  user_id: '5848fdf860053555135587e7',
  is_high: false,
  external_id: 'testing-invoice',
  merchant_name: 'Xendit',
  amount: 2000000,
  xendit_fee_amount: 20000,
  received_amount: 1980000,
  payer_email: 'test@xendit.co',
  description: 'Invoice callback test',
  status: 'PAID',
  id: '593f4ed1c3d3bb7f39733d83'
}");
Response response = client.target("https://api.xendit.co/invoice_callback_url")
  .request(MediaType.APPLICATION_JSON_TYPE)
  .header("X-CALLBACK-TOKEN", "MuaJALKJSDK12LASHD123kSAKSDHzjahwUWjkasJSDSA12KSNAK21n==")
  .post(payload);

System.out.println("status: " + response.getStatus());
System.out.println("headers: " + response.getHeaders());
System.out.println("body:" + response.readEntity(String.class));

When an invoice is paid, our systems will send a callback to the URL configured in the dashboard. For further instruction about callback please read the invoices documentation

This example is only used to show the body parameters that is sent from Xendit APIs to your callback URL. If you want to test this callback request, use the test feature in dashboard and go to Settings > Developers > Callbacks.

Invoice Callback Request

Example Invoice Callback Request for Payment Through Bank

curl --include \
     --request POST \
     --header "X-CALLBACK-TOKEN: MuaJALKJSDK12LASHD123kSAKSDHzjahwUWjkasJSDSA12KSNAK21n==" \
     --header "Content-Type: application/json" \
     --data-binary "{
      id: \"593f4ed1c3d3bb7f39733d83\",
      external_id: \"testing-invoice\",
      user_id: \"5848fdf860053555135587e7\",
      is_high: false,
      payment_method: \"BANK_TRANSFER\",
      status: \"PAID\",
      merchant_name: \"Xendit\",
      amount: 2000000,
      paid_amount: 2000000,
      bank_code: \"MANDIRI\",
      paid_at: \"2017-06-14T02:32:50.912Z\",
      payer_email: \"test@xendit.co\",
      description: \"Invoice callback test\",
      adjusted_received_amount: 1995000,
      fees_paid_amount: 5000,
      created: \"2017-06-13T02:32:49.827Z\",
      updated: \"2017-06-13T02:32:50.912Z\",
      currency: \"IDR\",
      payment_channel: \"MANDIRI\",
      payment_destination: \"8458478548758748\",
}" \
'{{your_company_domain}}/{{callback_url}}'

Example Invoice Callback Request for Payment Through Retail Outlet

curl --include \
     --request POST \
     --header "X-CALLBACK-TOKEN: MuaJALKJSDK12LASHD123kSAKSDHzjahwUWjkasJSDSA12KSNAK21n==" \
     --header "Content-Type: application/json" \
     --data-binary "{
      id: \"593f4ed1c3d3bb7f39733d83\",
      external_id: \"testing-invoice\",
      user_id: \"5848fdf860053555135587e7\",
      is_high: false,
      payment_method: \"RETAIL_OUTLET\",
      status: \"PAID\",
      merchant_name: \"Xendit\",
      amount: 2000000,
      paid_amount: 2000000,
      paid_at: \"2017-06-14T02:32:50.912Z\",
      payer_email: \"test@xendit.co\",
      description: \"Invoice callback test\",
      adjusted_received_amount: 1995000,
      fees_paid_amount: 5000,
      created: \"2017-06-13T02:32:49.827Z\",
      updated: \"2017-06-13T02:32:50.912Z\",
      currency: \"IDR\",
      payment_channel: \"ALFAMART\",
      payment_destination: \"TEST815\",
}" \
'{{your_company_domain}}/{{callback_url}}'



Parameter Description
id An invoice ID generated by Xendit
user_id Your Xendit Business ID
external_id The invoice ID in your server, that can be used to reconcile between you and Xendit
is_high Should unique numbers go above or below the amount.
merchant_name The name of your company or website
amount Nominal amount for the invoice (without taxes, fees)
status PAID the invoice has successfully been paid
EXPIRED the invoice has expired. Expired invoice callbacks are not enabled by default - if you want to enable it for your business, you can do so in your Xendit Dashboard
payer_email Email of the payer, we get this information from your API call
description Description for the invoice, we get this information from your API call
fees_paid_amount Xendit fees that was directly paid from this invoice - thanks for supporting a better world of payments :)
adjusted_received_amount Amount attributable to you net of our fees.
bank_code
only if payment_method is POOL
Code of the bank used to received the money only if payment method is POOL
e.g. MANDIRI
retail_outlet_name
only if payment_method is RETAIL_OUTLET
Code of the retail outlet used to received the money only if payment method is RETAIL_OUTLET
e.g. ALFAMART
ewallet_type
only if payment_method is EWALLET
Code of the e-wallet used to received the money only if payment method is EWALLET
e.g. OVO
on_demand_link
only for invoices from ondemand
Link of the ondemand that created this invoice
recurring_payment_id
only for invoices from recurring
ID of the recurring that created this invoice
paid_amount Total amount paid for the invoice
updated An ISO timestamp that tracks when the invoice was updated
created An ISO timestamp that tracks when the invoice was created
mid_label MID label that you have when you are using credit card payment and have acquiring bank. You will get this response when you add this parameter when create invoice through API
currency Currency of the amount that you created. You will get this response when you add this parameter when create invoice through API
success_redirect_url URL that end user will be redirected to upon successful invoice payment. You will get this response when you add this parameter when create invoice through API
failure_redirect_url URL that end user will be redirected to upon expiration of this invoice. You will get this response when you add this parameter when create invoice through API
paid_at Date time data when your customer pay the invoice. You will get this response when your invoice is paid
credit_card_charge_id Credit card charge ID when your customer pay the invoice with credit card. You will get this response when your invoice is paid with Credit Card
payment_method Payment method that is used when a customer pays the invoice. You will get this response when your invoice is paid
Example : ["BANK_TRANSFER", "CREDIT_CARD", "RETAIL_OUTLET",
"EWALLET"]
payment_channel The payment channel used when a customer pays the invoice. You will get this response when your invoice is paid
Example : ["BCA", "BRI", "MANDIRI",
"BNI", "PERMATA", "ALFAMART",
"OVO", "CREDIT_CARD"]
payment_destination Virtual Account number or Retail Outlet payment code used to pay the invoice (will not be shown for cards and e-wallet payments). You will get this response when your invoice is paid

Invoice Callback Errors

Note that in the case where we don't get a successful response from your servers on the first try, we will retry 2 times more with a 30 second delay between each retry. After 3 failures, we get internal alerts that a callback has failed. Our team will then contact you to resolve the issue.

Recurring Payments

Create a Recurring Payment

Endpoint: Create Recurring Payment

POST https://api.xendit.co/recurring_payments

Recurring payments allow you to automatically bill your customers using our system.

Create Recurring Request

Example: Create Recurring Request

curl https://api.xendit.co/recurring_payments -X POST \
   -u xnd_development_O46JfOtygef9kMNsK+ZPGT+ZZ9b3ooF4w3Dn+R1k+2fT/7GlCAN3jg==: \
   -d external_id=recurring_31451441 \
   -d payer_email=sample_email@xendit.co \
   -d interval=MONTH \
   -d interval_count=1 \
   -d description='Monthly room cleaning service' \
   -d amount=125000
<?php
  require 'vendor/autoload.php';

  $options['secret_api_key'] = 'xnd_development_P4qDfOss0OCpl8RtKrROHjaQYNCk9dN5lSfk+R1l9Wbe+rSiCwZ3jw==';

  $xenditPHPClient = new XenditClient\XenditPHPClient($options);

  $external_id = 'recurring_31451441';
  $amount = 125000;
  $payer_email = 'sample_email@xendit.co';
  $interval = 'MONTH';
  $interval_count = 1;
  $description = 'Monthly room cleaning service';

  $response = $xenditPHPClient->createRecurringPayment($external_id, $amount, $payer_email, $interval, $interval_count, $description);
  print_r($response);
?>
Parameter Description
external_id
required
string ID of your choice (typically the unique identifier of a recurring payment in your system)
payer_email
required
string Email of the end user you're charging
description
required
string Description for the recurring payment and invoices
amount
required
number Amount per invoice per interval.
The minimum amount to create an invoice is 10.000 IDR. The maximum amount is 1.000.000.000 IDR
interval
required
string One of DAY, WEEK, MONTH. The frequency with which a recurring payment invoice should be billed.
interval_count
required
number The number of intervals (specified in the interval property) between recurring. For example, interval=MONTH and interval_count=3 bills every 3 months.
total_recurrence
optional
number The number of times you will charge your customer. If you input it as 3, Xendit will charge your customer 3 times. If you input total_recurrence as 3, interval_count as 1 and interval as "DAY", Xendit will charge customer 3 times in first day after you trigger create recurring api, the day after and 2 days after you trigger create recurring api.
invoice_duration
optional
number duration of time that end user have in order to pay the invoice before it's expired (in Second). If it's not filled, invoice_duration will follow your business default invoice duration.

invoice_duration should and will always be less than the interval-interval_count combination.
should_send_email
optional

default: false
boolean Specify should the end user get email when invoice is created, paid, or expired; or not
missed_payment_action
optional

default: IGNORE
string One of IGNORE, STOP. If there is an invoice from a recurring payment that expired, IGNORE will continue with the recurring payment as usual. STOP will stop the recurring payment.
credit_card_token
optional
string Token ID for credit card autocharge. If it's empty then the autocharge is disabled. This token must be multiple use (is_multiple_use is true). please refer create cards token on how to create multi-use token. The token will still be there even if it's failed to charge.
start_date
optional
string (ISO 8601) time when the first invoice will be issued. When left blank, the invoice will be created immediately
success_redirect_url
optional
string url that end user will be redirected to upon successful payment to invoice created by this recurring payment.
example : https://yourcompany.com/example_item/10/success_page
failure_redirect_url
optional
string url that end user will be redirected to upon expireation of invoice created by this recurring payment.
example : https://yourcompany.com/example_item/10/failed_checkout
recharge
optional
default: true
boolean Input this parameter as true when you want to enable auto-charged and capture card information through XenInvoice.
charge_immediately
optional

boolean Specify should the first invoice created immediately when creating recurring payment with a valid start_date,
The next invoice will be created at start_date and the calculation for the following recurring invoice will be at
interval*interval_count + start_date

Create Recurring Response

Example: Create Recurring Response

{
    "id": "579c8d61f23fa4ca35e52da3",
    "user_id": "5781d19b2e2385880609791c",
    "external_id": "recurring_31451441",
    "status": "ACTIVE",
    "amount": 125000,
    "payer_email": "sample_email@xendit.co",
    "description": "Monthly room cleaning service",
    "interval": "MONTH",
    "interval_count": 1,
    "recurrence_progress": 1,
    "should_send_email": false,
    "missed_payment_action": "IGNORE",
    "last_created_invoice_url": "https://invoice-staging.xendit.co/web/invoices/5dddeea6bdb99f4b23e5eef7",
    "created": "2017-06-12T14:00:00.306Z",
    "updated": "2017-06-12T14:00:00.306Z",
    "start_date": "2017-07-12T14:00:00.306Z",
    "recharge": true
}
Parameter Description
id An recurring ID generated by Xendit
user_id Your Xendit Business ID
external_id The recurring ID in your server, that can be used to reconcile between you and Xendit
status ACTIVE the recurring payment is currently active
STOPPED the recurring payment has been stopped
PAUSED the recurring payment is currently paused and will not automatically creating invoices. resume to reactivate
amount Nominal amount of the recurring payment in IDR
payer_email Email of the payer, we get this information from your API call
description Description for the recurring payment and invoices
should_send_email A flag showing should payer get email when invoice is created, paid, or expired; or not
interval One of DAY, WEEK, MONTH. The frequency with which a recurring payment invoice should be billed.
interval_count The number of intervals (specified in the interval property) between recurring. For example, interval=MONTH and interval_count=3 bills every 3 months.
total_recurrence The number of times you will charge your customer. If you input it as 3, Xendit will charge your customer 3 times. If you input total_recurrence as 3, interval_count as 1 and interval as "DAY", Xendit will charge customer 3 times in first day after you trigger create recurring api, the day after and 2 days after you trigger create recurring api.
recurrence_progress The current cycle of recurring payment. If your end customer is on the 4th cycle of the recurring, you will get 4 from recurrence_progress response
last_created_invoice_url url leading to the last invoice create by this recurring payment
credit_card_token Token ID for credit card autocharge. If it's empty then the autocharge is disabled. This token must be multiple use (is_multiple_use is true). please refer create cards token on how to create multi-use token. The token will still be there even if it's failed to charge.
success_redirect_url
optional
string url that end user will be redirected to upon successful payment to invoice created by this recurring payment.
example : https://yourcompany.com/example_item/10/success_page
failure_redirect_url
optional
string url that end user will be redirected to upon expireation of invoice created by this recurring payment.
example : https://yourcompany.com/example_item/10/failed_checkout
invoice_duration
optional
number duration of time that end user have in order to pay the invoice before it's expired (in Second).

invoice_duration should and will always be less than the interval-interval_count combination.
created An ISO timestamp that tracks when the recurring payment was created
updated An ISO timestamp that tracks when the recurring payment was updated
charge_immediately
optional

boolean A flag showing should the first invoice created immediately when creating recurring payment with a valid start_date
recharge When this parameter is true, it means you want to enable auto-charged and capture card information through XenInvoice.

Create Recurring Payment Errors

Error Code Description
API_VALIDATION_ERROR
400
Inputs are failing validation. The errors field contains details about which fields are violating validation.
INVALID_JSON_FORMAT
400
The request body is not a valid JSON format.
INVALID_CREDIT_CARD_TOKEN_ERROR
400
Credit Card token is invalid.
REQUEST_FORBIDDEN_ERROR
403
API key in use does not have necessary permissions to perform the request. Please assign proper permissions for the key. Learn more here

Get a Recurring Payment

Endpoint: Get a Recurring Payment

GET https://api.xendit.co/recurring_payments/{id}

Get Recurring Payment Request

Example Get Recurring Payment Request

curl https://api.xendit.co/recurring_payments/{id} \
  -X GET \
  -u xnd_development_O46JfOtygef9kMNsK+ZPGT+ZZ9b3ooF4w3Dn+R1k+2fT/7GlCAN3jg==:
Parameter Description
id
required
string ID of the recurring payment to retrieve

Get Recurring Response

Example Get Recurring Payment Response

{
    "id": "579c8d61f23fa4ca35e52da3",
    "user_id": "5781d19b2e2385880609791c",
    "external_id": "recurring_31451441",
    "status": "ACTIVE",
    "amount": 125000,
    "payer_email": "sample_email@xendit.co",
    "description": "Monthly room cleaning service",
    "interval": "MONTH",
    "interval_count": 1,
    "recurrence_progress": 1,
    "should_send_email": true,
    "missed_payment_action": "IGNORE",
    "last_created_invoice_url": "https://invoice-staging.xendit.co/web/invoices/5dddeea6bdb99f4b23e5eef7",
    "created": "2017-06-12T14:00:00.306Z",
    "updated": "2018-06-12T14:00:00.306Z",
    "start_date": "2017-07-12T14:00:00.306Z",
    "recharge":true
}
Parameter Description
id An recurring ID generated by Xendit
user_id Your Xendit Business ID
external_id The recurring ID in your server, that can be used to reconcile between you and Xendit
status ACTIVE the recurring payment is currently active
STOPPED the recurring payment has been stopped
PAUSED the recurring payment is currently paused and will not automatically creating invoices. resume to reactivate
amount Nominal amount of the recurring payment
payer_email Email of the payer, we get this information from your API call
description Description for the recurring payment and invoices
should_send_email A flag showing should payer get email when invoice is created, paid, or expired; or not
interval One of DAY, WEEK, MONTH. The frequency with which a recurring payment invoice should be billed.
interval_count number The number of intervals (specified in the interval property) between recurring. For example, interval=MONTH and interval_count=3 bills every 3 months.
total_recurrence The number of times you will charge your customer. If you input it as 3, Xendit will charge your customer 3 times. If you input total_recurrence as 3, interval_count as 1 and interval as "DAY", Xendit will charge customer 3 times in first day after you trigger create recurring api, the day after and 2 days after you trigger create recurring api.
recurrence_progress The current cycle of recurring payment. If your end customer is on the 4th cycle of the recurring, you will get 4 from recurrence_progress response
last_created_invoice_url url leading to the last invoice create by this recurring payment
credit_card_token Token ID for credit card autocharge. If it's empty then the autocharge is disabled. This token must be multiple use (is_multiple_use is true). please refer invoice callback on how to create multi-use token. The token will still be there even if it's failed to charge.
success_redirect_url
optional
string url that end user will be redirected to upon successful payment to invoice created by this recurring payment.
example : https://yourcompany.com/example_item/10/success_page
failure_redirect_url
optional
string url that end user will be redirected to upon expireation of invoice created by this recurring payment.
example : https://yourcompany.com/example_item/10/failed_checkout
invoice_duration
optional
number duration of time that end user have in order to pay the invoice before it's expired (in Second).
created An ISO timestamp that tracks when the recurring payment was created
updated An ISO timestamp that tracks when the recurring payment was updated
charge_immediately
optional

boolean A flag showing should the first invoice created immediately when creating recurring payment with a valid start_date
recharge When this parameter is true, it means you want to enable auto-charged and capture card information through XenInvoice.

Get Recurring Payment Errors

Error Code Description
REQUEST_FORBIDDEN_ERROR
403
API key in use does not have necessary permissions to perform the request. Please assign proper permissions for the key. Learn more here
NOT_FOUND_ERROR
404
Could not find recurring by id.

Edit Recurring Payment

Endpoint: Edit Recurring Payment

PATCH https://api.xendit.co/recurring_payments/{id}

Edit Recurring Payment Request

Example: Edit Recurring Payment Request

curl https://api.xendit.co/recurring_payments/579c8d61f23fa4ca35e52da3 \
   -X PATCH \
   -u xnd_development_O46JfOtygef9kMNsK+ZPGT+ZZ9b3ooF4w3Dn+R1k+2fT/7GlCAN3jg==: \
   -d amount=80000 \
   -d interval=WEEK \
   -d interval_count=2 \
   -d should_send_email=true \
   -d missed_payment_action=STOP \
   -d credit_card_token=522f0ba2ab70de5d2b409eee \
Parameter Description
id
required
string id of recurring you want to update
amount
optional
number Edit amount per invoice per interval.
The minimum amount to create an invoice is 10.000 IDR. The maximum amount is 1.000.000.000 IDR
credit_card_token
optional
string Multi use token ID for credit card autocharge. If it's empty then the autocharge is disabled. The token will still be there even if it's failed to charge
interval
optional
string Edit the frequency with which a recurring payment invoice should be billed. One of DAY, WEEK, MONTH.
interval_count
optional
number Edit the number of intervals (specified in the interval property) between recurring. For example, interval=MONTH and interval_count=3 bills every 3 months.
should_send_email
optional
boolean Edit whether the end user get email when invoice is created, paid, or expired; or not
invoice_duration
optional
number duration of time that end user have in order to pay the invoice before it's expired (in Second). If it's not filled, invoice_duration will follow your business default invoice duration.

invoice_duration should and will always be less than the interval-interval_count combination.
missed_payment_action
optional
string Edit action if there is an invoice from a recurring payment that expired, IGNORE will continue with the recurring payment as usual. STOP will stop the recurring payment.

Edit Recurring Payment Response

Example: Edit Recurring Payment Response

{
    "id": "579c8d61f23fa4ca35e52da3",
    "user_id": "5781d19b2e2385880609791c",
    "external_id": "recurring_31451441",
    "status": "ACTIVE",
    "amount": 80000,
    "payer_email": "sample_email@xendit.co",
    "description": "Monthly room cleaning service",
    "interval": "WEEK",
    "interval_count": 2,
    "recurrence_progress": 1,
    "should_send_email": true,
    "recharge": true,
    "missed_payment_action": "STOP",
    "created": "2017-06-12T14:00:00.306Z",
    "updated": "2017-06-12T14:00:00.306Z",
    "start_date": "2017-06-19T14:00:00.306Z"
}

All response parameters will be the same as get recurring

Edit Recurring Payment Errors

Error Code Description
NOT_FOUND_ERROR
404
Could not find recurring by id.
API_VALIDATION_ERROR
400
Inputs are failing validation. The errors field contains details about which fields are violating validation.
INVALID_JSON_FORMAT
400
The request body is not a valid JSON format.
INVALID_CREDIT_CARD_TOKEN_ERROR
400
Credit card token is invalid.
REQUEST_FORBIDDEN_ERROR
403
API key in use does not have necessary permissions to perform the request. Please assign proper permissions for the key. Learn more here

Stop Recurring Payment

Endpoint: Stop Recurring

POST https://api.xendit.co/recurring_payments/{id}/stop!

Stop Recurring Payment Request

Example: Stop Recurring Payment Request

curl https://api.xendit.co/recurring_payments/{id}/stop! -X POST \
    -u xnd_development_O46JfOtygef9kMNsK+ZPGT+ZZ9b3ooF4w3Dn+R1k+2fT/7GlCAN3jg==:
<?php
  require 'vendor/autoload.php';

  $options['secret_api_key'] = 'xnd_development_P4qDfOss0OCpl8RtKrROHjaQYNCk9dN5lSfk+R1l9Wbe+rSiCwZ3jw==';

  $xenditPHPClient = new XenditClient\XenditPHPClient($options);

  $id = '579c8d61f23fa4ca35e52da3';

  $response = $xenditPHPClient->stopRecurring($id);
  print_r($response);
?>
Parameter Description
id
required
string ID of the recurring payment to stop

Stop Recurring Response

Example: Stop Recurring Payment Response

{
    "id": "579c8d61f23fa4ca35e52da3",
    "user_id": "5781d19b2e2385880609791c",
    "external_id": "recurring_31451441",
    "status": "STOPPED",
    "amount": 125000,
    "payer_email": "sample_email@xendit.co",
    "description": "Monthly room cleaning service",
    "interval": "MONTH",
    "interval_count": 1,
    "recurrence_progress": 1,
    "should_send_email": true,
    "missed_payment_action": "IGNORE",
    "recharge": true,
    "created": "2017-06-12T14:00:00.306Z",
    "updated": "2018-06-12T14:00:00.306Z",
    "start_date": "2017-07-12T14:00:00.306Z"
}

All response parameters will be the same as get recurring

Stop Recurring Payment Errors

Error Code Description
REQUEST_FORBIDDEN_ERROR
403
API key in use does not have necessary permissions to perform the request. Please assign proper permissions for the key. Learn more here
NOT_FOUND_ERROR
404
Could not find recurring by id.

Pause Recurring Payment

Endpoint: Pause Recurring Payment

POST https://api.xendit.co/recurring_payments/{id}/pause!

Pause Recurring Payment Request

Example Pause Recurring Payment Request

curl https://api.xendit.co/recurring_payments/{id}/pause!
  -X POST \
  -u xnd_development_O46JfOtygef9kMNsK+ZPGT+ZZ9b3ooF4w3Dn+R1k+2fT/7GlCAN3jg==:
Parameter Description
id
required
string ID of the recurring payment to pause

Pause Recurring Payment Response

Example Pause Recurring Response

{
    "id": "579c8d61f23fa4ca35e52da3",
    "user_id": "5781d19b2e2385880609791c",
    "external_id": "recurring_31451441",
    "status": "PAUSED",
    "amount": 125000,
    "payer_email": "sample_email@xendit.co",
    "description": "Monthly room cleaning service",
    "interval": "MONTH",
    "interval_count": 1,
    "recurrence_progress": 1,
    "should_send_email": true,
    "recharge": true,
    "missed_payment_action": "IGNORE",
    "created": "2017-06-12T14:00:00.306Z",
    "updated": "2018-06-12T14:00:00.306Z",
    "start_date": "2017-07-12T14:00:00.306Z"
}

All response parameters will be the same as get recurring

Pause Recurring Payment Errors

Error Code Description
REQUEST_FORBIDDEN_ERROR
403
API key in use does not have necessary permissions to perform the request. Please assign proper permissions for the key. Learn more here
NOT_FOUND_ERROR
404
Could not find recurring by id.

Resume Recurring Payment

Endpoint: Resume Recurring

POST https://api.xendit.co/recurring_payments/{id}/resume!

Resume Recurring Request

Example Resume Recurring Request

curl https://api.xendit.co/recurring_payments/{id}/resume!
  -X POST \
  -u xnd_development_O46JfOtygef9kMNsK+ZPGT+ZZ9b3ooF4w3Dn+R1k+2fT/7GlCAN3jg==:
Parameter Description
id
required
string ID of the recurring payment to resume

Resume Recurring Response

Example Resume Recurring Response

{
    "id": "579c8d61f23fa4ca35e52da3",
    "user_id": "5781d19b2e2385880609791c",
    "external_id": "recurring_31451441",
    "status": "ACTIVE",
    "amount": 125000,
    "payer_email": "sample_email@xendit.co",
    "description": "Monthly room cleaning service",
    "interval": "MONTH",
    "interval_count": 1,
    "recurrence_progress": 1,
    "should_send_email": true,
    "missed_payment_action": "IGNORE",
    "recharge": true,
    "created": "2017-06-12T14:00:00.306Z",
    "updated": "2018-06-12T14:00:00.306Z",
    "start_date": "2017-07-12T14:00:00.306Z"
}

All response parameters will be the same as get recurring

Resume Recurring Payment Errors

Error Code Description
REQUEST_FORBIDDEN_ERROR
403
API key in use does not have necessary permissions to perform the request. Please assign proper permissions for the key. Learn more here
NOT_FOUND_ERROR
404
Could not find recurring by id.

Recurring Callback

Xendit will notify you of all Recurring Payment Invoice activity via the usual invoice callback. Please visit invoice callback to get more information about setting up your callback URL and getting invoice callbacks.

Additional parameters from invoice callback if you are using recurring payments:

Parameter Description
recurring_payment_id string ID of the recurring payment for this invoice




Get List of Payments

Getting list of the payments can be done by searching invoices with certain recurring_payment_id and it can be done using List all invoices.

Additional parameters from listing all invoice if you are using recurring payments:

Get List of Payments Request

Parameter Description
recurring_payment_id string ID of the recurring payment for this invoice















Payouts

Easily send funds to customers with our payouts UI, allowing them to choose their payout destination.

Create Payout

Endpoint: Create Payouts

POST https://api.xendit.co/payouts

Create Payout Request

Example Create Payout Request

curl https://api.xendit.co/payouts -X POST \
-u xnd_development_O46JfOtygef9kMNsK+ZPGT+ZZ9b3ooF4w3Dn+R1k+2fT/7GlCAN3jg==: \
-d external_id=demo_2392329329 \
-d amount=23000
Parameter Description
external_id
required
string ID of your choice (typically the unique identifier of a payout in your system).

Maximum: 200 characters
amount
required
integer positive Amount to be paid out. The maximum amount depends on your balance.

Create Payout Response

Example Create Payout Response

{
  "id": "67f1b30c-0262-4955-8777-95aa0478c2fc",
  "external_id": "demo_2392329329",
  "amount": 23000,
  "passcode": "827995",
  "merchant_name": "First Business",
  "status": "ISSUED",
  "expiration_timestamp": "2019-12-10T06:13:21.637Z",
  "created": "2019-12-09T06:13:20.363Z",
  "payout_url": "https://payout.xendit.co/web/67f1b30c-0262-4955-8777-95aa0478c2fc"
}
Parameter Description
id
required
string A payout ID generated by Xendit
external_id
required
string The payout ID in your server, that can be used to reconcile between you and Xendit.

Maximum: 200 characters
amount
required
integer positive Amount to be paid out. The maximum amount depends on your balance.
passcode
required
string Randomly-generated passcode to be used to claim the amount.
merchant_name
optional
string The name of your company or website.
status
required
ISSUED string The payout has been issued (first status when successfully created a payout).
DISBURSING string The payout is being disbursed. The amount of the payout is disbursing from your balance into destination account's balance.
VOIDED string The payout has been voided. This issue is raised because the payout has been expired or manually voided by hitting the void endpoint.
LOCKED string The payout has been locked due to too many (3) failed attempts.
COMPLETED string The payout has completed.
FAILED string The payout has failed. The list of failures are described in the failure_reason field.
expiration_timestamp
optional
ISO8601 An ISO timestamp that the payout expires. Default is 24 hours after creation.

Timezone: GMT+0
created
optional
ISO8601 An ISO timestamp that tracks when the payout was created.

Timezone: GMT+0
payout_url
optional
stringPublic URL for this payout, in case you want to use our UI.
email
optional
stringAn email you're sending notification to.
bank_code
optional
stringBank code for the relevant bank, learn more here
account_holder_name
optional
stringBank account holder name.
account_number
optional
string Bank account number.
disbursement_id
optional
string ID of the disbursement. You can find out here
failure_reason
optional
string If the status is FAILED, this describes the failure.
claimed_timestamp
optional
ISO8601 An ISO timestamp that tracks when the payout was claimed.

Timezone: GMT+0
completed_timestamp
optional
ISO8601 An ISO timestamp that tracks when the payout was completed.

Timezone: GMT+0
failed_timestamp
optional
ISO8601 An ISO timestamp that tracks when the payout was failed.

Timezone: GMT+0
payment_id
optional
string Our internal system’s payment ID that can be used as payment reference.

Create Payout Failure Reason

Error Code Description
INSUFFICIENT_BALANCE
400
The balance in your account is insufficient to make the payout in the desired amount.
DUPLICATE_PAYOUT_ERROR
400
The payout with the same external_id has already been made before.
UNAUTHORIZED_MERCHANT_ERROR
403
This merchant is not authorized to perform this request.

Get Payout

Endpoint: Get a Payout

GET https://api.xendit.co/payouts/:id

Get Payout Request

Example Get Payout Request

curl https://api.xendit.co/payouts/:id -X GET \
    -u xnd_development_O46JfOtygef9kMNsK+ZPGT+ZZ9b3ooF4w3Dn+R1k+2fT/7GlCAN3jg==:
Parameter Description
id
required
string ID of the payout to retrieve

Get Payout Response

Example Get Payout Response

{
  "id": "00754a09-ad00-4475-b874-1dd97f83fc24",
  "external_id": "ext-121313",
  "amount": 20000,
  "passcode": "315820",
  "merchant_name": "First Business",
  "status": "ISSUED",
  "expiration_timestamp": "2019-12-10T06:45:30.041Z",
  "created": "2019-12-09T06:45:28.628Z",
  "payout_url": "https://payout.xendit.co/web/00754a09-ad00-4475-b874-1dd97f83fc24"
}
Parameter Description
id
required
string A payout ID generated by Xendit
external_id
required
string The payout ID in your server, that can be used to reconcile between you and Xendit.

Maximum: 200 characters
amount
required
integer positive Amount to be paid out. The maximum amount depends on your balance.
passcode
required
string Randomly-generated passcode to be used to claim the amount.
merchant_name
optional
string The name of your company or website.
status
required
ISSUED string The payout has been issued (first status when successfully created a payout).
DISBURSING string The payout is being disbursed. The amount of the payout is disbursing from your balance into destination account's balance.
VOIDED string The payout has been voided. This issue is raised because the payout has been expired or manually voided by hitting the void endpoint.
LOCKED string The payout has been locked due to too many (3) failed attempts.
COMPLETED string The payout has completed.
FAILED string The payout has failed. The list of failures are described in the failure_reason field.
expiration_timestamp
optional
ISO8601 An ISO timestamp that the payout expires. Default is 24 hours after creation.

Timezone: GMT+0
created
optional

ISO8601 An ISO timestamp that tracks when the payout was created.

Timezone: GMT+0

payout_url
optional
string Public URL for this payout, in case you want to use our UI.
email
optional
string[] An email you're sending notification to.
bank_code
optional
stringBank code for the relevant bank, learn more here
account_holder_name
optional
string Bank account holder name.
account_number
optional
string Bank account number.
disbursement_id
optional
string ID of the disbursement. You can find out here
failure_reason
optional
string If the status is FAILED, this describes the failure.
claimed_timestamp
optional
ISO8601 An ISO timestamp that tracks when the payout was claimed.

Timezone: GMT+0
completed_timestamp
optional
ISO8601 An ISO timestamp that tracks when the payout was completed.

Timezone: GMT+0
failed_timestamp
optional
ISO8601 An ISO timestamp that tracks when the payout was failed.

Timezone: GMT+0
payment_id
optional
string Our internal system’s payment ID that can be used as payment reference.

Get Payout Failure Reason

Error Code Description
PAYOUT_NOT_FOUND_ERROR
404
The payout was not found in the system.
UNAUTHORIZED_MERCHANT_ERROR
403
This merchant is not authorized to perform this request.

Void a Payout

Endpoint: Void a Payout

POST https://api.xendit.co/payouts/:id/void

You can cancel an issued payout by voiding it using this endpoint.

Void Payout Request

Example Void Payout Request

curl https://api.xendit.co/payouts/:id/void -X POST \
    -u xnd_development_O46JfOtygef9kMNsK+ZPGT+ZZ9b3ooF4w3Dn+R1k+2fT/7GlCAN3jg==:
Parameter Description
id
required
string ID of the payout to retrieve

Void Payout Response

Example Void Payout Response

{
  "id": "00754a09-ad00-4475-b874-1dd97f83fc24",
  "external_id": "ext-121312",
  "amount": 20000,
  "passcode": "315820",
  "merchant_name": "First Business",
  "status": "VOIDED",
  "expiration_timestamp": "2019-12-10T06:45:30.041Z",
  "created": "2019-12-09T06:45:28.628Z"
}
Parameter Description
id
required
string A payout ID generated by Xendit
external_id
required
string The payout ID in your server, that can be used to reconcile between you and Xendit.

Maximum: 200 characters
amount
required
integer positive Amount to be paid out. The maximum amount depends on your balance.
passcode
required
string Randomly-generated passcode to be used to claim the amount.
merchant_name
optional
string The name of your company or website.
status
required
ISSUED string The payout has been issued (first status when successfully created a payout).
DISBURSING string The payout is being disbursed. The amount of the payout is disbursing from your balance into destination account's balance.
VOIDED string The payout has been voided. This issue is raised because the payout has been expired or manually voided by hitting the void endpoint.
LOCKED string The payout has been locked due to too many (3) failed attempts.
COMPLETED string The payout has completed.
FAILED string The payout has failed. The list of failures are described in the failure_reason field.
expiration_timestamp
optional
ISO8601 An ISO timestamp that the payout expires. Default is 24 hours after creation.

Timezone: GMT+0
created
optional
ISO8601 An ISO timestamp that tracks when the payout was created.

Timezone: GMT+0
payout_url
optional
string Public URL for this payout, in case you want to use our UI.
email
optional
string[] An email you're sending notification to.
bank_code
optional
string Bank code for the relevant bank, learn more here
account_holder_name
optional
string Bank account holder name.
account_number
optional
string Bank account number.
disbursement_id
optional
string ID of the disbursement. You can find out here
failure_reason
optional
string If the status is FAILED, this describes the failure.
claimed_timestamp
optional
ISO8601 An ISO timestamp that tracks when the payout was claimed.

Timezone: GMT+0
completed_timestamp
optional
ISO8601 An ISO timestamp that tracks when the payout was completed.

Timezone: GMT+0
failed_timestamp
optional
ISO8601 An ISO timestamp that tracks when the payout was failed.

Timezone: GMT+0
payment_id
optional
string Our internal system’s payment ID that can be used as payment reference.

Void Payout Failure Reason

Error Code Description
PAYOUT_NOT_FOUND_ERROR
404
The payout was not found in the system.
UNAUTHORIZED_MERCHANT_ERROR
403
This merchant is not authorized to perform this request.

Disbursements

Disbursements allow you to instruct Xendit to instantly send money to any bank account across Indonesia on your behalf.

Create Disbursement

Endpoint: Create Disbursement

POST https://api.xendit.co/disbursements

Create Disbursement Request

Example Create Disbursement Request

<?php
  require 'vendor/autoload.php';

  $options['secret_api_key'] = 'xnd_development_P4qDfOss0OCpl8RtKrROHjaQYNCk9dN5lSfk+R1l9Wbe+rSiCwZ3jw==';

  $xenditPHPClient = new XenditClient\XenditPHPClient($options);

  $external_id = 'demo_1475459775872';
  $amount = 17000;
  $bank_code = 'BCA';
  $account_holder_name = 'Bob Jones';
  $account_number = '1231241231';
  $disbursement_options['description'] = 'Reimbursement for shoes';

  $response = $xenditPHPClient->createDisbursement($external_id, $amount, $bank_code, $account_holder_name, $account_number, $disbursement_options);
  print_r($response);
?>
import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.client.Entity;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.MediaType;

Client client = ClientBuilder.newClient();
Entity payload = Entity.json("{  'external_id': 'disbursement_12345',  'amount': 500000,  'bank_code': 'BCA',  'account_holder_name': 'Rizky',  'account_number': '1231241231',  'description': 'Custom description'}");
Response response = client.target("https://api.xendit.co/disbursements")
  .request(MediaType.APPLICATION_JSON_TYPE)
  .header("Authorization", "Basic eG5kX2RldmVsb3BtZW50X1A0cURmT3NzME9DcGw4UnRLclJPSGphUVlOQ2s5ZE41bFNmaytSMWw5V2JlK3JTaUN3WjNqdz09Og==")
  .post(payload);

System.out.println("status: " + response.getStatus());
System.out.println("headers: " + response.getHeaders());
System.out.println("body:" + response.readEntity(String.class));
Header Parameter Description
X-IDEMPOTENCY-KEY
optional
string A unique key to prevent processing duplicate requests. Can be your external_id or any GUID. Must be unique across development & production environments.

Characters Special and alphanumeric
Maximum length No maximum characters
Minimum length 1 character
Request Body Parameter Description
external_id
required
string ID of the disbursement in your system, used to reconcile disbursements after they have been completed.

Characters Special and alphanumeric
Maximum length 1000 maximum characters
Minimum length 1 character
bank_code
required
string Code of the destination bank

The bank code must match the bank codes here precisely
account_holder_name
required
string Name of account holder as per the bank's or e-wallet's records. Used for verification and error/customer support scenarios.

Characters Special and alphanumeric
Maximum length No maximum characters
Minimum length 1 character
account_number
required
string Destination bank account number. If disbursing to an e-wallet, phone number registered with the e-wallet account.

Characters Numeric and hyphens
BCA required length 10 characters
Other banks maximum length No maximum characters
Other banks minimum length 1 character
E-wallets Phone number registered with the e-wallet (Example: 0812XXXXXX)

*** We support disbursements to virtual accounts of major banks (BRI, BNI, Mandiri, CIMB Niaga, Permata, BTN, and NOBU Bank).
*** We support disbursements to major e-wallets (GoPay, OVO, and Mandiri e-cash).

description
required
string Description to send with the disbursement

Characters Special and alphanumeric
Maximum length No maximum characters
Minimum length 1 character
amount
required
number Amount to disburse

Characters Numerical integers, no decimals
Maximum limit (BCA, Mandiri, BNI, BNI Syariah, BRI, Permata) No limit***
Minimum limit (BCA, Mandiri, BNI, BNI Syariah, BRI, Permata) No limit
Maximum limit (Other bank) Rp 50.000.000
Minimum limit (Other bank) Rp 10.000

*** While there is theoretically no maximum transfer limit for transfers to these banks, please note that we may have to report all transaction amounts above Rp 100.000.000 to the financial authorities in Indonesia along with supporting documentation regarding the underlying transactions.

email_to
optional
string[] Email addresses that get notified of disbursement details after the disbursement is completed.
Maximum 3 email addresses accepted.
email_cc
optional
string[] Email addresses that get notified as carbon copy receiver of disbursement details after the disbursement is completed.
Maximum 3 email addresses accepted.
Only allowed if email_to provided.
email_bcc
optional
string[] Email addresses that get notified as blind carbon copy receiver of disbursement details after the disbursement is completed.
Maximum 3 email addresses accepted.
Only allowed if email_to provided.

Create Disbursement Response

Example Create Disbursement Response

{
  "user_id": "5785e6334d7b410667d355c4",
  "external_id": "12345",
  "amount": 1000,
  "bank_code": "BCA",
  "account_holder_name": "RAIDY WIJAYA",
  "disbursement_description": "Refunds for shoes",
  "status": "PENDING",
  "id": "57f1ce05bb1a631a65eee662",
  "email_to": ["test+to1@xendit.co","test+to2@xendit.co"],
  "email_cc": ["test+bcc@xendit.co"],
  "email_bcc": ["test+bcc@xendit.co"]
}
Parameter Description
user_id
required
string Your Xendit Business ID
external_id
required
string Custom ID of your choice to identify the transaction. Our customers often use a phone number, email address, or transaction/order ID
amount
required
number Amount to disburse
bank_code
required
string Bank code of destination bank or e-wallet. See bank codes
account_holder_name
required
string Name of account holder as per the bank's or e-wallet’s records. Used for verification and error/customer support scenarios
disbursement_description
required
This is the description you give us :)
status
required
string
PENDING Transfer is initiated but not yet completed by bank.
id
required
string Unique disbursement ID
email_to
optional
string[] Email addresses that get notified of disbursement details after the disbursement is completed.
This response parameter is only returned if this field is filled.
email_cc
optional
string[] Email addresses that get notified as carbon copy receiver of disbursement details after the disbursement is completed.
This response parameter is only returned if this field is filled.
email_bcc
optional
string[] Email addresses that get notified as blind carbon copy receiver of disbursement details after the disbursement is completed.
This response parameter is only returned if this field is filled.

Create Disbursement Errors

Error Code Description
API_VALIDATION_ERROR
400
Inputs are failing validation. The errors field contains details about which fields are violating validation.
INVALID_JSON_FORMAT
400
The request body is not a valid JSON format.
DISBURSEMENT_DESCRIPTION_NOT_FOUND_ERROR
400
Disbursement description is not set in Settings > Sending Money > Disbursements. Add a default description before retrying.
DIRECT_DISBURSEMENT_BALANCE_INSUFFICIENT_ERROR
400
Not enough balance to disburse. Add more balance before retrying.
DUPLICATE_TRANSACTION_ERROR
400
Idempotency key has been used before. Use a unique idempotency key and try again.
BANK_CODE_NOT_SUPPORTED_ERROR
400
Destination bank code is not supported.
RECIPIENT_ACCOUNT_NUMBER_ERROR
400
For transfers to BCA, account_number input needs to be 10 digits. Check the account number length before retrying.
RECIPIENT_AMOUNT_ERROR
400
The transfer amount requested is lower than the prescribed minimum for the chosen destination bank. Amend the transfer amount before retrying.
MAXIMUM_TRANSFER_LIMIT_ERROR
400
The transfer amount requested is higher than the prescribed maximum for the chosen destination bank. Amend the transfer amount before retrying.
REQUEST_FORBIDDEN_ERROR
403
API key in use does not have necessary permissions to perform the request. Please assign proper permissions for the key. Learn more here
SERVER_ERROR
500
Error connecting to our server. Please use Get disbursement by external_id API to check whether the disbursement has already been created. If you receive DIRECT_DISBURSEMENT_NOT_FOUND_ERROR, the disbursement has not been created; please retry the disbursement request in 1-2 hours.

Get Disbursement by ID

Endpoint: Get Disbursement by id

GET https://api.xendit.co/disbursements/{disbursement_id}

This endpoint queries the current status of a disbursement. This is often used for checking the status of a transaction.

Get Disbursement Request

Example Get Disbursement Request

curl https://api.xendit.co/disbursements/57c9010f5ef9e7077bcb96b6 -X GET \
  -u xnd_development_O46JfOtygef9kMNsK+ZPGT+ZZ9b3ooF4w3Dn+R1k+2fT/7GlCAN3jg==:
<?php
  require 'vendor/autoload.php';

  $options['secret_api_key'] = 'xnd_development_P4qDfOss0OCpl8RtKrROHjaQYNCk9dN5lSfk+R1l9Wbe+rSiCwZ3jw==';

  $xenditPHPClient = new XenditClient\XenditPHPClient($options);

  $disbursement_id = '587cc7ea77535fb94bb4e8eb';

  $response = $xenditPHPClient->getDisbursement($disbursement_id);
  print_r($response);
?>
import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.client.Entity;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.MediaType;

Client client = ClientBuilder.newClient();
Response response = client.target("https://api.xendit.co/disbursements/{disbursement_id}")
  .request(MediaType.APPLICATION_JSON_TYPE)
  .header("Authorization", "Basic eG5kX2RldmVsb3BtZW50X1A0cURmT3NzME9DcGw4UnRLclJPSGphUVlOQ2s5ZE41bFNmaytSMWw5V2JlK3JTaUN3WjNqdz09Og==")
  .get();

System.out.println("status: " + response.getStatus());
System.out.println("headers: " + response.getHeaders());
System.out.println("body:" + response.readEntity(String.class));
Parameter Description
disbursement_id
required
string ID of the disbursement to retrieve
The disbursement_id must match the unique disbursement ID provided in our success response at disbursement creation precisely

Get Disbursement Response

Example Get Disbursement Response

{
  "user_id": "5785e6334d7b410667d355c4",
  "external_id": "disbursement_12345",
  "amount": 500000,
  "bank_code": "BCA",
  "account_holder_name": "Rizky",
  "disbursement_description": "Custom description",
  "status": "PENDING",
  "id": "57c9010f5ef9e7077bcb96b6",
  "email_to": ["test+to1@xendit.co","test+to2@xendit.co"],
  "email_cc": ["test+bcc@xendit.co"],
  "email_bcc": ["test+bcc@xendit.co"]
}
Parameter Description
user_id Your Xendit Business ID
external_id Custom ID set at disbursement creation. Our customers often use a phone number, email address, or transaction/order ID
amount Amount to disburse
bank_code Destination bank code. See bank codes
account_holder_name Bank account name as per the bank's records. Used for verification and error/customer support scenarios
disbursement_description This is the description you give us :)
status PENDING Transfer is initiated.
COMPLETED Bank has confirmed transmission of funds.
FAILED Bank rejected disbursement. We will not retry.
id Unique disbursement ID
email_to Email addresses that get notified of disbursement details after the disbursement is completed.
This response parameter is only returned if this field is filled.
email_cc Email addresses that get notified as carbon copy receiver of disbursement details after the disbursement is completed.
This response parameter is only returned if this field is filled.
email_bcc Email addresses that get notified as blind carbon copy receiver of disbursement details after the disbursement is completed.
This response parameter is only returned if this field is filled.

Get Disbursement Errors

Error Code Description
INVALID_JSON_FORMAT
400
The request body is not a valid JSON format.
REQUEST_FORBIDDEN_ERROR
403
API key in use does not have necessary permissions to perform the request. Please assign proper permissions for the key. Learn more here
DIRECT_DISBURSEMENT_NOT_FOUND_ERROR
404
Could not find direct disbursement.

Get Disbursements by External ID

Endpoint: Get Disbursements by External ID

GET https://api.xendit.co/disbursements?external_id={external_id}

This endpoint queries the current status of all disbursements with requested external_id. This is often used to check the status of a transaction with external_id.

Get Disbursement Request

Example Get Disbursement Request

curl https://api.xendit.co/disbursements?external_id=72655 -X GET \
  -u xnd_development_O46JfOtygef9kMNsK+ZPGT+ZZ9b3ooF4w3Dn+R1k+2fT/7GlCAN3jg==:
<?php
  require 'vendor/autoload.php';

  $options['secret_api_key'] = 'xnd_development_P4qDfOss0OCpl8RtKrROHjaQYNCk9dN5lSfk+R1l9Wbe+rSiCwZ3jw==';

  $xenditPHPClient = new XenditClient\XenditPHPClient($options);

  $external_id = 'disbursement_12345';

  $response = $xenditPHPClient->getDisbursementByExternalId($external_id);
  print_r($response);
?>
import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.client.Entity;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.MediaType;

Client client = ClientBuilder.newClient();
Response response = client.target("https://api.xendit.co/disbursements?external_id={external_id}")
  .request(MediaType.APPLICATION_JSON_TYPE)
  .header("Authorization", "Basic eG5kX2RldmVsb3BtZW50X1A0cURmT3NzME9DcGw4UnRLclJPSGphUVlOQ2s5ZE41bFNmaytSMWw5V2JlK3JTaUN3WjNqdz09Og==")
  .get();

System.out.println("status: " + response.getStatus());
System.out.println("headers: " + response.getHeaders());
System.out.println("body:" + response.readEntity(String.class));
Query Description
external_id
required
string Custom ID of the disbursement set by the customer at disbursement creation
The external_id must match the external_id used at disbursement creation precisely

Get Disbursement Response

Example Get Disbursement Response

[{
  "user_id": "5785e6334d7b410667d355c4",
  "external_id": "disbursement_12345",
  "amount": 500000,
  "bank_code": "BCA",
  "account_holder_name": "Rizky",
  "disbursement_description": "Custom description",
  "status": "PENDING",
  "id": "57c9010f5ef9e7077bcb96b6"
},{
  "user_id": "5785e6334d7b410667d355c4",
  "external_id": "disbursement_12345",
  "amount": 450000,
  "bank_code": "BNI",
  "account_holder_name": "Jajang",
  "disbursement_description": "Custom description",
  "status": "COMPLETED",
  "id": "5a963089fd5fe5b6508f0b7b",
  "email_to": ["test+to1@xendit.co","test+to2@xendit.co"],
  "email_cc": ["test+bcc@xendit.co"],
  "email_bcc": ["test+bcc@xendit.co"]
}]
Parameter Description
user_id Your Xendit Business ID
external_id Custom ID set at disbursement creation. Our customers often use a phone number, email address, or transaction/order ID
amount Amount to disburse
bank_code Destination bank code. See bank codes
account_holder_name Bank account name as per the bank's records. Used for verification and error/customer support scenarios
disbursement_description This is the description you give us :)
status PENDING Transfer is initiated.
COMPLETED Bank has confirmed transmission of funds.
FAILED Bank rejected disbursement. We will not retry.
id Unique disbursement ID
email_to Email addresses that get notified of disbursement details after the disbursement is completed.
This response parameter is only returned if this field is filled.
email_cc Email addresses that get notified as carbon copy receiver of disbursement details after the disbursement is completed.
This response parameter is only returned if this field is filled.
email_bcc Email addresses that get notified as blind carbon copy receiver of disbursement details after the disbursement is completed.
This response parameter is only returned if this field is filled.

Get Disbursement Errors

Error Code Description
REQUEST_FORBIDDEN_ERROR
403
API key in use does not have necessary permissions to perform the request. Please assign proper permissions for the key. Learn more here
DIRECT_DISBURSEMENT_NOT_FOUND_ERROR
404
Could not find direct disbursement.

Disbursement Callback

Endpoint: Disbursement Callback

POST https://yourcompany.com/disbursement_callback_url
import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.client.Entity;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.MediaType;

Client client = ClientBuilder.newClient();
Entity payload = Entity.json("{ 'id' : '57e214ba82b034c325e84d6e' , 'user_id' : '57c5aa7a36e3b6a709b6e148' , 'external_id' : 'disbursement_123124123' , 'amount' : '50000, 'bank_code' : 'BCA' , 'xendit_fee_amount' : ', 'xendit_fee_user_id' : 'XENDIT_FEES' , 'account_holder_name' : 'XENDIT' , 'transaction_id' : '57ec8b7e906aa2606ecf8ffc' , 'transaction_sequence' : '1799' , 'disbursement_id' : '57ec8b8130d2d0243f438e11' , 'disbursement_description' : 'Xendit disbursement' , 'failure_code' : 'INVALID_DESTINATION' , 'is_instant' : 'alse, 'status' : 'FAILED' , 'updated' : '2016-10-10T08:15:03.404Z' , 'created' : '2016-10-10T08:15:03.404Z' , 'email_to' : ' 'test+to1@xendit.co' , 'test+to2@xendit.co '], 'email_cc' : ' 'test+bcc@xendit.co '], 'email_bcc' : ' 'test+bcc@xendit.co ']}");
Response response = client.target("https://yourcompany.com/disbursement_callback_url")
  .request(MediaType.APPLICATION_JSON_TYPE)
  .post(payload);

System.out.println("status: " + response.getStatus());
System.out.println("headers: " + response.getHeaders());
System.out.println("body:" + response.readEntity(String.class));

When a disbursement transaction is successful, our callback APIs will hit your URL that you already set in dashboard. For further information about callbacks please read these docs.

This example is only used to show the body parameters that send from Xendit APIs to your callback URL. If you want to test this callback request, use the test feature in dashboard and go to Settings -> Configuration -> Disbursement.

Disbursement Callback Request

Example Disbursement Callback Request

curl --include \
     --request POST \
     --header "Content-Type: application/json" \
     --header "X-CALLBACK-TOKEN: MuaJALKJSDK12LASHD123kSAKSDHzjahwUWjkasJSDSA12KSNAK21n====" \
     --data-binary "{
    \"id\": \"57e214ba82b034c325e84d6e\",
    \"user_id\": \"57c5aa7a36e3b6a709b6e148\",
    \"external_id\": \"disbursement_123124123\",
    \"amount\": 150000,
    \"bank_code\": \"BCA\",
    \"account_holder_name\": \"XENDIT\",
    \"disbursement_description\": \"Xendit disbursement\",
    \"failure_code\": \"INVALID_DESTINATION\",
    \"is_instant\": false,
    \"status\": \"FAILED\",
    \"updated\": \"2016-10-10T08:15:03.404Z\",
    \"created\": \"2016-10-10T08:15:03.404Z\",
    \"email_to\": [\"test+to1@xendit.co\", \"test+to2@xendit.co\"],
    \"email_cc\": [\"test+cc@xendit.co\"],
    \"email_bcc\": [\"test+bcc@xendit.co\"]
}" \
'https://yourcompany.com/disbursement_callback_url'
Parameter Description
is_instant Indicates whether the disbursement is being disbursed instantly
user_id Your Xendit Business ID
external_id Custom ID set at disbursement creation. Our customers often use a phone number, email address, or transaction/order ID
amount Amount to disburse
bank_code Destination bank code. See bank codes
account_holder_name Bank account name as per the bank's records. Used for verification and error/customer support scenarios
disbursement_description This is the description you give us :)
status COMPLETED Bank has confirmed transmission of funds.
FAILED Disbursement failed because of failure code
failure_code (optional) INSUFFICIENT_BALANCE The balance in your account is insufficient to make the disbursement in the desired amount
UNKNOWN_BANK_NETWORK_ERROR The bank networks have returned an unknown error to us. We are unable to predict whether the disbursement will succeed should you retry the same disbursement request.
TEMPORARY_BANK_NETWORK_ERROR The bank networks are experiencing a temporary error. Please retry the disbursement in 1-3 hours
INVALID_DESTINATION The banks have reported that the destination account is unregistered or blocked. If unsure about this, please retry again or contact the destination bank directly regarding the status of the destination account
SWITCHING_NETWORK_ERROR At least one of the switching networks is encountering an issue. Please retry the disbursement in 1-3 hours
REJECTED_BY_BANK The bank has rejected this transaction for unclear reasons. We are unable to predict whether the disbursement will succeed should you retry the same disbursement request.
TRANSFER_ERROR We’ve encountered a fatal error while processing this disbursement. Certain API fields in your request may be invalid. Please contact our customer support team for more information
TEMPORARY_TRANSFER_ERROR We’ve encountered a temporary issue while processing this disbursement. Please retry the disbursement in 1-2 hours

For detailed information regarding the different error codes above, please see Common Errors in Disbursements.
id Unique disbursement ID
email_to Email addresses that get notified of disbursement details after the disbursement is completed.
This callback parameter is only returned if this field is filled.
email_cc Email addresses that get notified as carbon copy receiver of disbursement details after the disbursement is completed.
This callback parameter is only returned if this field is filled.
email_bcc Email addresses that get notified as blind carbon copy receiver of disbursement details after the disbursement is completed.
This callback parameter is only returned if this field is filled.

Disbursement Callback Errors

Note that in the case where we don't get a successful response from your servers on the first try, we will retry 2 times more with a 30 second delay between each retry. After 3 failures, we get internal alerts that a callback has failed. Our team will then contact you to resolve the issue.

Get Available Banks

Endpoint: Get Available Disbursement Banks

GET https://api.xendit.co/available_disbursements_banks

Example Get Available Disbursement Banks Request

curl https://api.xendit.co/available_disbursements_banks -X GET \
    -u xnd_development_O46JfOtygef9kMNsK+ZPGT+ZZ9b3ooF4w3Dn+R1k+2fT/7GlCAN3jg==:
<?php
  require 'vendor/autoload.php';

  $options['secret_api_key'] = 'xnd_development_P4qDfOss0OCpl8RtKrROHjaQYNCk9dN5lSfk+R1l9Wbe+rSiCwZ3jw==';

  $xenditPHPClient = new XenditClient\XenditPHPClient($options);

  $response = $xenditPHPClient->getAvailableDisbursementBanks();
  print_r($response);
?>
import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.client.Entity;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.MediaType;

Client client = ClientBuilder.newClient();
Response response = client.target("https://api.xendit.co/available_disbursements_banks")
  .request(MediaType.APPLICATION_JSON_TYPE)
  .header("Authorization", "Basic eG5kX2RldmVsb3BtZW50X1A0cURmT3NzME9DcGw4UnRLclJPSGphUVlOQ2s5ZE41bFNmaytSMWw5V2JlK3JTaUN3WjNqdz09Og==")
  .get();

System.out.println("status: " + response.getStatus());
System.out.println("headers: " + response.getHeaders());
System.out.println("body:" + response.readEntity(String.class));

This API endpoint will provide you the current list of banks we support for disbursements. We support transfers to 140+ banks in Indonesia, including some BPDs and BPRs, and virtual accounts of major banks (BRI, BNI, Mandiri, CIMB Niaga, Permata, BTN, and NOBU Bank). We also support disbursements to major e-wallets (GoPay, OVO, and Mandiri e-cash). If you would like us to support payment to a specific destination, please contact us at support@xendit.co.

Get Available Disbursement Banks Response

Get Available Disbursement Banks Response

[
  {
    "name": "Bank Mandiri",
    "code": "MANDIRI",
    "can_disburse": true,
    "can_name_validate": true
  },
  {
    "name": "Bank Rakyat Indonesia (BRI)",
    "code": "BRI",
    "can_disburse": true,
    "can_name_validate": true
  },
  {
    "name": "Bank Central Asia (BCA)",
    "code": "BCA",
    "can_disburse": true,
    "can_name_validate": true
  }
]
Parameter Description
name Full name of the bank or e-wallet
code Code of the bank or e-wallet you would like to disburse to

Batch Disbursement

Batch disbursements (beta) are a set of instructions containing multiple commands to disburse funds to any banks in Indonesia.

Note: Idempotency can be achieved by sending a header with the key X-IDEMPOTENCY-KEY.

Create Batch Disbursement

With this API endpoint you can create multiple disbursements at the same time.

Endpoint: Create Batch Disbursement

POST https://api.xendit.co/batch_disbursements

Create batch disbursement request (Money-out write permission)

Header Description
X-IDEMPOTENCY-KEY
optional
string A unique key to prevent processing duplicate requests. Can be your external_id or any GUID. Must be unique across development & production environments.
Parameter Description
reference
required
string ID of the batch disbursement in your system, used to reconcile disbursements after they have been completed
disbursements
required
Disbursement Item[] List of disbursements in the batch

Disbursement Item

Parameter Description
amount
required
number Amount to disburse
bank_code
required
string Code of the receiving bank
bank_account_name
required
string Receiving bank account holder name
bank_account_number
required
string Receiving bank account number
description
required
string Description to accompany the disbursement
external_id
optional
string ID of disbursement in your system
email_to
optional
string[] Email addresses that get notified of disbursement details after the disbursement is completed
email_cc
optional
string[] Email addresses that get notified as carbon copy receiver of disbursement details after the disbursement is completed
email_bcc
optional
string[] Email addresses that get notified as blind carbon copy receiver of disbursement details after the disbursement is completed

Create Batch Disbursement Response

Example Create Disbursement Response

{
  "created": "2017-03-30T06:12:47.212Z",
  "reference": "qwerty1234",
  "total_uploaded_amount": 30000,
  "total_uploaded_count": 2,
  "status": "NEEDS_APPROVAL",
  "id": "58dca1dffee4228917d37336"
}
Parameter Description
created
required
string Timestamp of batch disbursement creation in ISO format
reference
required
string ID of the batch disbursement in your system, used to reconcile disbursements after they have been completed
total_uploaded_count
required
number The count of all disbursements in the batch
total_uploaded_amount
required
number Total amount of all disbursements in the batch
status
required
string
NEEDS_APPROVAL Batch disbursement is created but needs to be approved to be processed further
id
required
string Unique ID of batch disbursement in our system

Create Batch Disbursement Errors

Error Code Description
API_VALIDATION_ERROR
400
Inputs has failed in validation. The errors field in the response will contain details about which fields are violating validation.
INVALID_JSON_FORMAT
400
The request body is not a valid JSON format.
DUPLICATE_TRANSACTION_ERROR
400
Request failed because idempotency key has been seen before.
INVALID_API_KEY
401
Wrong API key is being used.
BATCH_DISBURSEMENT_MAXIMUM_ROWS_LIMIT_EXCEEDED_ERROR
400
Request failed because the disbursements contain more than 1000 items.
REQUEST_FORBIDDEN_ERROR
403
API key in use does not have necessary permissions to perform the request. Please assign proper permissions for the key. Learn more here

Batch Disbursement Callback

Endpoint: Disbursement Callback

POST https://yourcompany.com/disbursement_callback_url

After creating a batch disbursement via API, to receive a callback, you must log into your Dashboard and do the following steps:

When all disbursements in a batch disbursement has been processed, our system will hit the callback URL that you have already set. We will also give you callback if a batch disbursement has been deleted in the dashboard. Please contact our technical support to set your callback URL.

Disbursement Callback Request

Parameter Description
created Timestamp of batch disbursement creation in ISO format
updated Timestamp of the latest batch disbursement status change in ISO format
reference ID of the batch disbursement in your system, used to reconcile disbursements after they have been completed
total_uploaded_count The count of all disbursements in the batch that you requested
total_uploaded_amount Total amount of all disbursements in the batch that you requested
approved_at Timestamp of batch disbursement approved in ISO format
approver_id User ID of the person who approves the batch disbursement
status COMPLETED All disbursements are successfully paid
CHECK Some disbursements are successfully paid
DELETED Batch disbursement has been deleted
FAILED All disbursements are not successfully paid
id Unique ID of batch disbursement in our system
user_id Your Xendit Business ID
total_error_count The count of all disbursements in the batch that are not successfully paid
total_error_amount Total amount of all disbursements in the batch that are not successfully paid
total_disbursed_count The count of all disbursements in the batch that are succesfully paid
total_disbursed_amount Total amount of all disbursements in the batch that are succesfully paid
disbursements Details of each disbursement in the batch, explained below

Disbursement

Parameter Description
created Timestamp of batch disbursement item creation in ISO format
updated Timestamp of latest batch disbursement status update in ISO format
external_id ID of disbursement from your system
amount Amount to disburse
bank_code Receiving bank code. See bank codes
bank_account_number Receiving bank account number
bank_account_name Receiving bank account holder name
description Description to accompany the disbursement
email_to Email addresses that get notified of disbursement details after the disbursement is completed
email_cc Email addresses that get notified as carbon copy receiver of disbursement details after the disbursement is completed
email_bcc Email addresses that get notified as blind carbon copy receiver of disbursement details after the disbursement is completed
status COMPLETED Disbursement is successfully paid
FAILED Disbursement is not successfully paid
bank_reference Transaction reference number from the bank
valid_name Valid receiving account holder name according to receiving bank
failure_code The error code associated with the failure of disbursement
failure_message The error message associated with the failure of disbursement
id Unique ID of the batch disbursement item in our system

Batch Disbursement Callback Errors

Note that in the case where we don't get a successful response from your servers on the first try, we will retry 2 times more with a 30 second delay between each retry. After 3 failures, we get internal alerts that a callback has failed. Our team will then contact you to resolve the issue.

Get Available Banks

Endpoint: Get Available Disbursement Banks

GET https://api.xendit.co/available_disbursements_banks

Example Get Available Disbursement Banks Request

curl https://api.xendit.co/available_disbursements_banks -X GET \
    -u xnd_development_O46JfOtygef9kMNsK+ZPGT+ZZ9b3ooF4w3Dn+R1k+2fT/7GlCAN3jg==:
<?php
  require 'vendor/autoload.php';

  $options['secret_api_key'] = 'xnd_development_P4qDfOss0OCpl8RtKrROHjaQYNCk9dN5lSfk+R1l9Wbe+rSiCwZ3jw==';

  $xenditPHPClient = new XenditClient\XenditPHPClient($options);

  $response = $xenditPHPClient->getAvailableDisbursementBanks();
  print_r($response);
?>
import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.client.Entity;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.MediaType;

Client client = ClientBuilder.newClient();
Response response = client.target("https://api.xendit.co/available_disbursements_banks")
  .request(MediaType.APPLICATION_JSON_TYPE)
  .header("Authorization", "Basic eG5kX2RldmVsb3BtZW50X1A0cURmT3NzME9DcGw4UnRLclJPSGphUVlOQ2s5ZE41bFNmaytSMWw5V2JlK3JTaUN3WjNqdz09Og==")
  .get();

System.out.println("status: " + response.getStatus());
System.out.println("headers: " + response.getHeaders());
System.out.println("body:" + response.readEntity(String.class));

This API endpoint will provide you the current list of banks we support for disbursements. The current list of supported banks is >140 just for Indonesia, including some BPDs and BPRs.

Get Available Disbursement Banks Response

Get Available Disbursement Banks Response

[
  {
    "name": "Bank Central Asia (BCA)",
    "code": "BCA"
  },
  {
    "name": "Bank Mandiri",
    "code": "MANDIRI"
  },
  {
    "name": "Bank Rakyat Indonesia (BRI)",
    "code": "BRI"
  }
]
Parameter Description
name Full name of the bank
code Code of the bank, relevant during creation of virtual accounts

xenPlatform

Description

xenPlatform is Xendit's solution for platform businesses that work with third-party partners. Platform businesses face complex payments challenges that range from partner onboarding, to moving funds, to payouts and billing.

With xenPlatform, you can onboard and create accounts for your partners, transact on behalf of them, split payments, monitor their transactions, and directly bill them.

Overview

Once xenPlatform has been activated for your account, you may use the Account API to create sub accounts that are linked to your master account.

Thereafter simply include a for-user-id header in any standard Xendit API call to create a transaction for those accounts.

These accounts and their transactions will appear in the xenPlatform tab of your Xendit dashboard.

Create Account

The Create Account API allows your xenPlatform enabled account to create sub-accounts that are linked to your account. The response includes the corresponding user_id value that you should store in order to make transactions for that sub-account in the future.

There are two types of accounts that can be created: STANDARD, CORE.

For STANDARD accounts: When a successful POST request is made to the Create Account API with a valid email in the account_email field, a sub-account is immediately created and a sub-account invitation email is sent to that email for further registration. Via the sub-account invitation email, your third-party partners can complete registration in order to get access to their own Xendit dashboard.

For CORE accounts: Core accounts do not get access to their own Xendit Dashboards. When a successful POST request is made to the Create Account API with a valid email in the account_email field, a sub-account is immediately created. No invitation email is sent to that email for further registration. The business_name parameter is mandatory for CORE accounts.

Endpoint: Create Account

POST https://api.xendit.co/accounts

Example: Create Account

curl https://api.xendit.co/accounts -X POST \
   -u xnd_development_O46JfOtygef9kMNsK+ZPGT+ZZ9b3ooF4w3Dn+R1k+2fT/7GlCAN3jg==: \
   -d account_email=angie@pinkpanther.com \
   -d type=CORE \
   -d business_profile[business_name]="Angie's lemonade stand" \
  <?php
      $url = 'https://api.xendit.co/accounts';
      $apiKey = 'xnd_development_O46JfOtygef9kMNsK+ZPGT+ZZ9b3ooF4w3Dn+R1k+2fT/7GlCAN3jg==:';
      $headers = [];
      $headers[] = 'Content-Type: application/json';
      $data = [
          'account_email' => 'angie@pinkpanther.com',
          'type' => 'CORE',
          'business_profile' => [
            'business_name' => 'Angie\'s lemonade stand'
          ]
      ];

      $curl = curl_init();

      $payload = json_encode($data);
      curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
      curl_setopt($curl, CURLOPT_USERPWD, $apiKey.":");
      curl_setopt($curl, CURLOPT_URL, $url);
      curl_setopt($curl, CURLOPT_POST, true);
      curl_setopt($curl, CURLOPT_POSTFIELDS, $payload);
      curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);

      $result = curl_exec($curl);
      echo $result;
Parameter Description
account_email
required
string Email identifier for your account

Minimum length 1 character
Maximum length No maximum characters
type
required
string Type of account you are creating

Available values: STANDARD, CORE
business_profile
optional
object Business information about the account being created
string business_name
optional
Name of the business

Create Account Response

Example: Create Account Response

{
    "created": "2019-01-01T08:51:44.484Z",
    "status": "SUCCESSFUL",
    "account_email": "angie@pinkpanther.com",
    "user_id": "57fb4e076fb3fa296b7f5a17",
    "type": "CORE"
}
Parameter Description
created
required
string Timestamp of when the account was created

Timezone: GMT+0
status
required
string The status of account creation

Available values: SUCCESSFUL
account_email
required
string The email identifier of the account created
user_id
required
stringThe user_id of the account created, use this to create transactions on behalf of your accounts
type
required
stringThe type of account created

Available values: STANDARD, CORE

Create Invoice for Sub-account (Money-in write permission)

Once a sub-account has been created, you may make transactions for them by simply including a for-user-id field in the header of your request to any Xendit API. The value in this field should include the full user_id of a sub-account that has previously been created by you.

This example demonstrates how to create an invoice for a sub-account using the Create Invoice API.

Note that for the Create Invoice API, the response will provide you with a confirmation that the invoice was created for the correct sub-account user_id.

Please refer to the Xendit API reference for all supported APIs.

Endpoint: Create Invoice

POST https://api.xendit.co/v2/invoices

Post Invoice Request

Example POST Invoice Request

curl https://api.xendit.co/v2/invoices -X POST \
   -u xnd_development_O46JfOtygef9kMNsK+ZPGT+ZZ9b3ooF4w3Dn+R1k+2fT/7GlCAN3jg==: \
   -H for-user-id=57fb4e076fb3fa296b7f5a17 \
   -d external_id=lmnd_001 \
   -d description="1 order of Angie's lemonade" \
   -d amount=10000 \
   -d payer_email=inspector@jacques.com \
   -d should_send_email=true \
  <?php
      $url = 'https://api.xendit.co/v2/invoices';
      $apiKey = 'xnd_development_O46JfOtygef9kMNsK+ZPGT+ZZ9b3ooF4w3Dn+R1k+2fT/7GlCAN3jg==:';
      $headers = [];
      $headers[] = 'Content-Type: application/json';
      $headers[] = 'for-user-id: 57fb4e076fb3fa296b7f5a17'
      $data = [
          'external_id' => 'lmnd_001',
          'description' => '1 order of Angie\'s lemonade',
          'amount' => 10000,
          'payer_email' => 'inspector@jacques.com',
          'should_send_email' => true
      ];

      $curl = curl_init();

      $payload = json_encode($data);
      curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
      curl_setopt($curl, CURLOPT_USERPWD, $apiKey.":");
      curl_setopt($curl, CURLOPT_URL, $url);
      curl_setopt($curl, CURLOPT_POST, true);
      curl_setopt($curl, CURLOPT_POSTFIELDS, $payload);
      curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);

      $result = curl_exec($curl);
      echo $result;
Header Parameter Description
for-user-id
optional
string The user-id that you want to make this transaction for



Body Parameter Description
external_id
required
string ID of your choice (typically the unique identifier of an invoice in your system)
payer_email
required
string Email of the end user you're charging
description
required
string Description of the invoice
amount
required
number Amount on the invoice. The minimum amount to create an invoice is 10000.
should_send_email
optional

default: false
boolean Specify should the end user get email when invoice is created, paid, or expired; or not
callback_virtual_account_id
optional
string To allow payment via Fixed Virtual Account, pass in the id field value from the response when the fixed virtual account was created. See Create Fixed Virtual Accounts
invoice_duration
optional
number duration of time that end user have in order to pay the invoice before it's expired (in Second)
success_redirect_url
optional
string url that end user will be redirected to upon successful invoice payment.
example : https://yourcompany.com/example_item/10/success_page
failure_redirect_url
optional
string url that end user will be redirected to upon expiration of this invoice.
example : https://yourcompany.com/example_item/10/failed_checkout
payment_methods
optional
array of strings choices of payment channels that is available in your account. leave this field empty if all payment channel is expected to be available in this particular invoice.
example : ["BCA", "BRI", "MANDIRI", "BNI",
"PERMATA", "ALFAMART", "CREDIT_CARD",
"OVO"]
mid_label
optional
string MID label that you have when you are using credit card payment and have acquiring bank.
currency
optional
string Currency of the amount that you created
example : "IDR"
fixed_va
optional

default: false
boolean Input this parameter as true to enable one VA number for Your end customers.

Create Invoice Response

Example Create Invoice Response

{
  "id": "579c8d61f23fa4ca35e52da4",
  "user_id": "57fb4e076fb3fa296b7f5a17",
  "external_id": "lmnd_001",
  "status": "PENDING",
  "merchant_name": "Angie's lemonade stand",
  "merchant_profile_picture_url": "https://xnd-companies.s3.amazonaws.com/prod/1493610897264_473.png",
  "amount": 10000,
  "payer_email": "inspector@jacques.com",
  "description": "1 order of Angie's lemonade",
  "invoice_url": "https://invoice.xendit.co/web/invoices/595b6248c763ac05592e3eb4",
  "expiry_date": "2019-01-01T11:20:01.017Z",
  "available_banks": [
   {
            "bank_code": "MANDIRI",
            "collection_type": "POOL",
            "bank_account_number": "8860810000525",
            "transfer_amount": 10000,
            "bank_branch": "Virtual Account",
            "account_holder_name": "LANSUR13",
            "identity_amount": 0
        },
        {
            "bank_code": "BRI",
            "collection_type": "POOL",
            "bank_account_number": "2621510002426",
            "transfer_amount": 10000,
            "bank_branch": "Virtual Account",
            "account_holder_name": "LANSUR13",
            "identity_amount": 0
        },
        {
            "bank_code": "BNI",
            "collection_type": "POOL",
            "bank_account_number": "880810000689",
            "transfer_amount": 10000,
            "bank_branch": "Virtual Account",
            "account_holder_name": "LANSUR13",
            "identity_amount": 0
        }
  ],
  "available_retail_outlets": [
      {
          "retail_outlet_name": "ALFAMART",
          "payment_code": "ALFA123456",
          "transfer_amount": 10000
      }
  ],
  "should_exclude_credit_card": false,
  "should_send_email": false,
  "created": "2017-06-12T14:00:00.306Z",
  "updated": "2017-06-12T14:00:00.306Z",
  "mid_label": "test-mid",
  "currency": "IDR",
  "fixed_va":true
}
Parameter Description
id
required
string An invoice ID generated by Xendit
user_id
required
string Your Xendit Business ID
external_id
required
string The invoice ID in your server, that can be used to reconcile between you and Xendit
status
required
string

PENDING the invoice has yet to be paid
merchant_name
required
string The name of your company or website
merchant_profile_picture_url
required
string The URL to profile picture of your company
amount
required
integer positive Nominal amount for the invoice
payer_email
required
string Email of the payer, we get this information from your API call
description
required
string Description for the invoice, we get this information from your API call
invoice_url
required
string Public URL for this invoice, it’s there in case you want to use our UI
expiry_date
required
string ISO date and time that the invoice expires. Default is 24 hours.
available_banks
required
Available payment methods through banks as per your config
string bank_code
required
BCA / MANDIRI / BNI / BRI / PERMATA
string collection_type
required
POOL type is nonfixed virtual account
string bank_account_number
required
Bank account number for users to pay into
integer positive transfer_amount
required
Amount the user should transfer
string bank_branch
required
Bank account type
string account_holder_name
required
Bank account holder name
available_retail_outlets
required
Available payment methods through retail outlet as per your config
string retail_outlet_name
required
Name of the retail outlet
string payment_code
required
Unique code that you use to pay in retail outlet
integer positive transfer_amount
required
Amount the user should transfer
boolean should_exclude_credit_card
required
A flag showing if credit card should be excluded in invoice UI or not
boolean should_send_email
required
A flag showing should payer get email when invoice is created, paid, or expired; or not
string created
required
An ISO timestamp that tracks when the invoice was created
string updated
required
An ISO timestamp that tracks when the invoice was updated
string mid_label
required
MID label that you have when you are using credit card payment and have acquiring bank. You will get this response when you add this parameter when create invoice through API
string currency
required
Currency of the amount that you created. You will get this response when you add this parameter when create invoice through API
boolean fixed_va
required
Input this parameter as true to enable one VA number for Your end customers.

Create Disbursement for Sub-account Request

You may also create a Disbursement request on behalf of your sub-accounts to send funds out from your sub-accounts' Cash balance. The value in this field should include the full user_id of a sub-account that has previously been created by you.

This example demonstrates how to create a disbursement for a sub-account using the Create Disbursement API.

Note that for the Create Disbursement API, the response will provide you with a confirmation that the invoice was created for the correct sub-account user_id.

Please refer to the Xendit API reference for all supported APIs.

Endpoint: Create Disbursement

POST https://api.xendit.co/disbursements

Create Disbursement Request

Example Create Disbursement Request

curl https://api.xendit.co/disbursements -X POST \
   -u xnd_development_O46JfOtygef9kMNsK+ZPGT+ZZ9b3ooF4w3Dn+R1k+2fT/7GlCAN3jg==: \
   -H for-user-id=57fb4e076fb3fa296b7f5a17 \
   -d external_id=settlement_lmnd_001 \
   -d amount=7500 \
   -d bank_code="BCA" \
   -d account_holder_name="Pink Panther" \
   -d account_number="1231241231" \
   -d description="Settlement to Angie's Lemonade stand through FnB platform" \
  <?php
      $url = 'https://api.xendit.co/disbursements';
      $apiKey = 'xnd_development_O46JfOtygef9kMNsK+ZPGT+ZZ9b3ooF4w3Dn+R1k+2fT/7GlCAN3jg==:';
      $headers = [];
      $headers[] = 'Content-Type: application/json';
      $headers[] = 'for-user-id: 57fb4e076fb3fa296b7f5a17'
      $data = [
          'external_id' => 'settlement_lmnd_001',
          'amount' => 7500,
          'bank_code' => "BCA",
          'account_holder_name' => 'Angie Pink',
          'account_number' => '1231241231',
          'description' => 'Settlement to Angie\'s Lemonade stand through FnB platform'
      ];

      $curl = curl_init();

      $payload = json_encode($data);
      curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
      curl_setopt($curl, CURLOPT_USERPWD, $apiKey.":");
      curl_setopt($curl, CURLOPT_URL, $url);
      curl_setopt($curl, CURLOPT_POST, true);
      curl_setopt($curl, CURLOPT_POSTFIELDS, $payload);
      curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);

      $result = curl_exec($curl);
      echo $result;
Header Parameter Description
for-user-id
optional
string The user-id that you want to make this transaction for

X-IDEMPOTENCY-KEY
optional
string A unique key to prevent processing duplicate requests. Can be your external_id or any GUID. Must be unique across test & live environments.

Characters Special and alphanumeric
Maximum length No maximum characters
Minimum length 1 character
Request Body Parameter Description
external_id
required
string ID of the disbursement in your system, used to reconcile disbursements after they have been completed.

Characters Special and alphanumeric
Maximum length 1000 maximum characters
Minimum length 1 character
bank_code
required
string Code of the destination bank

The bank code must match the bank codes here precisely
account_holder_name
required
string Name of account holder as per the bank's or e-wallet's records. Used for verification and error/customer support scenarios.

Characters Special and alphanumeric
Maximum length No maximum characters
Minimum length 1 character
account_number
required
string Destination bank account number. If disbursing to an e-wallet, phone number registered with the e-wallet account.

Characters Numeric and hyphens
BCA required length 10 characters
Other banks maximum length No maximum characters
Other banks minimum length 1 character
E-wallets Phone number registered with the e-wallet (Example: 0812XXXXXX)

*** We support disbursements to virtual accounts of major banks (BRI, BNI, Mandiri, CIMB Niaga, Permata, BTN, and NOBU Bank).
*** We support disbursements to major e-wallets (GoPay, OVO, and Mandiri e-cash).

description
required
string Description to send with the disbursement

Characters Special and alphanumeric
Maximum length No maximum characters
Minimum length 1 character
amount
required
number Amount to disburse

Characters Numerical integers, no decimals
Maximum limit (BCA, Mandiri, BNI, BNI Syariah, BRI, Permata) No limit***
Minimum limit (BCA, Mandiri, BNI, BNI Syariah, BRI, Permata) No limit
Maximum limit (Other bank) Rp 50.000.000
Minimum limit (Other bank) Rp 10.000

*** While there is theoretically no maximum transfer limit for transfers to these banks, please note that we may have to report all transaction amounts above Rp 100.000.000 to the financial authorities in Indonesia along with supporting documentation regarding the underlying transactions.

email_to
optional
string[] Email addresses that get notified of disbursement details after the disbursement is completed.
Maximum 3 email addresses accepted.
email_cc
optional
string[] Email addresses that get notified as carbon copy receiver of disbursement details after the disbursement is completed.
Maximum 3 email addresses accepted.
Only allowed if email_to provided.
email_bcc
optional
string[] Email addresses that get notified as blind carbon copy receiver of disbursement details after the disbursement is completed.
Maximum 3 email addresses accepted.
Only allowed if email_to provided.

Create Disbursement Response

Example Create Disbursement Response

{
  "user_id": "57fb4e076fb3fa296b7f5a17",
  "external_id": "settlement_lmnd_001",
  "amount": 7500,
  "bank_code": "BCA",
  "account_holder_name": "Angie Pink",
  "disbursement_description": "Settlement to Angie's Lemonade stand through FnB platform",
  "status": "PENDING",
  "id": "57f1ce05bb1a631a65eee662",
  "email_to": ["angie@pinkpanther.com"]
}
Parameter Description
user_id
required
string Your Xendit Business ID
external_id
required
string Custom ID of your choice to identify the transaction. Our customers often use a phone number, email address, or transaction/order ID
amount
required
number Amount to disburse
bank_code
required
string Bank code of destination bank or e-wallet. See bank codes
account_holder_name
required
string Name of account holder as per the bank's or e-wallet’s records. Used for verification and error/customer support scenarios
disbursement_description
required
This is the description you give us :)
status
required
string
PENDING Transfer is initiated but not yet completed by bank.
id
required
string Unique disbursement ID
email_to
optional
string[] Email addresses that get notified of disbursement details after the disbursement is completed.
This response parameter is only returned if this field is filled.
email_cc
optional
string[] Email addresses that get notified as carbon copy receiver of disbursement details after the disbursement is completed.
This response parameter is only returned if this field is filled.
email_bcc
optional
string[] Email addresses that get notified as blind carbon copy receiver of disbursement details after the disbursement is completed.
This response parameter is only returned if this field is filled.

Account Updated Callback

Endpoint: Account Updated Callback

POST https://yourcompany.com/xenplatform_callback_url

The Account Updated callback can be used to let your system know when your sub-accounts have been successfully registered and live payments enabled.

This example is used to show the body parameters that will be sent from Xendit APIs to your callback URL.

You will receive callbacks from the Create Account API at 2 points during the sub-account onboarding process:

  1. when a sub-account has been registered
  2. when live payments has been enabled for your sub-account (i.e. activated)

Please configure your callback URL in the settings page of your Xendit dashboard in order to receive these callbacks. You may also test this callbacks request in the same settings page.

Account Updated Callback Request

Example Account Updated Callback Request

curl https://yourcompany.com/xenplatform_callback_url -X POST \
   -u xnd_development_O46JfOtygef9kMNsK+ZPGT+ZZ9b3ooF4w3Dn+R1k+2fT/7GlCAN3jg==: \
   -d created="2019-01-01T10:51:44.484Z" \
   -d event_type="account.registered" \
   -d data[user_id]="57fb4e076fb3fa296b7f5a17" \
   -d data[account_info][payments_enabled]=false \
  <?php
      $url = 'https://yourcompany.com/xenplatform_callback_url';
      $apiKey = 'xnd_development_O46JfOtygef9kMNsK+ZPGT+ZZ9b3ooF4w3Dn+R1k+2fT/7GlCAN3jg==:';
      $headers = [];
      $headers[] = 'Content-Type: application/json';
      $data = [
          'created' => '2019-01-01T10:51:44.484Z',
          'event_type' => 'account.registered',
          'data' => [
            'user_id' => '57fb4e076fb3fa296b7f5a17',
            'account_info' => [
              'payments_enabled' => false
            ]
          ]
      ];

      $curl = curl_init();

      $payload = json_encode($data);
      curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
      curl_setopt($curl, CURLOPT_USERPWD, $apiKey.":");
      curl_setopt($curl, CURLOPT_URL, $url);
      curl_setopt($curl, CURLOPT_POST, true);
      curl_setopt($curl, CURLOPT_POSTFIELDS, $payload);
      curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);

      $result = curl_exec($curl);
      echo $result;
Parameter Description
string created
required
Indicates when the callback was sent
string event_type
required
The type of event callback that was sent

Available values: account.registered, account.activated
object data
required
Contains metadata for the event type
string user_id
required
User ID of the sub account
object account_info
required
Account info meta data

Account Info Metadata Object Parameters

Parameter Description
boolean payments_enabled
required
Boolean value indicating whether payments has been enabled for the sub-account

Test Scenarios

This section includes test scenarios and other information to make sure your integration works as planned. Use it to trigger different flows in your integration and ensure they are handled accordingly

Checklists

Xendit has designed its live and test modes to function as similarly as possible. Flipping the switch is mostly a matter of swapping your API keys.

If you are a developer, or had a developer perform an integration for you, you should also consider the following items before going live.

Handle Edge Cases

We have created several test cases you can use to replicate various states and responses. Beyond these options, perform your due diligence, testing your integration with:

We also recommend you have someone else test your integration, especially if that other person is not a developer themselves.

Review Error Handling

Once you have gone live is an unfortunate time to discover you have not properly written your code to handle every possible error type, including those that should "never" happen. Be certain your code is defensive, handling not just the common errors, but all possibilities.

When testing your error handling, especially watch what information is shown to your users. A card being declined (i.e., CARD_DECLINED) is a different concern than an error on your backend (e.g., an API_VALIDATION_ERROR).

Review Your Logging

Xendit logs every request made with you API keys. We recommend that you log all important data on your end, too, despite the apparent redundancy. Your own logs will be a life-saver if your server has a problem contacting Xendit or there's an issue with your API keys--both cases would prevent us from logging your request.

Regularly examine your logs to ensure they're storing all the information you may need and they are not storing anything of a sensitive nature (e.g., personally identifiable information).

Independent From Test Mode Objects

Xendit objects created in test mode--such as charge, virtual accounts, retail outlets, etc---are not usable in live mode. This prevents your test data from being inadvertently used in your production code. When recreating necessary objects in live mode, be certain to use the same ID values (e.g. the same Virtual Account external ID) to guarantee your code will continue to work without issue

Register Live Callback URL

Your Xendit account can have both test and live callback URLs. If you are using callback, make sure you have defined live endpoints in your Xendit account. Then confirm that the live endpoint functions exactly the same as your test endpoint.

While examining your callback status, also take a moment to check that your live endpoint:

Secure Your API keys

As a security measure, we recommend change your API keys on a regular basis, and also just before going live. This is in case they have been saved somewhere outside of your codebase during development. Make sure your workflow doesn't result in your API keys being represented or stored in multiple places--this leads to bugs--or even ending up in your version control software.

Changelog

API Reference Changelog

Version 1.8.6 (Jan 17, 2020)

Version 1.8.5 (Jan 14, 2020)

Version 1.8.4 (Jan 9, 2020)

Introduce new Node.js library

Version 1.8.3 (Jan 6, 2020)

Added xenPlatform API reference

Version 1.8.2 (December 15, 2019)

Update Disbursement amount limits

Version 1.8.1 (December 14, 2019)

Update several callback requests in invoice

Version 1.8.0 (December 12, 2019)

Version 1.7.0 (December 11, 2019)

Version 1.6.0 (December 9, 2019)

Version 1.5.4 (November 27, 2019)

Update several responses in recurring API documentation

Version 1.5.3 (November 26, 2019)

Version 1.5.2 (November 21, 2019)

Change redirect_url to checkout_url field in checkoutRequest response for LinkAja API

Version 1.4.2 (November 7, 2019)

Update parameter description for Invoice callback

Version 1.4.1 (October 31, 2019)

Remove items in Invoices

Version 1.4.0 (October 30, 2019)

Version 1.3.4 (October 23, 2019)