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

# External Gateway Integration Guide

> Integrate your own payment system or third‑party checkout with UniBee using External Gateway Invoices, while UniBee manages subscriptions and invoicing.

## Overview

**External Gateway** mode is designed for teams who want UniBee to manage **subscriptions, invoices, billing cycles and entitlements**, while **your own system or a third‑party gateway handles the actual payment and refunds**.

In this model:

* **UniBee handles**:
  * Subscription lifecycle and billing cycles
  * Invoice generation and status
  * Entitlement logic (activation, renewal, cancellation)
  * Webhooks to your backend
* **Your system handles**:
  * Creating payment orders
  * Showing a checkout page / cashier
  * Executing charge and refund on your own gateway
  * Calling UniBee External Gateway APIs to report results

Funds flow only between **your customer and your payment system**. UniBee does not charge cards directly; it updates invoice and subscription status based on the results you report.

***

## Data Flow at a Glance

| Direction                | Description                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 |
| ------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **UniBee → Your System** | For payment attempts, UniBee creates or reuses a **Payment** and sends `payment.created` to tell you to charge. For refund tasks, UniBee sends `refund.created` to tell you to execute a refund. When users click “Pay” in UniBee UI, they stay on UniBee’s intermediate page until your backend calls [Update External Gateway Payment Link](/api-reference/payment/update-external-gateway-payment-link) (`POST /merchant/payment/external_gateway_payment/update_link`) to write `paymentLink` for that `paymentId`; then UniBee redirects the user to your payment URL. |
| **Your System → UniBee** | After your gateway finishes a charge, call Payment APIs (`external_gateway_payment/mark_paid` or `mark_failed`). After your gateway finishes a refund, call Refund APIs (`external_gateway_refund/mark_success` or `mark_failed`) to sync Payment/Refund/Invoice/Subscription states in UniBee.                                                                                                                                                                                                                                                                             |

For high‑level product behavior from the invoice perspective, see also:\
[External Gateway Invoices](/documentation/invoices/external-gateway-invoices).

***

## 1. Configuration and Security

### 1.1 Configure External Gateway in UniBee

Before integration, you need to configure one or more External Gateways in UniBee:

1. Log in as a merchant → **Configuration → Payment Gateways**.
2. Add and configure an **External Gateway** (similar to other gateways).
3. For each External Gateway, UniBee provides:
   * A unique **`gatewayId`**
   * An **External Gateway API Key** (also called **GatewayKey**) used **only** for HMAC signatures

Use `gatewayId` to distinguish multiple external channels (e.g. `custom_gateway_A`, `custom_gateway_B`), and keep the GatewayKey strictly confidential.

### 1.2 Dual Authentication & Signature Rule

All **External Gateway Payment / Refund APIs** share the same security model:

1. **Merchant OpenAPI auth**
   * HTTP header `Authorization: Bearer <UNIBEE_API_KEY>`
2. **Request body signature** using the **GatewayKey**:

* Signature string (concatenate with `|` in this exact order):
  * For **payment** APIs: `paymentId|externalTransactionId|timestamp`
  * For **refund** APIs: `refundId|externalRefundId|timestamp`
* Algorithm: `HMAC-SHA256(GatewayKey, signatureString)`
* Encoding: hex string used as `signature`
* Anti‑replay: `timestamp` must be within UniBee’s accepted time window (currently implemented as ±12 hours). Use current Unix timestamp in seconds.

```text theme={null}
// Payment APIs
signatureString = paymentId + "|" + externalTransactionId + "|" + timestamp

// Refund APIs
signatureString = refundId  + "|" + externalRefundId + "|" + timestamp

signature       = hex( HMAC_SHA256(GatewayKey, signatureString) )
```

***

## 2. Core APIs (Payment / Refund‑based)

The new External Gateway flow is built around **Payment** and **Refund** resources. All integration endpoints live under `/merchant/payment/*`:

### 2.1 Update External Gateway Payment Link

When your own gateway generates or changes a checkout URL, you can write it back to the UniBee **Payment** so invoice links / intermediate pages can redirect to the latest URL.

* **API:** [Update External Gateway Payment Link](/api-reference/payment/update-external-gateway-payment-link)\
  Path: `POST /merchant/payment/external_gateway_payment/update_link`

Typical fields (see API reference for full schema):

* `paymentId` — UniBee Payment ID
* `externalTransactionId` — your order / payment ID
* `paymentLink` — your hosted checkout URL
* `timestamp`, `signature` — using the signing rule above

UniBee always uses the most recently updated `paymentLink`.

### 2.2 Mark External Gateway Payment as Paid

After your external gateway confirms that a payment has succeeded, you report the result at the Payment level:

* **API:** [Mark External Gateway Payment As Paid](/api-reference/payment/mark-external-gateway-payment-as-paid)\
  Path: `POST /merchant/payment/external_gateway_payment/mark_paid`

Effects:

* Marks the corresponding Payment as **Paid**
* Transitions the related Invoice to **Paid**
* Triggers subscription activation / renewal logic
* Emits related webhooks (for example `invoice.paid`, `subscription.updated`)

Common fields:

* `paymentId` — UniBee Payment ID
* `externalTransactionId` — your payment order ID (used as an idempotency key)
* `paidTime` — timestamp when payment succeeded (optional)
* `metadata` — extra information (optional)
* `timestamp`, `signature`

> Repeated calls with the same `(paymentId, externalTransactionId)` are idempotent and will not double‑charge or double‑record revenue.

### 2.3 Mark External Gateway Payment as Failed

When a payment attempt ultimately fails or you give up retries, you can explicitly mark the Payment as failed:

