Skip to content

QR / MPM

QR / MPM

Merchant-Presented-Mode QR: generate, decode, pay host-to-host, query, cancel, and refund — plus the One-Time-Token flow used by ApplyOTT.

resp, err := transfercredit.GenerateQRMPM(ctx, transport, hb, transfercredit.GenerateQRMPMRequest{
	PartnerReferenceNo: "2020102900000000000001",
	Amount: &snap.Money{Value: "500000.00", Currency: "IDR"},
	FeeAmount: &snap.Money{Value: "500000.00", Currency: "IDR"},
})
if err != nil {
	// errors.Is(err, snap.ErrBadRequest), snap.ErrUnauthorized, etc.
}

GenerateQRMPM

GenerateQRMPM calls the SNAP Generate QR MPM endpoint (Service Code 47, path …/{version}/qr/qr-mpm-generate, HTTP POST — no method override). hb must already carry every field snap.HeaderBuilder needs except Body, which GenerateQRMPM sets itself so the exact marshaled bytes are used for both signing and the wire body.

This operation is not idempotent and this package does not retry. Callers that retry a failed or timed-out call should reuse the same X-EXTERNAL-ID, since the server’s own duplicate-detection keys on it.

func GenerateQRMPM(ctx context.Context, t *snap.Transport, hb snap.HeaderBuilder, req GenerateQRMPMRequest) (GenerateQRMPMResponse, error)

Request — GenerateQRMPMRequest

GenerateQRMPMRequest is the request body for API Generate QR MPM (Service Code 47). Every field is Optional per the Guides tab — no field in this request is documented Mandatory.

FieldTypePresence
partnerReferenceNostringOptional
amount*snap.MoneyOptional
feeAmount*snap.MoneyOptional
merchantIdstringOptional
subMerchantIdstringOptional
storeIdstringOptional
terminalIdstringOptional
validityPeriodstringOptional

Response — GenerateQRMPMResponse

GenerateQRMPMResponse is the response body for API Generate QR MPM.

QRContent, QRURL, and QRImage form a one-of-three condition the type system cannot express: per the Guides tab, “if [qrContent is] null, qrUrl or qrImage must be filled.” All three are Optional here; callers must check which of the three came back non-empty.

FieldTypePresence
responseCodestringMandatory
responseMessagestringMandatory
qrContentstringOptional
qrUrlstringOptional
redirectUrlstringOptional
merchantNamestringOptional
storeIdstringOptional
terminalIdstringOptional

ApplyOTT

ApplyOTT calls the SNAP Payment Redirect - Apply OTT endpoint (Service Code 49, path …/{version}/qr/apply-ott, HTTP POST — no method override). hb must already carry every field snap.HeaderBuilder needs except Body, which ApplyOTT sets itself so the exact marshaled bytes are used for both signing and the wire body.

This operation is not idempotent and this package does not retry. Callers that retry a failed or timed-out call should reuse the same X-EXTERNAL-ID, since the server’s own duplicate-detection keys on it.

func ApplyOTT(ctx context.Context, t *snap.Transport, hb snap.HeaderBuilder, req ApplyOTTRequest) (ApplyOTTResponse, error)

This endpoint takes no typed request body beyond the call parameters shown above.

Response — ApplyOTTResponse

ApplyOTTResponse is the response body for API Payment Redirect - Apply OTT.

FieldTypePresence
responseCodestringMandatory
responseMessagestringMandatory
userResources[]ApplyOTTUserResourceMandatory
ApplyOTTUserResource fields

ApplyOTTUserResource is one entry in an ApplyOTTResponse’s userResources array. Despite sharing a field name with the request, this is a distinct shape (an object, not a bare string).

FieldTypePresence
resourceTypestringMandatory
valuestringMandatory

DecodeQRMPM

DecodeQRMPM calls the SNAP Decode QR MPM endpoint (Service Code 48, path …/{version}/qr/qr-mpm-decode, HTTP POST — no method override). hb must already carry every field snap.HeaderBuilder needs except Body, which DecodeQRMPM sets itself so the exact marshaled bytes are used for both signing and the wire body.

This is a read-only decode; unlike GenerateQRMPM it carries no non-idempotency note.

func DecodeQRMPM(ctx context.Context, t *snap.Transport, hb snap.HeaderBuilder, req DecodeQRMPMRequest) (DecodeQRMPMResponse, error)

Request — DecodeQRMPMRequest

DecodeQRMPMRequest is the request body for API Decode QR MPM (Service Code 48). QRContent and ScanTime are Mandatory per the Guides tab.

FieldTypePresence
partnerReferenceNostringOptional
qrContentstringMandatory
amount*snap.MoneyOptional
merchantIdstringOptional
subMerchantIdstringOptional
scanTimestringMandatory

Response — DecodeQRMPMResponse

DecodeQRMPMResponse is the response body for API Decode QR MPM.

