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 fintech lending and eCommerce, 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 API, you must append a colon and Base 64 encode the API key you find in the dashboard. For example if your API key is

xnd_development_P4qDfOss0OCpl8RtKrROHjaQYNCk9dN5lSfk+R1l9Wbe+rSiCwZ3jw==

First, add a colon at the end

xnd_development_P4qDfOss0OCpl8RtKrROHjaQYNCk9dN5lSfk+R1l9Wbe+rSiCwZ3jw==:

Finally, Base64 encode the colon appended key to get

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, we provide you API keys for both the development and production environments. All requests made in the development environment will never hit the banking networks and will not cost you anything.

Before using the API, make sure that you have registered and get your account authenticated as API requests without authentication will fail. To authenticate your account, you have to include your secret API key in the request which can be accessed in Xendit Dashboard. You can manage your API keys in the Dashboard > Settings > API Keys. Your development and production keys determine your environment. Your API keys should be kept private so do not share your secret API keys.

All the API requests should be made over HTTPS instead of HTTP (all calls made over plain HTTP will fail). We also provide PHP client libraries to save you time. We’re developing more libraries and plugins in the near future and if you write your own library, we would love to hear about it. Make sure you’ve completed the authentication before using our API.

Balances

Get balance

Endpoint: Get Balance

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

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. You can assign your money into different accounts according to your business logic (eg: cash account, tax account, escrow account) and each account has its own balance that can be accessed in the dashboard.

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 account. Some use cases include: deciding when you may need to withdraw funds, determining if you have funds to disburse, and if you just like to check it’s still there :P

Currently, the API only supports querying the balance for your cash account. Anything else related to the account (eg: adding new account, transferring money from accounts besides cash account, etc.) will be done at the beginning in initial configuration with our technical team.

Get Invoice Response

Example Get Invoice 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",
    "status": "IN_REVIEW",
    "risk_score": 29,
    "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.

Fraud detection can be performed at the tokenization stage. See Fraud Detection for details on submitting additional fields to enable fraud detection.

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

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
stringIncluded if authentication was bundled for single use token.
status
required
string Tokenization status. See Tokenization Statuses
risk_score
optional
string Risk score from Fraud Detection System. See Fraud Detection
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.
HIGH_RISK_TRANSACTION This status means that transaction rejected due to high fraud risk score.

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.
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.

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
risk_score
optional
string Risk score from Fraud Detection System. See Fraud Detection
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 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"
    }'
<?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",
    "eci": "05",
    "capture_amount": 15000,
    "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",
    "eci": "05",
    "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
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.

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,...)
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.
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.
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

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.
TOKEN_NOT_FOUND_ERROR
404
The token ID was not found in the system.

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",
  "capture_amount": 9900,
  "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

Parameter Description
credit_card_charge_id
required
string Charge ID of authorization
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
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",
  "capture_amount": 9900,
  "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

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.
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": "SUCCEEDED",
  "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.

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

Refund Request

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
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

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
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.
INSUFFICIENT_BALANCE_ERROR
400
Insufficient balance to create refund
REFUND_AMOUNT_EXCEEDED_ERROR
400
Refunded amount would exceed total charge
DUPLICATE_REFUND_ERROR
400
external_id has already been used
CREDIT_CARD_CHARGE_NOT_FOUND_ERROR
404
credit_card_charge_id not found

Create Subscription

Definition: Create Subscription

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

Example Create Subscription Request

curl -X POST \
  https://api.xendit.co/managed_subscriptions \
  -u xnd_development_O46JfOtygef9kMNsK+ZPGT+ZZ9b3ooF4w3Dn+R1k+2fT/7GlCAN3jg==: \
  -H 'content-type: application/json' \
  -d '{
    "token_id": "59644ba513c7f01759213052",
    "authentication_id": "59644bb713c7f01759213053",
    "amount": 75000,
    "frequency": "MONTHLY",
    "start_date": "2017-07-15T10:00:00.000Z",
    "end_date": "2018-07-15T10:00:00.000Z"
}'
// BETA - Not yet added to PHP Library

When a Subscription is created, Xendit takes care of charging the credit card periodically, at an interval set in the frequency field.

Create Subscription Request

