# Invoices

Invoices start as `draft`. Sending or taking payment finalizes them
(status is no longer `draft`). Paying in full moves them to `paid`; a
partial payment leaves them `open`.

Only drafts can be updated or deleted, and an invoice's client can't
be changed. Deleted invoices are hidden until you restore them.

## The invoice object

- `id` (string): Example: `0abcDEF1234567890xyzAB`.
- `number` (string)
- `status` (string): One of `draft`, `open`, `paid`, `void`.
- `client_id` (string): Example: `0abcDEF1234567890xyzAB`.
- `client` (object): The client embedded in invoices and subscriptions, without `payment_methods`.
- `client.id` (string): Example: `0abcDEF1234567890xyzAB`.
- `client.name` (string)
- `client.emails` (array of string): Min 1 items.
- `client.address` (string or null)
- `client.currency` (string): Three-letter currency code, in lowercase. Example: `usd`.
- `client.language` (string): Two-letter language code, in lowercase. One of `da`, `en`, `fr`, `de`, `it`, `no`, `pt`, `es`.
- `client.default_payment_method_id` (string or null): The card `POST /invoices/{id}/pay` uses when no `payment_method_id` is sent. Null when the client has no card on file. Example: `0abcDEF1234567890xyzAB`.
- `client.created_at` (timestamp): Date and time in UTC. Example: `2024-06-15T12:00:00.000000Z`.
- `client.updated_at` (timestamp): Date and time in UTC. Example: `2024-06-15T12:00:00.000000Z`.
- `client.is_deleted` (boolean)
- `currency` (string): Three-letter currency code, in lowercase. Example: `usd`.
- `language` (string): Two-letter language code, in lowercase. One of `da`, `en`, `fr`, `de`, `it`, `no`, `pt`, `es`.
- `date` (date): Example: `2024-06-15`.
- `notes` (string or null)
- `items` (array of object)
- `items[].description` (string)
- `items[].amount` (integer): Amount in the smallest currency unit (cents). Example: `10000`. Min 0.
- `items[].quantity` (string): Quantity as a decimal string, without trailing zeros. Example: `1`.
- `items[].total` (integer): Amount in the smallest currency unit (cents). Example: `10000`. Min 0.
- `discounts` (array of object)
- `discounts[].amount` (integer or null): Fixed amount off, in cents. Example: `10000`. Min 0.
- `discounts[].percent` (string or null): Percent off the subtotal, as a decimal string without trailing zeros. Example: `12.5`.
- `discount_amount` (integer): Total discount applied to the subtotal, computed from `discounts`. Example: `10000`. Min 0.
- `taxable_amount` (integer): Amount in the smallest currency unit (cents). Example: `10000`. Min 0.
- `tax_rates` (array of object)
- `tax_rates[].id` (string): The tax rate's ID. Use it in `tax_rates`. Example: `0abcDEF1234567890xyzAB`.
- `tax_rates[].name` (string): Example: `TPS`.
- `tax_rates[].percentage` (string): Percentage as a decimal string, without trailing zeros. Example: `5`.
- `tax_rates[].amount` (integer): Tax amount for this rate. Example: `10000`. Min 0.
- `tax_amount` (integer): Amount in the smallest currency unit (cents). Example: `10000`. Min 0.
- `subtotal` (integer): Amount in the smallest currency unit (cents). Example: `10000`. Min 0.
- `total` (integer): Amount in the smallest currency unit (cents). Example: `10000`. Min 0.
- `amount_paid` (integer): Amount in the smallest currency unit (cents). Example: `10000`. Min 0.
- `amount_refunded` (integer): Part of `amount_paid` that has been refunded. Example: `10000`. Min 0.
- `amount_remaining` (integer): Amount in the smallest currency unit (cents). Example: `10000`. Min 0.
- `accept_cards` (boolean)
- `sent_at` (timestamp or null): Date and time in UTC. Example: `2024-06-15T12:00:00.000000Z`.
- `paid_at` (timestamp or null): Date and time in UTC. Example: `2024-06-15T12:00:00.000000Z`.
- `created_at` (timestamp): Date and time in UTC. Example: `2024-06-15T12:00:00.000000Z`.
- `updated_at` (timestamp): Date and time in UTC. Example: `2024-06-15T12:00:00.000000Z`.
- `is_deleted` (boolean)

