In the SNAP-based Core API flow, Midtrans will call Payment Notification API on the merchant side to send payment notifications. Merchant should implement this Payment Notification API as stated in the contract below.
Midtrans will generate a pair of private and public key for signature generation and share the public key to merchant. Merchant will then need to give Midtrans a partner id that will be used in request header as X-PARTNER-ID.
Please make sure to whitelist this set of IPs to be able to accept notification from Midtrans.
Environment IPs Staging 3.1.141.98/32
52.76.190.190/32
13.251.192.204/32Production 13.228.166.126/32
52.220.80.5/32
3.1.123.95/32
Receiving payment notifications for GoPay and GoPay Tokenization (non Pre-Auth) transaction
This section will describe how merchant should implement payment notification API for GoPay and GoPay Tokenization (non-Pre Auth) transactions for Midtrans to call.
Path | /{version}/debit/notify |
---|---|
HTTP Method | POST |
Version | v1.0 |
SNAP Service Code | 56 |
Request Header
Field Name | Field Type | Mandatory | Field Description | |
Content-type | String | M | Media type of the resource, i.e. application/json | |
X-TIMESTAMP | String | M | Client’s current local time in ISO-8601 format | |
X-SIGNATURE | String | M | Created using asymmetric signature
Asymmetric-Signature format: SHA256withRSA (privateKey, stringToSign) with stringToSign = HTTPMethod +”:“+ EndpointUrl +":“+ Lowercase(HexEncode(SHA-256(minify(RequestBody)))) + ":“ + TimeStamp |
|
X-PARTNER-ID | String | M | Unique identifier for partner | |
X-EXTERNAL-ID | String | M | Numeric string. Reference number that should be unique in the same day or 1 day idempotency key | |
CHANNEL-ID | String | M | Mandatory field from Bank Indonesia that can take any value with correct format 5 digits numeric string |
Content-type:application/json
X-TIMESTAMP:2024-03-19T14:30:00+07:00
X-SIGNATURE: da1fa417c72d6b91c257e01e54fac824
X-PARTNER-ID:
X-EXTERNAL-ID:12345678901234567890
CHANNEL-ID:12345
Request Body
Field Name | Field Type | Mandatory | Field Description |
createdTime | String | O | Transaction created timestamp |
latestTransactionStatus | String | M | Latest transaction status
Possible Values:
|
originalReferenceNo | String | M | Transaction identifier on service provider system. For e.g: GopayOrderId |
finishedTime | String | O | Transaction completed timestamp (for latestTranscationStatus = 00) |
originalPartnerReferenceNo | String | O | Original transaction identifier on service consumer system. (Merchant’s orderId) |
originalExternalId | String(36) | O | Original External-ID on header message when doing charge (/payment-host-to-host) |
merchantId | String | O | Merchant ID |
amount | Object | O | Transaction amount |
amount.value | String | M | Transaction amount |
amount.currency | String | M | Transaction currency |
additionalInfo | Object | M | Additional info |
additionalInfo.refundHistory | Array of Object | C | Array of refund transactions. Only available if transaction status is refund
|
additionalInfo.refundHistory.refundNo | String | M | Unique identifier of refund transaction generated by provider. |
additionalInfo.refundHistory.partnerRefundNo | String | M | Unique identifier of refund transaction generated by client. |
additionalInfo.refundHistory.refundAmount | Object | M | Refund amount |
additionalInfo.refundHistory.refundAmount.value | String | M | Net amount of the refund. If it's IDR then the value includes 2 decimal digits.
e.g. IDR 10.000,- will be placed with 10000.00 |
additionalInfo.refundHistory.refundAmount.currency | String | M | Currency |
additionalInfo.refundHistory.reason | String | M | Refund reason |
additionalInfo.refundHistory.refundTime | String | M | Refund time |
additionalInfo.totalRefundAmount | Object | C | Total refund amount. Only available if transaction status is refund or partial refund .
|
additionalInfo.totalRefundAmount.value | String | M | Total refund amount. If it's IDR then the value includes 2 decimal digits.
e.g. IDR 10.000,- will be placed with 10000.00 |
additionalInfo.totalRefundAmount.currency | String | M | Currency |
additionalInfo.fraudStatus | String | M | Detection result by Fraud Detection System (FDS) |
additionalInfo.validUpTo | String | M | The time when the payment will be automatically expired. Using ISO 8601 format. |
additionalInfo.userPaymentDetails | Array of object | M | Payment option used by user |
additionalInfo.userPaymentDetails.payMethod | String | M | Payment method used by user. E.g: gopay |
additionalInfo.userPaymentDetails.payOption | String | M | Payment option used by user. Possible value: - GoPay = `GOPAY_WALLET` - GoPay Later = `PAY_LATER` - GoPay Tabungan by Jago = `GOPAY_SAVINGS` |
{
"createdTime": "2020-01-01T00:00:00+07:00",
"latestTransactionStatus": "00",
"originalReferenceNo": "gopayOrderId",
"finishedTime": "2020-01-02T00:00:00+07:00",
"originalPartnerReferenceNo": "merchant-order-id",
"transactionStatusDesc": "desc",
"originalExternalId":"merchant-order-id",
"additionalInfo": {
"userPaymentDetails": [
{
"payMethod": "gopay",
"payOption": "GOPAY_WALLET"
}
],
"fraudStatus": "accept",
"refundHistory":[
{
"refundNo":"96194816941239812",
"partnerReferenceNo":"239850918204981205970",
"refundAmount":{
"value":"12345678.00",
"currency":"IDR"
},
"refundDate":"2020-12-23T07:44:16+07:00",
"reason":"Customer Complain"
}
],
"validUpTo": "2021-01-01T00:00:00+07:00",
}
}
Response Header
Field Name | Field Type | Mandatory | Field Description | |
Content-type | String | M | Media type of the resource, i.e. application/json | |
X-TIMESTAMP | String | M | Client’s current local time in ISO-8601 format |
Content-type: application/json
X-TIMESTAMP: 2024-03-19T14:30:00+07:00
Response Body
Field Name | Field Type | Mandatory | Field Description | |
responseCode | String (7) | M | Error code to specify the error returned. | |
responseMessage | String (150) | M | Debug message to provide more information. |
{
"responseCode":"2005600",
"responseMessage":"Request has been processed successfully"
}
Receiving payment notifications for GoPay QRIS transaction
This section will describe how merchant should implement payment notification API for GoPay QRIS transactions for Midtrans to call.
Path | /{version}/qr/qr-mpm-notify |
---|---|
HTTP Method | POST |
Version | v1.0 |
SNAP service code | 52 |
Request Header
Field Name | Field Type | Mandatory | Field Description | |
Content-type | String | M | Media type of the resource, i.e. application/json | |
X-TIMESTAMP | String | M | Client’s current local time in ISO-8601 format | |
X-SIGNATURE | String | M | Created using asymmetric signature
Asymmetric-Signature format : SHA256withRSA (privateKey, stringToSign) with stringToSign = HTTPMethod +”:“+ EndpointUrl +":“+ Lowercase(HexEncode(SHA-256(minify(RequestBody)))) + ":“ + TimeStamp |
|
X-PARTNER-ID | String | M | Unique identifier for caller | |
X-EXTERNAL-ID | String | M | Numeric string. Reference number that should be unique in the same day or 1 day idempotency key | |
CHANNEL-ID | String | M | Mandatory field from Bank Indonesia that can take any value with correct format 5 digits numeric string |
Content-type:application/json
X-TIMESTAMP:2020-01-01T00:00:00+07:00
X-SIGNATURE: da1fa417c72d6b91c257e01e54fac824
X-PARTNER-ID:
X-EXTERNAL-ID:12345678901234567890
CHANNEL-ID:12345
Request Body
Field Name | Field Type | Mandatory | Field Description |
originalReferenceNo | String | M | Transaction identifier on service provider system. For e.g: GopayOrderId |
originalPartnerReferenceNo | String | O | Original transaction identifier on service consumer system. (Merchant’s orderId) |
latestTransactionStatus | String | M | Latest transaction status
Possible Values:
|
amount | Object | O | Amount of the order |
amount.value | String | M | Transaction amount |
amount.currency | String | M | Transaction currency |
additionalInfo | Object | M | Additional info |
additionalInfo.refundHistory | Array of Object | C | Array of refund transactions. Only available if transaction status is refund
|
additionalInfo.refundHistory.refundNo | String | M | Unique identifier of refund transaction generated by provider. |
additionalInfo.refundHistory.partnerRefundNo | String | M | Unique identifier of refund transaction generated by client. |
additionalInfo.refundHistory.refundAmount | Object | M | Refund amount |
additionalInfo.refundHistory.refundAmount.value | String | M | Net amount of the refund. If it's IDR then the value includes 2 decimal digits.
e.g. IDR 10.000,- will be placed with 10000.00 |
additionalInfo.refundHistory.refundAmount.currency | String | M | Currency |
additionalInfo.refundHistory.reason | String | M | Refund reason |
additionalInfo.refundHistory.refundTime | String | M | Refund time |
additionalInfo.totalRefundAmount | Object | C | Total refund amount. Only available if transaction status is refund or partial refund .
|
additionalInfo.totalRefundAmount.value | String | M | Total refund amount. If it's IDR then the value includes 2 decimal digits.
e.g. IDR 10.000,- will be placed with 10000.00 |
additionalInfo.totalRefundAmount.currency | String | M | Currency |
additionalInfo.qris | Array of Object | C | Array of QRIS transaction information, based on ASPI's regulation |
additionalInfo.qris.issuerName | String | M | Issuer company for the payment process |
additionalInfo.qris.acquirerName | String | M | Acquirer company for the payment process |
additionalInfo.qris.transactionType | String | M | ASPI Transaction type based on the combination of issuer and acquirer (if the issuer and acquirer is the same will be ON-US, if it's different will become OFF-US) |
{
"originalReferenceNo":"2020102977770000000009",
"originalPartnerReferenceNo":"2020102900000000000001",
"latestTransactionStatus":"00",
"transactionStatusDesc":"success",
"amount":{
"value":"12345678.00",
"currency":"IDR"
},
"externalStoreID":"124928924949487",
"additionalInfo":{
"qris" :{
"issuerName":"gopay"
"acquirerName":"gopay"
"transactionType":"ON-US"
}
}
}
Response Header
Field Name | Field Type | Mandatory | Field Description | |
Content-type | String | M | Media type of the resource, i.e. application/json | |
X-TIMESTAMP | String | M | Client’s current local time in ISO-8601 format |
Content-type: application/json
X-TIMESTAMP: 2024-03-19T14:30:00+07:00
Response Body
Field Name | Field Type | Mandatory | Field Description | |
responseCode | String (7) | M | Error code to specify the error returned. | |
responseMessage | String (150) | M | Debug message to provide more information. |
{
"responseCode":"2005600",
"responseMessage":"Request has been processed successfully"
}
List of response code
Response Code | HTTP Status | Description |
2005200 | 200 | Successful |
2025200 | 202 | Transaction still on process |
4005200 | 400 | General request failed error, including message parsing failed. |
4005201 | 400 | Invalid format |
4005202 | 400 | Missing or invalid format on mandatory field |
4015200 | 401 | General unauthorized error (No Interface Def, API is Invalid, Oauth Failed, Verify Client Secret Fail, Client Forbidden Access API, Unknown Client, Key not Found) |
4015201 | 401 | Token found in request is invalid (Access Token Not Exist, Access Token Expiry) |
4015203 | 401 | Token not found in the system. This occurs on any API that requires token as input parameter |
4035200 | 403 | Transaction expired |
4035201 | 403 | This merchant is not allowed to call Direct Debit APIs |
4035202 | 403 | Exceeds Transaction Amount Limit |
4035203 | 403 | Suspected Fraud |
4035204 | 403 | Too many request, Exceeds Transaction Frequency Limit |
4035205 | 403 | Account or User status is abnormal |
4035206 | 403 | Cut off In Progress |
4035209 | 403 | The account is dormant |
4035214 | 403 | Insufficient Funds |
4035215 | 403 | Transaction Not Permitted |
4035216 | 403 | Suspend Transaction |
4035218 | 403 | Indicates inactive account |
4035219 | 403 | Merchant is suspended from calling any APIs |
4035220 | 403 | Merchant aggregated purchase amount on that day exceeds the agreed limit |
4035221 | 403 | Set limit not allowed on particular token |
4035222 | 403 | The token limit desired by the merchant is not within the agreed range between the merchant and the Issuer |
4035223 | 403 | Account aggregated purchase amount on that day exceeds the agreed limit |
4045200 | 404 | Invalid transaction status |
4045201 | 404 | Transaction not found |
4045202 | 404 | Invalid Routing |
4045204 | 404 | Transaction is cancelled by customer |
4045208 | 404 | Merchant does not exist or status abnormal |
4045210 | 404 | Invalid API transition within a journey |
4045213 | 404 | The amount doesn't match with what supposed to |
4045216 | 404 | Partner number can't be found |
4045217 | 404 | Terminal does not exist in the system |
4045218 | 404 | Inconsistent request parameter |
4055200 | 405 | Requested function is not supported |
4055201 | 405 | Requested operation to cancel/refund transaction Is not allowed at this time. |
4095200 | 409 | Cannot use same X-EXTERNAL-ID in same day |
4095201 | 409 | Transaction has previously been processed indicates the same partnerReferenceNo already success |
4295200 | 429 | Maximum transaction limit exceeded |
5005200 | 500 | General Error |
5005201 | 500 | Unknown Internal Server Failure, Please retry the process again |
5005202 | 500 | Backend system failure, etc |
5045200 | 504 | timeout from the issuer |
Receiving payment notifications for Bank Transfer (VA)
This section will describe how merchant should implement payment notification API for Bank Transfer (VA) transactions for Midtrans to call.
Path | /{version}/transfer-va/payment |
---|---|
HTTP Method | POST |
Version | v1.0 |
SNAP service code | 25 |
Request Header
Field Name | Field Type | Mandatory | Field Description | |
Content-type | String | M | Media type of the resource, i.e. application/json | |
X-TIMESTAMP | String | M | Client’s current local time in ISO-8601 format | |
X-SIGNATURE | String | M | Created using asymmetric signature
Asymmetric-Signature format : SHA256withRSA (privateKey, stringToSign) with stringToSign = HTTPMethod +”:“+ EndpointUrl +":“+ Lowercase(HexEncode(SHA-256(minify(RequestBody)))) + ":“ + TimeStamp |
|
X-PARTNER-ID | String | M | Unique identifier for caller | |
X-EXTERNAL-ID | String | M | Numeric string. Reference number that should be unique in the same day or 1 day idempotency key | |
CHANNEL-ID | String | M | Mandatory field from Bank Indonesia that can take any value with correct format 5 digits numeric string |
Content-type:application/json
X-TIMESTAMP:2020-01-01T00:00:00+07:00
X-SIGNATURE:da1fa417c72d6b91c257e01e54fac824
X-PARTNER-ID:G12345678
X-EXTERNAL-ID:12345678901234567890
CHANNEL-ID:12345
Request Body
Field Name | Field Type | Mandatory | Field Description | |
partnerServiceId | String(8) | M | partnerServiceId from the virtual account number | |
customerNo | String(20) | M | customerNo from the virtual account number | |
virtualAccountNo | String(28) | M | Virtual account number for the transaction | |
virtualAccountName | String(255) | O | The customer name | |
virtualAccountEmail | String(255) | O | The customer’s email | |
virtualAccountPhone | String(30) | O | The customer’s phone number | |
trxId | String(64) | M | This value will be the trxId used in the create VA request. | |
paymentRequestId | String | C | Unique identifier for this Payment from Midtrans.
This value will exist if the payment has been completed |
|
paidAmount | Object | C | Amount paid for this transaction
This value will exist if the payment has been completed |
|
paidAmount.value | String(16, 2) | M | The numeric string of the amount up to two decimal places | |
paidAmount.currency | String(3) | M | The currency of the value paid. Should be IDR | |
trxDateTime | Date(25) | M | ISO-8601 datetime in GMT+7 when the VA is paid | |
referenceNo | String | O | Payment auth code generated by Midtrans | |
additionalInfo | Object | O | ||
additionalInfo.bank | String | M | Indicates the bank chosen to create the VA at. The banks that can be used will differ based on the banks chosen by the merchant during the onboarding process. Possible values are
|
|
additionalInfo.merchantId | String(10) | M | This is the merchantId shared by Midtrans during the onboarding process | |
additionalInfo.paymentFlagStatus | String(2) | M | Status for Payment Flag
00 - Success 01 - Initiated 02 - Paying 03 - Pending 04 - Refunded 05 - Canceled 06 - Failed 07 - Not found 08 - Expired 09 - Denied |
|
additionalInfo.customField | Object | M | A collection of up to three fields sent by the merchant. It will also be displayed on the Dashboard under “order detail” | |
additionalInfo.customField.1 | String(255) | M | First field that contains the custom data set by the merchant | |
additionalInfo.customField.2 | String(255) | M | Second field that contains the custom data set by the merchant | |
additionalInfo.customField.3 | String(255) | M | Third field that contains the custom data set by the merchant |
{
"partnerServiceId":" 088899",
"customerNo":"12345678901234567890",
"virtualAccountNo":" 08889912345678901234567890",
"virtualAccountName":"Jokul Doe",
"virtualAccountEmail":"[email protected]",
"virtualAccountPhone":"6281828384858",
"trxId":"abcdefgh1234",
"paymentRequestId":"abcdef-123456-abcdef",
"paidAmount":{
"value":"12345678.00",
"currency":"IDR"
},
"trxDateTime":"20201231T235959Z",
"referenceNo":"123456789012345",
"additionalInfo":{
"bank":"BCA",
"paymentFlagStatus": "00",
"merchantId":"G059876677",
"customField": {
"1": "custom-field-1",
"2": "custom-field-2",
"3": "custom-field-3"
}
}
}
Response Header
Field Name | Field Type | Mandatory | Field Description | |
Content-type | String | M | Media type of the resource, i.e. application/json | |
X-TIMESTAMP | String | M | Client’s current local time in ISO-8601 format |
Content-type:application/json
X-TIMESTAMP:2020-01-01T00:00:00+07:00
Response Body
Field Name | Field Type | Mandatory | Field Description | |
responseCode | String(7) | M | Response code | |
responseMessage | String(150) | M | Response description | |
virtualAccountData | Object | M | ||
virtualAccountData.partnerServiceId | String(8) | M | partnerServiceId from Create VA Response | |
virtualAccountData.customerNo | String(29) | M | customerNo from Create VA Response | |
virtualAccountData.virtualAccountNo | String(28) | M | Virtual account number for the transaction | |
virtualAccountData.trxId | String(64) | M | This value will be the trxId used in the create VA request. | |
virtualAccountData.trxDateTime | Date(25) | M | ISO-8601 datetime in GMT+7 when the VA is paid |
{
"responseMessage": "Successful",
"responseCode": "2002500",
"virtualAccountData": {
"partnerServiceId": " 088899",
"customerNo": "12345678901234567890",
"virtualAccountNo": " 08889912345678901234567890",
"trxDateTime":"20201231T235959Z",
"trxId": "midtrans-testing-001"
}
List of response code
Response Code | HTTP Status | Description |
2003100 | 200 | Success |
4003102 | 400 | Invalid Mandatory Field |
4013100 | 401 | Unauthorized. |
5003101 | 500 | Internal Server Error |
5043100 | 504 | Timeout |
2002700 | 200 | Success |
4012700 | 401 | Unauthorized. Signature |
5002700 | 500 | Internal Server Error |
4002700 | 400 | Bad Request |
4042713 | 404 | Invalid Amount |
4002701 | 400 | Invalid Field Format X-TIMESTAMP |
2002700 | 200 | Success |
4012700 | 401 | Unauthorized. Signature |
5002700 | 500 | Internal Server Error |
4002700 | 400 | Bad Request |
4042713 | 404 | Invalid Amount |
4002701 | 400 | Invalid Field Format X-TIMESTAMP |
Notification retry mechanism for Open API
In case we got error response when sending notification (non 2xx response) to merchants, Midtrans will retry up to 3 times with exponential interval. For now our retry mechanism is as follows:
1st retry delay time = 20ms
2nd retry delay time = 40ms
3rd retry delay time = 80ms
Notes: this interval can change anytime as part of improvement, we will update it periodicaly