> ## Documentation Index
> Fetch the complete documentation index at: https://docs.avraapi.com/llms.txt
> Use this file to discover all available pages before exploring further.

# KOKO

> Use KOKO LKR redirect checkout with signed callback and order-view reconciliation.

## When to use KOKO

Use KOKO for an LKR-only, buy-now-pay-later redirect checkout. The shared `createOrder()` function prepares the signed provider form. Your backend then preserves either KOKO's signed callback or browser return and completes the original session. AvraAPI verifies the signed callback and, by default, reconciles it with KOKO's signed order view before an order can be fulfilled.

| Capability | Support |
| - | - |
| Checkout mode | `redirect` only |
| Currency | LKR only |
| PHP SDK | Signed order view plus callback/return payload wrappers released |
| Laravel SDK | Released through the `AvraAPI::payment()` Facade accessor |
| Node.js SDK | Released: signed order view plus callback and return payload wrappers. |
| Payment Elements | Standard KOKO redirect hand-off |
| Completion rule | Signed callback validation and default order-view reconciliation |

<Note>
  The shared UPG lifecycle—availability, `createOrder()`, and `completePayment()`—is documented in [Quick Setup](/universal-payment-gateway/quick-setup). This page covers only KOKO-specific functions and presentation.
</Note>

## SDK Functions

<Tabs>
  <Tab title="PHP SDK">
    | Function | Purpose |
    | - | - |
    | `payment()->koko()->orderView()` | Retrieves and validates the signed KOKO order view for a known order ID. |
    | `KokoCallbackPayload::fromForm()` | Maps KOKO's signed callback form fields into the exact completion payload. |
    | `KokoReturnPayload::fromQuery()` | Maps the unsigned browser return query into the completion payload. |
  </Tab>

  <Tab title="Laravel SDK">
    | Function | Purpose |
    | - | - |
    | Laravel Facade | Use `AvraAPI::payment()` with the released typed helpers shown in the Laravel samples below. |
  </Tab>

  <Tab title="Node.js SDK">
    | Function | Purpose |
    | - | - |
    | `client.payment().koko().orderView()` | Retrieves and validates a signed KOKO order view. |
    | `KokoCallbackPayload.fromForm()` | Maps the signed callback form into the completion payload. |
    | `KokoReturnPayload.fromQuery()` | Maps an unsigned browser return into the completion payload. |
  </Tab>
</Tabs>

## Retrieve a signed KOKO order view

Use `orderView()` from your backend to inspect a KOKO order that your application created. The SDK requests the provider's signed order view, verifies the returned order ID and RSA signature, and maps the verified fields into `KokoOrderView`.

<Tabs>
  <Tab title="PHP SDK">
    ```php theme={null}
    use Avraapi\Apix\Payments\GatewayEnvironment;

    $view = $apix->payment()->koko()->orderView(
        orderId: $order->id,
        gatewayEnvironment: GatewayEnvironment::Sandbox,
    );
    ```

    **SDK response** — `KokoOrderView`:

    ```json theme={null}
    {
      "order_id": "ORDER-2026-000184",
      "gateway_reference": "KOKO-320000000000",
      "provider_status": "SUCCESS",
      "request_id": "01j..."
    }
    ```

    The SDK object exposes `$view->orderId`, `$view->gatewayReference`, `$view->providerStatus`, and `$view->requestId`. It also has `$view->native`, the raw signed provider object. `native` is server-only diagnostic data and must not be returned to a browser, logs, queues, or analytics.
  </Tab>

  <Tab title="Laravel SDK">
    ```php theme={null}
    use Avraapi\Laravel\Facades\AvraAPI;

    use Avraapi\Apix\Payments\GatewayEnvironment;

    $view = AvraAPI::payment()->koko()->orderView(
        orderId: $order->id,
        gatewayEnvironment: GatewayEnvironment::Sandbox,
    );
    ```
  </Tab>

  <Tab title="Node.js SDK">
    ```ts theme={null}
    import { GatewayEnvironment } from '@avraapi/node-sdk';

    const view = await client.payment().koko().orderView(
      order.id,
      GatewayEnvironment.Sandbox,
    );

    // view.orderId, view.gatewayReference, view.providerStatus, view.requestId
    // Keep view.native on the server only.
    ```
  </Tab>
</Tabs>

## Prepare a signed callback payload

