SaaS invoice billing
Generate invoices with expiration, tracking, and webhook handling.
Last updated
Was this helpful?
Generate invoices with expiration, tracking, and webhook handling.
Last updated
Was this helpful?
Was this helpful?
You are helping me integrate CoinCircuit crypto invoicing into my existing SaaS billing system. I have the CoinCircuit MCP server connected.
**If you have access to the CoinCircuit MCP server, call these tools for the most accurate and detailed schema outputs:**
- Call `get_endpoint` with method `post` and path `/api/v1/invoices` in the CoinCircuit MCP for the full invoice creation schema.
- Call `search_api` with query `invoice webhook` and type `schemas` to list all invoice webhook payload schemas.
- Call `get_schema` with name `InvoicePaidWebhookDto` for the exact invoice.paid webhook payload.
- Call `get_schema` with name `InvoiceExpiredWebhookDto` for the invoice.expired webhook payload.
Use the live MCP data as your source of truth. The details below are a guide, but if the MCP returns something different, trust the MCP.
## API Basics
- **Base URL:** `https://api.coincircuit.io`
- **Auth:** `x-api-key` header on every request.
## Project Context
I have a SaaS app that bills customers monthly. I'm adding crypto invoice payments via CoinCircuit so customers can pay in any supported crypto (USDT, BTC, ETH, etc.).
## What I Need You to Implement
### 1. Invoice creation on subscription renewal
**Endpoint:** `POST /api/v1/invoices`
*(Call `get_endpoint` with method `post`, path `/api/v1/invoices`, section `request` in the CoinCircuit MCP for the exact request body schema with all field types and validations.)*
**Required fields:**
- `amount` (string) - the subscription price as a string with up to 2 decimal places, e.g. `"29.99"`
- `currency` (string) - `"NGN"` or `"USD"`
- `description` (string) - e.g. "Pro Plan - May 2026"
- `expiresAt` (string, ISO 8601) - when the invoice expires. Max 2 days from creation. Defaults to 12 hours if omitted.
- `customer` (object) - must include `email` (required). Optional: `firstName`, `lastName`, `phone` (E.164), `telegramId`
**Optional fields:**
- `reference` (string) - custom invoice reference, e.g. `"INV-2026-005"`. Auto-generated if omitted.
- `periodStart` / `periodEnd` (string, ISO 8601) - billing period dates for subscription context
- `nextPaymentDate` (string, ISO 8601) - next billing date, shown on the invoice
- `metadata` (object) - store `subscriptionId`, `plan`, etc. for webhook reconciliation
- `successUrl` / `cancelUrl` (string) - redirect URLs after payment
- `asset` (string) - lock to a specific crypto (`"BTC"`, `"ETH"`, `"USDT"`, `"USDC"`, `"SOL"`, `"BNB"`, `"TRX"`)
- `chain` (string) - lock to a specific blockchain (`"bitcoin"`, `"ethereum"`, `"solana"`, `"bsc"`, `"tron"`, `"base"`, `"arbitrum"`)
**Example request body:**
```json
{
"amount": "29.99",
"currency": "USD",
"description": "Pro Plan - May 2026",
"expiresAt": "2026-05-03T00:00:00.000Z",
"customer": {
"email": "subscriber@example.com",
"firstName": "John",
"lastName": "Doe"
},
"periodStart": "2026-05-01T00:00:00.000Z",
"periodEnd": "2026-05-31T23:59:59.000Z",
"nextPaymentDate": "2026-06-01T00:00:00.000Z",
"metadata": {
"subscriptionId": "sub_abc123",
"plan": "pro"
},
"successUrl": "https://myapp.com/billing/success"
}
```
**Response (201):** Returns the invoice object. Key fields:
- `data.id` - invoice UUID
- `data.reference` - invoice reference (e.g. `"inv_ref_abc123xyz789"`)
- `data.url` - payment URL (e.g. `https://checkout.coincircuit.io/invoice/inv-abc123`)
- `data.status` - starts as `"pending"`, transitions to `"partial"`, `"paid"`, or `"expired"`
- `data.state` - `"open"` (accepting payments) or `"closed"` (finalized)
- `data.amount` / `data.amountPaid` - track payment progress
- `data.isRefunded` - boolean
*(Call `get_endpoint` with method `post`, path `/api/v1/invoices`, section `success` in the CoinCircuit MCP for the full response schema.)*
**Error responses:** 400 (invalid input or expiresAt exceeds 2 days), 401 (bad API key)
### 2. Send the payment link
The response includes `data.url`. Email this to the customer or display it in your app's billing dashboard. The hosted page handles crypto selection, address display, and payment detection automatically.
### 3. Webhook event handling
*(Call `get_schema` with name `InvoicePaidWebhookDto` in the CoinCircuit MCP for the full invoice.paid webhook payload with all nested fields including the payments array.)*
**Invoice events** (envelope: `{ event: string, data: { invoice: InvoiceObject, payments?: PaymentArray } }`):
- `invoice.created` - confirmation the invoice was created. Good for logging. *(Call `get_schema` with name `InvoiceCreatedWebhookDto` for details.)*
- `invoice.paid` - full payment received. **Activate or extend the subscription.** The `data.payments` array contains details on each payment session: `asset`, `chain`, `amount`, `address`, `txHash`, `explorerUrl`, `status`.
- `invoice.updated` - partial payment received. Check `data.invoice.amountPaid` vs `data.invoice.amount` to track progress. `data.invoice.status` will be `"partial"`. *(Call `get_schema` with name `InvoiceUpdatedWebhookDto` for details.)*
- `invoice.expired` - invoice expired unpaid. Suspend access or create a new invoice with a reminder email. *(Call `get_schema` with name `InvoiceExpiredWebhookDto` for details.)*
**Invoice webhook data fields:**
- `data.invoice.reference` - matches your invoice
- `data.invoice.metadata` - your `subscriptionId` and `plan` are here
- `data.invoice.amount` / `data.invoice.amountPaid` - track cumulative payments
- `data.invoice.status` - `"pending"`, `"partial"`, `"paid"`, `"expired"`
- `data.invoice.paidAt` - ISO 8601 timestamp when fully paid
- `data.invoice.periodStart` / `data.invoice.periodEnd` - billing period
- `data.invoice.customer.email` - for confirmation emails
**Webhook security:** Same as checkout: verify HMAC-SHA256 via `x-webhook-signature`, deduplicate via `x-delivery-id`.
## Constraints
- Invoice `amount` is a **string** with up to 2 decimal places (e.g. `"29.99"`), same as checkout sessions
- `expiresAt` max is 2 days from creation. Defaults to 12 hours.
- Invoices support partial payments. Track `amountPaid` before activating the subscription.
- The invoice stays `"open"` until fully paid or expired
- Supported currencies: NGN, USD