Parameter Description
token_id
required
string ID of the token that represents the credit card you wish to periodically charge
authentication_id
required
string The id of a 3DS authentication
amount
required
number The amount to be charged periodically
frequency
required
string An enum value representing the frequency at which Xendit will charge the credit card. See frequency details
start_date
required
string The ISO date on which Xendit will charge the card for the first time for this subscription. Note: The time is not required.
end_date
required
string The ISO date on which the subscription expires, after which Xendit will no longer charge the credit card. Note: The time is not required

Example Subscription Response

{
  "token_id": "591e7edafe439c3c698bc8a9",
  "authorization_id": "5963c7b313c7f01759213033",
  "amount": 75000,
  "frequency": "MONTHLY",
  "start_date": "2017-07-10T17:00:00.000Z",
  "end_date": "2018-07-09T17:00:00.000Z",
  "status": "ACTIVE",
  "id": "5963c7b313c7f01759213034"
}

Create Subscription Response

The create Subscription response will conform to the structure outlined by the Subscription Schema

Subscription Schema

Parameter Description
id
required
string A unique identifier representing the Subscription
token_id
required
string ID of the token that represents the credit card you wish to periodically charge
authorization_id
required
string The id of the authorization performed before the subscription begins
amount
required
number The amount to be charged periodically
frequency
required
string An enum value representing the frequency at which Xendit will charge the credit card. See frequency details
start_date
required
string The ISO date on which Xendit will charge the card for the first time for this subscription
end_date
required
string The ISO date when the subscription expires, after which Xendit will no longer charge the credit card
status
required
string An enum value representing the status of the subscription. See status details

Subscription Statuses

Status Description
ACTIVE The subscription is active and the card will be charged periodically
CANCELLED The subscription is cancelled and the credit card will no longer be charged

Subscription Frequency

Status Description
DAILY The card will be charged every day
WEEKLY The card will be charged every 7 days
MONTHLY The card will be charged on the same day each month, rounded to the latest day of the month (e.g. May 31st, then June 30th)
YEARLY The card will be charged on the same day each year

Create Subscription 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.
INVALID_START_DATE_ERROR
400
The start date is before today (GMT+7)
INVALID_END_DATE_ERROR
400
The end date is not after the start date
AMOUNT_GREATER_THAN_AUTHENTICATED_ERROR
400
The amount value exceeds the amount the user agreed on in the 3DS authentication
AUTHENTICATION_ID_MISSING_ERROR
400
The authentication_id field is missing but is required in order to create this Subscription
TOKEN_NOT_FOUND_ERROR
404
A valid token with the provided token id could not be found
AUTHENTICATION_NOT_FOUND_ERROR
404
A valid 3DS authentication with the provided authentication id could not be found

Subscription callback

Example: Subscription Callback (Charge Success)

{
    "id": "59158cac7c865a48268c91f",
    "status": "CAPTURED",
    "external_id": "your-external-id-01",
    "capture_amount": 700,
    "business_id": "5785e6334d7b410667d355c4",
    "merchant_reference_code": "59158c7a7c865a48268c91f0",
    "merchant_id": "xendit",
    "eci": "05",
    "charge_type": "RECURRING",
    "card_type": "CREDIT",
    "card_brand": "VISA",
    "masked_card_number": "400000XXXXXX0002",
    "created": "2017-05-12T10:21:32.725Z"
}

Example: Subscription Callback (Charge Failed)

{
    "id": "59158cac7c865a48268c91f",
    "status": "FAILED",
    "failure_reason": "CARD_DECLINED",
    "external_id": "your-external-id-01",
    "capture_amount": 700,
    "business_id": "5785e6334d7b410667d355c4",
    "merchant_reference_code": "59158c7a7c865a48268c91f0",
    "merchant_id": "xendit",
    "eci": "05",
    "charge_type": "RECURRING",
    "card_type": "CREDIT",
    "card_brand": "VISA",
    "masked_card_number": "400000XXXXXX0002",
    "created": "2017-05-12T10:21:32.725Z"
}

Every time a charge created at interval that you've been specified, we will notify you using a callback. You can set your callback URL in the Dashboard at Settings > Configuration > Credit Cards.

