Native Payment API

Use the Native Payment API 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.

  • 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.

Send a post request to the payment service endpoint with payment session_id, then the payment service collected token to perform the payment process.

Quick Apple Pay Example (cURL)

curl -X POST "https://sandbox.ottu.net/b/pbl/v2/payment/apple-pay/" \
  -H "Authorization: Api-Key GYj5Na8H.29g9hqNjm11nORQMa2WiZwIBQQ49MdAL" \
  -H "Content-Type: application/json" \
  -d '{
    "payload": {
      "pg_code": "apple-pay", 
      "session_id": "str",
      "payload": {
        "paymentData": {
          ...
        }
      } // the apple payment token without modifications
    }
  }'

Ottu securely processes the Apple Pay request and returns a unified success response once the payment is completed.

{
  "result": "success",
  "message": "successful payment",
  "pg_response": {}
}

Use the response values to reconcile the payment in your backend and update your order state.

Continue with the sections below to learn more about response fields, error handling, and webhook integration.

Supported Methods

For detailed information on authentication procedures, please refer to the Authentication section.

  1. Client → Ottu (Public API Key )

    1. The client collects the wallet or tokenized payment payload and calls the Native Payment API directly using the Public API Key.

    2. The client receives the API callback response.

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 (Inquiry) API is called by the backend after the client confirms that the payment has been completed.

  1. Client → Backend → Ottu (Private API Key– Recommended)

    1. The client sends the payment payload to Backend

    2. Backend calls Ottu native payment API

    3. Backend receive payment response callback

    4. Backend process callback response and notify client side with payment status

  • A valid session_id obtained from the Checkout API.

  • A Merchant Gateway ID (MID) with the payment service activated and properly configured in Ottu.

To complete the setup, the Service Setup section for the specific payment service being implemented must be followed, such as:

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 API.

The prerequisites and checklist mentioned in the general Setup section should be applied. They can be accessed here.

  1. Apple Pay is configured on the client side (iOS / web).

  2. The encrypted paymentData object is collected from Apple Pay.

  3. The payload, along with the session_id, is sent to the Ottu Payment API.

  4. Ottu processes via the configured Apple Pay gateway and returns a unified result (succeeded, failed).

Native Payment API(Apple Pay)

post

Allows merchants to submit an Apple Pay payment directly via server-to-server integration. This endpoint requires private key authentication and expects a valid Apple Pay token structure in the request payload under payload.

Typical use case: The merchant collects the Apple Pay token on their frontend and sends it to this endpoint along with session and amount information.

Authorizations
AuthorizationstringRequired
Body
pg_codestring | nullOptional

The unique pg_code used for this payment instrument.

session_idstringRequired

A unique identifier for the payment transaction (session).

