CPM
CPM
Customer-Presented-Mode QR (the customer shows a QR, the merchant scans it): generate, pay, query, cancel, refund; payment results also arrive as an inbound notification.
resp, err := transferdebit.CPMPayment(ctx, transport, hb, transferdebit.CPMPaymentRequest{
PartnerReferenceNo: "2020102900000000000001",
QRContent: "...",
MerchantID: "...",
})
if err != nil {
// errors.Is(err, snap.ErrBadRequest), snap.ErrUnauthorized, etc.
}CPMGenerateQR
CPMGenerateQR calls the SNAP Generate QR CPM endpoint (Service Code 59, HTTP POST). Pass hb with everything except Body already set — CPMGenerateQR marshals the request itself and uses those exact bytes 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 CPMGenerateQR(ctx context.Context, t *snap.Transport, hb snap.HeaderBuilder, req CPMGenerateQRRequest) (CPMGenerateQRResponse, error)Request — CPMGenerateQRRequest
CPMGenerateQRRequest is the request body for Generate QR CPM. partnerTrxDate is the only Mandatory field.
| Field | Type | Presence |
|---|---|---|
partnerReferenceNo | string | Optional |
userAccessToken | string | Optional |
merchantId | string | Optional |
subMerchantId | string | Optional |
partnerTrxDate | string | Mandatory |
additionalInfo | json.RawMessage | Optional |
Response — CPMGenerateQRResponse
CPMGenerateQRResponse is the response body for Generate QR CPM. expiryTime is the only other Mandatory field; qrContent/qrUrl are both plain Optional (no one-of-many rule between them).
| Field | Type | Presence |
|---|---|---|
responseCode | string | Mandatory |
responseMessage | string | Mandatory |
referenceNo | string | Optional |
partnerReferenceNo | string | Optional |
qrContent | string | Optional |
qrUrl | string | Optional |
expiryTime | string | Mandatory |
additionalInfo | json.RawMessage | Optional |
CPMPayment
CPMPayment calls the SNAP CPM Payment endpoint (Service Code 60, HTTP POST). Pass hb with everything except Body already set — CPMPayment marshals the request itself.
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 CPMPayment(ctx context.Context, t *snap.Transport, hb snap.HeaderBuilder, req CPMPaymentRequest) (CPMPaymentResponse, error)Request — CPMPaymentRequest
CPMPaymentRequest is the request body for CPM Payment. partnerReferenceNo, qrContent, and merchantId are Mandatory.
items has no fixed schema in the standard, so it’s typed json.RawMessage — the same treatment as additionalInfo and every other genuinely untyped field.
| Field | Type | Presence |
|---|---|---|
partnerReferenceNo | string | Mandatory |
qrContent | string | Mandatory |
amount | *snap.Money | Optional |
feeAmount | *snap.Money | Optional |
merchantId | string | Mandatory |
subMerchantId | string | Optional |
title | string | Optional |
expiryTime | string | Optional |
items | json.RawMessage | Optional |
externalStoreId | string | Optional |
merchantName | string | Optional |
merchantLocation | string | Optional |
acquirerName | string | Optional |
terminalId | string | Optional |
scannerInfo | *CPMPaymentScannerInfo | Optional |
additionalInfo | json.RawMessage | Optional |
CPMPaymentScannerInfo fields
CPMPaymentScannerInfo is the optional scannerInfo object describing the device that scanned the QR. All four fields are Optional.
| Field | Type | Presence |
|---|---|---|
deviceId | string | Optional |
deviceVersion | string | Optional |
deviceModel | string | Optional |
deviceIp | string | Optional |
Response — CPMPaymentResponse
CPMPaymentResponse is the response body for CPM Payment. referenceNo is Conditional — present only on success. No other field is Mandatory.
| Field | Type | Presence |
|---|---|---|
responseCode | string | Mandatory |
responseMessage | string | Mandatory |
referenceNo | string | Optional |
partnerReferenceNo | string | Optional |
transactionDate | string | Optional |
additionalInfo | json.RawMessage | Optional |
CPM Payment Notification
CPMPaymentNotificationRequest after verifying it with snap.ServerVerifier (see Verifying inbound requests), then reply with the shape below.Received — CPMPaymentNotificationRequest
CPMPaymentNotificationRequest is the request body for Payment Notification (Service Code 79) — a settlement callback the PJP receives, not a call this package makes. Wire your own HTTP handler for this path, authenticate the inbound call with ServerVerifier.VerifyTransactionRequest, then json.Unmarshal the body into this type.
merchantId and latestTransactionStatus are Mandatory; every other field is Optional.
| Field | Type | Presence |
|---|---|---|
originalPartnerReferenceNo | string | Optional |
originalReferenceNo | string | Optional |
merchantId | string | Mandatory |
subMerchantId | string | Optional |
externalStoreId | string | Optional |
amount | *snap.Money | Optional |
latestTransactionStatus | string | Mandatory |
transactionStatusDesc | string | Optional |
customerNumber | string | Optional |
accountType | string | Optional |
destinationNumber | string | Optional |
destinationAccountName | string | Optional |
sessionId | string | Optional |
bankCode | string | Optional |
additionalInfo | json.RawMessage | Optional |
Your handler replies with — CPMPaymentNotificationResponse
CPMPaymentNotificationResponse is envelope-only — just responseCode and responseMessage, no other fields.
| Field | Type | Presence |
|---|---|---|
responseCode | string | Mandatory |
responseMessage | string | Mandatory |
CPMQueryPayment
CPMQueryPayment calls the SNAP Query Payment endpoint (Service Code 61, HTTP POST) to check a previous CPM payment’s status. Pass hb with everything except Body already set — CPMQueryPayment marshals the request itself. This is a read-only lookup, safe to retry freely.
func CPMQueryPayment(ctx context.Context, t *snap.Transport, hb snap.HeaderBuilder, req CPMQueryPaymentRequest) (CPMQueryPaymentResponse, error)Request — CPMQueryPaymentRequest
CPMQueryPaymentRequest is the request body for Query Payment. No field is Mandatory — query by whichever reference, merchant, or store ID you have.
| Field | Type | Presence |
|---|---|---|
originalReferenceNo | string | Optional |
originalPartnerReferenceNo | string | Optional |
originalExternalId | string | Optional |
merchantId | string | Optional |
subMerchantId | string | Optional |
externalStoreId | string | Optional |
additionalInfo | json.RawMessage | Optional |
Response — CPMQueryPaymentResponse
CPMQueryPaymentResponse is the response body for Query Payment. latestTransactionStatus and paidTime are Mandatory; originalReferenceNo is Conditional — present only on success.
| Field | Type | Presence |
|---|---|---|
responseCode | string | Mandatory |
responseMessage | string | Mandatory |
originalReferenceNo | string | Optional |
originalPartnerReferenceNo | string | Optional |
originalExternalId | string | Optional |
title | string | Optional |
latestTransactionStatus | string | Mandatory |
transactionStatusDesc | string | Optional |
paidTime | string | Mandatory |
additionalInfo | json.RawMessage | Optional |
CPMCancelPayment
CPMCancelPayment calls the SNAP Cancel Payment endpoint (Service Code 62, HTTP POST). Pass hb with everything except Body already set — CPMCancelPayment marshals the request itself.
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 CPMCancelPayment(ctx context.Context, t *snap.Transport, hb snap.HeaderBuilder, req CPMCancelPaymentRequest) (CPMCancelPaymentResponse, error)Request — CPMCancelPaymentRequest
CPMCancelPaymentRequest is the request body for Cancel Payment. originalPartnerReferenceNo is the only Mandatory field.
| Field | Type | Presence |
|---|---|---|
originalPartnerReferenceNo | string | Mandatory |
originalReferenceNo | string | Optional |
originalExternalId | string | Optional |
merchantId | string | Optional |
subMerchantId | string | Optional |
externalStoreId | string | Optional |
amount | *snap.Money | Optional |
reason | string | Optional |
additionalInfo | json.RawMessage | Optional |
Response — CPMCancelPaymentResponse
CPMCancelPaymentResponse is the response body for Cancel Payment. originalReferenceNo and cancelTime are Conditional — present only on success.
| Field | Type | Presence |
|---|---|---|
responseCode | string | Mandatory |
responseMessage | string | Mandatory |
originalPartnerReferenceNo | string | Optional |
originalReferenceNo | string | Optional |
originalExternalId | string | Optional |
cancelTime | string | Optional |
transactionDate | string | Optional |
additionalInfo | json.RawMessage | Optional |
CPMRefundPayment
CPMRefundPayment calls the SNAP Refund Payment endpoint (Service Code 80, HTTP POST). Pass hb with everything except Body already set — CPMRefundPayment marshals the request itself.
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 CPMRefundPayment(ctx context.Context, t *snap.Transport, hb snap.HeaderBuilder, req CPMRefundPaymentRequest) (CPMRefundPaymentResponse, error)Request — CPMRefundPaymentRequest
CPMRefundPaymentRequest is the request body for Refund Payment. originalPartnerReferenceNo and partnerRefundNo are Mandatory.
| Field | Type | Presence |
|---|---|---|
merchantId | string | Optional |
subMerchantId | string | Optional |
externalStoreId | string | Optional |
originalPartnerReferenceNo | string | Mandatory |
originalReferenceNo | string | Optional |
originalExternalId | string | Optional |
partnerRefundNo | string | Mandatory |
refundAmount | *snap.Money | Optional |
reason | string | Optional |
additionalInfo | json.RawMessage | Optional |
Response — CPMRefundPaymentResponse
CPMRefundPaymentResponse is the response body for Refund Payment. refundNo and refundTime are Mandatory; partnerRefundNo is Optional here (unlike Direct Debit Payment Refund’s own response, where it’s Mandatory).
| Field | Type | Presence |
|---|---|---|
responseCode | string | Mandatory |
responseMessage | string | Mandatory |
originalPartnerReferenceNo | string | Optional |
originalReferenceNo | string | Optional |
originalExternalId | string | Optional |
refundNo | string | Mandatory |
partnerRefundNo | string | Optional |
refundAmount | *snap.Money | Optional |
refundTime | string | Mandatory |
additionalInfo | json.RawMessage | Optional |