Parameter Description
id
required
string ID of the charge captured.
status
required
string Status of the charge. See Charge Statuses
failure_reason
optional
string If status is FAILED, this describes the failure. See Charge Failure Reasons
external_id
required
string A unique identifier of your choice
capture_amount
required
number The charge amount
business_id
required
string The ID of your business in Xendit.
merchant_reference_code
required
string An ID used to reconcile transactions with the bank.
merchant_id
required
string Your merchant ID used for processing credit cards with the bank.
eci
optional
string Status of 3DS authentication. See ECI codes
charge_type
required
string Types of charges. See Charge types
card_type
required
string Type of card (CREDIT or DEBIT)
card_brand
required
string Card scheme (VISA, MASTERCARD,...)
created
required
string An ISO timestamp that tracks when the charge was made

Get Subscription

Definition: Get Subscription

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

Example Get Subscription Request

curl https://api.xendit.co/managed_subscriptions/591e7edafe439c3c698bc8a9 \
    -X GET \
    -u xnd_development_O46JfOtygef9kMNsK+ZPGT+ZZ9b3ooF4w3Dn+R1k+2fT/7GlCAN3jg==:
// BETA - Not yet added to PHP Library

Example Subscription Response

{
  "token_id": "591e7edafe439c3c698bc8a9",
  "authorization_id": "5963c7b313c7f01759213033",
  "amount": 75000,
  "frequency": "MONTHLY",
  "start_date": "2017-07-10T17:00:00.000Z",
  "end_date": "2018-07-09T17:00:00.000Z",
  "status": "ACTIVE",
  "id": "5963c7b313c7f01759213034"
}

Get Subscription Request

Parameter Description
id
required
string The id of the Subscription you would like to retrieve

Get Subscription Response

The get Subscription response will conform to the structure outlined by the Subscription Schema

Get Subscription Errors

Error Code Description
API_VALIDATION_ERROR
400
Inputs are failing validation. The errors field contains details about which fields are violating validation.
MANAGED_SUBSCRIPTION_NOT_FOUND_ERROR
404
A Subscription with the given id was not found

Cancel Subscription

Definition: Cancel Subscription

POST https://api.xendit.co/managed_subscriptions/:id/cancellation

Example Cancel Subscription Request

curl https://api.xendit.co/managed_subscriptions/591e7edafe439c3c698bc8a9/cancellation \
    -X POST \
    -u xnd_development_O46JfOtygef9kMNsK+ZPGT+ZZ9b3ooF4w3Dn+R1k+2fT/7GlCAN3jg==:
// BETA - Not yet added to PHP Library

Example Subscription Cancellation Response

{
  "token_id": "591e7edafe439c3c698bc8a9",
  "authorization_id": "5963c7b313c7f01759213033",
  "amount": 75000,
  "frequency": "MONTHLY",
  "start_date": "2017-07-10T17:00:00.000Z",
  "end_date": "2018-07-09T17:00:00.000Z",
  "status": "CANCELLED",
  "id": "5963c7b313c7f01759213034"
}

Cancel Subscription Request

Parameter Description
id
required
string The id of the Subscription you would like to cancel

Cancel Subscription Response

The cancel Subscription response will confirm to the structure outlined by the Subscription Schema

Cancel Subscription Errors

Error Code Description
API_VALIDATION_ERROR
400
Inputs are failing validation. The errors field contains details about which fields are violating validation.
MANAGED_SUBSCRIPTION_NOT_FOUND_ERROR
404
A Subscription with the given id was not found

Fraud Detection

Javascript Function: createToken (with Fraud Detection)

Xendit.card.createToken(tokenData, fraudData, 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
    }
});

Javascript Function: createAuthentication (with Fraud Detection)

Xendit.card.createAuthentication(authenticationData, fraudData, 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
    }
});

Example fraudData object