```json
{
  "id": "0abcDEF1234567890xyzAB",
  "number": "AB-0001",
  "status": "draft",
  "client_id": "0abcDEF1234567890xyzAB",
  "client": {
    "id": "0abcDEF1234567890xyzAB",
    "name": "Jane Doe",
    "emails": [
      "jane@example.com"
    ],
    "address": "1 Main St",
    "currency": "usd",
    "language": "en",
    "default_payment_method_id": null,
    "created_at": "2024-06-15T12:00:00.000000Z",
    "updated_at": "2024-06-15T12:00:00.000000Z",
    "is_deleted": false
  },
  "currency": "usd",
  "language": "en",
  "date": "2024-06-15",
  "notes": "these are the notes",
  "items": [
    {
      "description": "Design work",
      "amount": 10000,
      "quantity": "1",
      "total": 10000
    }
  ],
  "discounts": [],
  "discount_amount": 0,
  "taxable_amount": 10000,
  "tax_rates": [],
  "tax_amount": 0,
  "subtotal": 10000,
  "total": 10000,
  "amount_paid": 0,
  "amount_refunded": 0,
  "amount_remaining": 10000,
  "accept_cards": false,
  "sent_at": null,
  "paid_at": null,
  "created_at": "2024-06-15T12:00:00.000000Z",
  "updated_at": "2024-06-15T12:00:00.000000Z",
  "is_deleted": false
}
```

## List invoices

`GET /invoices`

### Query parameters

- `search` (string): Matches number, notes, client name and emails, and item descriptions. Not case-sensitive. Example: `design`.
- `status` (string): One of `draft`, `open`, `paid`, `void`.
- `client_id` (string): The client ID. Example: `0abcDEF1234567890xyzAB`.
- `limit` (integer): Number of results per page. Default: `10`. Min 1. Max 100.
- `cursor` (string): To get the next page, pass the `next_cursor` from the previous response.
- `created_at` (object): Keys `gt`, `gte`, `lt`, `lte`. Example: `created_at[gt]=2024-06-15T12:00:00.000000Z`.
- `updated_at` (object): Keys `gt`, `gte`, `lt`, `lte`. Example: `updated_at[gt]=2024-06-15T12:00:00.000000Z`.

### Response

