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

# DEUNA

> Charge cards, Nequi, Mercado Pago, Deuna App Wallet, DaviPlata, and PSE through the DEUNA Payment Widget with @fire-spark/payments-deuna-widget.

DEUNA (deuna.com) is a payment orchestrator. Fire spark charges every DEUNA method through its **Payment Widget**: the DEUNA widget collects the payment, Fire spark creates the DEUNA order with your private key, and the status Fire spark reads back from DEUNA is the one that counts.

| | |
| - | - |
| Countries | Ecuador (card, Deuna App Wallet), Colombia (card, Nequi, DaviPlata, Mercado Pago, PSE) |
| Currencies | The order currency (USD in Ecuador, COP in Colombia) |
| Status | Available (beta) |
| Package | `@fire-spark/payments-deuna-widget` |

| Method | Processor (`processor`) | What the customer does |
| - | - | - |
| Card (`CARD`) | `card` | Types the card in the DEUNA form |
| Wallet (`WALLET`) | `nequi` | Approves a push notification in the Nequi app |
| Wallet (`WALLET`) | `mercadopago` | Pays in Mercado Pago (secure browser) |
| Wallet (`WALLET`) | `deuna_wallet` | Scans a QR or types a 6-digit code in the Deuna! app |
| Wallet (`WALLET`) | `daviplata` | Types their ID number and the one-time code DaviPlata sends to their phone (valid 3 min) |
| Bank transfer (`BANK_TRANSFER`) | `pse` | Pays at their bank through PSE |

## Requirements

* A DEUNA merchant account with the processors you want enabled, and its **public** and **private** API keys for each environment (sandbox and production are separate).
* The DEUNA SDK in your channel: `@deuna/react-native-sdk` (React Native 0.73+, Expo SDK 50+ with a development build) or the DEUNA Web SDK. Fire spark does not bundle it; your channel opens the widget.
* Processors set to capture on authorization. The widget flow has no separate capture step.

## Activate it

1. In the dashboard, open your merchant, go to **Payments**, and create a payment with the provider **DEUNA** and the method you need (`CARD`, `WALLET`, or `BANK_TRANSFER`).
2. In **Connection Settings**, fill in:

| Field | Key | Secret | Notes |
| - | - | - | - |
| Public key | `public_key` | No | Sent to the channel to open the widget |
| Private key | `private_key` | Yes | Stays in the Fire spark API; never sent to channels |
| Webhook signature | `webhook_signature` | Yes | Secret DEUNA signs `X-Signature` with. Optional, see [Webhooks](#webhooks) |
| Store code | `store_code` | No | Your DEUNA store code, if you have several |
| Processor | `processor` | No | Required for `WALLET`: `nequi`, `mercadopago`, `deuna_wallet`, or `daviplata` |

3. In the DEUNA Admin, set the webhook URL to `https://<your-api-host>/api/webhooks/payments/deuna` for each environment.

## Use it in the SDK

```bash theme={null}
pnpm add @fire-spark/payments-deuna-widget @deuna/react-native-sdk react-native-webview
```

Your channel implements a small **bridge** that opens the DEUNA widget and resolves with the first final callback. The adapter does the rest: it asks Fire spark for the DEUNA order token, opens the widget through the bridge, and confirms the status.

```typescript theme={null}
import { createDeunaWidgetApi } from "@fire-spark/storefront";
import { deunaWidgetPayments } from "@fire-spark/payments-deuna-widget";
import type { DeunaWidgetBridge } from "@fire-spark/payments-deuna-widget";

// One bridge per app, built on the DEUNA SDK instance you mount once.
const bridge: DeunaWidgetBridge = {
  open: input => {
    return new Promise(resolve => {
      const close = () => deunaSDK.close();
      input.signal.addEventListener("abort", () => {
        close();
        resolve({ type: "closed", by: "system" });
      });
      deunaSDK.initPaymentWidget({
        orderToken: input.orderToken,
        paymentMethods: input.paymentMethods,
        language: input.language,
        callbacks: {
          onSuccess: order => {
            close();
            resolve({ type: "success", order });
          },
          onPending: order => resolve({ type: "pending", order }),
          onExpired: () => resolve({ type: "expired" }),
          onError: error => {
            close();
            const code = error?.metadata?.code ?? null;
            resolve({ type: "error", code, errorType: error?.type ?? null });
          },
          onClosed: action => {
            resolve({ type: "closed", by: action === "userAction" ? "user" : "system" });
          }
        }
      });
    });
  }
};

const api = createDeunaWidgetApi(httpOptions);

order.setPaymentAdapters([
  deunaWidgetPayments({ method: "CARD", bridge, api }),
  deunaWidgetPayments({
    method: "WALLET",
    bridge,
    api,
    // Deep links back into the app after Mercado Pago or PSE.
    callbackUrls: { on_success: "myapp://deuna/success", on_failed: "myapp://deuna/failed" }
  }),
  deunaWidgetPayments({ method: "BANK_TRANSFER", bridge, api })
]);

const result = await order.payIntent({ payment: deunaPayment });
```

Initialize the DEUNA SDK with `publicApiKey: payment.config.public_key` and the environment of the payment. For Mercado Pago on React Native, pass an `InAppBrowserAdapter` (`@deuna/react-native-in-app-browser`) when you initialize the DEUNA SDK. On web, load the DEUNA Web SDK from its CDN and implement the same bridge with `DeunaSDK.initPaymentWidget`.

`payIntent({ payment })` places one real tender. To split DEUNA with another method, call `order.setTenders` with an allocation and then `payIntent()`. See [Use payments in the SDK](https://firespark.cloud/docs/guides/payments/use-payments-in-the-sdk.md).

### What happens on each widget callback

| Widget | Tender |
| - | - |
| `onSuccess` | `PAID` once Fire spark reads `processed`, `authorized`, or `captured`; stays `PENDING` while DEUNA is still processing |
| `onPending` | `PENDING`; the SDK polls the status until it is final or the request expires |
| `onExpired` | `FAILED` with `WALLET_EXPIRED` |
| `onError` | `FAILED` with the code from the table below |
| `onClosed` (customer) | `PAID` if the payment already went through, otherwise `FAILED` with `CANCELLED_BY_USER` |

## Storefront endpoints

The adapter calls these through `createDeunaWidgetApi`. They use the storefront session.

| Endpoint | What it does |
| - | - |
| `POST /api/storefront/v1/payments/deuna/{payment_id}/tokenize` | Creates the DEUNA order for one payment attempt and returns `{ order_token, order_id }`. The amount comes from the tender, never from the request. |
| `GET /api/storefront/v1/payments/deuna/{payment_id}/orders/{order_token}` | Returns `{ order_token, status, transaction_id, error }` for one of the customer's DEUNA orders. |

## What the customer sees

The DEUNA widget, in Spanish by default (`language: "es"`). The result metadata includes `attempt_reference` and `provider` (`order_token`, `processor`, `status`, `transaction_id`). Wallet `details` record the processor and the DEUNA reference; card tenders have no card details. There is no voucher.

## Webhooks

`POST /api/webhooks/payments/deuna` updates the tender when DEUNA notifies a status change. With **Webhook signature** set, `X-Signature` must be the Base64 HMAC-SHA256 of the raw body with that secret, or the notice is rejected (`401`). Fire spark always reads the order back from DEUNA with your private key before changing the tender, so a notice without a signature only counts once DEUNA confirms it.

## Refunds

Fire spark does not refund DEUNA payments. A reversal of a paid DEUNA tender is flagged for manual review: refund it in the DEUNA Admin. DaviPlata payments cannot be refunded through DEUNA: request the reimbursement from DaviPlata manually.

## Common errors

| Spark code | Provider code | What to do |
| - | - | - |
| `CARD_DECLINED` | `PAYMENT_DECLINED`, `denied` (card) | Ask for another card or method |
| `WALLET_REJECTED` | `PAYMENT_DECLINED`, `PAYMENT_FAILED`, `denied` | Ask for another method |
| `WALLET_EXPIRED` | `expired`, `DP-4562` | The push, QR, or code expired. Start again |
| `INSUFFICIENT_FUNDS` | `DP-9000` | Ask for another method |
| `INVALID_CREDENTIALS` | `AUTHENTICATION_FAILED` | Check the keys and their environment in Connection Settings |
| `PROVIDER_UNAVAILABLE` | `INITIALIZATION_FAILED`, `RATE_LIMIT_EXCEEDED`, `PROVIDER_UNAVAILABLE`, `DP-4200`, `DP-4504` | Retryable. Try again |
| `CANCELLED_BY_USER` | — | The customer closed the widget before paying |
| `AMBIGUOUS` | `IDEMPOTENCY_CONFLICT`, unknown status | Flagged for review. Check the order in the DEUNA Admin |

## Compatibility

| `@fire-spark/payments-deuna-widget` | Provider | `@fire-spark/payments` |
| - | - | - |
| 0.10.0 | DEUNA API v2, `@deuna/react-native-sdk` 2.1.10 | Same version |


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