{        
    "billing_first_name": "Giuseppe",
    "billing_last_name": "Contini",
    "billing_street_1": "123 Elm St.",
    "billing_city": "Cambridge",
    "billing_state": "MA",
    "billing_country": "US",
    "billing_postal_code": "02139",
    "billing_email": "joe@xendit.co",
    "billing_customer_id": "joe_16171235678",
    "billing_phone_number": "+16171235678",
    "shipping_first_name": "Joe",
    "shipping_last_name": "Contini",
    "shipping_street_1": "Jl. Casablanca Raya 88",
    "shipping_city": "Jakarta Selatan",
    "shipping_state": "Jakarta",
    "shipping_country": "ID",
    "shipping_postal_code": "12870",
    "shipping_phone_number": "+6281213831234",
    "shipping_method": "JNE",
    "items" : [
       {    
         "product_sku" : "106101100105",
         "product_code" : "Lightsaber_green_02",
         "product_name" : "Electrum Lightsaber",
         "quantity" : "1",
         "unit_price" : "4000000"
       }
    ]
}

Example Tokenization Response (with Fraud Detection)

{
    "id": "586f4a15dd75f9e1722f8488",
    "status": "VERIFIED",
    "risk_score": 29,
    "payer_authentication_url": "https://api.xendit.co/credit_card_tokens/586f4a15dd75f9e1722f8488/authentication_redirect?api_key=xnd_public_development_O4iFfuQhgLOsl8M9eeEYGzeWYNH3otV5w3Dh%2FBFj%2FmHW%2B72nCQR%2F"
}

Fraud detection is performed by including an additional fraudData object during Tokenization for single charges, and during Authentication for multiple charges.

Fraud Fields

Parameter Description
billing_first_name
required
string Billing first name
billing_last_name
required
string Billing last name
billing_street_1
required
string Billing address
billing_city
required
string Billing city
billing_state
required
string Billing State. Required only for US/Canada.
billing_country
required
string Billing Country
billing_postal_code
required
string Billing postal code. Required only for US/Canada.
billing_email
required
string Billing email
billing_customer_id
optional
string Billing customer ID
billing_phone_number
optional
string Billing phone number
shipping_first_name
optional
string Shipping first name
shipping_last_name
optional
string Shipping last name
shipping_street_1
optional
string Shipping address
shipping_city
optional
string Shipping city
shipping_state
optional
string Shipping state. Required for U.S. and Canada
shipping_country
optional
string Shipping country
shipping_postal_code
optional
string Shipping postal code. Required only for US/Canada.
shipping_phone_number
optional
string Shipping phone number
shipping_method
optional
string Shipping method
items
optional
array Items in the order. See Fraud Item Fields

Fraud Item Fields

Parameter Description
product_sku
required
string Product SKU
product_code
required
string Product code
product_name
required
string Product name
quantity
required
string Quantity
unit_price
required
string Unit price

See Create Token for the list of Tokenization Statuses, Tokenization Failure Reasons, and Tokenization Errors that can be returned when using fraud detection.

Virtual Accounts

Get banks for virtual accounts

Endpoint: Get Available Banks for Virtual Accounts

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

Example Get Banks for Virtual Accounts 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 Banks for Virtual Accounts Response

Example Get Banks for Virtual Accounts Response

{
  "name": "Bank Central Asia (BCA)",
  "code": "BCA"
}
Parameter Description
name Full name of the bank
code Code of the bank, relevant during creation of virtual accounts

Create fixed virtual accounts

Endpoint: Create Fixed Virtual Account (FVA)

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. 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 Accounts 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=BCA \
   -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 = 'BCA';
  $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': 'BCA',  '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 ID of the user in your system
bank_code
required
string Bank code of the virtual account you want to create
name
required
string Name of user/virtual account - this will be displayed as is in the UX, e.g. ATM confirmation screens
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
suggested_amount
optional
number The suggested amount you want to assign. If you do not send one, external id will be used
Note: suggested amounts is only supported for BCA
is_closed
optional
boolean When set to true, the virtual account will be closed and will only accept the amount specified in expected_amount
Note: closed virtual accounts are only supported for BCA and BNI
expected_amount
optional
number The amount that the virtual account will expect if is_closed is set to true.
Note: closed virtual accounts are only supported for BCA and BNI

Create Fixed Virtual Accounts Response

Example Create Fixed Virtual Accounts Response

