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

> ## Agent Instructions
> Tribridge is a crypto payment gateway for Solana and Sui (TON is coming soon). API base URL is https://api.tribridge.xyz. The API Reference documents ONLY the public endpoint surface: checkout sessions (create/get/generate-wallet/customer/simulate/verify/cancel), the two public payment-link endpoints, health probes, and the changelog. Server-side calls that create payments authenticate with the x-api-key header using a tri_test_... key (fully simulated test mode, no real funds) or tri_live_... key (real mainnet payments) - never expose keys client-side; all other documented endpoints are public with no auth. Dashboard, admin, OTP/auth, payouts, wallets, and webhook-management endpoints are intentionally NOT part of the public docs - they are dashboard-only and must not be presented as public API. Merchant test mode is simulated, not testnet. Refunds are automatic only (underpaid/overpaid), there is no manual refund endpoint. Always verify webhook HMAC-SHA256 signatures from the X-Tribridge-Signature header before trusting payloads. If you are an AI agent: fetch https://docs.tribridge.xyz/llms-full.txt for all documentation in one file, https://docs.tribridge.xyz/openapi/openapi.json for the machine-readable OpenAPI spec, or connect to the read-only MCP server at https://docs.tribridge.xyz/mcp. Any page is available as Markdown by appending .md to its URL. Use only the documented endpoints and fields; do not invent SDK packages or endpoints.

# Subscriptions

> Recurring stablecoin plans on Solana. Sui subscriptions are coming soon. Plans, checkout, lifecycle, mandates and webhooks.

> [!WARNING]
>
> **Current support: Solana only.** Sui subscriptions and Sui wallet payments are marked **coming soon** in the dashboard and disabled on the backend. The existing one-off Sui address/QR payment flow still works; only Sui subscriptions and Sui wallet-pay are disabled.

Subscriptions are a separate, flagged engine. Existing one-off payments, payment links, QR, refunds and payouts are unchanged.

> [!WARNING]
>
> The engine ships **off by default** in the repo. Enable it with `SUBSCRIPTIONS_ENABLED=true` and `SUBSCRIPTIONS_SOLANA_ENABLED=true`. Test-mode subscriptions (`livemode=false`) use a deterministic sandbox and never touch a chain.

## Concepts

* **Plan** — amount in USD-pegged USDC (6 decimals), interval (`day|week|month|year`), optional trial, optional max cycles, accepted chains/assets. **Price is immutable**: create a new plan to change it.
* **Subscription** — one customer on one plan. States: `incomplete → trialing → active → past_due → unpaid`, plus `paused`, `canceled`, `expired`.
* **Mandate** — the customer's on-chain authorization. Solana: a **capped SPL delegate approval** (never unlimited).
* **Invoice** — one per billing period. Gross, platform fee and net are stored in integer base units.
* **Charge attempt** — one signed send with a unique idempotency key. Ambiguous sends are reconciled on-chain before any retry.
* **Delegate wallet** — a dedicated Solana hot wallet that customers approve to pull USDC. It pays network fees and must hold SOL. It is never the vault or treasury key.

## How Solana subscriptions work

1. Merchant creates a plan.
2. Merchant sends the hosted subscribe link (or creates a checkout through the API).
3. Customer connects a Solana wallet and reviews the exact amount, interval, first charge and maximum authorization.
4. Customer signs one `ApproveChecked` transaction granting the Tribridge delegate a capped allowance:
   `amount × min(max_cycles, default_cap_cycles)`. The default cap is 12 cycles.
5. Backend verifies the delegate, allowance, balance and token account.
6. No trial: the first invoice is charged immediately. Trial: first charge at `trial_end`.
7. On renewal: re-check the mandate, then the delegate signs one `TransferChecked` for exactly one cycle to the treasury.
8. If the delegate was replaced or revoked, the allowance is too low, or the balance is insufficient, the backend **does not send** and starts dunning + a needs-reauthorization notice.

The customer can revoke the approval at any time. Cancellation in the portal is manual only.

## Create a plan

```bash theme={null}
curl -X POST https://api.tribridge.xyz/v1/plans \
  -H "x-api-key: tri_test_..." \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Pro",
    "amount_usd": "9.99",
    "interval": "month",
    "trial_days": 7,
    "max_cycles": 12,
    "accepted_chains": ["solana"],
    "accepted_assets": ["USDC"]
  }'
```

## Create a hosted subscription checkout

```bash theme={null}
curl -X POST https://api.tribridge.xyz/v1/subscriptions/checkout \
  -H "x-api-key: tri_live_..." \
  -H "Content-Type: application/json" \
  -d '{
    "plan_id": "PLAN_UUID",
    "customer_ref": "user_123",
    "customer_email": "user@example.com",
    "success_url": "https://merchant.example/thanks"
  }'
```

Returns `{ subscription_id, checkout_url, subscription }`. Send the customer to `checkout_url`.

### API vs dashboard

**API:** create the plan once, then create one checkout per customer from your backend. Listen to signed webhooks. Best when subscriptions are embedded in your own product.