ReferenceNo and RedirectURL are both modeled Optional — the standard’s own conditions for when each is required are contradictory, so neither is asserted here.

FieldTypePresence
responseCodestringMandatory
responseMessagestringMandatory
referenceNostringOptional
redirectUrlstringOptional
merchantNamestringOptional
merchantCategorystringOptional
merchantLocationstringOptional
merchantInfos[]MPMMerchantInfoMandatory
transactionAmount*snap.MoneyOptional
feeAmount*snap.MoneyOptional
MPMMerchantInfo fields

MPMMerchantInfo is one entry in a DecodeQRMPMResponse’s merchantInfos array.

MerchantPAN is documented as numeric but sent quoted as a string on the wire — an ambiguous shape, so it’s typed json.RawMessage rather than string or a numeric type.

FieldTypePresence
merchantPANjson.RawMessageMandatory
acquirerNamestringMandatory

QRMPMPaymentH2H

QRMPMPaymentH2H calls the SNAP Payment - Host to Host endpoint (Service Code 50, path …/{version}/qr/qr-mpm-payment, HTTP POST — no method override). hb must already carry every field snap.HeaderBuilder needs except Body, which QRMPMPaymentH2H sets itself so the exact marshaled bytes are used for both signing and the wire body.

This operation is not idempotent and this package does not retry. Callers that retry a failed or timed-out call should reuse the same X-EXTERNAL-ID, since the server’s own duplicate-detection keys on it.

func QRMPMPaymentH2H(ctx context.Context, t *snap.Transport, hb snap.HeaderBuilder, req QRMPMPaymentH2HRequest) (QRMPMPaymentH2HResponse, error)

Request — QRMPMPaymentH2HRequest

QRMPMPaymentH2HRequest is the request body for API Payment - Host to Host (Service Code 50). PartnerReferenceNo is Mandatory; every other field is Optional per the Guides tab.

VerificationID also appears on the response under the same name with a different documented max length — both are plain string in Go, this package doesn’t enforce length limits.

FieldTypePresence
partnerReferenceNostringMandatory
merchantIdstringOptional
subMerchantIdstringOptional
amount*snap.MoneyOptional
feeAmount*snap.MoneyOptional
otpstringOptional
verificationIdstringOptional

Response — QRMPMPaymentH2HResponse

QRMPMPaymentH2HResponse is the response body for API Payment - Host to Host.

FieldTypePresence
responseCodestringMandatory
responseMessagestringMandatory
referenceNostringOptional
transactionDatestringOptional
verificationIdstringOptional

QR MPM Payment Notification

Inbound only — this package does not call an endpoint for this. A partner/switcher POSTs it to your callback URL; unmarshal the body into QRMPMPaymentNotificationRequest after verifying it with snap.ServerVerifier (see Verifying inbound requests), then reply with the shape below.

Received — QRMPMPaymentNotificationRequest

QRMPMPaymentNotificationRequest is the request body for API Payment Notification (Service Code 52, path …/{version}/qr/qr-mpm-notify). This is a settlement callback the PJP receives, not a call this package makes — wire your own HTTP handler for this path, authenticate the request with ServerVerifier.VerifyTransactionRequest, then json.Unmarshal the body into this type. OriginalReferenceNo and LatestTransactionStatus are Mandatory; every other field is Optional.

FieldTypePresence
originalReferenceNostringMandatory
originalPartnerReferenceNostringOptional
latestTransactionStatusstringMandatory
customerNumberstringOptional
accountTypestringOptional
destinationNumberstringOptional
destinationAccountNamestringOptional
amount*snap.MoneyOptional
sessionIdstringOptional
bankCodestringOptional
externalStoreIdstringOptional

Your handler replies with — QRMPMPaymentNotificationResponse

QRMPMPaymentNotificationResponse is the response body your handler sends back — no fields beyond the standard responseCode/responseMessage envelope.

FieldTypePresence
responseCodestringMandatory
responseMessagestringMandatory

QRMPMQueryPayment

QRMPMQueryPayment calls the SNAP Query Payment endpoint (Service Code 51, path …/{version}/qr/qr-mpm-query, HTTP POST — no method override). hb must already carry every field snap.HeaderBuilder needs except Body, which QRMPMQueryPayment sets itself so the exact marshaled bytes are used for both signing and the wire body.

This is a read-only status query; unlike the package’s mutating calls it carries no non-idempotency note, matching TransactionStatusInquiryBank’s precedent.

func QRMPMQueryPayment(ctx context.Context, t *snap.Transport, hb snap.HeaderBuilder, req QRMPMQueryPaymentRequest) (QRMPMQueryPaymentResponse, error)

Request — QRMPMQueryPaymentRequest

QRMPMQueryPaymentRequest is the request body for API Query Payment (Service Code 51) — the same base fields as TransactionStatusInquiryBankRequest, plus MerchantID, SubMerchantID, and ExternalStoreID. ServiceCode is the only Mandatory field.