{
   "owner_id":"57b4e5181473eeb61c11f9b9",
   "external_id":"demo-1475804036622",
   "bank_code":"BCA",
   "merchant_code":"02938",
   "name":"Rika Sutanto",
   "account_number":"029382548",
   "is_closed": false,
   "id":"57f6fbf26b9f064272622aa6"
}
Parameter Description
owner_id Your user ID
external_id An ID of your choice we append to all transactions. Often your unique ID like a phone number, email or transaction ID
bank_code Bank code for the relevant bank, e.g. BCA
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.

Create Fixed Virtual Accounts 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.

Update fixed virtual accounts

Endpoint: Update Fixed Virtual Account (FVA)

PATCH https://api.xendit.co/callback_virtual_accounts/{fixed_virtual_account_id}

Fixed Virtual Account is so adaptable, and it's all based on your needs. Therefore, we provide you this endpoint to easily update your fixed virtual account as you like.

Update Fixed Virtual Accounts Request

Parameter Description
suggested_amount
optional
number suggested amount you want to assign
is_closed
optional
boolean When set to true, the virtual account will be closed and will only accept the amount specified in expected_amount
Note: closed virtual accounts are only supported for BCA and BNI
expected_amount
optional
number The amount that the virtual account will expect if is_closed is set to true.
Note: closed virtual accounts are only supported for BCA and BNI

Update Fixed Virtual Accounts Response

Example update Fixed Virtual Accounts Response

{
   "owner_id":"57b4e5181473eeb61c11f9b9",
   "external_id":"demo-1475804036622",
   "bank_code":"BCA",
   "merchant_code":"02938",
   "name":"Rika Sutanto",
   "account_number":"029382548",
   "suggested_amount":50000,
   "is_closed": false,
   "id":"57f6fbf26b9f064272622aa6"
}
Parameter Description
owner_id Your user ID
external_id An ID of your choice we append to all transactions. Often your unique ID like a phone number, email or transaction ID
bank_code Bank code for the relevant bank, e.g. BCA
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

Update Fixed Virtual Accounts 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.

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: 'BCA',
    amount: 99000,
    transaction_timestamp: '2016-10-10T08:15:03.080Z',
    merchant_code: '02938',
    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", "eG5kX2RldmVsb3BtZW50X1A0cURmT3NzME9DcGw4UnRLclJPSGphUVlOQ2s5ZE41bFNmaytSMWw5V2JlK3JTaUN3WjNqdz09Og==")
  .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. 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 and go to settings -> configuration -> fixed virtual account.

Fixed Virtual Account Callback Request

Example Fixed Virtual Account Callback Request

curl --include \
     --request POST \
     --header "Content-Type: application/json" \
     --header "X-CALLBACK-TOKEN: eG5kX2RldmVsb3BtZW50X1A0cURmT3NzME9DcGw4UnRLclJPSGphUVlOQ2s5ZE41bFNmaytSMWw5V2JlK3JTaUN3WjNqdz09Og==" \
     --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: \"BCA\",
    amount: 99000,
    transaction_timestamp: \"2016-10-10T08:15:03.080Z\",
    merchant_code: \"02938\",
    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 we append to all transactions. Often your unique ID like a phone number, email or transaction ID
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. BCA
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 Callback Errors

Note that in the case where we don't get a response from your servers, we will retry 5 times with a 10 second delay between each retry. After 5 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 11000.
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

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,
  "received_amount": 47500,
  "payer_email": "albert@xendit.co",
  "description": "This is a description",
  "invoice_url": "https://invoice.xendit.co/web/invoices/595b6248c763ac05592e3eb4",
  "xendit_fee_amount": 500,
  "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": "UNIQUE",
      "bank_branch": "KCP Jkt Mayestik",
      "bank_account_number": "1261006593021",
      "account_holder_name": "SENDIRI DIGITAL INDO",
      "transfer_amount": 54002,
      "identity_amount": 2
    }
  ],
  "should_exclude_credit_card": 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 An ID of your choice we append to all transactions. Often your unique ID like a phone number, email or transaction ID
status PENDING the invoice has yet to be paid
COMPLETED the invoice has successfully been 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
received_amount Amount attributable to you net of our fees. Thanks for using us :)
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
xendit_fee_amount Xendit fees - thanks for supporting a better world of payments :)
expiry_date ISO date and time that the invoice expires. Default is 24 hours. If you'd like to change the default for your account, please contact our support team.
available_banks
bank_code
collection_type

