Native Payments
Use Native Payments when you want full control of the client experience (web or mobile) and prefer not to use the Checkout SDK. Your client or backend collects a payment payload and sends it to Ottu to process the payment for a given session_id.
A payment payload can be:
- Wallet payment data (e.g., Apple Pay paymentData, Google Pay paymentMethodData) â typically encrypted by the wallet.
- Gateway token / network token (card-on-file or one-click use cases) â not necessarily encrypted.
Ottu processes the payload with the configured gateway and returns a normalized callback result.
Ottu offers SDKs and tools to speed up your integration. See Getting Started for all available options.
When to Useâ
- Apple Pay or Google Pay buttons are rendered and managed by you.
- Existing tokenization has already been implemented and needs to be used to charge with a gateway token.
- Granular, SDK-less control of the UX is required, while Ottu's orchestration and gateway integrations are still leveraged.
Setupâ
- A valid session_id obtained from the Checkout API.
- A Merchant Gateway ID (MID) with the payment service activated and properly configured in Ottu.
If multiple gateways are configured, always include the pg_code corresponding to the MID that has the target payment service enabled.
Example:
If a transaction has knet and mpgs pg_code but only knet supports Apple Pay, you must send
pg_code: knet when calling the Apple Pay endpoint.
Checklistâ
- Created a valid session_id.
- Completed Apple Pay / Google Pay setup (if applicable).
- Selected the correct invocation model (client or backend).
- Used the appropriate API key type (Public API Key vs. Private API Key).
- Implemented backend sync logic.
Configuring your native wallet from the session responseâ
Before you can render an Apple Pay or Google Pay button, you have to build the wallet's payment request. Several of those values â the gateway identifier, the gateway merchant ID, your wallet merchant ID â must come from Ottu, not from your own configuration. Ottu already returns them per transaction in the session response, so you never have to hardcode them.
gateway_merchant_id is not your wallet merchant_idThese are two different values and they are not interchangeable:
gateway_merchant_idâ the payment gateway's merchant identifier (for example, your MPGS merchant ID). This is what goes into the wallet's gateway tokenization setting (gatewayMerchantIdfor Google Pay).merchant_idâ your wallet (Google / Apple) merchant identifier (for example, a Google PayBCR2DNâŚID). It is used only for the wallet's own merchant info.
Putting the wallet merchant_id where the gateway expects gateway_merchant_id is a common, hard-to-diagnose mistake: the wallet sheet renders and produces a token, but the gateway rejects that token at the payment step (MPGS, for example, returns "not authorized to use this Google Pay payment token"). Always read both values from the session response per transaction â never hardcode them.
Where the fields liveâ
The wallet configuration is returned under sdk_setup_preload_payload.payment_services[] â one object per configured wallet. Request it by setting include_sdk_setup_preload=true when you create or retrieve the session.
These values are not in the top-level payment_methods array (which can be empty for native flows). Read each wallet's config from payment_services[], matched by its flow discriminator ("google_pay" or "apple_pay") and its pg_code.
Google Payâ
Map each payment_services[] field to its Google Pay request setting:
payment_services[] field | Google Pay setting | Notes |
|---|---|---|
gateway | tokenization gateway | e.g. mpgs |
gateway_merchant_id | tokenization gatewayMerchantId | the gateway's merchant ID â not your Google merchant ID |
merchant_id | merchantInfo.merchantId | your Google Pay (BCR2DNâŚ) merchant ID |
merchant_name | merchantInfo.merchantName | display name |
environment | Google Pay environment | PRODUCTION / TEST |
currency_code | transaction currency | |
country_code | transaction country | |
total_price | transaction total |
After Google Pay returns the token, POST it to the native endpoint (payment_url, i.e. POST /pbl/v2/payment/google-pay/) with session_id, pg_code, and the payload â as shown in Step-by-Step below.
Apple Payâ
Apple Pay's payment_services[] entry has a different field set â verified against the live SDK response, it does not mirror Google Pay:
payment_services[] field | Apple Pay payment request use | Notes |
|---|---|---|
merchant_id | Apple Pay merchant identifier | the merchantIdentifier used when validating the merchant session |
domain | merchant domain | the registered domain used for Apple Pay merchant/session validation |
shop_name | display name | shown on the Apple Pay sheet |
currency_code | payment request currency | |
country_code | payment request country | |
amount | payment request total | Apple Pay uses amount here, not total_price |
session_id | Ottu session | used for the merchant-session validation step |
validation_url | Ottu validation endpoint | your client calls this to validate the Apple Pay merchant session before showing the sheet |
Unlike Google Pay, the Apple Pay entry does not contain gateway or gateway_merchant_id, and there is no environment field:
- The gateway tokenization (the equivalent of Google Pay's
gatewayMerchantId) is handled by Ottu server-side during the merchant-session validation (validation_url) and decryption â you do not set it in the client payment request. - The Apple Pay environment (sandbox vs. production) is determined by the Apple account and device, not by a value in the response.
After Apple Pay returns the encrypted paymentData, POST it to the native endpoint (payment_url, i.e. POST /pbl/v2/payment/apple-pay/) with session_id, pg_code, and the payload â as shown in Step-by-Step below.
Guideâ
Workflowâ
Client â Ottuâ
- The client collects the wallet or tokenized payment payload and calls the Native Payments endpoint directly.
- The client receives the API callback response.
Never embed Private API Keys in client-side code â they grant full API access and will be compromised if exposed. Use a Public API Key for client-side calls.
If the call is made from the client side, the backend must be synchronized with the payment result by ensuring that one of the following actions is performed:
- The API response is forwarded to the backend, or
- The Payment Status Query API is called by the backend after the client confirms that the payment has been completed.
Client â Backend â Ottu (Recommended)â
- The client sends the payment payload to the backend.
- The backend calls the Ottu Native Payments endpoint.
- The backend receives the payment response callback.
- The backend processes the callback response and notifies the client side with the payment status.
Step-by-Stepâ
- Apple Pay
- Google Pay
- Auto-Debit
curl -X POST "https://sandbox.ottu.net/b/pbl/v2/payment/apple-pay/" \
-H "Authorization: Api-Key your_api_key" \
-H "Content-Type: application/json" \
-d '{
"session_id": "your_session_id",
"pg_code": "apple-pay-gateway",
"payload": {
"paymentData": {
"data": "base64_encrypted_payment_data...",
"signature": "base64_signature...",
"header": {
"publicKeyHash": "hash...",
"ephemeralPublicKey": "key..."
},
"version": "EC_v1"
},
"paymentMethod": {
"displayName": "Visa 5766",
"network": "Visa",
"type": "debit"
},
"transactionIdentifier": "transaction_id..."
}
}'
curl -X POST "https://sandbox.ottu.net/b/pbl/v2/payment/google-pay/" \
-H "Authorization: Api-Key your_api_key" \
-H "Content-Type: application/json" \
-d '{
"session_id": "your_session_id",
"pg_code": "google-pay-gateway",
"payload": {
"apiVersion": 2,
"apiVersionMinor": 0,
"paymentMethodData": {
"type": "CARD",
"tokenizationData": {
"type": "PAYMENT_GATEWAY",
"token": "encrypted_token..."
}
}
}
}'
curl -X POST "https://sandbox.ottu.net/b/pbl/v2/payment/auto-debit/" \
-H "Authorization: Api-Key your_api_key" \
-H "Content-Type: application/json" \
-d '{
"session_id": "your_session_id",
"token": "saved_card_token"
}'
Response (all endpoints return the same structure):
{
"result": "success",
"message": "successful payment",
"pg_response": {}
}
Use the response values to reconcile the payment in your backend and update your order state.
Idempotencyâ
Native Payments are direct-charge endpoints: one request charges the customer immediately, so a flaky network or an over-eager retry can charge twice. To make a charge safe to retry, send an Idempotency-Key request header. Generate one value per charge attempt â a UUID works well â and send that same value on every retry of that attempt; a fresh value for the same charge would defeat the protection:
curl -X POST "https://sandbox.ottu.net/b/pbl/v2/payment/auto-debit/" \
-H "Authorization: Api-Key your_api_key" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: 5f3b9c2a-1e4d-4a7b-9c8e-2d6f0a1b3c4d" \
-d '{ "session_id": "your_session_id", "token": "saved_card_token" }'
The same Idempotency-Key header works on every direct-charge endpoint â Apple Pay, Google Pay, wallet, and cash included.
The key is scoped to the transaction (its session_id) and recorded only after a successful charge. That single rule produces three behaviors:
| Scenario | What happens |
|---|---|
| Replaying a key from a successful charge | Rejected with 409 Conflict before any charge â the customer is never double-charged |
| Reusing a key after a failed charge | The charge proceeds â failed payments stay retryable, because the key was never recorded |
Sending no Idempotency-Key header | No replay protection â unchanged behavior, existing integrations unaffected |
A blocked replay returns 409 Conflict:
{
"detail": "Duplicate request detected. Idempotency-Key already used.",
"result": "failed"
}
The contract applies to every direct-charge endpoint:
| Endpoint | Charge |
|---|---|
POST /b/pbl/v2/payment/apple-pay/ | Apple Pay |
POST /b/pbl/v2/payment/google-pay/ | Google Pay |
POST /b/pbl/v2/payment/auto-debit/ | Saved-token / recurring |
POST /b/pbl/v2/payment/wallet/ | M-Wallet balance |
POST /b/pbl/v2/payment/cash/ | Cash acknowledgement |
This is distinct from the Tracking-Key header used by the Operations API (refund, capture, void). A replayed Tracking-Key returns the latest status of the original operation, whereas a replayed Idempotency-Key on a direct charge is rejected with 409. Use Idempotency-Key for charges, Tracking-Key for operations.
Two identical requests sent at the same instant are serialized internally â the first to claim the charge proceeds, the other gets 409 Conflict. Prefer sequential retries (wait for a response or timeout before retrying) over firing duplicates in parallel.
Use Casesâ
The general Setup prerequisites and checklist apply to all providers below.
Never modify wallet payloads (Apple Pay, Google Pay) â any change invalidates token decryption. Always include pg_code if multiple gateways are configured.
- Apple Pay
- Google Pay
- Auto-Debit
- Configure Apple Pay on the client side (iOS / web).
- Collect the encrypted
paymentDataobject from Apple Pay. - Send the payload with the session_id to
POST /b/pbl/v2/payment/apple-pay/. - Ottu processes via the configured Apple Pay gateway and returns a unified result (
succeeded,failed).
- Configure Google Pay on the client side (Android / web).
- Collect the wallet payment payload (
paymentMethodData,email,addresses, etc.). - Send the payload with the session_id to
POST /b/pbl/v2/payment/google-pay/. - Ottu processes through the configured gateway and returns a normalized response.
If the response contains type: "iframe", render it for 3D Secure authentication.
- Ensure the token is active and usable for the merchant.
- Use an existing session_id created via the Checkout API.
- Send the token in the
tokenfield toPOST /b/pbl/v2/payment/auto-debit/. - Ottu processes the payment with the configured gateway and returns the callback result.
Supports CIT (Cardholder Initiated) and MIT (Merchant Initiated) transactions.
API Referenceâ
Select the payment provider to see its full interactive API schema:
- Apple Pay
- Google Pay
- Auto-Debit
FAQâ
What's Next?â
- Checkout API â Create sessions with
payment_instrumentfor one-step checkout - Recurring Payments â Use tokens for auto-debit payments
- Webhooks â Receive payment result notifications