Payment Notification API

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

8.215.39.156/32

8.215.77.79/32

147.139.213.119/32

8.215.56.11/32

8.215.39.87/32

8.215.42.0/32

8.215.59.158/32

149.129.222.246/32

8.215.26.108/32

8.215.13.84/32

Sandbox

34.142.147.133/32

34.142.169.131/32

34.142.231.22/32

35.240.161.215/32

34.142.227.232/32

34.124.184.175/32

35.197.130.2/32

34.142.233.114/32

8.215.26.211/32

8.215.22.135/32

8.215.93.92/32

8.215.93.214/32

8.215.93.76/32

8.215.33.37/32

8.215.26.148/32

8.215.194.225/32

8.215.12.199/32

149.129.255.111/32

Production

13.228.166.126/32

52.220.80.5/32

3.1.123.95/32

8.215.30.222/32

147.139.209.49/32

8.215.32.142/32

147.139.163.77/32

8.215.25.24/32

8.215.3.193/32

147.139.210.20/32

149.129.238.95/32

8.215.9.206/32

147.139.134.22/32

⚠️

Notes on Future Compatibility and Best Practices

To ensure your integration remains robust and scalable, please be aware that Midtrans may introduce additional parameters to the payment notification payload in the future, most likely under the additionalInfo section, but not limited to it. These enhancements are designed to provide greater flexibility and support for evolving business needs.

To prevent any issues caused by these future changes, we strongly recommend that merchants always perform signature verification on the entire payload, rather than validating fields individually. This practice ensures a seamless, secure, and simple implementation that can adapt to future updates without requiring significant changes on your side.

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 MethodPOST
Versionv1.0
SNAP Service Code56

Request Header

Field NameField TypeMandatoryField 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

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 NameField TypeMandatoryField Description

createdTime

String

O

Transaction created timestamp

latestTransactionStatus

String

M

Latest transaction status

Possible Values:

  • 00 - Success
  • 03 - Pending
  • 04 - Refunded
  • 05 - Canceled
  • 06 - Failure
  • 08 - Expiry
  • 09 - Rejected

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

String

M

Refund status. Possible values:

  • 00 --> Refund success
  • 06 --> Refund failed

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

Array of object

M

Payment option used by user. This will be not available for deeplink redirection payment flow with pending status.

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"
         }
        ],
         "refundHistory":[
  	{
     	     	"refundNo":"96194816941239812",
      			"refundStatus":"00",
     	     	"partnerReferenceNo":"239850918204981205970",
          		"refundAmount":{
          	   	     	"value":"12345678.00",
         	    	     	"currency":"IDR"
     	     	},
     	     	"refundDate":"2020-12-23T07:44:16+07:00",
          		"reason":"Customer Complain"
  	}
   ]
    }
}

Response Header

Field NameField TypeMandatoryField 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 NameField TypeMandatoryField 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 MethodPOST
Versionv1.0
SNAP service code52

Request Header

Field NameField TypeMandatoryField 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

Content-type:application/json
X-TIMESTAMP:2020-01-01T00:00:00+07:00
X-SIGNATURE: da1fa417c72d6b91c257e01e54fac824
X-PARTNER-ID: 
X-EXTERNAL-ID:12345678901234567890

Request Body

Field NameField TypeMandatoryField 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:

  • 00 - Success
  • 03 - Pending
  • 04 - Refunded
  • 05 - Canceled
  • 06 - Failure
  • 08 - Expiry
  • 09 - Rejected

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 NameField TypeMandatoryField 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 NameField TypeMandatoryField 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 CodeHTTP StatusDescription

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 MethodPOST
Versionv1.0
SNAP service code25

Request Header

Asymmetric-Signature format :

SHA256withRSA (privateKey, stringToSign) with

stringToSign = HTTPMethod +”:“+ EndpointUrl +":“+ Lowercase(HexEncode(SHA-256(minify(RequestBody)))) + ":“ + TimeStamp

Field NameField TypeMandatoryField 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

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

Content-type:application/json
X-TIMESTAMP:2020-01-01T00:00:00+07:00
X-SIGNATURE:da1fa417c72d6b91c257e01e54fac824
X-PARTNER-ID:G12345678
X-EXTERNAL-ID:12345678901234567890

Request Body

Field NameField TypeMandatoryField 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

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

  • Permata
  • BCA
  • Mandiri
  • CIMB
  • BNI
  • BRI

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

String

M

Time when transaction is settled.

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"
    },
    "referenceNo":"123456789012345",
    "additionalInfo":{
       "bank":"BCA",
       "paymentFlagStatus": "00",
       "merchantId":"G059876677",
       "paidTime":"2020-01-01T00:00:00+07:00",  
       "customField": {
          "1": "custom-field-1",
          "2": "custom-field-2",
          "3": "custom-field-3"
       }
    }
 }

Response Header

Field NameField TypeMandatoryField 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 NameField TypeMandatoryField 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.

{
    "responseMessage": "Successful",
    "responseCode": "2002500",
    "virtualAccountData": {
        "partnerServiceId": "  088899",
        "customerNo": "12345678901234567890",
        "virtualAccountNo": "  08889912345678901234567890",
        "trxId": "midtrans-testing-001"
}

List of response code

Response CodeHTTP StatusDescription

2002500

200

Success

4002500

400

Bad Request

4002501

400

Invalid Field Format X-TIMESTAMP

4002502

400

Invalid Mandatory Field

4012500

401

Unauthorized. Signature

4042513

404

Invalid Amount

5002500

500

Internal Server Error

5042500

504

Timeout

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