bank_branch
account_holder_name
bank_account_number
transfer_amount
identity_amount
Available payment methods as per your config
Bank code (see bank codes)
UNIQUE type is unique amounts
POOL type is nonfixed virtual account
Name of the bank branch (if unique amounts)
Name of the bank account (if unique amounts)
Bank account number for users to pay into
Amount the user should transfer
Amount to identify the payment (if unique amounts)
should_exclude_credit_card A flag showing if credit card should be excluded in invoice UI or not
created An ISO timestamp that tracks when the invoice was created
updated An ISO timestamp that tracks when the invoice was updated

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 Rp11000.
NO_COLLECTION_METHODS_ERROR
400
Your account has no payment methods configured (unique amount, virtual account, credit card). Please contact support and we will set this up for you.
UNIQUE_AMOUNT_UNAVAILABLE_ERROR
404
There is no unique amount available for invoice amount that you've specified.
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

Get an 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));
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,
  "received_amount": 47500,
  "payer_email": "albert@xendit.co",
  "description": "This is a description",
  "invoice_url": "https://invoice.xendit.co/web/invoices/595b6248c763ac05592e3eb4",
  "xendit_fee_amount": 500,
  "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": "UNIQUE",
      "bank_branch": "KCP Jkt Mayestik",
      "bank_account_number": "1261006593021",
      "account_holder_name": "SENDIRI DIGITAL INDO",
      "transfer_amount": 54002,
      "identity_amount": 2
    }
  ],
  "should_exclude_credit_card": 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 An ID of your choice we append to all transactions. Often your unique ID like a phone number, email or transaction ID
status PENDING the invoice has yet to be paid
COMPLETED the invoice has successfully been 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
received_amount Amount attributable to you net of our fees. Thanks for using us :)
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
xendit_fee_amount Xendit fees - thanks for supporting a better world of payments :)
expiry_date ISO date and time that the invoice expires. Default is 24 hours. If you'd like to change the default for your account, please contact our support team.
available_banks
bank_code
collection_type

bank_branch
account_holder_name
bank_account_number
transfer_amount
identity_amount
Available payment methods as per your config
Bank code (see bank codes)
UNIQUE type is unique amounts
POOL type is nonfixed virtual account
Name of the bank branch (if unique amounts)
Name of the bank account (if unique amounts)
Bank account number for users to pay into
Amount the user should transfer
Amount to identify the payment (if unique amounts)
should_exclude_credit_card

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

updated

An ISO timestamp that tracks when the invoice was updated

created

An ISO timestamp that tracks when the invoice was created

Get Invoice Errors

Error Code Description
INVALID_JSON_FORMAT
400
The request body is not a valid JSON format.
INVOICE_NOT_FOUND_ERROR
404
Could not find invoice by id.

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: 'UNIQUE',
  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: 'COMPLETED',
  id: '593f4ed1c3d3bb7f39733d83'
}");
Response response = client.target("https://api.xendit.co/invoice_callback_url")
  .request(MediaType.APPLICATION_JSON_TYPE)
  .header("X-CALLBACK-TOKEN", "eG5kX2RldmVsb3BtZW50X1A0cURmT3NzME9DcGw4UnRLclJPSGphUVlOQ2s5ZE41bFNmaytSMWw5V2JlK3JTaUN3WjNqdz09Og==")
  .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 -> Configuration -> Accept Payments.

Invoice Callback Request

Example Invoice Callback Request

