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

# DirectPay

> Use DirectPay overlay or embedded checkout with signed backend callback completion.

## When to use DirectPay

DirectPay is the released in-page gateway for LKR and USD one-time payments. The shared `createOrder()` call prepares the signed DirectPay browser session. Choose `overlay` to open the provider checkout window or `embedded` to present it in a dedicated page container. In both cases, the signed DirectPay callback—not a browser event—decides the final payment result.

| Capability | Support |
| - | - |
| Checkout modes | `overlay`, `embedded` |
| Currencies | LKR and USD |
| Payment type | `ONE_TIME` only |
| PHP SDK | Signed callback payload wrapper released |
| Laravel SDK | Released through the `AvraAPI::payment()` Facade accessor |
| Node.js SDK | Released: signed DirectPay callback payload wrapper and shared completion. |
| Payment Elements | DirectPay overlay or a dedicated embedded container |
| Completion rule | Exact raw callback body and Authorization HMAC verification |
| Not part of this release | Status lookup, refunds, card management, card-on-file, recurring, authorization, capture, and void APIs |

<Note>
  The shared UPG lifecycle—availability, `createOrder()`, and `completePayment()`—is documented in [Quick Setup](/universal-payment-gateway/quick-setup). This page covers the released DirectPay V3 one-time checkout only.
</Note>

## SDK Functions

<Tabs>
  <Tab title="PHP SDK">
    | Function | Purpose |
    | - | - |
    | `new DirectPayCallbackPayload(...)->toArray()` | Preserves the exact callback body and Authorization header for common completion. |
    | `payment()->completePayment(...)` | Verifies DirectPay's callback HMAC and maps a normalized payment result. |
  </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 |
    | - | - |
    | `new DirectPayCallbackPayload(...).toPayload()` | Preserves the exact raw callback body and authorization header. |
    | `client.payment().completePayment(...)` | Verifies and completes the server-side callback. |
  </Tab>
</Tabs>

## Preserve a signed DirectPay callback

DirectPay signs the exact callback body with the configured HMAC secret. Read the original body and the exact Authorization header from your backend callback request before parsing or transforming either value. The SDK wrapper only preserves them for shared completion.

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

    $payload = new DirectPayCallbackPayload(
        rawBody: (string) file_get_contents('php://input'),
        authorization: (string) ($_SERVER['HTTP_AUTHORIZATION'] ?? ''),
    );
    ```

    **SDK response** — `DirectPayCallbackPayload::toArray()`:

    ```json theme={null}
    {
      "raw_body": "{\"data\":{\"transaction\":{...}}}",
      "authorization": "hmac provider-signature"
    }
    ```

    The wrapper rejects missing or blank values. The raw body and Authorization signature are server-only evidence: do not construct them from a browser event, and do not send them to browser state, logs, queues, or analytics.
  </Tab>

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

    $payload = new DirectPayCallbackPayload(
        rawBody: (string) file_get_contents('php://input'),
        authorization: (string) ($_SERVER['HTTP_AUTHORIZATION'] ?? ''),
    );
    ```
  </Tab>

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

    const rawBody = await readRawRequestBody(request); // Your server helper.
    const payload = new DirectPayCallbackPayload(
      rawBody,
      String(request.headers.authorization ?? ''),
    ).toPayload();
    ```
  </Tab>
</Tabs>

## Complete a signed DirectPay callback

Use the stored completion context and the exact callback payload. AvraAPI verifies the callback HMAC, parses the verified body, validates amount and currency against the prepared order, and checks a returned order ID whenever DirectPay supplies one.

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

    $result = $apix->payment()->completePayment(new PaymentCompletionOptions(
        gateway: GatewayCode::DirectPay,
        completionContext: $order->completion_context,
        payload: $payload->toArray(),
    ));
    ```

    **SDK response** — `PaymentCompletionResult`:

    ```json theme={null}
    {
      "gateway": "directpay",
      "verified": true,
      "payment_status": "succeeded",
      "provider_status": "SUCCESS",
      "order_id": "ORDER-2026-000184",
      "gateway_reference": "DP-320000000000",
      "amount": "12000.00",
      "currency": "LKR"
    }
    ```

    The SDK exposes `$result->paymentStatus`, `$result->providerStatus`, `$result->gatewayReference`, `$result->amount`, and `$result->currency`. `SUCCESS` and `APPROVED` map to `succeeded`; `PENDING` and `PROCESSING` map to `pending`; unrecognised statuses map to `unknown`. The current released adapter maps DirectPay cancellation and decline statuses to `failed`.
  </Tab>

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

    use Avraapi\Apix\Payments\GatewayCode;
    use Avraapi\Apix\Payments\PaymentCompletionOptions;

    $result = AvraAPI::payment()->completePayment(new PaymentCompletionOptions(
        gateway: GatewayCode::DirectPay,
        completionContext: $order->completion_context,
        payload: $payload->toArray(),
    ));
    ```
  </Tab>

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

    const result = await client.payment().completePayment(
      new PaymentCompletionOptions({
        gateway: GatewayCode.DirectPay,
        completionContext: order.completionContext,
        payload,
        reconcileProvider: true,
      }),
    );
    ```
  </Tab>
</Tabs>

## Payment Elements

Render DirectPay as one explicit method. Use `mode: 'embedded'` when your page has the dedicated DirectPay container; change only the mode to `overlay` when you want the provider window instead. The checkout session must still be created by your backend through the shared SDK flow.

```js theme={null}
elements.renderMethods('#payment-methods', {
  methods: [{
    gateway: 'directpay',
    mode: 'embedded',
    label: 'Credit or debit card — DirectPay',
    description: 'Complete your card payment securely in this page.',
  }],
});
```

An Elements `checkout_completed`, close, or error event is UI state only. For rendering, the required embedded container, visual customization, events, and the checkout lifecycle, see [More Payment Elements features](/universal-payment-gateway/payment-elements/overview).

## Gateway-specific options

The released `providerOptions.prefill_customer` option is an explicit opt-in:

* Omit it or set it to `false` by default. DirectPay's browser package can log its input, so customer contact fields are not prefilled automatically.
* Set `prefill_customer: true` only when you accept that the approved customer fields will be included in the provider checkout session.
* Merchant credentials, HMAC secret, callback signature, and checkout signing values are never browser options.

The DirectPay V3 browser session has no released redirect URL mode. Do not attempt to use DirectPay's separate unpublished/advanced provider operations as UPG SDK functions.

## Completion, webhooks, and safety

DirectPay does not have a released, authenticated status lookup in the current UPG scope. Do not invent polling or treat an overlay/embedded browser event as confirmation. The only authoritative path is the signed callback to your configured response URL, followed by shared `completePayment()` with the original server-only completion context.

Fulfil only a verified `succeeded` result. Preserve `pending` and `unknown` orders for merchant-side handling rather than changing their payment status from client-side UI events.


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