Appearance
SDK Card Payment - Non Direct Payment
Endpoint Information
| Property | Value |
|---|---|
| Method + URL | POST /card-v2/v1/charge |
| Content-Type | application/json |
| Authorization | Basic <Base64Token> |
Headers
| Header | Required | Description |
|---|---|---|
Authorization | ✅ Required | Basic {Base64 of merchantId:secretUnbound:hashKey} |
Content-Type | ✅ Required | application/json |
X-Idempotency-Key | Recommended | Unique key per request to make retries safe |
Request Body
This is the exact request payload generated by PaymentGateway after PaymentViewModel builds and serializes a PaymentRequest.
Field names follow the Kotlin data classes, while the JSON wire format uses snake_case where annotated with @SerialName.
Full Request Body Example
json
{
"externalId": "1Ktru19Cp7",
"orderId": "ONxeTcEBE6",
"currency": "IDR",
"source": "payment_page",
"paymentMethod": "card",
"paymentChannel": "BRICC",
"paymentMode": "CLOSE",
"paymentDetails": {
"amount": 10000,
"isCustomerPayingFee": false,
"transactionDescription": "Clothes",
"expiredTime": ""
},
"itemDetails": [
{
"itemId": "Artikel 1",
"name": "shirt",
"amount": 10000,
"qty": 1
}
],
"customerDetails": {
"email": "[email protected]",
"fullName": "Testing",
"phone": "0897xxxxxxx",
"ipAddress": "182.30.91.67"
},
"billingAddress": {
"fullName": "CC Test",
"address": "...",
"city": "Tangerang",
"postalCode": "19127",
"country": "ID"
},
"shippingAddress": {
"fullName": "MCP",
"address": "...",
"city": "Malang",
"postalCode": "10210",
"country": "ID"
},
"cardDetails": {
"cardNumber": "",
"cardExpiredMonth": "",
"cardExpiredYear": "",
"cardCvn": "",
"cardHolderName": ""
},
"returnUrl": "https://superapp-stg.ifortepay.id/",
"callbackUrl": "https://mcpid.free.beeceptor.com",
"paymentOptions": {
"useRewards": true,
"campaign_code": "002",
"tenor": "0"
},
"additionalData": ""
}PaymentRequest Fields
| Field | Type | Required | Description |
|---|---|---|---|
externalId | String | ✅ Required | Unique merchant-side ID (max 64 chars) |
orderId | String | ✅ Required | Order ID (max 64 chars) |
currency | String | ✅ Required | "IDR" |
paymentMethod | String | ✅ Required | "card" or "ewallet" depending on flow |
paymentChannel | String | ✅ Required | "BRICC" |
paymentMode | String | ✅ Required | "CLOSE" or "OPEN" |
paymentDetails | Object | ✅ Required | See PaymentDetails below |
itemDetails | Array | ✅ Required | List of line items (minimum 1) |
customerDetails | Object | ✅ Required | Customer contact information |
billingAddress | Object | ✅ Required | Billing address |
shippingAddress | Object | ✅ Required | Shipping address |
cardDetails | Object | Conditional | Manual entry or auto-filled via NFC |
returnUrl | String | ✅ Required | Redirect URL after payment completes |
callbackUrl | String | Optional | Webhook URL for asynchronous payment status updates |
paymentOptions | Object | Optional | Reward points and installment configuration |
PaymentDetails
| Field | Type | Required | Description |
|---|---|---|---|
amount | Long | ✅ Required | Charge amount in the smallest currency unit |
isCustomerPayingFee | Boolean | ✅ Required | Indicates whether the customer absorbs the processing fee |
transactionDescription | String | ✅ Required | Free-text description displayed on statements |
expiredTime | String (ISO-8601) | Optional | Expiration timestamp for the payment request |
ItemDetails (Array Element)
| Field | Type | Required | Description |
|---|---|---|---|
itemId | String | ✅ Required | Merchant-defined item identifier |
name | String | ✅ Required | Item name |
amount | Int | ✅ Required | Unit price (Int, narrower than PaymentDetails.amount) |
qty | Int (1–999) | ✅ Required | Quantity |
description | String | Optional | Free-text item description |
CustomerDetails
| Field | Type | Required | Description |
|---|---|---|---|
email | String | ✅ Required | Customer email |
fullName | String | ✅ Required | Customer full name |
phone | String | ✅ Required | Customer phone number |
ipAddress | String | ✅ Required | Customer device IP address |
BillingAddress / ShippingAddress
| Field | Type | Required | Description |
|---|---|---|---|
fullName | String | ✅ Required | Recipient name |
phone | String | ✅ Required | Recipient phone number |
address | String | ✅ Required | Street address |
city | String | ✅ Required | City |
postalCode | String | ✅ Required | Postal / ZIP code |
country | String | ✅ Required | ISO country code (e.g. "ID") |
CardDetails
Card information can be filled manually by the user or automatically through autofillFromNfc() after a successful NFC scan.
| Field | Type | Required | Description |
|---|---|---|---|
cardNumber | String (13–19 digits) | Conditional | PAN, spaces are stripped before submission |
cardExpiredMonth | String (MM) | Conditional | Two-digit expiry month |
cardExpiredYear | String (YY/YYYY) | Conditional | Expiry year |
cardCvn | String (3–4 digits) | Conditional | Card Verification Number (CVN) |
cardHolderName | String | Conditional | Name printed on the card (automatically uppercased by the UI) |
PaymentOptions
| Field | Type | Required | Description |
|---|---|---|---|
useRewards | Boolean | Optional | Apply reward point redemption |
campaign_code | String | Optional | Promotion / campaign code |
tenor | String ("0", "3", "6", "12") | Optional | Installment period in months ("0" = full payment) |
Responses
This section describes the possible API responses returned by the Payment Gateway.
200 — Success
json
{
"statusCode": "200",
"statusMessage": "SUCCESS",
"data": {
"transactionId": "TXN-2026016183-001",
"externalId": "1Ktru19Cp7",
"paymentStatus": "SUCCESS",
"link": "https://..."
}
}401 — Unauthorized
json
{
"statusCode": "401",
"statusMessage": "UNAUTHORIZED",
"errors": [
{
"field": "authorization",
"message": "Invalid token"
}
]
}400 — Validation Error
json
{
"statusCode": "400",
"statusMessage": "VALIDATION_ERROR",
"errors": [
{
"field": "amount",
"message": "Must be > 0"
}
]
}Mapping to PaymentSdkResult
The SDK converts API responses into a unified PaymentSdkResult before invoking the callback to the host application.
Success Response
text
responseCode "00"
↓
PaymentSdkResult(
isSuccess = true,
link = data.link
)Failed Response
text
Any other responseCode
↓
PaymentSdkResult(
isSuccess = false,
responseMessage = ...
)Note
This mapping is identical for:
- Business-level failures returned with HTTP
200- Standard HTTP error responses (
400,401,500, etc.)See
PaymentViewModel.onSuccessDone()andPaymentViewModel.onFailedDone()(Section 17) for the implementation details.
Error Codes
The following table lists the HTTP status codes that may be returned by the Payment Gateway, along with the recommended handling for each response.
| HTTP Code | Status | Recommended Action |
|---|---|---|
| 400 | VALIDATION_ERROR | Fix the validation errors listed in the response, then resubmit the request. |
| 401 | UNAUTHORIZED | Regenerate the Base64 authorization token. The merchant credentials may be invalid or expired. |
| 409 | DUPLICATE_ORDER | Generate a new, unused orderId before retrying the request. |
| 422 | INVALID_CARD | Ask the customer to re-enter the card information or perform another NFC scan. |
| 500 | INTERNAL_ERROR | Retry the request. This usually indicates a temporary server-side issue. |
| 503 | SERVICE_UNAVAILABLE | Retry the request using an exponential backoff strategy. |