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

# Invoices

Create, send, and manage invoices through the admin API.

For general conventions, see [JSON-API Conventions](https://docs.anny.co/developers/guides/json-api-conventions.md). For authentication, see [Authentication](https://docs.anny.co/developers/guides/authentication.md).

***

## Prerequisites

* Bearer token with admin access + `?o={organization_id}`

***

## Invoice Actions

### Cancel an Invoice

```http theme={null}
POST /api/v1/invoices/{invoice_id}/cancel?o={org_id}
```

Creates a credit note and voids the invoice.

### Mark as Paid

Mark a SENT invoice as paid without processing a payment:

```http theme={null}
PUT /api/v1/invoices/{invoice_id}/set-paid?o={org_id}

{
  "send_notification": true
}
```

Set `send_notification` to `true` to email the customer a payment confirmation.

### Change Recipient

Transfers an invoice to a different customer. This cancels the original invoice and creates a new copy for the new recipient:

```http theme={null}
POST /api/v1/invoices/{invoice_id}/change-recipient?o={org_id}

{
  "customer_id": "new-customer-uuid"
}
```

***

## Creating an Invoice

All examples below assume `BASE_URL = https://{your-domain}/api/v1`.

**1. Find a Customer by Email**

```http theme={null}
GET {BASE_URL}/customers?o={org_id}&filter[email]=jane@example.com&include=address
```

The `email` filter performs an exact (case-insensitive) match.

For a fuzzy name/email/phone search, use the `search` filter instead:

```http theme={null}
GET {BASE_URL}/customers?o={org_id}&filter[search]=jane&include=address
```

#### Filter by Custom Field

Custom fields are referenced by their UUID. See [Custom Field Filters](https://docs.anny.co/developers/guides/json-api-conventions.md#custom-field-filters) for the full syntax and supported operators.

```http theme={null}
GET {BASE_URL}/customers?o={org_id}&filter[custom_fields][{FIELD_UUID}][f_id]={FIELD_UUID}&filter[custom_fields][{FIELD_UUID}][o]==&filter[custom_fields][{FIELD_UUID}][v]=Premium
```

For checkbox fields, pass `true` / `false` as the value. For multi-select fields, the `in` operator accepts comma-separated values.

**2. Create a Customer (if not found)**

```http theme={null}
POST {BASE_URL}/customers?o={org_id}
```

```json theme={null}
{
  "data": {
    "type": "customers",
    "attributes": {
      "given_name": "Jane",
      "family_name": "Doe",
      "email": "jane@example.com",
      "company": "Acme Inc",
      "locale": "de",
      "mobile": "+4917612345678"
    }
  }
}
```

**Required:** `email`, `locale`

Create the customer's address as a separate resource:

```http theme={null}
POST {BASE_URL}/addresses?o={org_id}
```

```json theme={null}
{
  "data": {
    "type": "addresses",
    "attributes": {
      "name": "Jane Doe",
      "street_address": "Hauptstraße 42",
      "zip_code": "50667",
      "city": "Köln",
      "country_code": "DE"
    },
    "relationships": {
      "addressable": {
        "data": { "type": "customers", "id": "{customer_id}" }
      }
    }
  }
}
```

**3. Create the Invoice (draft)**

```http theme={null}
POST {BASE_URL}/invoices?o={org_id}
```

```json theme={null}
{
  "data": {
    "type": "invoices",
    "attributes": {
      "currency": "EUR",
      "recipient": "Acme Inc\nJane Doe\nHauptstraße 42\n50667 Köln",
      "calculate_from_net": true
    },
    "relationships": {
      "customer": {
        "data": { "type": "customers", "id": "{customer_id}" }
      }
    }
  }
}
```

#### Customer linking

| Method | When to use |
| - | - |
| `relationships.customer` in the request body | Manual invoices — pass the customer ID directly |
| `relationships.reference` (order, subscription, booking pass) | Backend derives customer from the referenced entity |
| Neither | Create without a customer; link one later via PATCH |

When the invoice is **sent**, the backend snapshots `recipient` and `buyer_data` from the customer so the invoice stays valid even if the profile changes later.

#### Attributes

| Attribute | Type | Required | Notes |
| - | - | - | - |
| `currency` | string | **yes** | e.g. `"EUR"`, `"USD"` |
| `recipient` | string | no | Free-text address block; auto-filled from customer on send if blank |
| `invoicing_party` | string | no | Your company's address block |
| `calculate_from_net` | boolean | no | Default `false`. Set `true` when entering net amounts |
| `issued_at` | date | no | Required when status ≠ `draft` |
| `due_date` | date | no | |
| `notes` | string | no | Appears on the invoice |
| `vat_number` | string | no | |
| `is_quote` | boolean | no | Set `true` to create a quote instead |
| `number` | string | no | Must be unique within org if provided |

**4. Add Line Items**

```http theme={null}
POST {BASE_URL}/items?o={org_id}&calculate_from_net=true
```

```json theme={null}
{
  "data": {
    "type": "items",
    "attributes": {
      "title": "Consulting — March 2026",
      "quantity": 10,
      "single_net_amount": 150.00,
      "tax_rate": 19
    },
    "relationships": {
      "document": {
        "data": { "type": "invoices", "id": "{invoice_id}" }
      }
    }
  }
}
```

| Attribute | Type | Required | Notes |
| - | - | - | - |
| `title` | string | **yes** | Max 185 chars |
| `quantity` | integer | **yes** | |
| `tax_rate` | number | **yes** | ≥ 0 (e.g. `19` for 19%) |
| `single_net_amount` | number | **yes**\* | Required when `calculate_from_net=true` |
| `single_gross_amount` | number | **yes**\* | Required when `calculate_from_net=false` |
| `subtitle` | string | no | Max 185 chars |

\* Provide the amount matching the invoice direction. The backend derives the other automatically.

Repeat for each line item. Invoice totals recalculate after each item.

**5. Send the Invoice**

```http theme={null}
POST {BASE_URL}/invoices/{invoice_id}/send?o={org_id}
```

Transitions status to `sent` and delivers via the configured notification channel.

**6. Mark as Paid (optional)**

```http theme={null}
POST {BASE_URL}/invoices/{invoice_id}/set-paid?o={org_id}&sendNotification=true
```

***

## Full Workflow Summary

```text theme={null}
1. GET  /customers?filter[email]=...&include=address     → Find customer
2. POST /customers                                        → Create customer (if new)
3. POST /addresses                                        → Create customer address (if new)
4. POST /invoices                                         → Create draft invoice
5. POST /items  (repeat per line item)                    → Add line items
6. POST /invoices/{id}/send                               → Send invoice
7. POST /invoices/{id}/set-paid                           → Mark as paid
```

All endpoints include `?o={organization_id}` for tenant context.

***

## Common Errors

| Error | Cause | Solution |
| - | - | - |
| `403` — unauthorized | Missing permissions for invoice operations | Ensure admin token has the required abilities |
| `422` — invoice not in SENT status | `set-paid` on draft or already-paid invoice | Check invoice status first |


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