KOKO posts a signed form to the configured notification URL. Use `fromForm()` to require the exact callback binding fields before shared completion. This helper validates that the required fields are present; signature verification occurs during `completePayment()`.

<Tabs>
  <Tab title="PHP SDK">
    ```php theme={null}
    use Avraapi\Apix\Payments\Koko\KokoCallbackPayload;

    $payload = KokoCallbackPayload::fromForm($request->all())->toArray();
    ```

    **SDK response** — callback payload:

    ```json theme={null}
    {
      "orderId": "ORDER-2026-000184",
      "trnId": "KOKO-320000000000",
      "status": "SUCCESS",
      "desc": "Payment completed",
      "signature": "provider-signature"
    }
    ```

    The five field names intentionally match KOKO's callback contract. Do not rename, reformat, or reconstruct them before completion. AvraAPI verifies the callback signature using the Vault-held KOKO public key.
  </Tab>

  <Tab title="Laravel SDK">
    ```php theme={null}
    use Avraapi\Apix\Payments\Koko\KokoCallbackPayload;

    $payload = KokoCallbackPayload::fromForm($request->all())->toArray();
    ```
  </Tab>

  <Tab title="Node.js SDK">
    ```ts theme={null}
    import { KokoCallbackPayload } from '@avraapi/node-sdk';

    const payload = KokoCallbackPayload.fromForm(request.body).toPayload();
    ```
  </Tab>
</Tabs>

## Prepare a browser-return payload

KOKO's browser return is unsigned. It is still useful to trigger completion, but it cannot prove payment. `fromQuery()` requires the order ID and keeps the optional transaction ID and status only when they are present.

<Tabs>
  <Tab title="PHP SDK">
    ```php theme={null}
    use Avraapi\Apix\Payments\Koko\KokoReturnPayload;

    $payload = KokoReturnPayload::fromQuery($_GET)->toArray();
    ```

    **SDK response** — return payload:

    ```json theme={null}
    {
      "orderId": "ORDER-2026-000184",
      "trnId": "KOKO-320000000000",
      "status": "SUCCESS"
    }
    ```

    Only `orderId` is required by the wrapper. During shared completion, AvraAPI retrieves the signed order view and rejects a returned `trnId` that does not match it.
  </Tab>

  <Tab title="Laravel SDK">
    ```php theme={null}
    use Avraapi\Apix\Payments\Koko\KokoReturnPayload;

    $payload = KokoReturnPayload::fromQuery($_GET)->toArray();
    ```
  </Tab>

  <Tab title="Node.js SDK">
    ```ts theme={null}
    import { KokoReturnPayload } from '@avraapi/node-sdk';

    const payload = KokoReturnPayload.fromQuery(request.query).toPayload();
    ```
  </Tab>
</Tabs>

## Payment Elements

Use an explicit KOKO method when you want to promote eligible instalment checkout alongside other payment methods. The prepared KOKO session is a signed redirect form; Elements handles the standard browser hand-off but does not embed KOKO or present a plan selector.

```js theme={null}
elements.renderMethods('#payment-methods', {
  methods: [{
    gateway: 'koko',
    mode: 'redirect',
    label: 'Pay in instalments with KOKO Pay',
    description: 'Continue to KOKO for eligible interest-free instalments.',
  }],
});
```

Render KOKO only when server-side availability reports an active, usable LKR configuration. For rendering, visual customization, events, and the checkout lifecycle, see [More Payment Elements features](/universal-payment-gateway/payment-elements/overview).

## Gateway-specific options

There are no released KOKO-specific checkout `providerOptions`.

* KOKO accepts LKR only; a non-LKR checkout is rejected by the backend.
* The provider form fields, plugin registration values, and signature are created from Vault configuration on the backend. Do not create or alter them in the browser.
* Store the order ID and server-only completion context with your pending order. Never expose the signature or Vault configuration.

## Completion, webhooks, and safety

On KOKO callback, call shared `completePayment()` with the stored completion context and the exact callback payload. The default `reconcileProvider: true` verifies the callback signature and compares it with KOKO's signed order view. A browser-return flow also obtains the signed order view before it can result in a final payment state.

The normalized completion result may be `succeeded`, `pending`, `failed`, `cancelled`, or `unknown`. Fulfil only a verified `succeeded` result. Retain non-final orders for a bounded, idempotent backend retry; never use a browser return alone as proof of payment.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.