Responses
200Success
application/json
post
/b/pbl/v2/payment/apple-pay/
POST /b/pbl/v2/payment/apple-pay/ HTTP/1.1
Host: sandbox.ottu.net
Authorization: Basic username:password
Content-Type: application/json
Accept: */*
Content-Length: 320

{
  "payload": {
    "paymentData": {
      "version": "text",
      "data": "text",
      "signature": "text",
      "header": {
        "ephemeralPublicKey": "text",
        "wrappedKey": "text",
        "publicKeyHash": "text",
        "transactionId": "text"
      }
    },
    "paymentMethod": {
      "displayName": "text",
      "network": "text",
      "type": "text"
    },
    "transactionIdentifier": "text"
  },
  "pg_code": null,
  "session_id": "text"
}
{
  "pg_params": {
    "auth_code": null,
    "card_type": null,
    "card_holder": null,
    "cardholder_email": null,
    "card_expiry_month": null,
    "card_expiry_year": null,
    "full_card_expiry": null,
    "card_number": null,
    "card_issuer": null,
    "ref": null,
    "result": null,
    "track_id": null,
    "post_date": null,
    "transaction_id": null,
    "payment_id": null,
    "pg_message": null,
    "receipt_no": null,
    "transaction_no": null,
    "decision": null,
    "card_expiry": null,
    "card_details": null,
    "dcc_payer_amount": null,
    "dcc_payer_currency": null,
    "dcc_payer_exchange_rate": null,
    "rrn": null
  },
  "agreement": {
    "id": "text",
    "amount_variability": "fixed",
    "start_date": "2025-11-19",
    "expiry_date": "2025-11-19",
    "max_amount_per_cycle": "text",
    "cycle_interval_days": 1,
    "total_cycles": 1,
    "frequency": "irregular",
    "type": "recurring",
    "seller": {
      "name": "text",
      "short_name": "text",
      "category_code": "text"
    }
  },
  "amount": "text",
  "amount_details": {
    "currency_code": "text",
    "amount": "text",
    "total": "text",
    "fee": "text",
    "exchange_rate": "text"
  },
  "capture_delivery_address": true,
  "capture_delivery_location": true,
  "card_acceptance_criteria": {
    "min_expiry_time": 1
  },
  "currency_code": "text",
  "customer_address_city": "text",
  "customer_address_country": "text",
  "customer_address_line1": "text",
  "customer_address_line2": "text",
  "customer_birthdate": null,
  "customer_address_postal_code": "text",
  "customer_address_state": "text",
  "customer_email": "text",
  "customer_first_name": "text",
  "customer_id": "text",
  "customer_last_name": "text",
  "customer_phone": "text",
  "extra": null,
  "fee": "text",
  "gateway_account": "text",
  "gateway_name": "text",
  "gateway_response": {
    "ANY_ADDITIONAL_PROPERTY": "anything"
  },
  "initiator": {
    "id": 1,
    "first_name": "text",
    "last_name": "text",
    "username": "text",
    "email": "name@gmail.com",
    "phone": "text"
  },
  "is_sandbox": true,
  "message": "text",
  "order_no": null,
  "paid_amount": 1,
  "payment_type": "one_off",
  "reference_number": "text",
  "refunded_amount": 1,
  "remaining_amount": 1,
  "result": "pending",
  "session_id": "text",
  "settled_amount": 1,
  "signature": "text",
  "state": "text",
  "token": {
    "brand": null,
    "customer_id": "text",
    "cvv_required": true,
    "expiry_month": "text",
    "expiry_year": "text",
    "is_expired": true,
    "is_preferred": true,
    "name_on_card": null,
    "number": null,
    "pg_code": "text",
    "pg_name": "knet",
    "token": "text",
    "agreements": null
  },
  "transaction_log_id": null,
  "timestamp_utc": "2025-11-19T20:47:23.658Z",
  "transactions": [
    {
      "amount": "text",
      "currency_code": "text",
      "order_no": null,
      "session_id": "text",
      "state": "paid"
    }
  ],
  "voided_amount": 1
}

The prerequisites and checklist mentioned in the general Setup section should be applied. They can be accessed here.

  1. Google Pay is configured on the client side (Android / web).

  2. The wallet payment payload (paymentMethodData, email, addresses, etc.) is collected.

  3. The payload, along with the session_id, is sent to the Ottu Native Payment API.

  4. Ottu processes through the configured gateway and returns a normalized response.

Native Payment API(Google Pay)

post

Allows merchants to submit an Google Pay payment directly via server-to-server integration. This endpoint requires private key authentication and expects a valid Google Pay token structure in the request payload under payload.

Typical use case: The merchant collects the Google Pay token on their frontend and sends it to this endpoint along with session and amount information.

Authorizations
AuthorizationstringRequired
Body
pg_codestring | nullOptional

The unique pg_code used for this payment instrument.

session_idstringRequired

A unique identifier for the payment transaction (session).

Responses
200Success
application/json
Responseone of
or
or
post
/b/pbl/v2/payment/google-pay/
POST /b/pbl/v2/payment/google-pay/ HTTP/1.1
Host: sandbox.ottu.net
Authorization: Basic username:password
Content-Type: application/json
Accept: */*
Content-Length: 326