* **API:** [Mark External Gateway Payment As Failed](/api-reference/payment/mark-external-gateway-payment-as-failed)\
  Path: `POST /merchant/payment/external_gateway_payment/mark_failed`

This helps your internal systems track failure reasons and allows UniBee to correctly update invoice / subscription state or drive further retry logic as configured.

### 2.4 Report External Gateway Refund Result

Refunds are reported via dedicated **Refund** resources rather than directly on the invoice:

* **API:** [Mark External Gateway Refund As Success](/api-reference/payment/mark-external-gateway-refund-as-success)\
  Path: `POST /merchant/payment/external_gateway_refund/mark_success`
* **API:** [Mark External Gateway Refund As Failed](/api-reference/payment/mark-external-gateway-refund-as-failed)\
  Path: `POST /merchant/payment/external_gateway_refund/mark_failed`

Typical fields (see API reference for full schema):

* `refundId` — UniBee refund ID
* `externalRefundId` — your external refund transaction ID
* `timestamp`, `signature` — using the refund signing rule above

Refund trigger source:

* UniBee sends `refund.created` when a refund task is created for an External flow.
* Your system executes the refund in your gateway.
* Then your backend reports the final refund result with:
  * `external_gateway_refund/mark_success`, or
  * `external_gateway_refund/mark_failed`.

After you create or execute a refund in your own gateway:

1. Create or obtain the corresponding Refund on UniBee side (implementation details depend on your setup).
2. Call one of the Refund APIs to mark it **successful** or **failed**.
3. UniBee will:
   * Update refund status and amount
   * Move the Invoice into partially or fully refunded states
   * Emit refund‑related webhooks for your internal systems.

***

## 3. Webhooks: `payment.created` and `refund.created`

When UniBee decides it’s time to attempt payment for an External Gateway invoice (for example, before renewal, or when the user clicks “Pay”), it creates or reuses a **Payment** and sends a **`payment.created`** webhook.

`payment.created` is a **payment-only** trigger. Refund handling is a separate flow based on `refundId` and the External Gateway refund result APIs.

For External Gateway, refund execution should be driven by **`refund.created`** webhook events, not by `payment.created`.

### 3.1 Identifying External Payments

In your webhook handler:

* Check `payment.gatewayId` in the payload and compare it with your known External `gatewayId`s, **or**
* Inspect the `gateway` object and check that:
  * `gateway.gatewayType == 8` (External), or
  * `gateway.gatewayName == "external"` (depending on your configuration)

Once identified as External:

1. Read `invoiceId`, `paymentId`, amount and currency from the event.
2. Create/attach an order in your own system.
3. Decide when/how to charge the user (immediately, or later).
4. After the charge succeeds, call **`external_gateway_payment/mark_paid`**; if there is a refund, report it via `external_gateway_refund/mark_success` / `mark_failed`.

### 3.2 Typical Timing

* Renewal invoices are usually generated **a few days** before the period end.
* Around **2 hours before** the billing period ends (configurable), UniBee:
  * Creates or reuses a Payment
  * Sends one `payment.created` event for External gateways
* For subsequent automatic attempts, UniBee reuses the same Payment and **does not** send additional `payment.created` events.

You only need to react to the first `payment.created` per Payment.

***

## 4. Integration Patterns

### Pattern A: UniBee Checkout / Invoice Link + External Redirect

1. Your app calls UniBee to create a subscription / invoice with an External Gateway.
2. UniBee creates an External Gateway Payment for that invoice and returns an invoice or Checkout link.
3. When the user clicks “Pay”, UniBee opens an **External Gateway intermediate page**:
   * This page polls the current Payment and waits for a `paymentLink`.
4. Your backend calls `external_gateway_payment/update_link` with your checkout URL.
5. Once the intermediate page sees a valid `paymentLink`, it redirects the user to your checkout.
6. After the payment succeeds, your backend calls `external_gateway_payment/mark_paid`, and UniBee updates the Payment / Invoice / Subscription state accordingly.

### Pattern B: Your Own Checkout Only (No UniBee UI)

1. Your backend calls UniBee to create subscriptions or invoices with an External Gateway and stores the `invoiceId` / `paymentId`.
2. You use your own frontend and checkout; the user never visits UniBee’s pages.
3. After the payment succeeds in your gateway, you call `external_gateway_payment/mark_paid`.
4. If there is a refund, you report it via `external_gateway_refund/mark_success` / `mark_failed`.

In this pattern you typically do not need to call `external_gateway_payment/update_link`.

### Pattern C: Invoice Email / Invoice Center

If you rely on UniBee’s invoice emails or invoice center:

* Integrate `external_gateway_payment/update_link` so that the “Pay” button on the invoice always points to your latest valid checkout URL.
* Whenever your order URL changes or expires, call this endpoint again; UniBee will always use the newest value.

***

## 5. Best Practices

* **Use UniBee as the source of truth for invoices and subscriptions**\
  Even if your gateway handles the money, keep all invoices and subscription state in UniBee so reporting and entitlement logic stay consistent.

* **Drive state from your gateway events**\
  Only call the External Gateway Payment / Refund APIs after your own gateway definitively confirms the result (via its own webhook or API).

* **Keep payment links fresh**\
  If your checkout URLs can expire or change, always update them via `external_gateway_payment/update_link` before the user clicks “Pay”.

* **Subscribe to UniBee webhooks**\
  Subscribe to both **`payment.created`** (payment execution trigger) and **`refund.created`** (refund execution trigger), and also consume result events such as `invoice.paid`, `refund.success`, and `subscription.updated` for downstream sync.

* **Leverage idempotency**\
  Use stable external IDs per operation (`externalTransactionId` for payment, `externalRefundId` for refund). Repeating the same call with the same key tuple is safe — UniBee treats it as idempotent and avoids duplicate state transitions.
