Skip to main content

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

DirectionDescription
UniBee → Your SystemFor 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 (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 → UniBeeAfter 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.

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.
// 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/*: 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. 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: 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.update.success)
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: 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: 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 gatewayIds, 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

  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, invoice.refund.success, subscription.update.success 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.