curl --include \
     --request POST \
     --header "X-CALLBACK-TOKEN: eG5kX2RldmVsb3BtZW50X1A0cURmT3NzME9DcGw4UnRLclJPSGphUVlOQ2s5ZE41bFNmaytSMWw5V2JlK3JTaUN3WjNqdz09Og==" \
     --header "Content-Type: application/json" \
     --data-binary "{
      id: \"593f4ed1c3d3bb7f39733d83\",
      user_id: \"5848fdf860053555135587e7\",
      external_id: \"testing-invoice\",
      is_high: false,
      merchant_name: \"Xendit\",
      amount: 2000000,
      xendit_fee_amount: 20000,
      received_amount: 1980000,
      status: \"COMPLETED\"
      payer_email: \"test@xendit.co\",
      description: \"Invoice callback test\",
      adjusted_xendit_fee_amount: 19064,
      adjusted_received_amount: 1980000,
      payment_method: \"UNIQUE\",
      bank_code: \"MANDIRI\",
      paid_amount: 1999064,
      updated: \"2017-06-13T02:32:50.912Z\",
      created: \"2017-06-13T02:32:49.827Z\",
}" \
'https://api.xendit.co/invoice_callback_url'
Parameter Description
id An invoice ID generated by Xendit
user_id Your Xendit Business ID
external_id An ID of your choice we append to all transactions. Often your unique ID like a phone number, email or transaction ID
is_high Should unique numbers go above or below the amount. If true, it would mean a 100.000 invoice would display a unique amount above, e.g. 100.123
status COMPLETED the invoice has successfully been paid
merchant_name The name of your company or website
amount Nominal amount for the invoice (without taxes, fees)
received_amount Amount attributable to you net of our fees. Thanks for using us :)
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
xendit_fee_amount Xendit fees - thanks for supporting a better world of payments :)
expiry_date ISO date and time that the invoice expires. We reserve unique numbers only for a specific period of time. After that, we’ll reset with a different number. You can configure this expiry time in dashboard.
paid_amount Total amount paid for the invoice
bank_code Code of the bank used to received the money if payment method is UNIQUE or POOL
payment_method The way the invoice is being paid
UNIQUE type is unique amounts
POOL type is nonfixed virtual account
CREDIT_CARD type is credit card
adjusted_received_amount Amount attributable to you net of our fees. Thanks for using us :)
adjusted_xendit_fee_amount Xendit fees - thanks for supporting a better world of payments :)

Invoice Callback Errors

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

Disburse Funds

Disbursements are objects 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

curl https://api.xendit.co/disbursements -X POST \
   -u xnd_development_O46JfOtygef9kMNsK+ZPGT+ZZ9b3ooF4w3Dn+R1k+2fT/7GlCAN3jg==: \
   -H "X-IDEMPOTENCY-KEY: unique-id-12345" \
   -d external_id=demo_1475459775872 \
   -d bank_code=BCA \
   -d account_holder_name='Bob Jones' \
   -d account_number='1231241231' \
   -d description='Reimbursement for shoes' \
   -d amount=17000
<?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';

  $response = $xenditPHPClient->createDisbursement($external_id, $amount, $bank_code, $account_holder_name, $account_number);
  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 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
external_id
required
string ID of the disbursement in your system, used to reconcile disbursements after they have been completed
bank_code
required
string Code of the destination bank
account_holder_name
required
string Name of the destination bank account owner
account_number
required
string Number for destination bank account
description
required
string Description to send with the disbursement
amount
required
number Amount to disburse

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"
}
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 Destination bank code. See bank codes
account_holder_name
required
string Bank account name as per the bank'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

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 Dashboard > Configuration > Disbursement. 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.

Get disbursement

Endpoint: Get Disbursement

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

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"
}
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 but not yet completed by bank.
DISBURSING Funds are being sent by the bank.
COMPLETED Bank has confirmed transmission of funds.
FAILED Bank rejected disbursement. We will not retry.
id Unique disbursement ID

Get Disbursement Errors

Error Code Description
INVALID_JSON_FORMAT
400
The request body is not a valid JSON format.
INVALID_PERMISSION_ERROR
403
Could not access that disbursement.
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': 150000,  'bank_code': 'BCA',  'xendit_fee_amount': 0,  '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': false,  'status': 'FAILED',  'updated': '2016-10-10T08:15:03.404Z',  'created': '2016-10-10T08:15:03.404Z'}");
Response response = client.target("https://api.xendit.co/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: eG5kX2RldmVsb3BtZW50X1A0cURmT3NzME9DcGw4UnRLclJPSGphUVlOQ2s5ZE41bFNmaytSMWw5V2JlK3JTaUN3WjNqdz09Og==" \
     --data-binary "{
    \"id\": \"57e214ba82b034c325e84d6e\",
    \"user_id\": \"57c5aa7a36e3b6a709b6e148\",
    \"external_id\": \"disbursement_123124123\",
    \"amount\": 150000,
    \"bank_code\": \"BCA\",
    \"xendit_fee_amount\": 0,
    \"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\": false,
    \"status\": \"FAILED\",
    \"updated\": \"2016-10-10T08:15:03.404Z\",
    \"created\": \"2016-10-10T08:15:03.404Z\"
}" \
'https://api.xendit.co/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 Your account balance is not enough to do disbursement with desired amount
INVALID_DESTINATION Your destination account is not registered
DIRECT_DISBURSEMENT_FAILED Disbursement failed because various reason, please contact our support for more details
id Unique disbursement ID