**Dashboard:** create a plan, copy the hosted subscribe link, manage pause/resume/cancel, copy the customer portal link, view invoices and retry failed charges. Best for no-code merchants, testing and operations. Both use the same engine and tables.

## Lifecycle

1. Customer reviews the terms and authorizes in their wallet.
2. No trial: first invoice charged immediately. Failure → `incomplete` (expires after 24h).
3. Trial: `trialing`; first invoice at `trial_end`.
4. Renewals: invoice at `next_billing_at`, mandate re-verified, charge executed.
5. Failures: typed reason, retry at +1/+3/+5 days, `past_due` after the first failure, `invoice.failed` webhook, then `canceled`/`unpaid` per plan policy.
6. `max_cycles` reached → `expired`.

Month math is UTC anchor-based (Jan 31 → Feb 28/29 → Mar 31, no drift).

## Endpoints

| Method | Path | Auth |
| - | - | - |
| POST/GET | `/v1/plans`, `/v1/plans/:id` | API key or dashboard JWT |
| PATCH/DELETE | `/v1/plans/:id` | API key or dashboard JWT |
| POST | `/v1/subscriptions/checkout` | API key or dashboard JWT |
| GET | `/v1/subscriptions`, `/v1/subscriptions/:id` | API key or dashboard JWT |
| POST | `/v1/subscriptions/:id/pause`, `/resume`, `/cancel`, `/retry`, `/portal-link` | API key or dashboard JWT |
| GET | `/v1/subscriptions/:id/invoices` | API key or dashboard JWT |
| POST | `/v1/test/subscriptions/:id/advance` | Test mode only |
| GET | `/subscriptions/checkout/:token` | Public signed token |
| POST | `/subscriptions/checkout/:token/approval-tx`, `/authorize` | Public signed token |
| GET | `/subscriptions/portal/:token` | Public signed token |
| POST | `/subscriptions/portal/:token/pause`, `/resume`, `/cancel`, `/topup-tx`, `/revoke-tx` | Public signed token |

Customer cancel is manual: cancel-at-period-end is confirmed in a Tribridge modal, then the subscription cancels at the boundary.

## Webhooks

Reuses the existing HMAC-SHA256 delivery and retry pipeline (`X-Tribridge-Signature`).

`subscription.created`, `subscription.active`, `subscription.trial_will_end`, `subscription.past_due`, `subscription.paused`, `subscription.resumed`, `subscription.canceled`, `subscription.expired`, `invoice.upcoming`, `invoice.paid`, `invoice.failed`, `mandate.needs_reauthorization`.

Payloads include `subscription_id`, `invoice_id`, `plan_id`, `livemode` (as `is_test`), and a `data` object with the full subscription/plan/invoice snapshot.

## Fees and ledger

The existing platform fee is used (`max($0.10, 1%)`). The invoice stores gross, fee and net; the ledger credits the merchant net through a completed `payments` row, so payouts and balances work unchanged. Subscription charges appear in **Transactions** with source `subscription`, and lifecycle events appear in **Logs → Subscription**.

## Test mode

Test subscriptions are `livemode=false` and always use the sandbox adapter:

```bash theme={null}
curl -X POST https://api.tribridge.xyz/v1/test/subscriptions/SUB_ID/advance \
  -H "x-api-key: tri_test_..." \
  -d '{"failure":"insufficient_balance"}'
```

Supported injections: `insufficient_balance`, `allowance_exhausted`, `delegate_revoked`, `account_closed`, `rpc_error`, `ambiguous`. Send `{"failure":null}` to clear.

## Mainnet requirements (Solana)

Required backend env:

```env theme={null}
SOLANA_NETWORK=mainnet
SOLANA_RPC_URL=https://mainnet.helius-rpc.com/?api-key=...
SOLANA_USDC_MINT=
HELIUS_API_KEY=...
HELIUS_WEBHOOK_ID=...
HELIUS_WEBHOOK_AUTH_SECRET=...

SUBSCRIPTIONS_ENABLED=true
SUBSCRIPTIONS_SOLANA_ENABLED=true
SUBSCRIPTIONS_SUI_ENABLED=false
WALLET_CONNECT_PAY_ENABLED=true
WALLET_CONNECT_SUI_ENABLED=false

SUBSCRIPTIONS_SOLANA_DELEGATE_PRIVATE_KEY=<base58 delegate secret>
SUBSCRIPTIONS_SOLANA_TREASURY_ADDRESS=<Solana treasury/vault address>
SUBSCRIPTIONS_SOLANA_DEFAULT_CAP_CYCLES=12
```

The delegate is a **new dedicated hot wallet** funded with SOL. The treasury can be your existing Solana vault address; it only receives USDC. See **Admin → Delegated Wallets** for balances and configuration status.

## Refunds

Normal automatic refunds cover underpaid, overpaid and wrong-token deposits.

If funds arrived on-chain but the payment was not recorded: a **super admin** can open Admin → Payments → payment drawer → **Refund unrecorded payment**. It refunds the actual deposit-wallet balance to the payer, signs a real transaction, marks the payment `refunded`, and writes an audit log. It refuses completed/test payments and zero balances.


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