{
  "payload": {
    "apiVersion": 1,
    "apiVersionMinor": 1,
    "paymentMethodData": {
      "type": "text",
      "description": "text",
      "info": {
        "ANY_ADDITIONAL_PROPERTY": "anything"
      },
      "tokenizationData": {
        "ANY_ADDITIONAL_PROPERTY": "anything"
      }
    },
    "email": "name@gmail.com",
    "shippingAddress": {
      "ANY_ADDITIONAL_PROPERTY": "anything"
    }
  },
  "pg_code": null,
  "session_id": "text"
}
{
  "pg_params": {
    "auth_code": null,
    "card_type": null,
    "card_holder": null,
    "cardholder_email": null,
    "card_expiry_month": null,
    "card_expiry_year": null,
    "full_card_expiry": null,
    "card_number": null,
    "card_issuer": null,
    "ref": null,
    "result": null,
    "track_id": null,
    "post_date": null,
    "transaction_id": null,
    "payment_id": null,
    "pg_message": null,
    "receipt_no": null,
    "transaction_no": null,
    "decision": null,
    "card_expiry": null,
    "card_details": null,
    "dcc_payer_amount": null,
    "dcc_payer_currency": null,
    "dcc_payer_exchange_rate": null,
    "rrn": null
  },
  "agreement": {
    "id": "text",
    "amount_variability": "fixed",
    "start_date": "2025-11-19",
    "expiry_date": "2025-11-19",
    "max_amount_per_cycle": "text",
    "cycle_interval_days": 1,
    "total_cycles": 1,
    "frequency": "irregular",
    "type": "recurring",
    "seller": {
      "name": "text",
      "short_name": "text",
      "category_code": "text"
    }
  },
  "amount": "text",
  "amount_details": {
    "currency_code": "text",
    "amount": "text",
    "total": "text",
    "fee": "text",
    "exchange_rate": "text"
  },
  "capture_delivery_address": true,
  "capture_delivery_location": true,
  "card_acceptance_criteria": {
    "min_expiry_time": 1
  },
  "currency_code": "text",
  "customer_address_city": "text",
  "customer_address_country": "text",
  "customer_address_line1": "text",
  "customer_address_line2": "text",
  "customer_birthdate": null,
  "customer_address_postal_code": "text",
  "customer_address_state": "text",
  "customer_email": "text",
  "customer_first_name": "text",
  "customer_id": "text",
  "customer_last_name": "text",
  "customer_phone": "text",
  "extra": null,
  "fee": "text",
  "gateway_account": "text",
  "gateway_name": "text",
  "gateway_response": {
    "ANY_ADDITIONAL_PROPERTY": "anything"
  },
  "initiator": {
    "id": 1,
    "first_name": "text",
    "last_name": "text",
    "username": "text",
    "email": "name@gmail.com",
    "phone": "text"
  },
  "is_sandbox": true,
  "message": "text",
  "order_no": null,
  "paid_amount": 1,
  "payment_type": "one_off",
  "reference_number": "text",
  "refunded_amount": 1,
  "remaining_amount": 1,
  "result": "pending",
  "session_id": "text",
  "settled_amount": 1,
  "signature": "text",
  "state": "text",
  "token": {
    "brand": null,
    "customer_id": "text",
    "cvv_required": true,
    "expiry_month": "text",
    "expiry_year": "text",
    "is_expired": true,
    "is_preferred": true,
    "name_on_card": null,
    "number": null,
    "pg_code": "text",
    "pg_name": "knet",
    "token": "text",
    "agreements": null
  },
  "transaction_log_id": null,
  "timestamp_utc": "2025-11-19T20:47:23.658Z",
  "transactions": [
    {
      "amount": "text",
      "currency_code": "text",
      "order_no": null,
      "session_id": "text",
      "state": "paid"
    }
  ],
  "voided_amount": 1
}

The prerequisites and checklist mentioned in the general Setup section should be applied. They can be accessed here.

  1. Ensure the token is active and usable for the merchant.

  2. Use an existing session_id created via the Checkout API.

  3. Send the token in the token field to Ottu.

  4. Ottu processes the payment with the configured gateway and returns the callback result.

Supports CIT (Cardholder Initiated) and MIT (Merchant Initiated) transactions.

Native Payment API(Auto Debit)

post

This endpoint will take a session id and check for it's related payment if it's possible to be auto charged or not. if possible it will charge the payment and return the operation response. 📝 NOTE Optional fields may not be represented in response body.

Authorizations
AuthorizationstringRequired
Header parameters
AuthorizationstringRequired

Private API key to be provided in the format Api-Key <key>.

Default: Api-Key vSUmxsXx.V81oYvOWFMcIywaOu57Utx6VSCmG11lo
Body

Auto debit serializer should take session_id and consumer payment token then validate if session id is valid if session id is valid then validate if payment gateway supports auto debit if payment gateway supports auto debit then validate if payment gateway has implemented auto debit if payment gateway has implemented auto debit then charge the token and return charge response from client auto_debit method which should be implemented in client

session_idstring · max: 128Required

A unique identifier for each payment transaction, used to maintain the session state during the payment process.

tokenstringRequired

Use this field to provide the unique identifier of a saved customer card for processing a payment in the API request.