Disbursement Callback Errors

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

Get available disbursement 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

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
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.

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 response from your servers, we will retry 5 times with a 10 second delay between each retry. After 5 failures, we get internal alerts that a callback has failed. Our team will then contact you to resolve the issue.

Get available disbursement 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

Name Validator

Endpoint: Validate Name

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

Example Name Validator Request

curl https://api.xendit.co/bank_account_data_requests \
    -X POST \
    -u xnd_development_O46JfOtygef9kMNsK+ZPGT+ZZ9b3ooF4w3Dn+R1k+2fT/7GlCAN3jg==: \
    -d bank_account_number="1550001953382" \
    -d bank_code="MANDIRI"
<?php
  require 'vendor/autoload.php';

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

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

  $bank_account_number = '1550001953382';
  $bank_code = 'MANDIRI';

  $response = $xenditPHPClient->validateBankAccountHolderName($bank_account_number, $bank_code);
  print_r($response);
?>

The Name Validator can be used to look up the name of an account holder for any bank account in Indonesia. Because it can take a few seconds to look up the name with the banks, the result is returned in a callback if it is not already cached. Be sure to have a callback URL configured for Bank account data in the Xendit Dashboard Configuration.

Name Validator Request

Parameter Description
bank_account_number string (required)
The bank account number
bank_code string (required)
The bank code. See Bank Codes

Name Validator Response

Example Name Validator Response (Uncached)

{
  "bank_account_number": "5015378625",
  "bank_code": "BCA",
  "reference": "58cd618ba0464eb64acdb246",
  "status": "PENDING",
  "updated": "2017-07-03T10:51:44.484Z"
}

Example Name Validator Response (Cached)

{
  "bank_account_number": "1234567899",
  "bank_account_holder_name": "JOE CONTINI",
  "bank_code": "MANDIRI",
  "reference": "58cd618ba0464eb64acdb246",
  "status": "SUCCESS",
  "updated": "2017-03-24T08:11:07.624Z"
}

Example Name Validator Callback

{
  "bank_account_number": "1234567899",
  "bank_account_holder_name": "JOE CONTINI",
  "bank_code": "MANDIRI",
  "status": "SUCCESS",
  "updated": "2017-03-24T08:11:07.624Z"
}

If the account number has not been cached, the response will have "status": "PENDING", and you will be a sent a callback when the request completes.

Once cached, the name will be returned immediately in the response.

Name Validator Schema

Parameter Description
bank_code string (required)
The bank code. See Bank Codes
bank_account_number string (required)
The bank account number
bank_account_holder_name string (required)
Account Holder Name
status string (required)
PENDING The name validation request is still being processed
SUCCESS The name validation request has been completed
FAILURE The name validation request has failed
failure_reason string (optional)
See Name Validator Errors
reference string (required)
The ID of the business that made the request
updated string (required)
The last updated date of the name validation request

Name Validator Errors

Error Code Description
MAX_RETRY_TIMES_EXCEED_ERROR
400
Our system has retried the request several times but still failed because of an unknown error response from the bank.
RECIPIENT_NOT_FOUND_ERROR
404
There’s no bank recipient with this account number.
UNSUPPORTED_BANK_CODE_ERROR
404
Destination bank is not supported, request is using the wrong bank code.

Errors

Below are some of most common errors across all our endpoints. Specific errors are located under each endpoint. If you have any questions please contact us.

Error code Meaning
400 Bad request, e.g. validation error
401 Unauthorised access, e.g. the wrong API key
403 Forbidden access, e.g. API key does not have permission for this endpoint
404 Page or data not found
500 Unhandled error - contact us when this happens