FieldTypePresence
originalPartnerReferenceNostringOptional
originalReferenceNostringOptional
originalExternalIdstringOptional
serviceCodestringMandatory
transactionDatestringOptional
amount*snap.MoneyOptional
merchantIdstringOptional
subMerchantIdstringOptional
externalStoreIdstringOptional
additionalInfojson.RawMessageOptional

Response — QRMPMQueryPaymentResponse

QRMPMQueryPaymentResponse is the response body for API Query Payment — the same fields as TransactionStatusInquiryBankResponse, plus PaidTime and TerminalID.

FieldTypePresence
responseCodestringMandatory
responseMessagestringMandatory
originalPartnerReferenceNostringOptional
originalReferenceNostringOptional
originalExternalIdstringOptional
serviceCodestringOptional
transactionDatestringOptional
amount*snap.MoneyOptional
beneficiaryAccountNostringMandatory
beneficiaryBankCodestringOptional
previousResponseCodestringOptional
referenceNumberstringMandatory
sourceAccountNostringMandatory
transactionIdstringOptional
latestTransactionStatusstringMandatory
transactionStatusDescstringOptional
additionalInfojson.RawMessageOptional
paidTimestringOptional
terminalIdstringOptional

QRMPMCancelPayment

QRMPMCancelPayment calls the SNAP Cancel Payment endpoint (Service Code 77, path …/{version}/qr/qr-mpm-cancel, HTTP POST — no method override). hb must already carry every field snap.HeaderBuilder needs except Body, which QRMPMCancelPayment sets itself so the exact marshaled bytes are used for both signing and the wire body.

This operation is not idempotent and this package does not retry. Callers that retry a failed or timed-out call should reuse the same X-EXTERNAL-ID, since the server’s own duplicate-detection keys on it.

func QRMPMCancelPayment(ctx context.Context, t *snap.Transport, hb snap.HeaderBuilder, req QRMPMCancelPaymentRequest) (QRMPMCancelPaymentResponse, error)

Request — QRMPMCancelPaymentRequest

QRMPMCancelPaymentRequest is the request body for API Cancel Payment (Service Code 77). Unlike the package’s other originalX-pattern endpoints, this row documents no serviceCode field and all three originalX fields as Optional — MerchantID and Reason are the only Mandatory fields.

FieldTypePresence
originalPartnerReferenceNostringOptional
originalReferenceNostringOptional
originalExternalIdstringOptional
merchantIdstringMandatory
subMerchantIdstringOptional
externalStoreIdstringOptional
reasonstringMandatory
amount*snap.MoneyOptional

Response — QRMPMCancelPaymentResponse

QRMPMCancelPaymentResponse is the response body for API Cancel Payment. CancelTime is Conditional (modeled Optional, per this package’s usual handling — see Core Conventions); TransactionDate is Optional.

FieldTypePresence
responseCodestringMandatory
responseMessagestringMandatory
cancelTimestringOptional
transactionDatestringOptional

QRMPMRefundPayment

QRMPMRefundPayment calls the SNAP Refund Payment endpoint (Service Code 78, path …/{version}/qr/qr-mpm-refund, HTTP POST — no method override). hb must already carry every field snap.HeaderBuilder needs except Body, which QRMPMRefundPayment sets itself so the exact marshaled bytes are used for both signing and the wire body.

This operation is not idempotent and this package does not retry. Callers that retry a failed or timed-out call should reuse the same X-EXTERNAL-ID, since the server’s own duplicate-detection keys on it.

func QRMPMRefundPayment(ctx context.Context, t *snap.Transport, hb snap.HeaderBuilder, req QRMPMRefundPaymentRequest) (QRMPMRefundPaymentResponse, error)

Request — QRMPMRefundPaymentRequest

QRMPMRefundPaymentRequest is the request body for API Refund Payment (Service Code 78). OriginalPartnerReferenceNo and PartnerRefundNo are Mandatory; every other field is Optional per the Guides tab.

FieldTypePresence
merchantIdstringOptional
subMerchantIdstringOptional
externalStoreIdstringOptional
originalPartnerReferenceNostringMandatory
originalReferenceNostringOptional
originalExternalIdstringOptional
partnerRefundNostringMandatory
refundAmount*snap.MoneyOptional
reasonstringOptional

Response — QRMPMRefundPaymentResponse

QRMPMRefundPaymentResponse is the response body for API Refund Payment. RefundNo and RefundTime are Mandatory; PartnerRefundNo and RefundAmount are Optional (echoed back, not guaranteed).

FieldTypePresence
responseCodestringMandatory
responseMessagestringMandatory
refundNostringMandatory
partnerRefundNostringOptional
refundAmount*snap.MoneyOptional
refundTimestringMandatory