Registration
Registration
Account binding, card registration, and OTP verification — the registration package (Service Codes 01-10, 81). Two flows live here: the account flow (OAuth-based binding, driven by GetOAuthURL → AccountBinding) and the card flow (CardRegistration and its Set Limit/Inquiry/Unbinding variants).
resp, err := registration.AccountBinding(ctx, transport, hb, registration.AccountBindingRequest{
MerchantID: "...",
})
if err != nil {
// errors.Is(err, snap.ErrBadRequest), snap.ErrUnauthorized, etc.
}Every function below has the same call shape: fill in hb (everything except Body — the function marshals the request and sets Body itself), call it, and check err. See Core Conventions for the full pattern.
GetOAuthURL
Starts the OAuth account-binding flow by building an authorization URL (Service Code 10). This is a read-only GET call: hb.EndpointURL must be a bare http(s) URL with no query string or fragment — it errors instead of silently merging into one.
func GetOAuthURL(ctx context.Context, t *snap.Transport, hb snap.HeaderBuilder, req GetOAuthURLRequest) (GetOAuthURLResponse, error)Request — GetOAuthURLRequest
Unlike every other endpoint here, this isn’t JSON — GetOAuthURL builds a URL query string directly from these fields. RedirectURL, Scopes, and State are Mandatory; SeamlessSign is Conditional (required only if SeamlessData is set); everything else is Optional.
| Query parameter | Type | Presence |
|---|---|---|
RedirectURL | string | Mandatory |
Scopes | []string (joined with ,) | Mandatory |
State | string | Mandatory |
MerchantID | string | Optional |
SubMerchantID | string | Optional |
Lang | string (ISO 639-1) | Optional |
AllowRegistration | *bool | Optional |
SeamlessData | string | Optional |
MobileNumber | string | Optional |
VerifiedTime | string | Optional |
ExternalUID | string | Optional |
DeviceID | string | Optional |
SeamlessSign | string | Conditional — required if SeamlessData is set |
Response — GetOAuthURLResponse
Every field is Mandatory.
| Field | Type | Presence |
|---|---|---|
responseCode | string | Mandatory |
responseMessage | string | Mandatory |
authCode | string | Mandatory |
state | string | Mandatory |
AccountCreation
Creates an account (Service Code 06).
Not idempotent. On retry, reuse the same X-EXTERNAL-ID — a fresh one risks creating a second account.
func AccountCreation(ctx context.Context, t *snap.Transport, hb snap.HeaderBuilder, req AccountCreationRequest) (AccountCreationResponse, error)Request — AccountCreationRequest
Every field is Optional — this endpoint covers several onboarding flows (seamless data, OAuth redirect, direct creation), each using a different subset of fields.
| Field | Type | Presence |
|---|---|---|
partnerReferenceNo | string | Optional |
countryCode | string | Optional |
customerId | string | Optional |
deviceInfo | *DeviceInfo | Optional |
email | string | Optional |
lang | string | Optional |
locale | string | Optional |
name | string | Optional |
onboardingPartner | string | Optional |
phoneNo | string | Optional |
redirectUrl | string | Optional |
scopes | string | Optional |
seamlessData | string | Optional |
seamlessSign | string | Optional |
state | string | Optional |
merchantId | string | Optional |
subMerchantId | string | Optional |
terminalType | json.RawMessage | Optional |
additionalInfo | json.RawMessage | Optional |
DeviceInfo fields
DeviceInfo describes the device initiating a registration request.
| Field | Type | Presence |
|---|---|---|
os | string | Optional |
osVersion | string | Optional |
model | string | Optional |
manufacturer | string | Optional |
Response — AccountCreationResponse
apiKey is json.RawMessage because the standard doesn’t say whether it’s sent as a quoted string or a bare number — this accepts either without failing the whole decode.
| Field | Type | Presence |
|---|---|---|
responseCode | string | Mandatory |
responseMessage | string | Mandatory |
referenceNo | string | Optional |
partnerReferenceNo | string | Optional |
authCode | string | Optional |
apiKey | json.RawMessage | Optional |
accountId | string | Optional |
state | string | Optional |
additionalInfo | json.RawMessage | Optional |
AccountBinding
Binds a customer account for B2B2C use (Service Code 07).
Not idempotent. On retry, reuse the same X-EXTERNAL-ID — a fresh one risks a duplicate binding or a second token issuance.
func AccountBinding(ctx context.Context, t *snap.Transport, hb snap.HeaderBuilder, req AccountBindingRequest) (AccountBindingResponse, error)Request — AccountBindingRequest
MerchantID is the only Mandatory field.
| Field | Type | Presence |
|---|---|---|
partnerReferenceNo | string | Optional |
action | string | Optional |
additionalData | json.RawMessage | Optional |
userId | string | Optional |
email | string | Optional |
postalAddress | string | Optional |
authCode | string | Optional |
grantType | string | Optional |
isBindAndPay | string | Optional |
lang | string | Optional |
locale | string | Optional |
merchantId | string | Mandatory |
subMerchantId | string | Optional |
msisdn | string | Optional |
otp | string | Optional |
phoneNo | string | Optional |
platformType | string | Optional |
redirectUrl | string | Optional |
referenceId | string | Optional |
refreshToken | string | Optional |
successParams | *BindingSuccessParams | Optional |
additionalInfo | json.RawMessage | Optional |
BindingSuccessParams fields
The request-side successParams object.
| Field | Type | Presence |
|---|---|---|
accountId | string | Optional |
terminalId | string | Optional |
tokenRequestorId | string | Optional |
Response — AccountBindingResponse
| Field | Type | Presence |
|---|---|---|
responseCode | string | Mandatory |
responseMessage | string | Mandatory |
referenceNo | string | Optional |
partnerReferenceNo | string | Optional |
accountToken | string | Optional |
accessTokenInfo | *BindingAccessTokenInfo | Optional |
linkId | string | Optional |
nextAction | string | Optional |
linkageToken | string | Optional |
params | json.RawMessage | Optional |
pinWebViewUrl | string | Optional |
redirectToDeeplink | string | Optional |
redirectUrl | string | Optional |
userInfo | *BindingUserInfo | Optional |
additionalInfo | json.RawMessage | Optional |
BindingAccessTokenInfo fields
The response-side accessTokenInfo object. expiresIn/reExpiresIn here are ISO 8601 datetime strings — a different shape from the B2B/B2B2C access-token endpoints’ Token.ExpiresIn (a duration parsed from a seconds count). Same field name, different endpoint, different meaning.
| Field | Type | Presence |
|---|---|---|
accessToken | string | Optional |
expiresIn | string | Optional |
refreshToken | string | Optional |
reExpiresIn | string | Optional |
tokenStatus | string | Optional |
BindingUserInfo fields
The response-side userInfo object.
| Field | Type | Presence |
|---|---|---|
publicUserId | string | Optional |
AccountBindingInquiry
Looks up a bound account’s details (Service Code 08).
func AccountBindingInquiry(ctx context.Context, t *snap.Transport, hb snap.HeaderBuilder, req AccountBindingInquiryRequest) (AccountBindingInquiryResponse, error)Request — AccountBindingInquiryRequest
The standard doesn’t define an account-identifier field for this call; if your PJP needs one, put it in AdditionalInfo.
| Field | Type | Presence |
|---|---|---|
partnerReferenceNo | string | Optional |
additionalInfo | json.RawMessage | Optional |
Response — AccountBindingInquiryResponse
Flatter than AccountBindingResponse — no accessTokenInfo/userInfo nesting. accountTransactionLimit is json.RawMessage since the standard doesn’t guarantee it’s always sent as a quoted string across every PJP.
| Field | Type | Presence |
|---|---|---|
responseCode | string | Mandatory |
responseMessage | string | Mandatory |
referenceNo | string | Optional |
partnerReferenceNo | string | Optional |
accountCurrency | string | Optional |
accountName | string | Optional |
accountNo | string | Optional |
accountTransactionLimit | json.RawMessage | Optional |
endDatePeriod | string | Optional |
startDatePeriod | string | Optional |
additionalInfo | json.RawMessage | Optional |
AccountUnbinding
Removes an account binding (Service Code 09).
Not idempotent. On retry, reuse the same X-EXTERNAL-ID.
func AccountUnbinding(ctx context.Context, t *snap.Transport, hb snap.HeaderBuilder, req AccountUnbindingRequest) (AccountUnbindingResponse, error)Request — AccountUnbindingRequest
MerchantID is the only Mandatory field. LinkID and TokenID — which actually identify the binding to remove — are both Optional per the standard; this package doesn’t enforce that at least one is set, since that’s a business rule, not a wire-shape rule.
| Field | Type | Presence |
|---|---|---|
partnerReferenceNo | string | Optional |
linkId | string | Optional |
merchantId | string | Mandatory |
subMerchantId | string | Optional |
tokenId | string | Optional |
additionalInfo | json.RawMessage | Optional |
Response — AccountUnbindingResponse
| Field | Type | Presence |
|---|---|---|
responseCode | string | Mandatory |
responseMessage | string | Mandatory |
referenceNo | string | Optional |
partnerReferenceNo | string | Optional |
merchantId | string | Optional |
subMerchantId | string | Optional |
linkId | string | Optional |
unlinkResult | string | Optional |
additionalInfo | json.RawMessage | Optional |
OTP
Triggers OTP delivery, e.g. SMS (Service Code 81).
Triggers a real external side effect. On retry, reuse the same X-EXTERNAL-ID — a fresh one risks a duplicate OTP delivery.
func OTP(ctx context.Context, t *snap.Transport, hb snap.HeaderBuilder, req OTPRequest) (OTPResponse, error)Request — OTPRequest
JourneyID is the only Mandatory field. For a B2B2C-shaped call, set HeaderBuilder.B2B2C (and AuthorizationCustomer/DeviceID) the same as for any other B2B2C endpoint — no special field is needed here. BankCardToken is Conditional.
| Field | Type | Presence |
|---|---|---|
partnerReferenceNo | string | Optional |
journeyId | string | Mandatory |
merchantId | string | Optional |
subMerchant | string | Optional |
externalStoreId | string | Optional |
trxDateTime | string | Optional |
bankCardToken | string | Conditional |
otpTrxCode | string | Optional |
otpReasonCode | string | Optional |
otpReasonMessage | string | Optional |
additionalInfo | json.RawMessage | Optional |
Response — OTPResponse
chargeToken is Mandatory here (it’s Optional on CardRegistrationResponse — same field name, different endpoint).
| Field | Type | Presence |
|---|---|---|
responseCode | string | Mandatory |
responseMessage | string | Mandatory |
referenceNo | string | Optional |
partnerReferenceNo | string | Optional |
chargeToken | string | Mandatory |
additionalInfo | json.RawMessage | Optional |
VerifyOTP
Verifies a previously issued OTP (Service Code 04, Direct Integration).
Not idempotent — verifying consumes server-side state (invalidates the OTP, likely counts as an attempt). On retry, reuse the same X-EXTERNAL-ID — a fresh one risks burning an extra attempt or re-processing an already-completed call.
func VerifyOTP(ctx context.Context, t *snap.Transport, hb snap.HeaderBuilder, req VerifyOTPRequest) (VerifyOTPResponse, error)Request — VerifyOTPRequest
Every field is Optional.
| Field | Type | Presence |
|---|---|---|
originalPartnerReferenceNo | string | Optional |
originalReferenceNo | string | Optional |
action | string | Optional |
merchantId | string | Optional |
otp | string | Optional |
chargeToken | string | Optional |
type | string | Optional |
additionalInfo | json.RawMessage | Optional |
Response — VerifyOTPResponse
| Field | Type | Presence |
|---|---|---|
responseCode | string | Mandatory |
responseMessage | string | Mandatory |
originalReferenceNo | string | Optional |
originalPartnerReferenceNo | string | Optional |
accountNo | string | Optional |
bankCardToken | string | Optional |
cardPan | string | Optional |
customerId | string | Optional |
email | string | Optional |
expiredDatetime | string | Optional |
expiryDate | string | Optional |
identificationNo | string | Optional |
linkageToken | string | Optional |
phoneNo | string | Optional |
qParamsURL | string | Optional |
qParams | json.RawMessage | Optional |
sendOtpFlag | string | Optional |
subscribeDatetime | string | Optional |
tokenExpiryTime | string | Optional |
transactionTimestamp | string | Optional |
additionalInfo | json.RawMessage | Optional |
CardRegistration
Registers a card and mints a BankCardToken (Service Code 01).
Not idempotent — it mints a new token each call. On retry, reuse the same X-EXTERNAL-ID — a fresh one risks a duplicate card bind.
func CardRegistration(ctx context.Context, t *snap.Transport, hb snap.HeaderBuilder, req CardRegistrationRequest) (CardRegistrationResponse, error)Request — CardRegistrationRequest
BankCardNo and CustIDMerchant are the two Mandatory fields. CardData and Limit are json.RawMessage — the standard allows a non-string JSON form (a bare object or number) for both. If you’re assigning a Go string, quote it yourself first (e.g. json.RawMessage(“1000000”), not json.RawMessage(limitStr)) so it matches the expected wire shape.
| Field | Type | Presence |
|---|---|---|
partnerReferenceNo | string | Optional |
accountName | string | Optional |
cardData | json.RawMessage | Optional |
bankAccountNo | string | Optional |
bankCardNo | string | Mandatory |
bankCardType | string | Optional |
dateOfBirth | string | Optional |
email | string | Optional |
expiredDatetime | string | Optional |
expiryDate | string | Optional |
identificationNo | string | Optional |
identificationType | string | Optional |
custIdMerchant | string | Mandatory |
isBindAndPay | string | Optional |
merchantId | string | Optional |
terminalId | string | Optional |
journeyId | string | Optional |
subMerchantId | string | Optional |
externalStoreId | string | Optional |
limit | json.RawMessage | Optional |
merchantLogoUrl | string | Optional |
phoneNo | string | Optional |
sendOtpFlag | string | Optional |
type | string | Optional |
additionalInfo | json.RawMessage | Optional |
Response — CardRegistrationResponse
| Field | Type | Presence |
|---|---|---|
responseCode | string | Mandatory |
responseMessage | string | Mandatory |
referenceNo | string | Optional |
partnerReferenceNo | string | Optional |
bankCardToken | string | Mandatory |
chargeToken | string | Optional |
randomString | string | Optional |
tokenExpiryTime | string | Optional |
additionalInfo | json.RawMessage | Optional |
CardRegistrationInquiry
Looks up registered card accounts by merchant customer ID (Service Code 03). This is the package’s only read-only GET endpoint; custIDMerchant is passed as a URL path segment, validated and safely joined onto hb.EndpointURL.
func CardRegistrationInquiry(ctx context.Context, t *snap.Transport, hb snap.HeaderBuilder, custIDMerchant string) (CardRegistrationInquiryResponse, error)This endpoint takes no typed request body beyond the call parameters shown above.
Response — CardRegistrationInquiryResponse
| Field | Type | Presence |
|---|---|---|
responseCode | string | Mandatory |
responseMessage | string | Mandatory |
accountList | []CardRegistrationInquiryAccount | Optional |
additionalInfo | json.RawMessage | Optional |
CardRegistrationInquiryAccount fields
One entry in accountList, wrapping the nested accountData object.
| Field | Type | Presence |
|---|---|---|
accountData | CardRegistrationInquiryAccountData | Mandatory |
CardRegistrationInquiryAccountData fields
The nested accountData object. maxLimit and credentialNo are masked/formatted display strings (e.g. "************0750"), not raw values.
| Field | Type | Presence |
|---|---|---|
accountId | string | Optional |
createdDate | string | Optional |
credentialNo | string | Optional |
credentialType | string | Optional |
maxLimit | string | Optional |
status | string | Optional |
CardRegistrationSetLimit
Sets a spending limit on a registered card (Service Code 02).
func CardRegistrationSetLimit(ctx context.Context, t *snap.Transport, hb snap.HeaderBuilder, req CardRegistrationSetLimitRequest) (CardRegistrationSetLimitResponse, error)Request — CardRegistrationSetLimitRequest
BankCardToken is the only Mandatory field. Limit is json.RawMessage for the same reason as in CardRegistrationRequest — quote a Go string yourself before assigning it (e.g. json.RawMessage(“1000000”)).
| Field | Type | Presence |
|---|---|---|
partnerReferenceNo | string | Optional |
bankAccountNo | string | Optional |
bankCardNo | string | Optional |
limit | json.RawMessage | Optional |
bankCardToken | string | Mandatory |
otp | string | Optional |
additionalInfo | json.RawMessage | Optional |
Response — CardRegistrationSetLimitResponse
| Field | Type | Presence |
|---|---|---|
responseCode | string | Mandatory |
responseMessage | string | Mandatory |
referenceNo | string | Optional |
partnerReferenceNo | string | Optional |
additionalInfo | json.RawMessage | Optional |
CardRegistrationUnbinding
Removes a card registration (Service Code 05).
Not idempotent. On retry, reuse the same X-EXTERNAL-ID.
func CardRegistrationUnbinding(ctx context.Context, t *snap.Transport, hb snap.HeaderBuilder, req CardRegistrationUnbindingRequest) (CardRegistrationUnbindingResponse, error)Request — CardRegistrationUnbindingRequest
Token is the only Mandatory field.
| Field | Type | Presence |
|---|---|---|
partnerReferenceNo | string | Optional |
token | string | Mandatory |
bankCardNo | string | Optional |
type | string | Optional |
part | string | Optional |
merchantId | string | Optional |
subMerchantId | string | Optional |
terminalId | string | Optional |
tokenRequestorId | string | Optional |
journeyId | string | Optional |
transactionDate | string | Optional |
additionalInfo | json.RawMessage | Optional |
Response — CardRegistrationUnbindingResponse
| Field | Type | Presence |
|---|---|---|
responseCode | string | Mandatory |
responseMessage | string | Mandatory |
referenceNo | string | Optional |
partnerReferenceNo | string | Optional |
message | string | Optional |
customerId | string | Optional |
unsubscribeDate | string | Optional |
additionalInfo | json.RawMessage | Optional |