> For the complete documentation index, see [llms.txt](https://timechain.gitbook.io/neucron/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://timechain.gitbook.io/neucron/payments/invoices-and-payment-links.md).

# Invoices & Payment Links

Neucron gives your business a complete accounts receivable stack: you create customers, issue invoices against them, and attach payment links that clear funds directly into your wallets. You control exactly which assets over which rails a given invoice accepts, and every customer-facing surface (the invoice email, the payment page) carries your brand, not ours.

This page walks the full lifecycle: customer, invoice, payment link, email delivery, partial and multi-asset clearing, and reconciliation.

***

## The lifecycle at a glance

```mermaid
sequenceDiagram
    autonumber
    participant B as Your Business (SDK/API)
    participant N as Neucron
    participant C as Customer
    participant R as Supported Rails

    B->>N: createCustomer (customer profile)
    B->>N: createInvoice (line items + payment_option)
    B->>N: finaliseInvoice
    B->>N: createPaymentCollection (supportedAssets)
    B->>N: shareInvoice (email with payment link)
    N->>C: Branded email with payment link
    C->>N: Open link, choose an accepted asset
    N->>N: createPaymentSession (collection + assetID)
    C->>R: Send payment (full or partial)
    R-->>N: On-chain confirmation
    B->>N: checkPaymentSession / checkPaymentCollection (txHash)
    N-->>B: Clearing status (partial or complete)
    B->>N: markInvoiceAsPaid + sendPaymentConfirmation
    N->>C: Branded payment confirmation email
```

| Stage                 | SDK method                            | REST endpoint                            |
| --------------------- | ------------------------------------- | ---------------------------------------- |
| Create customer       | `sdk.customer.createCustomer`         | `POST /invoice/customer`                 |
| Create invoice        | `sdk.invoice.createInvoice`           | `POST /invoice`                          |
| Finalise invoice      | `sdk.invoice.finaliseInvoice`         | `POST /invoice/finalise`                 |
| Create payment link   | `sdk.invoice.createPaymentCollection` | `POST /invoice/payment-collection`       |
| Email invoice         | `sdk.invoice.shareInvoice`            | `POST /invoice/share`                    |
| Open checkout session | `sdk.invoice.createPaymentSession`    | `POST /payment-collection/session`       |
| Verify payment        | `sdk.invoice.checkPaymentSession`     | `POST /payment-collection/session/check` |
| Mark paid             | `sdk.invoice.markInvoiceAsPaid`       | `POST /invoice/mark-paid`                |
| Send confirmation     | `sdk.invoice.sendPaymentConfirmation` | `POST /invoice/confirmation`             |

***

## Step 1: Create the customer

Customers are the people or organizations you bill. A customer is either an `INDIVIDUAL` or a `BUSINESS`, and the record can hold address details, contact persons, payment terms, tax payer info, and a portal access flag.

```typescript
const { data: customer } = await sdk.customer.createCustomer({
    businessId: 'biz_123',
    customerData: {
        customer_type: 'BUSINESS',
        business_details: {
            company_name: 'Acme Corp',
            display_name: 'Acme',
            email: 'billing@acme.com',
        },
        payment_details: {
            currency: 'USD',
            payment_terms: 'Net 30',
        },
        allow_portal_access: true,
    },
});
```

Customer list responses carry receivable totals per customer (`total_invoices`, `total_invoiced`, `total_outstanding`), so your dashboard can show exposure without a separate query. Use `sdk.customer.inviteCustomer` (`POST /invoice/customer/invite`) to give a customer portal access.

***

## Step 2: Create the invoice

An invoice is issued against a `customer_id` and names a `deposit_wallet`: the wallet that receives cleared funds. Line items carry quantity, unit cost, and tax rate.

```typescript
const { data: invoice } = await sdk.invoice.createInvoice({
    businessId: 'biz_123',
    invoiceData: {
        currency: 'USD',
        customer_id: 'cust_1',
        deposit_wallet: 'wallet_1',
        invoice_number: 'INV-1001',
        issue_date: '2026-07-10',
        due_date: '2026-08-01',
        items: [
            {
                name: 'Consulting',
                quantity: 10,
                cost_per_unit: 100,
                tax_rate: 18,
                sac_code: '9983',
            },
        ],
        payment_option: [
            {
                chain: '<supported-rail>',
                network: 'MAIN',
                asset_option: [
                    {
                        asset_id: '<asset-id>',
                        asset_name: '<asset-name>',
                    },
                ],
            },
        ],
        payment_terms: 'Net 30',
        round_off: true,
    },
});
```

### Controlling which assets and rails you accept

The `payment_option` array is your acceptance policy for the invoice. Each entry pairs a rail (`chain` and `network`, where network is `MAIN` or `TEST`) with the list of assets on that rail you will accept (`asset_option`). Add multiple entries to accept multiple rails, and multiple `asset_option` entries to accept multiple assets per rail.

You decide this per invoice. One invoice can accept a single settlement asset on a single rail; another can present the customer a menu of supported assets on supported rails. The payment link you attach in the next step inherits and enforces this policy.

{% hint style="info" %}
Draft invoices stay editable with `sdk.invoice.updateInvoice` (`PUT /invoice`). Once the terms are final, lock the invoice with `sdk.invoice.finaliseInvoice` (`POST /invoice/finalise`) before issuing it.
{% endhint %}

***

## Step 3: Attach a payment link

A **payment collection** is the receivable link tied to your invoice. It declares the assets the link will accept (`supportedAssets`) and the wallet that receives funds.

```typescript
await sdk.invoice.createPaymentCollection({
    businessId: 'biz_123',
    invoiceID: 'inv_1',
    supportedAssets: ['<asset-id-1>', '<asset-id-2>'],
    walletID: 'wallet_1',
});
```

| Method                         | REST endpoint                      | Purpose                                                  |
| ------------------------------ | ---------------------------------- | -------------------------------------------------------- |
| `createPaymentCollection`      | `POST /invoice/payment-collection` | Create a collection linked to an invoice                 |
| `updatePaymentCollection`      | `POST /invoice/payment-collection` | Change the accepted asset set                            |
| `getInvoicePaymentCollections` | `GET /invoice/payment-collection`  | List collections on an invoice                           |
| `getPaymentCollection`         | `GET /payment-collection`          | Collection detail                                        |
| `getPaymentCollectionList`     | `GET /payment-collection/list`     | Filter by status (for example `OPEN`), reference, wallet |
| `getCollectionAssets`          | `GET /payment-collection/assets`   | Assets a collection currently accepts                    |
| `mapCollectionToInvoice`       | `POST /invoice/map-collection`     | Attach an existing collection to an invoice              |

You can also create a **public payment collection** with `sdk.invoice.createPublicPaymentCollection` (`POST /payment-collection`): a universal payment link not tied to any invoice, with an optional fixed `amount` and `currency` and free-form `metadata`. Use it for donations, deposits, or open-ended checkout.

***

## Step 4: Email the customer

Deliver the invoice and its payment link with `sdk.invoice.shareInvoice` (`POST /invoice/share`). Set `sendEmail: true` to dispatch branded email to one or more recipients.

```typescript
await sdk.invoice.shareInvoice({
    businessId: 'biz_123',
    invoiceID: 'inv_1',
    emails: ['billing@acme.com', 'ap@acme.com'],
    sendEmail: true,
});
```

Follow-up communication uses the same pattern:

* `sdk.invoice.sendInvoiceReminder` (`POST /invoice/reminder`) for due-date nudges.
* `sdk.invoice.sendPaymentConfirmation` (`POST /invoice/confirmation`) after clearing.

Both accept an `EmailPayload` with `emails`, optional `cc`, `bcc`, `note`, and `paid_at`.

### Branding the payment experience

Payment pages are whitelabelled. Set the display name and logo customers see on wallet payment pages:

```typescript
await sdk.invoice.createWalletPaymentCollectionCustomization({
    businessId: 'biz_123',
    walletID: 'wallet_1',
    payload: {
        display_name: 'Acme Payments',
        logo_url: 'https://cdn.example.com/logo.png',
    },
});
```

`updateWalletPaymentCollectionCustomization` modifies an existing customization, and `getWalletPaymentCollectionInfo` (`GET /payment-collection/wallet/info`) reads what is currently configured for a wallet or paymail.

***

## Step 5: Clearing: partial and multi-asset payments

This is where Neucron differs from a card checkout. A payment link is not a one-shot charge:

* The customer can **pay partially** and return later to pay the rest against the same invoice.
* The customer can **split payment across multiple assets**, for example part in one supported asset and the remainder in another.
* The payment link orchestrates all of it against the outstanding invoice balance.

Each payment attempt opens a **payment session**: a checkout session for one collection plus one chosen `assetID`.

```typescript
await sdk.invoice.createPaymentSession({
    businessId: 'biz_123',
    collectionID: 'col_1',
    assetID: '<asset-id>',
    metadata: { source: 'checkout' },
});
```

Because sessions are per-asset, a multi-asset payment is simply multiple sessions against the same collection. The collection tracks what has arrived and what remains.

### Verifying payment

Once the customer broadcasts a payment, verify it against the rail with the transaction hash:

```typescript
await sdk.invoice.checkPaymentSession({
    businessId: 'biz_123',
    sessionID: 'sess_1',
    txHash: 'abc123...',
});
```

`checkPaymentCollection` (`POST /payment-collection/check`) does the same at collection level, and `getPaymentSession` (`GET /payment-collection/session`) polls session status. `sdk.invoice.submitCollection` records an `asset_id` payment against an `invoice_id` when you reconcile inflows yourself.

{% hint style="warning" %}
Treat `checkPaymentSession` / `checkPaymentCollection` as your source of truth before releasing goods or marking an invoice paid. On-chain confirmation is the clearing event; email delivery is not.
{% endhint %}

***

## Step 6: Reconciliation

Close the loop:

1. `sdk.invoice.markInvoiceAsPaid` (`POST /invoice/mark-paid`) records settlement with `paid_at`, notifies stakeholders by email (`emails`, `cc`, `bcc`), and attaches a reconciliation `note`.
2. `sdk.invoice.sendPaymentConfirmation` sends the customer a branded receipt.
3. For finance reporting, `sdk.invoice.getInvoices` filters by status (for example `DRAFT`, `SENT`) with pagination, and the analytics helpers produce the rollups:

| Method                | REST endpoint                    | Use                                                                                                                     |
| --------------------- | -------------------------------- | ----------------------------------------------------------------------------------------------------------------------- |
| `getRevenueGraph`     | `GET /invoice/revenue`           | Revenue over time, `period` of `weekly`, `monthly`, `quarterly`, or `yearly`, filterable by `currency` and `customerID` |
| `getCustomerBalances` | `GET /invoice/customer-balances` | Outstanding balances per customer over a date range                                                                     |
| `getCustomers`        | `GET /invoice/customers`         | Per-customer `total_invoiced` and `total_outstanding`                                                                   |

{% hint style="info" %}
For off-link settlement (a wire, for example), call `markInvoiceAsPaid` directly with the actual `paid_at` timestamp. The invoice record becomes the single reconciliation anchor regardless of how funds arrived.
{% endhint %}

***

## Endpoint summary

| Area        | SDK service    | Key routes                                                                                                                             |
| ----------- | -------------- | -------------------------------------------------------------------------------------------------------------------------------------- |
| Customers   | `sdk.customer` | `/invoice/customers`, `/invoice/customer`, `/invoice/customer/invite`                                                                  |
| Invoices    | `sdk.invoice`  | `/invoice`, `/invoice/list`, `/invoice/finalise`, `/invoice/share`, `/invoice/reminder`, `/invoice/mark-paid`, `/invoice/confirmation` |
| Collections | `sdk.invoice`  | `/invoice/payment-collection`, `/payment-collection`, `/payment-collection/list`, `/payment-collection/assets`                         |
| Sessions    | `sdk.invoice`  | `/payment-collection/session`, `/payment-collection/session/check`, `/payment-collection/check`                                        |
| Branding    | `sdk.invoice`  | `/payment-collection/wallet/info`, `/payment-collection/wallet/customization`                                                          |
| Analytics   | `sdk.invoice`  | `/invoice/revenue`, `/invoice/customer-balances`                                                                                       |