Responses
200Success
application/json
post
/b/pbl/v2/payment/auto-debit/
POST /b/pbl/v2/payment/auto-debit/ HTTP/1.1
Host: sandbox.ottu.net
Authorization: Api-Key vSUmxsXx.V81oYvOWFMcIywaOu57Utx6VSCmG11lo
Content-Type: application/json
Accept: */*
Content-Length: 36

{
  "session_id": "text",
  "token": "text"
}
{
  "pg_params": {
    "auth_code": null,
    "card_type": null,
    "card_holder": null,
    "cardholder_email": null,
    "card_expiry_month": null,
    "card_expiry_year": null,
    "full_card_expiry": null,
    "card_number": null,
    "card_issuer": null,
    "ref": null,
    "result": null,
    "track_id": null,
    "post_date": null,
    "transaction_id": null,
    "payment_id": null,
    "pg_message": null,
    "receipt_no": null,
    "transaction_no": null,
    "decision": null,
    "card_expiry": null,
    "card_details": null,
    "dcc_payer_amount": null,
    "dcc_payer_currency": null,
    "dcc_payer_exchange_rate": null,
    "rrn": null
  },
  "agreement": {
    "id": "text",
    "amount_variability": "fixed",
    "start_date": "2025-11-19",
    "expiry_date": "2025-11-19",
    "max_amount_per_cycle": "text",
    "cycle_interval_days": 1,
    "total_cycles": 1,
    "frequency": "irregular",
    "type": "recurring",
    "seller": {
      "name": "text",
      "short_name": "text",
      "category_code": "text"
    }
  },
  "amount": "text",
  "amount_details": {
    "currency_code": "text",
    "amount": "text",
    "total": "text",
    "fee": "text",
    "exchange_rate": "text"
  },
  "capture_delivery_address": true,
  "capture_delivery_location": true,
  "card_acceptance_criteria": {
    "min_expiry_time": 1
  },
  "currency_code": "text",
  "customer_address_city": "text",
  "customer_address_country": "text",
  "customer_address_line1": "text",
  "customer_address_line2": "text",
  "customer_birthdate": null,
  "customer_address_postal_code": "text",
  "customer_address_state": "text",
  "customer_email": "text",
  "customer_first_name": "text",
  "customer_id": "text",
  "customer_last_name": "text",
  "customer_phone": "text",
  "extra": null,
  "fee": "text",
  "gateway_account": "text",
  "gateway_name": "text",
  "gateway_response": {
    "ANY_ADDITIONAL_PROPERTY": "anything"
  },
  "initiator": {
    "id": 1,
    "first_name": "text",
    "last_name": "text",
    "username": "text",
    "email": "name@gmail.com",
    "phone": "text"
  },
  "is_sandbox": true,
  "message": "text",
  "order_no": null,
  "paid_amount": 1,
  "payment_type": "one_off",
  "reference_number": "text",
  "refunded_amount": 1,
  "remaining_amount": 1,
  "result": "pending",
  "session_id": "text",
  "settled_amount": 1,
  "signature": "text",
  "state": "text",
  "token": {
    "brand": null,
    "customer_id": "text",
    "cvv_required": true,
    "expiry_month": "text",
    "expiry_year": "text",
    "is_expired": true,
    "is_preferred": true,
    "name_on_card": null,
    "number": null,
    "pg_code": "text",
    "pg_name": "knet",
    "token": "text",
    "agreements": null
  },
  "transaction_log_id": null,
  "timestamp_utc": "2025-11-19T20:47:23.658Z",
  "transactions": [
    {
      "amount": "text",
      "currency_code": "text",
      "order_no": null,
      "session_id": "text",
      "state": "paid"
    }
  ],
  "voided_amount": 1
}

1️ Can I call the Native Payment API directly from the client?

Yes, but only with the Public Key, and your backend must remain synchronized.

2️ Which model should I use in production?

Always prefer Client → Backend → Ottu using the Private Key.

3️How do I verify the payment result?

Use the Payment Status (Inquiry) API.

4️What if my transaction has multiple gateway codes?

Include the pg_code for the MID that has the corresponding payment service enabled (e.g., Apple Pay, Google Pay).

5️What happens if I modify wallet data?

The payment will fail — wallet tokens must be sent unmodified.

6️Can I charge saved tokens automatically?

Yes, use the Native Payment API for tokenized or recurring payments.

Last updated