- `200`: Paginated invoices. Returns a [paginated list](/docs/pagination) of [invoice objects](#the-invoice-object).

### Errors

- `400` `request_failed`: Your request could not be processed.
- `400` `api_version_unsupported`: The requested API version is not supported. Current version: 2026-08-21
- `401` `api_key_missing`: The API key is missing.
- `401` `api_key_invalid`: The API key is invalid or has been revoked.
- `404`: The record doesn't exist or was deleted.
- `422`: The request body or query parameters are invalid.
- `429`: Too many requests. The limit is 300 requests per 5 minutes.

### Example request

```bash
curl https://api.tallymark.com/invoices \
  -H "Authorization: Bearer $TALLYMARK_API_KEY"
```

### Example response

```json
{
  "data": [
    {
      "id": "0abcDEF1234567890xyzAB",
      "number": "AB-0001",
      "status": "draft",
      "client_id": "0abcDEF1234567890xyzAB",
      "client": {
        "id": "0abcDEF1234567890xyzAB",
        "name": "Jane Doe",
        "emails": [
          "jane@example.com"
        ],
        "address": "1 Main St",
        "currency": "usd",
        "language": "en",
        "default_payment_method_id": null,
        "created_at": "2024-06-15T12:00:00.000000Z",
        "updated_at": "2024-06-15T12:00:00.000000Z",
        "is_deleted": false
      },
      "currency": "usd",
      "language": "en",
      "date": "2024-06-15",
      "notes": "these are the notes",
      "items": [
        {
          "description": "Design work",
          "amount": 10000,
          "quantity": "1",
          "total": 10000
        }
      ],
      "discounts": [],
      "discount_amount": 0,
      "taxable_amount": 10000,
      "tax_rates": [],
      "tax_amount": 0,
      "subtotal": 10000,
      "total": 10000,
      "amount_paid": 0,
      "amount_refunded": 0,
      "amount_remaining": 10000,
      "accept_cards": false,
      "sent_at": null,
      "paid_at": null,
      "created_at": "2024-06-15T12:00:00.000000Z",
      "updated_at": "2024-06-15T12:00:00.000000Z",
      "is_deleted": false
    }
  ],
  "has_more": false,
  "next_cursor": null
}
```

## Create an invoice

`POST /invoices`

Creates an invoice. Pass `client_id` for an existing client, or a
`client` object to create one, but not both.

Without `pay` or `send` the invoice is a `draft`. `pay` and `send` are
attempts. The invoice is always created and the request succeeds even
if they don't go through, so check the returned invoice when it
matters:

- `pay: true` tries to charge the client's default saved card. If the
  card is declined, the invoice is returned finalized (`open`) and
  unpaid. If the client has no saved card, no charge is attempted.
  Check `status` and `amount_remaining`.
- `send: true` tries to email the invoice to the client, after the
  payment attempt. If the email can't be sent right now, the invoice is returned finalized
  (`open`) with `sent_at: null`. Retry with
  `POST /invoices/{id}/send`.

A finalized invoice can no longer be updated or deleted.

### Request body

Send exactly one of `client_id` (an existing client) or `client` (a
new client).

- `client_id` (string): Example: `0abcDEF1234567890xyzAB`.
- `client` (object): A new client. If a non-deleted client with exactly these emails (same order) already exists, it is reused and updated: its name, its address (cleared when `address` is omitted), and its currency and language (set to this request's).
- `client.name` (string, required): Max length 255.
- `client.email` (string or array of string, required): One email address, or a list of up to 4. Example: `jane@example.com`.
- `client.address` (string or null)
- `send` (boolean): Try to email the invoice to the client after creating it (and after the payment attempt). Never fails the request. Check `sent_at` to see if it was sent. Default: `false`.
- `pay` (boolean): Try to charge the client's default saved card after creating the invoice. Never fails the request. Check `status` and `amount_remaining` to see if it was paid. Default: `false`.
- `items` (array of object, required): Min 1 items.
- `items[].description` (string, required): Max length 255.
- `items[].amount` (integer, required): Amount in the smallest currency unit (cents). Example: `10000`. Min 0.
- `items[].quantity` (number, required): Rounded to 4 decimals. Example: `1`. Min 0.
- `discounts` (array of object): Max 1 items.
- `discounts[].amount` (integer or null): Fixed amount off, in cents. Example: `10000`. Min 0.
- `discounts[].percent` (number or null): Percent off the subtotal, up to 4 decimals. Example: `12.5`. Min 0. Max 100.
- `date` (date, required)
- `currency` (string, required): Three-letter currency code, in lowercase. Example: `usd`.
- `language` (string, required): Two-letter language code, in lowercase. One of `da`, `en`, `fr`, `de`, `it`, `no`, `pt`, `es`.
- `tax_rates` (array of string): Tax rate IDs belonging to the account. Deleted tax rates cannot be added, but ones already on the invoice can be kept.
- `include_default_tax_rates` (boolean): Adds the account's default tax rates on top of `tax_rates`. On update, if `tax_rates` is omitted, the defaults are added to the tax rates already on the invoice. A tax rate is never applied twice. Default: `false`.
- `accept_cards` (boolean, required)
- `notes` (string or null)

### Response

- `201`: Created invoice. Returns a [invoice object](#the-invoice-object).

### Errors

- `400` `request_failed`: Your request could not be processed.
- `400` `api_version_unsupported`: The requested API version is not supported. Current version: 2026-08-21
- `401` `api_key_missing`: The API key is missing.
- `401` `api_key_invalid`: The API key is invalid or has been revoked.
- `403` `api_key_read_only`: This API key is read-only and cannot make write requests.
- `404`: The record doesn't exist or was deleted.
- `422`: The request body or query parameters are invalid.
- `429`: Too many requests. The limit is 300 requests per 5 minutes.

### Example request

```bash
curl -X POST https://api.tallymark.com/invoices \
  -H "Authorization: Bearer $TALLYMARK_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "client": {
    "name": "Jane Doe",
    "email": "jane@example.com",
    "address": "1 Main St"
  },
  "items": [
    {
      "description": "Design work",
      "amount": 10000,
      "quantity": 1
    }
  ],
  "date": "2024-06-15",
  "currency": "usd",
  "language": "en",
  "accept_cards": false,
  "notes": "these are the notes"
}'
```

### Example response

```json
{
  "id": "0abcDEF1234567890xyzAB",
  "number": "AB-0001",
  "status": "draft",
  "client_id": "0abcDEF1234567890xyzAB",
  "client": {
    "id": "0abcDEF1234567890xyzAB",
    "name": "Jane Doe",
    "emails": [
      "jane@example.com"
    ],
    "address": "1 Main St",
    "currency": "usd",
    "language": "en",
    "default_payment_method_id": null,
    "created_at": "2024-06-15T12:00:00.000000Z",
    "updated_at": "2024-06-15T12:00:00.000000Z",
    "is_deleted": false
  },
  "currency": "usd",
  "language": "en",
  "date": "2024-06-15",
  "notes": "these are the notes",
  "items": [
    {
      "description": "Design work",
      "amount": 10000,
      "quantity": "1",
      "total": 10000
    }
  ],
  "discounts": [],
  "discount_amount": 0,
  "taxable_amount": 10000,
  "tax_rates": [],
  "tax_amount": 0,
  "subtotal": 10000,
  "total": 10000,
  "amount_paid": 0,
  "amount_refunded": 0,
  "amount_remaining": 10000,
  "accept_cards": false,
  "sent_at": null,
  "paid_at": null,
  "created_at": "2024-06-15T12:00:00.000000Z",
  "updated_at": "2024-06-15T12:00:00.000000Z",
  "is_deleted": false
}
```

## Show an invoice

`GET /invoices/{id}`

### Path parameters

- `id` (string, required): The invoice ID. Example: `0abcDEF1234567890xyzAB`.

### Response

- `200`: Invoice. Returns a [invoice object](#the-invoice-object).

### Errors

- `400` `request_failed`: Your request could not be processed.
- `400` `api_version_unsupported`: The requested API version is not supported. Current version: 2026-08-21
- `401` `api_key_missing`: The API key is missing.
- `401` `api_key_invalid`: The API key is invalid or has been revoked.
- `404`: The record doesn't exist or was deleted.
- `429`: Too many requests. The limit is 300 requests per 5 minutes.

### Example request

```bash
curl https://api.tallymark.com/invoices/0abcDEF1234567890xyzAB \
  -H "Authorization: Bearer $TALLYMARK_API_KEY"
```

### Example response

```json
{
  "id": "0abcDEF1234567890xyzAB",
  "number": "AB-0001",
  "status": "draft",
  "client_id": "0abcDEF1234567890xyzAB",
  "client": {
    "id": "0abcDEF1234567890xyzAB",
    "name": "Jane Doe",
    "emails": [
      "jane@example.com"
    ],
    "address": "1 Main St",
    "currency": "usd",
    "language": "en",
    "default_payment_method_id": null,
    "created_at": "2024-06-15T12:00:00.000000Z",
    "updated_at": "2024-06-15T12:00:00.000000Z",
    "is_deleted": false
  },
  "currency": "usd",
  "language": "en",
  "date": "2024-06-15",
  "notes": "these are the notes",
  "items": [
    {
      "description": "Design work",
      "amount": 10000,
      "quantity": "1",
      "total": 10000
    }
  ],
  "discounts": [],
  "discount_amount": 0,
  "taxable_amount": 10000,
  "tax_rates": [],
  "tax_amount": 0,
  "subtotal": 10000,
  "total": 10000,
  "amount_paid": 0,
  "amount_refunded": 0,
  "amount_remaining": 10000,
  "accept_cards": false,
  "sent_at": null,
  "paid_at": null,
  "created_at": "2024-06-15T12:00:00.000000Z",
  "updated_at": "2024-06-15T12:00:00.000000Z",
  "is_deleted": false
}
```

## Update an invoice

`POST /invoices/{id}/update`

Updates a draft invoice. Only the fields you send are changed; omitted
fields keep their current value. Send `notes: null` to clear the notes,
and `discounts: []` or `tax_rates: []` to remove them. The client
can't be changed.

### Path parameters

- `id` (string, required): The invoice ID. Example: `0abcDEF1234567890xyzAB`.

### Request body

Send at most one discount.

- `items` (array of object): Min 1 items.
- `items[].description` (string, required): Max length 255.
- `items[].amount` (integer, required): Amount in the smallest currency unit (cents). Example: `10000`. Min 0.
- `items[].quantity` (number, required): Rounded to 4 decimals. Example: `1`. Min 0.
- `discounts` (array of object): Max 1 items.
- `discounts[].amount` (integer or null): Fixed amount off, in cents. Example: `10000`. Min 0.
- `discounts[].percent` (number or null): Percent off the subtotal, up to 4 decimals. Example: `12.5`. Min 0. Max 100.
- `date` (date)
- `currency` (string): Three-letter currency code, in lowercase. Example: `usd`.
- `language` (string): Two-letter language code, in lowercase. One of `da`, `en`, `fr`, `de`, `it`, `no`, `pt`, `es`.
- `tax_rates` (array of string): Tax rate IDs belonging to the account. Deleted tax rates cannot be added, but ones already on the invoice can be kept.
- `include_default_tax_rates` (boolean): Adds the account's default tax rates on top of `tax_rates`. On update, if `tax_rates` is omitted, the defaults are added to the tax rates already on the invoice. A tax rate is never applied twice. Default: `false`.
- `accept_cards` (boolean)
- `notes` (string or null)

### Response

- `200`: Updated invoice. Returns a [invoice object](#the-invoice-object).

### Errors

- `400` `invoice_finalized`: This invoice is finalized and cannot be updated. Only drafts can be updated.
- `400` `request_failed`: Your request could not be processed.
- `400` `api_version_unsupported`: The requested API version is not supported. Current version: 2026-08-21
- `401` `api_key_missing`: The API key is missing.
- `401` `api_key_invalid`: The API key is invalid or has been revoked.
- `403` `api_key_read_only`: This API key is read-only and cannot make write requests.
- `404`: The record doesn't exist or was deleted.
- `422`: The request body or query parameters are invalid.
- `429`: Too many requests. The limit is 300 requests per 5 minutes.

### Example request

```bash
curl -X POST https://api.tallymark.com/invoices/0abcDEF1234567890xyzAB/update \
  -H "Authorization: Bearer $TALLYMARK_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "items": [
    {
      "description": "Design work",
      "amount": 15000,
      "quantity": 2
    }
  ],
  "notes": "Thanks for your business."
}'
```

### Example response

```json
{
  "id": "0abcDEF1234567890xyzAB",
  "number": "AB-0001",
  "status": "draft",
  "client_id": "0abcDEF1234567890xyzAB",
  "client": {
    "id": "0abcDEF1234567890xyzAB",
    "name": "Jane Doe",
    "emails": [
      "jane@example.com"
    ],
    "address": "1 Main St",
    "currency": "usd",
    "language": "en",
    "default_payment_method_id": null,
    "created_at": "2024-06-15T12:00:00.000000Z",
    "updated_at": "2024-06-15T12:00:00.000000Z",
    "is_deleted": false
  },
  "currency": "usd",
  "language": "en",
  "date": "2024-06-15",
  "notes": "these are the notes",
  "items": [
    {
      "description": "Design work",
      "amount": 10000,
      "quantity": "1",
      "total": 10000
    }
  ],
  "discounts": [],
  "discount_amount": 0,
  "taxable_amount": 10000,
  "tax_rates": [],
  "tax_amount": 0,
  "subtotal": 10000,
  "total": 10000,
  "amount_paid": 0,
  "amount_refunded": 0,
  "amount_remaining": 10000,
  "accept_cards": false,
  "sent_at": null,
  "paid_at": null,
  "created_at": "2024-06-15T12:00:00.000000Z",
  "updated_at": "2024-06-15T12:00:00.000000Z",
  "is_deleted": false
}
```

## Send an invoice

`POST /invoices/{id}/send`

Finalizes a draft (status becomes `open`) and emails the client.
Sending an already-sent invoice emails it again; `sent_at` keeps the
time of the first send. Sending a `paid` invoice emails the client a
receipt.

### Path parameters

- `id` (string, required): The invoice ID. Example: `0abcDEF1234567890xyzAB`.

### Response

- `200`: Sent invoice. Returns a [invoice object](#the-invoice-object).

### Errors

- `400` `invoice_void`: This invoice is void and cannot be sent.
- `400` `request_failed`: Your request could not be processed.
- `400` `api_version_unsupported`: The requested API version is not supported. Current version: 2026-08-21
- `401` `api_key_missing`: The API key is missing.
- `401` `api_key_invalid`: The API key is invalid or has been revoked.
- `403` `api_key_read_only`: This API key is read-only and cannot make write requests.
- `403` `account_not_verified`: Verify your account's email before performing this action.
- `404`: The record doesn't exist or was deleted.
- `429`: Too many requests, or the account can't send email right now because it hit its email limit.
- `429` `too_many_emails`: Unable to send invoice at this time.

### Example request

```bash
curl -X POST https://api.tallymark.com/invoices/0abcDEF1234567890xyzAB/send \
  -H "Authorization: Bearer $TALLYMARK_API_KEY"
```

### Example response

```json
{
  "id": "0abcDEF1234567890xyzAB",
  "number": "AB-0001",
  "status": "draft",
  "client_id": "0abcDEF1234567890xyzAB",
  "client": {
    "id": "0abcDEF1234567890xyzAB",
    "name": "Jane Doe",
    "emails": [
      "jane@example.com"
    ],
    "address": "1 Main St",
    "currency": "usd",
    "language": "en",
    "default_payment_method_id": null,
    "created_at": "2024-06-15T12:00:00.000000Z",
    "updated_at": "2024-06-15T12:00:00.000000Z",
    "is_deleted": false
  },
  "currency": "usd",
  "language": "en",
  "date": "2024-06-15",
  "notes": "these are the notes",
  "items": [
    {
      "description": "Design work",
      "amount": 10000,
      "quantity": "1",
      "total": 10000
    }
  ],
  "discounts": [],
  "discount_amount": 0,
  "taxable_amount": 10000,
  "tax_rates": [],
  "tax_amount": 0,
  "subtotal": 10000,
  "total": 10000,
  "amount_paid": 0,
  "amount_refunded": 0,
  "amount_remaining": 10000,
  "accept_cards": false,
  "sent_at": null,
  "paid_at": null,
  "created_at": "2024-06-15T12:00:00.000000Z",
  "updated_at": "2024-06-15T12:00:00.000000Z",
  "is_deleted": false
}
```

## Delete a draft invoice

`POST /invoices/{id}/delete`

Deletes a draft invoice. You can restore it later. Only drafts can be
deleted: once an invoice is sent or paid, it's final.

### Path parameters

- `id` (string, required): The invoice ID. Example: `0abcDEF1234567890xyzAB`.

### Response

- `200`: Deleted invoice (`is_deleted` true). Returns a [invoice object](#the-invoice-object).

### Errors

- `400` `invoice_finalized`: This invoice is finalized and cannot be deleted. Only drafts can be deleted.
- `400` `request_failed`: Your request could not be processed.
- `400` `api_version_unsupported`: The requested API version is not supported. Current version: 2026-08-21
- `401` `api_key_missing`: The API key is missing.
- `401` `api_key_invalid`: The API key is invalid or has been revoked.
- `403` `api_key_read_only`: This API key is read-only and cannot make write requests.
- `404`: The record doesn't exist or was deleted.
- `429`: Too many requests. The limit is 300 requests per 5 minutes.

### Example request

```bash
curl -X POST https://api.tallymark.com/invoices/0abcDEF1234567890xyzAB/delete \
  -H "Authorization: Bearer $TALLYMARK_API_KEY"
```

### Example response

```json
{
  "id": "0abcDEF1234567890xyzAB",
  "number": "AB-0001",
  "status": "draft",
  "client_id": "0abcDEF1234567890xyzAB",
  "client": {
    "id": "0abcDEF1234567890xyzAB",
    "name": "Jane Doe",
    "emails": [
      "jane@example.com"
    ],
    "address": "1 Main St",
    "currency": "usd",
    "language": "en",
    "default_payment_method_id": null,
    "created_at": "2024-06-15T12:00:00.000000Z",
    "updated_at": "2024-06-15T12:00:00.000000Z",
    "is_deleted": false
  },
  "currency": "usd",
  "language": "en",
  "date": "2024-06-15",
  "notes": "these are the notes",
  "items": [
    {
      "description": "Design work",
      "amount": 10000,
      "quantity": "1",
      "total": 10000
    }
  ],
  "discounts": [],
  "discount_amount": 0,
  "taxable_amount": 10000,
  "tax_rates": [],
  "tax_amount": 0,
  "subtotal": 10000,
  "total": 10000,
  "amount_paid": 0,
  "amount_refunded": 0,
  "amount_remaining": 10000,
  "accept_cards": false,
  "sent_at": null,
  "paid_at": null,
  "created_at": "2024-06-15T12:00:00.000000Z",
  "updated_at": "2024-06-15T12:00:00.000000Z",
  "is_deleted": false
}
```

## Restore a deleted invoice

`POST /invoices/{id}/restore`

Restores a deleted draft invoice.

### Path parameters

- `id` (string, required): The invoice ID. Example: `0abcDEF1234567890xyzAB`.

### Response

- `200`: Restored invoice (`is_deleted` false). Returns a [invoice object](#the-invoice-object).

### Errors

- `400` `request_failed`: Your request could not be processed.
- `400` `api_version_unsupported`: The requested API version is not supported. Current version: 2026-08-21
- `401` `api_key_missing`: The API key is missing.
- `401` `api_key_invalid`: The API key is invalid or has been revoked.
- `403` `api_key_read_only`: This API key is read-only and cannot make write requests.
- `404`: The record doesn't exist or was deleted.
- `429`: Too many requests. The limit is 300 requests per 5 minutes.

### Example request

```bash
curl -X POST https://api.tallymark.com/invoices/0abcDEF1234567890xyzAB/restore \
  -H "Authorization: Bearer $TALLYMARK_API_KEY"
```

### Example response

```json
{
  "id": "0abcDEF1234567890xyzAB",
  "number": "AB-0001",
  "status": "draft",
  "client_id": "0abcDEF1234567890xyzAB",
  "client": {
    "id": "0abcDEF1234567890xyzAB",
    "name": "Jane Doe",
    "emails": [
      "jane@example.com"
    ],
    "address": "1 Main St",
    "currency": "usd",
    "language": "en",
    "default_payment_method_id": null,
    "created_at": "2024-06-15T12:00:00.000000Z",
    "updated_at": "2024-06-15T12:00:00.000000Z",
    "is_deleted": false
  },
  "currency": "usd",
  "language": "en",
  "date": "2024-06-15",
  "notes": "these are the notes",
  "items": [
    {
      "description": "Design work",
      "amount": 10000,
      "quantity": "1",
      "total": 10000
    }
  ],
  "discounts": [],
  "discount_amount": 0,
  "taxable_amount": 10000,
  "tax_rates": [],
  "tax_amount": 0,
  "subtotal": 10000,
  "total": 10000,
  "amount_paid": 0,
  "amount_refunded": 0,
  "amount_remaining": 10000,
  "accept_cards": false,
  "sent_at": null,
  "paid_at": null,
  "created_at": "2024-06-15T12:00:00.000000Z",
  "updated_at": "2024-06-15T12:00:00.000000Z",
  "is_deleted": false
}
```

## Pay an invoice

`POST /invoices/{id}/pay`

Pays `amount` cents, or the full `amount_remaining` when `amount` is
omitted. A draft is finalized first. The invoice becomes `paid` once
nothing is left to pay; after a partial payment it stays `open` with
a lower `amount_remaining`.

- `processor: cash` records a payment made outside Tallymark (cash,
  check, bank transfer). No money moves.
- `processor: stripe` charges a card the client saved when paying in
  the app: `payment_method_id` from the client's `payment_methods`,
  or the client's `default_payment_method_id` when omitted.

If the card is declined, the invoice stays unpaid and you can call
this endpoint again to retry.

### Path parameters

- `id` (string, required): The invoice ID. Example: `0abcDEF1234567890xyzAB`.

### Request body

- `processor` (string, required): `cash` is recorded outside Tallymark (cash, check, bank transfer). No money moves. One of `stripe`, `cash`.
- `payment_method_id` (string or null): `stripe` only. One of the client's `payment_methods`. Omit to use the client's default card. Example: `0abcDEF1234567890xyzAB`.
- `amount` (integer or null): Omit (or null) to pay the full `amount_remaining`. Can't be more than `amount_remaining`. Example: `10000`. Min 1.

### Response

- `200`: Paid invoice. Returns a [invoice object](#the-invoice-object).

### Errors

- `400` `invoice_void`: This invoice is void and cannot be paid.
- `400` `amount_too_large`: The amount is more than what is left to pay on this invoice.
- `400` `amount_too_small`: The amount is below the minimum card charge for this currency.
- `400` `payment_method_not_found`: The payment method was not found on this client.
- `400` `request_failed`: Your request could not be processed.
- `400` `api_version_unsupported`: The requested API version is not supported. Current version: 2026-08-21
- `401` `api_key_missing`: The API key is missing.
- `401` `api_key_invalid`: The API key is invalid or has been revoked.
- `402` `payment_failed`: The payment could not be processed.
- `403` `api_key_read_only`: This API key is read-only and cannot make write requests.
- `403` `account_not_verified`: Verify your account's email before performing this action.
- `404`: The record doesn't exist or was deleted.
- `409` `already_paid`: This invoice is already paid.
- `409` `stripe_not_connected`: This account has not connected Stripe.
- `409` `no_payment_method`: This client has no card on file.
- `422`: The request body or query parameters are invalid.
- `429`: Too many requests. The limit is 300 requests per 5 minutes.

### Example request

```bash
curl -X POST https://api.tallymark.com/invoices/0abcDEF1234567890xyzAB/pay \
  -H "Authorization: Bearer $TALLYMARK_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "processor": "stripe",
  "payment_method_id": "0abcDEF1234567890xyzAB",
  "amount": 2500
}'
```

### Example response

```json
{
  "id": "0abcDEF1234567890xyzAB",
  "number": "AB-0001",
  "status": "draft",
  "client_id": "0abcDEF1234567890xyzAB",
  "client": {
    "id": "0abcDEF1234567890xyzAB",
    "name": "Jane Doe",
    "emails": [
      "jane@example.com"
    ],
    "address": "1 Main St",
    "currency": "usd",
    "language": "en",
    "default_payment_method_id": null,
    "created_at": "2024-06-15T12:00:00.000000Z",
    "updated_at": "2024-06-15T12:00:00.000000Z",
    "is_deleted": false
  },
  "currency": "usd",
  "language": "en",
  "date": "2024-06-15",
  "notes": "these are the notes",
  "items": [
    {
      "description": "Design work",
      "amount": 10000,
      "quantity": "1",
      "total": 10000
    }
  ],
  "discounts": [],
  "discount_amount": 0,
  "taxable_amount": 10000,
  "tax_rates": [],
  "tax_amount": 0,
  "subtotal": 10000,
  "total": 10000,
  "amount_paid": 0,
  "amount_refunded": 0,
  "amount_remaining": 10000,
  "accept_cards": false,
  "sent_at": null,
  "paid_at": null,
  "created_at": "2024-06-15T12:00:00.000000Z",
  "updated_at": "2024-06-15T12:00:00.000000Z",
  "is_deleted": false
}
```

## Refund an invoice

`POST /invoices/{id}/refund`

Refunds `amount` cents, or everything still refundable
(`amount_paid` − `amount_refunded`) when `amount` is omitted. Card
payments are refunded to the card. Refunding doesn't change `status`
or `amount_remaining`; check `amount_refunded`. The client is emailed
when the account notifies clients.

### Path parameters

- `id` (string, required): The invoice ID. Example: `0abcDEF1234567890xyzAB`.

### Request body

- `amount` (integer or null): Omit (or null) to refund everything still refundable. Example: `10000`. Min 1.

### Response

- `200`: Refunded invoice. Returns a [invoice object](#the-invoice-object).

### Errors

- `400` `amount_too_large`: The amount is more than what is left to refund on this invoice.
- `400` `request_failed`: Your request could not be processed.
- `400` `api_version_unsupported`: The requested API version is not supported. Current version: 2026-08-21
- `401` `api_key_missing`: The API key is missing.
- `401` `api_key_invalid`: The API key is invalid or has been revoked.
- `402` `refund_failed`: The invoice could not be refunded.
- `403` `api_key_read_only`: This API key is read-only and cannot make write requests.
- `404`: The record doesn't exist or was deleted.
- `409` `nothing_to_refund`: This invoice has no payments left to refund.
- `409` `stripe_not_connected`: This account has not connected Stripe.
- `422`: The request body or query parameters are invalid.
- `429`: Too many requests. The limit is 300 requests per 5 minutes.

### Example request

```bash
curl -X POST https://api.tallymark.com/invoices/0abcDEF1234567890xyzAB/refund \
  -H "Authorization: Bearer $TALLYMARK_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "amount": 2500
}'
```

### Example response

```json
{
  "id": "0abcDEF1234567890xyzAB",
  "number": "AB-0001",
  "status": "draft",
  "client_id": "0abcDEF1234567890xyzAB",
  "client": {
    "id": "0abcDEF1234567890xyzAB",
    "name": "Jane Doe",
    "emails": [
      "jane@example.com"
    ],
    "address": "1 Main St",
    "currency": "usd",
    "language": "en",
    "default_payment_method_id": null,
    "created_at": "2024-06-15T12:00:00.000000Z",
    "updated_at": "2024-06-15T12:00:00.000000Z",
    "is_deleted": false
  },
  "currency": "usd",
  "language": "en",
  "date": "2024-06-15",
  "notes": "these are the notes",
  "items": [
    {
      "description": "Design work",
      "amount": 10000,
      "quantity": "1",
      "total": 10000
    }
  ],
  "discounts": [],
  "discount_amount": 0,
  "taxable_amount": 10000,
  "tax_rates": [],
  "tax_amount": 0,
  "subtotal": 10000,
  "total": 10000,
  "amount_paid": 0,
  "amount_refunded": 0,
  "amount_remaining": 10000,
  "accept_cards": false,
  "sent_at": null,
  "paid_at": null,
  "created_at": "2024-06-15T12:00:00.000000Z",
  "updated_at": "2024-06-15T12:00:00.000000Z",
  "is_deleted": false
}
```
