> For the complete documentation index, see [llms.txt](https://developers.coincircuit.io/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://developers.coincircuit.io/promp-library/saas-invoice-billing.md).

# SaaS invoice billing

Generate invoices with expiration, tracking, and webhook handling.

Use this prompt to add CoinCircuit invoices to subscription billing and renewal flows.

`Invoices` `Webhooks`

### What this prompt covers

* Create invoices on subscription renewal
* Send hosted payment links to customers
* Track full and partial payments from webhooks

{% code title="saas-invoice-billing.prompt.md" expandable="true" collapsedlinecount="20" %}

````markdown
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
````

{% endcode %}


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://developers.coincircuit.io/promp-library/saas-invoice-billing.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
