OVO Open API
Introduction
OVO Open API Activation
info
If you are personal seller, you can't use the OVO Open API due to the limitation from the OVO. Worry not! If you wish to receive payments from OVO, you can activate OVO Push Payment which enable you to receive payments from OVO.
Requirements
- Client ID / Secret Key from OVO
- DOKU account. To access DOKU API, you need DOKU client id & DOKU client key that you can find in DOKU back office.
Integration Flow
Here is the overview flow for OVO Open API :
Direct API - OVO Open API Sequence Diagram

API list
Here is the sample of request header to implement every API list below :
Client-Id: MCH-0001-10791114622547
Request-Id: 15022aab-444f-4b04-afa8-ddfce89432ec
Request-Timestamp: 2020-08-11T08:45:42Z
Signature: HMACSHA256=vl9DBTX5KhEiXmnpOD0TSm8PYQknuHPdyHSTSc3W6Ps=
Request Header Explanation
Parameter | Description |
---|---|
Client-Id | Client ID retrieved from DOKU Back Office |
Request-Id | Unique random string (max 128 characters) generated from merchant side to protect duplicate request |
Request-Timestamp | Timestamp request on UTC time in ISO8601 UTC+0 format. It means to proceed transaction on UTC+7 (WIB), merchant need to subtract time with 7. Ex: to proceed transaction on September 22th 2020 at 08:51:00 WIB, the timestamp should be 2020-09-22T01:51:00Z |
Signature | Security parameter that needs to be generated on merchant Backend and placed to the header request to ensure that the request is coming from valid merchant. Please refer to this section to generate the signature |
Merchant and DOKU must validate signature in API list, see how to generate signature. You can refer to Generate Signature.
User Account Linkage
Merchant can binding OVO account to customer id, each OVO account can only binding to one customer on one merchant. Customer need to verify OTP and input PIN on OVO page.
API Request
Type | Value |
---|---|
HTTP Method | POST |
API endpoint (Sandbox) | https://api-sandbox.doku.com/ovo-open-api/v1/token |
API endpoint (Production) | https://api.doku.com/ovo-open-api/v1/token |
Here is the sample of request body to binding OVO account to customer id :
{
"customer": {
"id": "CUSTOMER_OVOxDOKU",
"name": "TESTINGQA",
"phone": "087872180555",
"email": "test@gmail.com",
"additional_info": "None"
},
"ovo_account": {
"account_mobile_phone": "6287872180555",
"success_registration_url": "https://www.wtdteam.com/success",
"failed_registration_url": "https://www.wtdteam.com/failed"
}
}
Request Body Explanation
Parameter | Type | Mandatory | Description |
---|---|---|---|
customer.id | string (50) | Mandatory | Merchant customer id |
customer.name | string (70) | Optional | Customer name |
customer.email | string (255) | Optional | Customer email |
customer.phone | string (20) | Optional | Customer phone number |
customer.additional_info | string (20) | Optional | Customer additional info |
ovo_account.account_mobile_phone | string (20) | Mandatory | Register phone number on OVO |
ovo_account.success_registration_url | string (2048) | Mandatory | URL for direct page after success register |
ovo_account.failed_registration_url | string (2048) | Mandatory | URL for direct page after failed register |
API Response
After hitting the above API request, DOKU will give the response.
Type | Value |
---|---|
HTTP Status | 201 |
Result | SUCCESS |
Here is the sample of response body:
{
"customer": {
"id": "CUSTOMER_OVOxDOKU",
"name": "TESTINGQA",
"phone": "087872180555",
"email": "test@gmail.com",
"additional_info": "None"
},
"ovo_account": {
"registration_url": "https://jokul.doku.com/ovo-open-api/registration/sessionId/27817263817263817",
"status": "PENDING"
}
}
Response Body Explanation
Parameter | Type | Mandatory | Description |
---|---|---|---|
customer.id | string (50) | Mandatory | Merchant customer id |
customer.name | string (70) | Optional | Customer name |
customer.email | string (255) | Optional | Customer email |
customer.phone | string (20) | Optional | Customer phone number |
customer.additional_info | string (20) | Optional | Customer additional info |
ovo_account.account_mobile_phone | string (20) | Mandatory | Register phone number on OVO |
ovo_account.registration_url | string (2048) | Mandatory | URL from DOKU for Customer to binding their account |
ovo_account.status | string | Mandatory | Always PENDING for Successfull token request (waiting for OTP verification & PIN vervification) |
Get List Token (OVO)
After successful account linkage, merchant can get OVO token that can be used for that customer to payment using OVO. Token is created by DOKU, and valid for 1 year.
API Request
Type | Value |
---|---|
HTTP Method | POST |
API endpoint (Sandbox) | https://api-sandbox.doku.com/tokenization/v1/tokens |
API endpoint (Production) | https://api.doku.com/tokenization/v1/tokens |
Here is the sample of request body to get Token for OVO :
{
"customer": {
"id": "CUSTOMER_OVOxDOKU"
},
"token_data": {
"type": "WALLET"
}
}
Request Body Explanation
Parameter | Type | Mandatory | Description |
---|---|---|---|
customer.id | string (50) | Mandatory | Customer id that already have active token |
token_data.type | string | Optional | DIRECT_DEBIT / CREDIT_CARD / WALLET , if not specified get all payment channel token |
API Response
After hitting the above API request, DOKU will give the response.
Type | Value |
---|---|
HTTP Status | 200 |
Result | SUCCESS |
{
"customer": {
"id": "CUSTOMER_OVOxDOKU",
"name": "TESTINGQA"
},
"token_data": {
"type": "WALLET"
},
"wallet": {
"issuer": "OVO",
"token_id": "fc72c4b0aedff916ab92e39cb80d3675",
"masked_phone_number": "****1454"
}
}
Response Body Explanation
Parameter | Type | Mandatory | Description |
---|---|---|---|
customer.id | string (50) | Mandatory | Merchant customer id |
customer.name | string (70) | Optional | Customer name |
token_data.type | string | Mandatory | Token Type : CREDIT CARD, DIRECT DEBIT , or WALLET |
wallet.issuer | string (255) | Mandatory | Issuer for wallet binding |
wallet.token_id | string (128) | Mandatory | Token generated by DOKU |
wallet.masked_phone_number | string (8) | Mandatory | Phone number masked |
Get Account Balance
This balance check API allows users to check their latest OVO balance. The user should be able to access their balance at any time so they can make accurate and up to date decision regarding their transactions.
API Request
Type | Value |
---|---|
HTTP Method | POST |
API endpoint (Sandbox) | https://api-sandbox.doku.com/ovo-open-api/v1/balance |
API endpoint (Production) | https://api.doku.com/ovo-open-api/v1/balance |
Here is the sample of request body to get balance for OVO :
{
"customer": {
"id": "CUSTOMER_OVOxDOKU"
},
"ovo_account": {
"token_id": "fc72c4b0aedff916ab92e39cb80d3111"
}
}
Request Body Explanation
Parameter | Type | Mandatory | Description |
---|---|---|---|
customer.id | string (64) | Mandatory | Customer id that already have active token |
ovo_account.token_id | string (128) | Mandatory | Token generated by DOKU |
API Response
After hitting the above API request, DOKU will give the response.
Type | Value |
---|---|
HTTP Status | 201 |
Result | SUCCESS |
{
"customer": {
"id": "CUSTOMER_OVOxDOKU",
"name": "TESTINGQA",
"phone": "087872180555",
"email": "test@gmail.com",
"additional_info": "None"
},
"ovo_account": {
"ovo_cash_balance": "100000",
"ovo_point_balance": "100000"
}
}
Response Body Explanation
Parameter | Type | Mandatory | Description |
---|---|---|---|
customer.id | string (50) | Mandatory | Merchant customer id |
customer.name | string (70) | Optional | Customer name |
customer.email | string (255) | Optional | Customer email |
customer.phone | string (20) | Optional | Customer phone number |
customer.additional_info | string (20) | Optional | Customer additional info |
ovo_account.ovo_cash_balance | number (10) | Mandatory | OVO Cash Balance |
ovo_account.ovo_point_balance | number (10) | Mandatory | OVO Point Balance |
Payment Using Token
Payment using OVO token from OVO cash balance or/and OVO point balance. When OVO have program for payment using OVO point, customer can paying using OVO point balance on merchant. Payment using mixed OVO point and OVO cash, OVO point will be deducted first and the remaining will be deducted from OVO cash. Customer need to verify payment by input PIN on OVO page.
API Request
Type | Value |
---|---|
HTTP Method | POST |
API endpoint (Sandbox) | https://api-sandbox.doku.com/ovo-open-api/v1/payment |
API endpoint (Production) | https://api.doku.com/ovo-open-api/v1/payment |
Here is the sample of request body to do payment using OVO Token :
{
"customer": {
"id": "CUSTOMER_OVOxDOKU",
"name": "TESTINGQA",
"phone": "087872180555",
"email": "test@gmail.com",
"additional_info": "None"
},
"additional_info": {
},
"order": {
"invoice_number": "MINV20201231468",
"line_items": [
{
"name": "bola",
"price": 10000,
"quantity": 1
},
{
"name": "ubi",
"price": 5000,
"quantity": 1
}
],
"amount": 15000
},
"ovo_account": {
"token_id":"bcdbcdbcdbcbdbcdb-bcdbcd-bcdbcdb",
"payment_use_ovo_point": false,
"success_payment_url": "https://www.wtdteam/success",
"failed_payment_url": "https://www.wtdteam/failed"
}
}
Request Body Explanation
Parameter | Type | Mandatory | Description |
---|---|---|---|
customer.id | string (50) | Mandatory | Merchant customer id |
customer.name | string (70) | Optional | Customer name |
customer.email | string (255) | Optional | Customer email |
customer.phone | string (20) | Optional | Customer phone number |
customer.additional_info | string (20) | Optional | Customer additional info |
additional_info | Json | Optional | additional info |
order.invoice_number | string (32) | Mandatory | Merchant transaction id unique per client id, only accept alphanumeric, _ and - Min length is 3, max length is 32 |
order.line_items.name | string | Optional | Privacy concern so optional, but if send will help our risk engine |
order.line_items.price | number | Optional | Privacy concern so optional, but if send will help our risk engine |
order.line_items.quantity | number | Mandatory | Privacy concern so optional, but if send will help our risk engine |
order.amount | number (10) | Mandatory | Converted total amount. |
ovo_account.token_id | string (128) | Mandatory | OVO E-Wallet Token |
ovo_account.payment_use_ovo_point | string (5) | Optional | Default false, if True will use all OVO Point first before use OVO Cash |
ovo_account.success_payment_url | string (2048) | Mandatory | URL for direct page after success payment |
ovo_account.failed_payment_url | string (2048) | Mandatory | URL for direct page after failed payment |
API Response
After hitting the above API request, DOKU will give the response.
Type | Value |
---|---|
HTTP Status | 201 |
Result | SUCCESS |
{
"customer": {
"id": "CUSTOMER_OVOxDOKU",
"name": "TESTINGQA",
"phone": "087872180555",
"email": "test@gmail.com",
"additional_info": "None"
},
"additional_info": {
},
"order": {
"invoice_number": "MINV20201231468",
"line_items": [
{
"name": "bola",
"price": 10000,
"quantity": 1
},
{
"name": "ubi",
"price": 5000,
"quantity": 1
}
],
"amount": 15000
},
"payment": {
"ovo_payment_url": "https://jokul.doku.com/ovo-open-api/payment/sessionId/27817263817263817263817",
"status": "PENDING"
}
}
Response Body Explanation
Parameter | Type | Mandatory | Description |
---|---|---|---|
customer.id | string (50) | Mandatory | Merchant customer id |
customer.name | string (70) | Optional | Customer name |
customer.email | string (255) | Optional | Customer email |
customer.phone | string (20) | Optional | Customer phone number |
customer.additional_info | string (20) | Optional | Customer additional info |
additional_info | Json | Optional | additional info |
order.invoice_number | string (32) | Mandatory | Merchant transaction id unique per client id, only accept alphanumeric, _ and - Min length is 3, max length is 32 |
order.line_items.name | string | Optional | Privacy concern so optional, but if send will help our risk engine |
order.line_items.price | number | Optional | Privacy concern so optional, but if send will help our risk engine |
order.line_items.quantity | number | Mandatory | Privacy concern so optional, but if send will help our risk engine |
order.amount | number (10) | Mandatory | Converted total amount. |
payment.ovo_payment_url | string (255) | Mandatory | url from DOKU for customer to input pin for transaction |
ovo_account.payment_use_ovo_point | string (5) | Optional | Default false, if True will use all OVO Point first before use OVO Cash |
payment.status | string | Mandatory | URL for direct page after success payment |
ovo_account.failed_payment_url | string (2048) | Mandatory | PENDING for successful token request (waiting for OTP verification) / SUCCESS if not need OTP, TOKEN_EXPIRED (need to input PIN twice and still can proceed to transaction) |
Refund
Refund OVO transaction. For payment using mixed OVO cash and OVO point, OVO point will be refunded first.
API Request
Type | Value |
---|---|
HTTP Method | POST |
API endpoint (Sandbox) | https://api-sandbox.doku.com/ovo-open-api/v1/payment-refund |
API endpoint (Production) | https://api.doku.com/ovo-open-api/v1/payment-refund |
Here is the sample of request body to do refund for OVO Transaction :
{
"order": {
"invoice_number": "MINV20201231468"
},
"payment": {
"original_request_id": "82014"
},
"refund": {
"amount": 1000,
"reason": "Cancel Order"
}
}
Request Body Explanation
Parameter | Type | Mandatory | Description |
---|---|---|---|
order.invoice_number | string (32) | Mandatory | Invoice number of the transaction that being refunded, same as the request payment |
payment.original_request_id | string (128) | Mandatory | Request ID from Payment Initiation of the transaction that being refunded |
refund.amount | number | Mandatory | Transaction amount that wants to be refunded |
refund.reason | string (255) | Optional | Reason refund |
API Response
After hitting the above API request, DOKU will give the response.
Type | Value |
---|---|
HTTP Status | 201 |
Result | SUCCESS |
{
"order": {
"invoice_number": "MINV20201231468"
},
"payment": {
"original_request_id": "82014"
},
"refund": {
"amount": 1000,
"reason": "Cancel Order",
"status": "SUCCESS",
"message": "SUCCESS"
}
}
Response Body Explanation
Parameter | Type | Mandatory | Description |
---|---|---|---|
order.invoice_number | string (32) | Mandatory | Same as the request |
payment.original_request_id | string (128) | Mandatory | Same as the request |
refund.amount | number | Mandatory | Amount to be refunded |
refund.reason | string (255) | Optional | Reason refund |
refund.status | string | Mandatory | SUCCESS / FAILED |
refund.message | string (10) | Optional | Reason if failed refund |
Unbind Linked Account
Customer should always have option to unlink their OVO account from any merchant.
API Request
Type | Value |
---|---|
HTTP Method | POST |
API endpoint (Sandbox) | https://api-sandbox.doku.com/ovo-open-api/v1/token-delete |
API endpoint (Production) | https://api.doku.com/ovo-open-api/v1/token-delete |
Here is the sample of request body to unlink their OVO Account :
{
"customer": {
"id": "TEST-CIMBXDOKU-05",
"name": "DOKUXCIMB"
},
"ovo_account": {
"token_id": "1614dc147e404f41f6d2de877fda1f94"
}
}
Request Body Explanation
Parameter | Type | Mandatory | Description |
---|---|---|---|
customer.id | string (50) | Mandatory | Merchant id |
customer.name | string (50) | Mandatory | Merchant name |
ovo_account.token_id | string (128) | Mandatory | Token created from register ovo account that owned by this customer id |
API Response
After hitting the above API request, DOKU will give the response.
Type | Value |
---|---|
HTTP Status | 201 |
Result | SUCCESS |
{
"customer": {
"id": "TEST-CIMBXDOKU-05",
"name": "DOKUXCIMB"
},
"ovo_account": {
"token_id": "1614dc147e404f41f6d2de877fda1f94",
"status": "SUCCESS",
"message": "Success Unbiding OVO Account"
}
}
Response Body Explanation
Parameter | Type | Mandatory | Description |
---|---|---|---|
customer.id | string (50) | Mandatory | Merchant id |
customer.name | string (50) | Mandatory | Merchant name |
ovo_account.token_id | string (128) | Mandatory | Token created from register ovo account that owned by this customer id |
ovo_account.status | string | Mandatory | DELETED Token |
ovo_account.message | string | Optional | SUCCESS unbind token_id from customer |
Technical Reference
Payment Notification
Guide how to handle payment notification can refer to Handling HTTP Notification.
Handling Idempotent Request
Idempotency is a concept where a request can be sent multiple times with the same result as the first request, that means the system only performs one process for identical requests.
The examples below illustrate how idempotency is works.
Two Request, Connectivity Lost
Situation:
T0: Partner sends a payment request to DOKU T1: DOKU server receives this request and processes it successfully. With response http status 200 T2: Partner's server loses power prior to receiving the response in T1. T3: Partner's server power is restored and the same payment request is sent with all the same parameters (same request-ID and request details but updated requestTimestamp) to the DOKU server.
Outcome:
In this case the DOKU server reply with the same reply given at T1 since all the parameters, except for responseTimestamp, are the same. The user is only debited once, at T0. T3 has no monetary impact to the user.
Please note
DOKU reply http status 409 (CONFLICT) with same response if any potential loss for DOKU or Partner. For example, when process transaction if merchant can't handle properly idempotency response, and probably they will define as another success order.
List of Error Code
Error message | Error Code | HTTP Status Code | Explanation |
---|---|---|---|
FAILED | 0021 | 200 | Failed After check status to ovo, executed by system scheduler |
Invalid Header Signature | invalid_signature | 400 | Invalid Signature |
Idempotent Request | idempotent_request | 400 | Double request with same request id under 20 second |
ovo account not available please register to ovo | account_error | 400 | OVO account not found |
customer id must not be empty | invalid_parameter | 400 | Not input object customer id (applied to every mandatory parameter) |
attribute customer id must not bigger than 50 character(s) | invalid_parameter | 400 | Object customer id > 50 character (applied to every parameter that more than data type max length) |
email format must be valid | invalid_parameter | 400 | Invalid format in customer email |
account mobile phone format must be 62xxxx | invalid_parameter | 400 | Invalid format in Account mobile phone number |
invalid url for attribute success registration url | invalid_parameter | 400 | Invalid format in success registration url |
invalid url for attribute failed registration url | invalid_parameter | 400 | Invalid format in failed registration url |
attribute refund reason must not bigger than 255 character(s) | invalid_parameter | 404 | Object refund reasong > 255 character (applied to every parameter that more than data type max length) |
invalid token_id | invalid_parameter | 401 | Invalid token id |
Customer change phone number on OVO Platform | account_error | 400 | Customer change phone number on OVO Platform, please proceed to unbind linked account |
charge payment failed | account_error | 400 | Charge payment failed |
High risk transaction | re_error | 400 | High risk transaction |
attribute account_mobile_phone must be 10-20 digits | invalid_parameter | 400 | account_mobile_phone not in valid range 10 - 20 digits |
something wrong in OVO | account_error | 400 | Something wrong in OVO system please contact DOKU team |
exceeds attempt limit, not allowed request otp for 30min | account_error | 400 | Exceeds OTP request limit for this account_mobile_phone |
transaction not found | account_error | 400 | Refund can't be processed, transaction not yet done / not found |
ovo account already registered | invalid_access | 401 | OVO is already registered to other customer |
token not found | not_found | 404 | Token ID not found |
Given customer token not match with saved customer token | not_found | 404 | Customer token not match with saved customer id merchant |
Customer not found on Merchants Customer List | not_found | 404 | Customer not found |
Original transaction not found | not_found | 404 | Original payment not found |
refund amount is greater than paid amount | account_error | 400 | Refund amount greater than paid amount |
merchant not found | not_found | 404 | Merchant not found |
failed after 1 hour(s) | 0001 | 404 | Payment failed after 1 hour, assumption : Customer didnt continue payment on ovo, executed by system scheduler |
customer id already used | invalid_access | 401 | customer id already used |
OVO account blocked temporary | account_error | 400 | OVO account blocked temporary |
transaction not found in OVO | account_error | 400 | transaction not found in OVO |
invoice_number already exist | invalid_access | 401 | invoice_number already exist |
customer id not found | not_found | 404 | customer id not found |
Given invoice number not match with saved invoice number | invalid_access | 401 | Given invoice number not match with saved invoice number |
Given invoice number to be refunded does not belong to the merchant | invalid_access | 401 | Given invoice number to be refunded does not belong to the merchant |