{
  "openapi": "3.1.0",
  "info": {
    "title": "Invoice-AI API",
    "version": "1.0.0",
    "description": "Stripe-shaped invoicing over HTTP: customers, products, prices, invoices and invoice items, with `cus_…`, `prod_…`, `price_…`, `in_…` and `ii_…` ids.\n\n- **Auth:** `Authorization: Bearer inv_live_…`, with per-key scopes.\n- **Envelope:** JSON bodies; responses wrap the resource in `{ \"data\": … }`; lists add `next_cursor`.\n- **Money:** integer minor units of the currency everywhere (`250000` is $2,500.00; ¥5,000 is `5000`).\n- **Errors:** RFC 9457 `application/problem+json` — branch on `code`.\n- **Idempotency:** operations that spend an invoice number, email or record payment require an `Idempotency-Key`.\n- **Rate limits:** 120 requests/minute per key. Sending email: 10/hour per key and 50/hour per account. See the `RateLimit-*` headers.",
    "contact": {
      "name": "Invoice-AI support",
      "url": "https://invoice.horizonpay.co"
    }
  },
  "servers": [
    {
      "url": "https://invoice.horizonpay.co/api/v1",
      "description": "Production"
    }
  ],
  "tags": [
    {
      "name": "Business",
      "x-displayName": "Business",
      "description": "Your business profile — the issuer printed on every invoice. Read-only over the API; edit it in Settings."
    },
    {
      "name": "Customers",
      "x-displayName": "Customers",
      "description": "The people and companies you bill. Every invoice references a customer by `cus_…` id. Customers are archived rather than deleted, so issued invoices keep naming who they were billed to."
    },
    {
      "name": "Products",
      "x-displayName": "Products",
      "description": "The things you sell. A product carries a name and description; amounts live on its prices. Archiving sets `active: false` and keeps history intact."
    },
    {
      "name": "Prices",
      "x-displayName": "Prices",
      "description": "Ways to charge for a product: an amount in integer minor units and a currency, one-time or recurring. Bill a price on an invoice line with `price: \"price_…\"`."
    },
    {
      "name": "Invoices",
      "x-displayName": "Invoices",
      "description": "Invoices move `draft` → `open` (finalize assigns a permanent, consecutive number) → `paid`, or `open` → `void`. Drafts are freely editable and deletable; finalized invoices are frozen. `overdue` is an open invoice past its due date, derived at read time. Operations that spend a number, send email or record payment require an `Idempotency-Key`."
    },
    {
      "name": "Invoice items",
      "x-displayName": "Invoice items",
      "description": "Individual lines of an invoice. Add or remove lines on a draft one at a time; totals are recomputed server-side and the whole invoice is returned."
    },
    {
      "name": "Webhook endpoints",
      "x-displayName": "Webhook endpoints",
      "description": "Register https endpoints to receive invoice events (`invoice.created`, `invoice.finalized`, `invoice.paid`, …). Deliveries are signed per [Standard Webhooks](https://www.standardwebhooks.com/) with `webhook-id`, `webhook-timestamp` and `webhook-signature` headers (HMAC-SHA256 over `{id}.{timestamp}.{body}`); failed deliveries are retried with backoff."
    }
  ],
  "security": [
    {
      "apiKey": []
    }
  ],
  "paths": {
    "/business": {
      "get": {
        "operationId": "getBusiness",
        "summary": "Retrieve the business profile",
        "tags": [
          "Business"
        ],
        "description": "Returns your business profile — the issuer printed on every invoice: legal name, address, tax id, default currency, bank details and invoice prefix. Read-only over the API; edit it in Settings.\n\n**Scope:** `business:read`",
        "x-required-scope": "business:read",
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "cURL",
            "source": "curl https://invoice.horizonpay.co/api/v1/business \\\n  -H \"Authorization: Bearer $INVOICE_AI_API_KEY\""
          },
          {
            "lang": "node",
            "label": "Node.js",
            "source": "import InvoiceAI from '@horizonpay/invoice-ai'\n\nconst invoiceai = new InvoiceAI() // reads INVOICE_AI_API_KEY\n\nconst business = await invoiceai.business.retrieve()\nconsole.log(business.legal_name, business.currency)"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "from invoice_ai import InvoiceAI\n\nclient = InvoiceAI()  # reads INVOICE_AI_API_KEY\n\nbusiness = client.business.retrieve()\nprint(business.legal_name, business.currency)"
          }
        ],
        "responses": {
          "200": {
            "description": "The business profile.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "example": {
                  "data": {
                    "id": "0c6f2d8e-3a41-4b9e-8f17-5d2a9c4e1b73",
                    "legal_name": "Horizon Consulting LLC",
                    "trade_name": "Horizon",
                    "country_code": "US",
                    "currency": "USD",
                    "tax_id": "US-EIN 98-7654321",
                    "address": {
                      "line1": "500 Congress Ave",
                      "line2": "Suite 1200",
                      "city": "Austin",
                      "region": "TX",
                      "postal_code": "78701",
                      "country_code": "US",
                      "country": "United States"
                    },
                    "email": "billing@horizon.example",
                    "phone": "+1 512 555 0199",
                    "bank": {
                      "bank_name": "First Austin Bank",
                      "account_name": "Horizon Consulting LLC",
                      "account_number": "000123456789",
                      "routing_number": "111000025"
                    },
                    "invoice_prefix": "INV",
                    "created_at": "2026-01-05T12:00:00.000Z"
                  }
                },
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "description": "The business profile.",
                      "$ref": "#/components/schemas/Business"
                    }
                  },
                  "required": [
                    "data"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "description": "No business profile yet — onboarding is unfinished. Another account's resource is also a `404`, so ids cannot be probed. Codes: `not_found`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "not_found": {
                    "summary": "No business profile yet. Finish onboarding first.",
                    "value": {
                      "type": "https://invoice.horizonpay.co/problems/not-found",
                      "title": "Not found",
                      "status": 404,
                      "detail": "No business profile yet. Finish onboarding first.",
                      "instance": "req_7f3c9a1e2b4d4e8a9c6f2d1b0a3e5f71",
                      "code": "not_found"
                    }
                  }
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/customers": {
      "get": {
        "operationId": "listCustomers",
        "summary": "List customers",
        "tags": [
          "Customers"
        ],
        "description": "Lists customers, newest first. Archived customers are left out unless `include_deleted=true`.\n\n**Scope:** `clients:read`",
        "x-required-scope": "clients:read",
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "cURL",
            "source": "curl \"https://invoice.horizonpay.co/api/v1/customers?query=acme\" \\\n  -H \"Authorization: Bearer $INVOICE_AI_API_KEY\""
          },
          {
            "lang": "node",
            "label": "Node.js",
            "source": "import InvoiceAI from '@horizonpay/invoice-ai'\n\nconst invoiceai = new InvoiceAI() // reads INVOICE_AI_API_KEY\n\nfor await (const customer of invoiceai.customers.list({ query: 'acme' })) {\n  console.log(customer.id, customer.name)\n}"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "from invoice_ai import InvoiceAI\n\nclient = InvoiceAI()  # reads INVOICE_AI_API_KEY\n\nfor customer in client.customers.list(query=\"acme\"):\n    print(customer.id, customer.name)"
          }
        ],
        "parameters": [
          {
            "in": "query",
            "name": "cursor",
            "schema": {
              "description": "The `next_cursor` from the previous page. Opaque — do not build it yourself.",
              "type": "string"
            },
            "description": "The `next_cursor` from the previous page. Opaque — do not build it yourself."
          },
          {
            "in": "query",
            "name": "limit",
            "schema": {
              "default": 25,
              "description": "Page size, 1–100. Defaults to 25.",
              "type": "integer",
              "minimum": 1,
              "maximum": 100
            },
            "description": "Page size, 1–100. Defaults to 25."
          },
          {
            "in": "query",
            "name": "query",
            "schema": {
              "description": "Case-insensitive substring match on `name`.",
              "examples": [
                "acme"
              ],
              "type": "string"
            },
            "description": "Case-insensitive substring match on `name`."
          },
          {
            "in": "query",
            "name": "include_deleted",
            "schema": {
              "description": "Include archived customers. Only the literal `true` enables it.",
              "type": "boolean"
            },
            "description": "Include archived customers. Only the literal `true` enables it."
          }
        ],
        "responses": {
          "200": {
            "description": "A page of customers.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "example": {
                  "data": [
                    {
                      "id": "cus_Nf3kQ8pR2mX7vB1cT9wL4sZ6",
                      "object": "customer",
                      "name": "Acme Industries",
                      "email": "ap@acme.example",
                      "phone": null,
                      "tax_id": "US-EIN 12-3456789",
                      "address": {
                        "line1": "4th Floor, Market Tower",
                        "line2": null,
                        "city": "Austin",
                        "state": "TX",
                        "postal_code": "73301",
                        "country": "US"
                      },
                      "deleted": false,
                      "created": "2026-09-22T09:30:00.000Z"
                    }
                  ],
                  "next_cursor": null
                },
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Customer"
                      },
                      "description": "Customers, newest first."
                    },
                    "next_cursor": {
                      "anyOf": [
                        {
                          "type": "string"
                        },
                        {
                          "type": "null"
                        }
                      ],
                      "description": "Pass as `cursor` to fetch the next page. `null` on the last page.",
                      "examples": [
                        "MjAyNi0wOS0yMlQwOTozMDowMC4wMDBafDdmM2M"
                      ]
                    }
                  },
                  "required": [
                    "data",
                    "next_cursor"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "422": {
            "description": "`cursor` is not a `next_cursor` this API returned. Codes: `validation`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "validation": {
                    "summary": "The cursor is not valid.",
                    "value": {
                      "type": "https://invoice.horizonpay.co/problems/validation",
                      "title": "Validation failed",
                      "status": 422,
                      "detail": "The cursor is not valid.",
                      "instance": "req_7f3c9a1e2b4d4e8a9c6f2d1b0a3e5f71",
                      "code": "validation",
                      "errors": [
                        {
                          "path": "cursor",
                          "message": "Pass the `next_cursor` from the previous page, unchanged."
                        }
                      ]
                    }
                  }
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      },
      "post": {
        "operationId": "createCustomer",
        "summary": "Create a customer",
        "tags": [
          "Customers"
        ],
        "description": "Creates a customer to bill. Only `name` is required. Calls are not deduplicated: the same name twice makes two customers.\n\n**Scope:** `clients:write`\n\n**Idempotency:** `Idempotency-Key` optional. With one, a retry with the same key and body replays the first response (`Idempotent-Replayed: true`); the same key with a different body is a `422` `idempotency_mismatch`.",
        "x-required-scope": "clients:write",
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "cURL",
            "source": "curl https://invoice.horizonpay.co/api/v1/customers \\\n  -H \"Authorization: Bearer $INVOICE_AI_API_KEY\" \\\n  -H \"Idempotency-Key: $(uuidgen)\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n    \"name\": \"Acme Industries\",\n    \"tax_id\": \"US-EIN 12-3456789\",\n    \"email\": \"ap@acme.example\",\n    \"address\": {\n      \"line1\": \"4th Floor, Market Tower\",\n      \"city\": \"Austin\",\n      \"state\": \"TX\",\n      \"postal_code\": \"73301\",\n      \"country\": \"US\"\n    }\n  }'"
          },
          {
            "lang": "node",
            "label": "Node.js",
            "source": "import InvoiceAI from '@horizonpay/invoice-ai'\n\nconst invoiceai = new InvoiceAI() // reads INVOICE_AI_API_KEY\n\nconst customer = await invoiceai.customers.create({\n  name: 'Acme Industries',\n  tax_id: 'US-EIN 12-3456789',\n  email: 'ap@acme.example',\n  address: {\n    line1: '4th Floor, Market Tower',\n    city: 'Austin',\n    state: 'TX',\n    postal_code: '73301',\n    country: 'US',\n  },\n})\nconsole.log(customer.id)"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "from invoice_ai import InvoiceAI\n\nclient = InvoiceAI()  # reads INVOICE_AI_API_KEY\n\ncustomer = client.customers.create(\n    name=\"Acme Industries\",\n    tax_id=\"US-EIN 12-3456789\",\n    email=\"ap@acme.example\",\n    address={\n        \"line1\": \"4th Floor, Market Tower\",\n        \"city\": \"Austin\",\n        \"state\": \"TX\",\n        \"postal_code\": \"73301\",\n        \"country\": \"US\",\n    },\n)\nprint(customer.id)"
          }
        ],
        "parameters": [
          {
            "in": "header",
            "name": "Idempotency-Key",
            "schema": {
              "description": "A unique key per distinct operation (a UUID works), reused only when retrying that same request. Up to 255 characters; stored for 24 hours.",
              "examples": [
                "6f1c2d9e-8a4b-4c3f-9e7d-2b5a1c8f4e30"
              ],
              "type": "string",
              "maxLength": 255
            },
            "description": "A unique key per distinct operation (a UUID works), reused only when retrying that same request. Up to 255 characters; stored for 24 hours."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "example": {
                "name": "Acme Industries",
                "tax_id": "US-EIN 12-3456789",
                "email": "ap@acme.example",
                "address": {
                  "line1": "4th Floor, Market Tower",
                  "city": "Austin",
                  "state": "TX",
                  "postal_code": "73301",
                  "country": "US"
                }
              },
              "schema": {
                "$ref": "#/components/schemas/CustomerCreate"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "The created customer.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "Idempotent-Replayed": {
                "$ref": "#/components/headers/IdempotentReplayed"
              }
            },
            "content": {
              "application/json": {
                "example": {
                  "data": {
                    "id": "cus_Nf3kQ8pR2mX7vB1cT9wL4sZ6",
                    "object": "customer",
                    "name": "Acme Industries",
                    "email": "ap@acme.example",
                    "phone": null,
                    "tax_id": "US-EIN 12-3456789",
                    "address": {
                      "line1": "4th Floor, Market Tower",
                      "line2": null,
                      "city": "Austin",
                      "state": "TX",
                      "postal_code": "73301",
                      "country": "US"
                    },
                    "deleted": false,
                    "created": "2026-09-22T09:30:00.000Z"
                  }
                },
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "description": "The created customer.",
                      "$ref": "#/components/schemas/Customer"
                    }
                  },
                  "required": [
                    "data"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "409": {
            "description": "A request with the same Idempotency-Key is still running. Codes: `conflict`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "conflict": {
                    "summary": "A request with this Idempotency-Key is still in flight. Retry in a moment.",
                    "value": {
                      "type": "https://invoice.horizonpay.co/problems/conflict",
                      "title": "Conflict",
                      "status": 409,
                      "detail": "A request with this Idempotency-Key is still in flight. Retry in a moment.",
                      "instance": "req_7f3c9a1e2b4d4e8a9c6f2d1b0a3e5f71",
                      "code": "conflict"
                    }
                  }
                }
              }
            }
          },
          "422": {
            "description": "The body failed validation, or the Idempotency-Key was reused with a different body. Codes: `validation`, `idempotency_mismatch`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "validation_1": {
                    "summary": "Some fields need attention.",
                    "value": {
                      "type": "https://invoice.horizonpay.co/problems/validation",
                      "title": "Validation failed",
                      "status": 422,
                      "detail": "Some fields need attention.",
                      "instance": "req_7f3c9a1e2b4d4e8a9c6f2d1b0a3e5f71",
                      "code": "validation",
                      "errors": [
                        {
                          "path": "email",
                          "message": "Enter a valid email"
                        }
                      ]
                    }
                  },
                  "idempotency_mismatch_2": {
                    "summary": "This Idempotency-Key was already used with a different request body.",
                    "value": {
                      "type": "https://invoice.horizonpay.co/problems/idempotency-mismatch",
                      "title": "Idempotency-Key reused",
                      "status": 422,
                      "detail": "This Idempotency-Key was already used with a different request body.",
                      "instance": "req_7f3c9a1e2b4d4e8a9c6f2d1b0a3e5f71",
                      "code": "idempotency_mismatch",
                      "errors": [
                        {
                          "path": "Idempotency-Key",
                          "message": "Generate a new key per distinct request, not per retry loop."
                        }
                      ]
                    }
                  }
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/customers/{id}": {
      "get": {
        "operationId": "retrieveCustomer",
        "summary": "Retrieve a customer",
        "tags": [
          "Customers"
        ],
        "description": "Returns a customer by `cus_…` id or UUID, including archived ones (`deleted: true`).\n\n**Scope:** `clients:read`",
        "x-required-scope": "clients:read",
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "cURL",
            "source": "curl https://invoice.horizonpay.co/api/v1/customers/cus_Nf3kQ8pR2mX7vB1cT9wL4sZ6 \\\n  -H \"Authorization: Bearer $INVOICE_AI_API_KEY\""
          },
          {
            "lang": "node",
            "label": "Node.js",
            "source": "import InvoiceAI from '@horizonpay/invoice-ai'\n\nconst invoiceai = new InvoiceAI() // reads INVOICE_AI_API_KEY\n\nconst customer = await invoiceai.customers.retrieve('cus_Nf3kQ8pR2mX7vB1cT9wL4sZ6')\nconsole.log(customer.name, customer.email)"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "from invoice_ai import InvoiceAI\n\nclient = InvoiceAI()  # reads INVOICE_AI_API_KEY\n\ncustomer = client.customers.retrieve(\"cus_Nf3kQ8pR2mX7vB1cT9wL4sZ6\")\nprint(customer.name, customer.email)"
          }
        ],
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "schema": {
              "type": "string",
              "description": "The customer, `cus_…` or UUID.",
              "examples": [
                "cus_Nf3kQ8pR2mX7vB1cT9wL4sZ6"
              ]
            },
            "required": true,
            "description": "The customer, `cus_…` or UUID."
          }
        ],
        "responses": {
          "200": {
            "description": "The customer.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "example": {
                  "data": {
                    "id": "cus_Nf3kQ8pR2mX7vB1cT9wL4sZ6",
                    "object": "customer",
                    "name": "Acme Industries",
                    "email": "ap@acme.example",
                    "phone": null,
                    "tax_id": "US-EIN 12-3456789",
                    "address": {
                      "line1": "4th Floor, Market Tower",
                      "line2": null,
                      "city": "Austin",
                      "state": "TX",
                      "postal_code": "73301",
                      "country": "US"
                    },
                    "deleted": false,
                    "created": "2026-09-22T09:30:00.000Z"
                  }
                },
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "description": "The customer.",
                      "$ref": "#/components/schemas/Customer"
                    }
                  },
                  "required": [
                    "data"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "description": "No such customer. Another account's resource is also a `404`, so ids cannot be probed. Codes: `not_found`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "not_found": {
                    "summary": "Client not found.",
                    "value": {
                      "type": "https://invoice.horizonpay.co/problems/not-found",
                      "title": "Not found",
                      "status": 404,
                      "detail": "Client not found.",
                      "instance": "req_7f3c9a1e2b4d4e8a9c6f2d1b0a3e5f71",
                      "code": "not_found"
                    }
                  }
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      },
      "patch": {
        "operationId": "updateCustomer",
        "summary": "Update a customer",
        "tags": [
          "Customers"
        ],
        "description": "Updates the fields you send and leaves the rest unchanged. Issued invoices keep the customer details they were billed with. No `Idempotency-Key` needed — repeating the call is harmless.\n\n**Scope:** `clients:write`",
        "x-required-scope": "clients:write",
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "cURL",
            "source": "curl -X PATCH https://invoice.horizonpay.co/api/v1/customers/cus_Nf3kQ8pR2mX7vB1cT9wL4sZ6 \\\n  -H \"Authorization: Bearer $INVOICE_AI_API_KEY\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{ \"phone\": \"+1 512 555 0100\" }'"
          },
          {
            "lang": "node",
            "label": "Node.js",
            "source": "import InvoiceAI from '@horizonpay/invoice-ai'\n\nconst invoiceai = new InvoiceAI() // reads INVOICE_AI_API_KEY\n\nconst customer = await invoiceai.customers.update('cus_Nf3kQ8pR2mX7vB1cT9wL4sZ6', {\n  phone: '+1 512 555 0100',\n})\nconsole.log(customer.phone)"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "from invoice_ai import InvoiceAI\n\nclient = InvoiceAI()  # reads INVOICE_AI_API_KEY\n\ncustomer = client.customers.update(\n    \"cus_Nf3kQ8pR2mX7vB1cT9wL4sZ6\",\n    phone=\"+1 512 555 0100\",\n)\nprint(customer.phone)"
          }
        ],
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "schema": {
              "type": "string",
              "description": "The customer, `cus_…` or UUID.",
              "examples": [
                "cus_Nf3kQ8pR2mX7vB1cT9wL4sZ6"
              ]
            },
            "required": true,
            "description": "The customer, `cus_…` or UUID."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "example": {
                "phone": "+1 512 555 0100"
              },
              "schema": {
                "$ref": "#/components/schemas/CustomerUpdate"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The updated customer.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "example": {
                  "data": {
                    "id": "cus_Nf3kQ8pR2mX7vB1cT9wL4sZ6",
                    "object": "customer",
                    "name": "Acme Industries",
                    "email": "ap@acme.example",
                    "phone": "+1 512 555 0100",
                    "tax_id": "US-EIN 12-3456789",
                    "address": {
                      "line1": "4th Floor, Market Tower",
                      "line2": null,
                      "city": "Austin",
                      "state": "TX",
                      "postal_code": "73301",
                      "country": "US"
                    },
                    "deleted": false,
                    "created": "2026-09-22T09:30:00.000Z"
                  }
                },
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "description": "The updated customer.",
                      "$ref": "#/components/schemas/Customer"
                    }
                  },
                  "required": [
                    "data"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "description": "No such customer. Another account's resource is also a `404`, so ids cannot be probed. Codes: `not_found`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "not_found": {
                    "summary": "Client not found.",
                    "value": {
                      "type": "https://invoice.horizonpay.co/problems/not-found",
                      "title": "Not found",
                      "status": 404,
                      "detail": "Client not found.",
                      "instance": "req_7f3c9a1e2b4d4e8a9c6f2d1b0a3e5f71",
                      "code": "not_found"
                    }
                  }
                }
              }
            }
          },
          "422": {
            "description": "The body failed validation. Codes: `validation`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "validation": {
                    "summary": "Some fields need attention.",
                    "value": {
                      "type": "https://invoice.horizonpay.co/problems/validation",
                      "title": "Validation failed",
                      "status": 422,
                      "detail": "Some fields need attention.",
                      "instance": "req_7f3c9a1e2b4d4e8a9c6f2d1b0a3e5f71",
                      "code": "validation",
                      "errors": [
                        {
                          "path": "name",
                          "message": "Enter your customer's name"
                        }
                      ]
                    }
                  }
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      },
      "delete": {
        "operationId": "deleteCustomer",
        "summary": "Archive a customer",
        "tags": [
          "Customers"
        ],
        "description": "Archives a customer (`deleted: true`). Customers are never hard-deleted, because issued invoices must keep naming who they billed. Archived customers drop out of `GET /customers` but stay readable by id; archiving twice changes nothing.\n\n**Scope:** `clients:write`",
        "x-required-scope": "clients:write",
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "cURL",
            "source": "curl -X DELETE https://invoice.horizonpay.co/api/v1/customers/cus_Nf3kQ8pR2mX7vB1cT9wL4sZ6 \\\n  -H \"Authorization: Bearer $INVOICE_AI_API_KEY\""
          },
          {
            "lang": "node",
            "label": "Node.js",
            "source": "import InvoiceAI from '@horizonpay/invoice-ai'\n\nconst invoiceai = new InvoiceAI() // reads INVOICE_AI_API_KEY\n\nconst customer = await invoiceai.customers.del('cus_Nf3kQ8pR2mX7vB1cT9wL4sZ6')\nconsole.log(customer.deleted)"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "from invoice_ai import InvoiceAI\n\nclient = InvoiceAI()  # reads INVOICE_AI_API_KEY\n\ncustomer = client.customers.delete(\"cus_Nf3kQ8pR2mX7vB1cT9wL4sZ6\")\nprint(customer.deleted)"
          }
        ],
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "schema": {
              "type": "string",
              "description": "The customer, `cus_…` or UUID.",
              "examples": [
                "cus_Nf3kQ8pR2mX7vB1cT9wL4sZ6"
              ]
            },
            "required": true,
            "description": "The customer, `cus_…` or UUID."
          }
        ],
        "responses": {
          "200": {
            "description": "The archived customer.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "example": {
                  "data": {
                    "id": "cus_Nf3kQ8pR2mX7vB1cT9wL4sZ6",
                    "object": "customer",
                    "name": "Acme Industries",
                    "email": "ap@acme.example",
                    "phone": null,
                    "tax_id": "US-EIN 12-3456789",
                    "address": {
                      "line1": "4th Floor, Market Tower",
                      "line2": null,
                      "city": "Austin",
                      "state": "TX",
                      "postal_code": "73301",
                      "country": "US"
                    },
                    "deleted": true,
                    "created": "2026-09-22T09:30:00.000Z"
                  }
                },
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "description": "The archived customer.",
                      "$ref": "#/components/schemas/Customer"
                    }
                  },
                  "required": [
                    "data"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "description": "No such customer. Another account's resource is also a `404`, so ids cannot be probed. Codes: `not_found`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "not_found": {
                    "summary": "Client not found.",
                    "value": {
                      "type": "https://invoice.horizonpay.co/problems/not-found",
                      "title": "Not found",
                      "status": 404,
                      "detail": "Client not found.",
                      "instance": "req_7f3c9a1e2b4d4e8a9c6f2d1b0a3e5f71",
                      "code": "not_found"
                    }
                  }
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/products": {
      "get": {
        "operationId": "listProducts",
        "summary": "List products",
        "tags": [
          "Products"
        ],
        "description": "Lists products, newest first. Archived products are included unless you filter with `active`.\n\n**Scope:** `products:read`",
        "x-required-scope": "products:read",
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "cURL",
            "source": "curl \"https://invoice.horizonpay.co/api/v1/products?active=true\" \\\n  -H \"Authorization: Bearer $INVOICE_AI_API_KEY\""
          },
          {
            "lang": "node",
            "label": "Node.js",
            "source": "import InvoiceAI from '@horizonpay/invoice-ai'\n\nconst invoiceai = new InvoiceAI() // reads INVOICE_AI_API_KEY\n\nfor await (const product of invoiceai.products.list({ active: true })) {\n  console.log(product.id, product.name)\n}"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "from invoice_ai import InvoiceAI\n\nclient = InvoiceAI()  # reads INVOICE_AI_API_KEY\n\nfor product in client.products.list(active=True):\n    print(product.id, product.name)"
          }
        ],
        "parameters": [
          {
            "in": "query",
            "name": "cursor",
            "schema": {
              "description": "The `next_cursor` from the previous page. Opaque — do not build it yourself.",
              "type": "string"
            },
            "description": "The `next_cursor` from the previous page. Opaque — do not build it yourself."
          },
          {
            "in": "query",
            "name": "limit",
            "schema": {
              "default": 25,
              "description": "Page size, 1–100. Defaults to 25.",
              "type": "integer",
              "minimum": 1,
              "maximum": 100
            },
            "description": "Page size, 1–100. Defaults to 25."
          },
          {
            "in": "query",
            "name": "query",
            "schema": {
              "description": "Case-insensitive substring match on `name`.",
              "examples": [
                "consulting"
              ],
              "type": "string"
            },
            "description": "Case-insensitive substring match on `name`."
          },
          {
            "in": "query",
            "name": "active",
            "schema": {
              "description": "`true` for active products only, `false` for archived only. Omit for both.",
              "type": "boolean"
            },
            "description": "`true` for active products only, `false` for archived only. Omit for both."
          }
        ],
        "responses": {
          "200": {
            "description": "A page of products.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "example": {
                  "data": [
                    {
                      "id": "prod_Hy7Rq2Lm9Xc4Vb8Nt3Kd6Pw1",
                      "object": "product",
                      "name": "Consulting retainer",
                      "description": "Monthly advisory block.",
                      "images": [],
                      "active": true,
                      "created": "2026-09-22T09:30:00.000Z",
                      "updated": "2026-09-22T09:30:00.000Z"
                    }
                  ],
                  "next_cursor": null
                },
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Product"
                      },
                      "description": "Products, newest first."
                    },
                    "next_cursor": {
                      "anyOf": [
                        {
                          "type": "string"
                        },
                        {
                          "type": "null"
                        }
                      ],
                      "description": "Pass as `cursor` to fetch the next page. `null` on the last page.",
                      "examples": [
                        "MjAyNi0wOS0yMlQwOTozMDowMC4wMDBafDdmM2M"
                      ]
                    }
                  },
                  "required": [
                    "data",
                    "next_cursor"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "422": {
            "description": "`cursor` is not a `next_cursor` this API returned. Codes: `validation`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "validation": {
                    "summary": "The cursor is not valid.",
                    "value": {
                      "type": "https://invoice.horizonpay.co/problems/validation",
                      "title": "Validation failed",
                      "status": 422,
                      "detail": "The cursor is not valid.",
                      "instance": "req_7f3c9a1e2b4d4e8a9c6f2d1b0a3e5f71",
                      "code": "validation",
                      "errors": [
                        {
                          "path": "cursor",
                          "message": "Pass the `next_cursor` from the previous page, unchanged."
                        }
                      ]
                    }
                  }
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      },
      "post": {
        "operationId": "createProduct",
        "summary": "Create a product",
        "tags": [
          "Products"
        ],
        "description": "Creates a product. Amounts live on prices: add one with `POST /prices` before billing it.\n\n**Scope:** `products:write`\n\n**Idempotency:** `Idempotency-Key` optional. With one, a retry with the same key and body replays the first response (`Idempotent-Replayed: true`); the same key with a different body is a `422` `idempotency_mismatch`.",
        "x-required-scope": "products:write",
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "cURL",
            "source": "curl https://invoice.horizonpay.co/api/v1/products \\\n  -H \"Authorization: Bearer $INVOICE_AI_API_KEY\" \\\n  -H \"Idempotency-Key: $(uuidgen)\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n    \"name\": \"Consulting retainer\",\n    \"description\": \"Monthly advisory block.\"\n  }'"
          },
          {
            "lang": "node",
            "label": "Node.js",
            "source": "import InvoiceAI from '@horizonpay/invoice-ai'\n\nconst invoiceai = new InvoiceAI() // reads INVOICE_AI_API_KEY\n\nconst product = await invoiceai.products.create({\n  name: 'Consulting retainer',\n  description: 'Monthly advisory block.',\n})\nconsole.log(product.id)"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "from invoice_ai import InvoiceAI\n\nclient = InvoiceAI()  # reads INVOICE_AI_API_KEY\n\nproduct = client.products.create(\n    name=\"Consulting retainer\",\n    description=\"Monthly advisory block.\",\n)\nprint(product.id)"
          }
        ],
        "parameters": [
          {
            "in": "header",
            "name": "Idempotency-Key",
            "schema": {
              "description": "A unique key per distinct operation (a UUID works), reused only when retrying that same request. Up to 255 characters; stored for 24 hours.",
              "examples": [
                "6f1c2d9e-8a4b-4c3f-9e7d-2b5a1c8f4e30"
              ],
              "type": "string",
              "maxLength": 255
            },
            "description": "A unique key per distinct operation (a UUID works), reused only when retrying that same request. Up to 255 characters; stored for 24 hours."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "example": {
                "name": "Consulting retainer",
                "description": "Monthly advisory block."
              },
              "schema": {
                "$ref": "#/components/schemas/ProductCreate"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "The created product.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "Idempotent-Replayed": {
                "$ref": "#/components/headers/IdempotentReplayed"
              }
            },
            "content": {
              "application/json": {
                "example": {
                  "data": {
                    "id": "prod_Hy7Rq2Lm9Xc4Vb8Nt3Kd6Pw1",
                    "object": "product",
                    "name": "Consulting retainer",
                    "description": "Monthly advisory block.",
                    "images": [],
                    "active": true,
                    "created": "2026-09-22T09:30:00.000Z",
                    "updated": "2026-09-22T09:30:00.000Z"
                  }
                },
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "description": "The created product.",
                      "$ref": "#/components/schemas/Product"
                    }
                  },
                  "required": [
                    "data"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "409": {
            "description": "A request with the same Idempotency-Key is still running. Codes: `conflict`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "conflict": {
                    "summary": "A request with this Idempotency-Key is still in flight. Retry in a moment.",
                    "value": {
                      "type": "https://invoice.horizonpay.co/problems/conflict",
                      "title": "Conflict",
                      "status": 409,
                      "detail": "A request with this Idempotency-Key is still in flight. Retry in a moment.",
                      "instance": "req_7f3c9a1e2b4d4e8a9c6f2d1b0a3e5f71",
                      "code": "conflict"
                    }
                  }
                }
              }
            }
          },
          "422": {
            "description": "The body failed validation, or the Idempotency-Key was reused with a different body. Codes: `validation`, `idempotency_mismatch`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "validation_1": {
                    "summary": "Some fields need attention.",
                    "value": {
                      "type": "https://invoice.horizonpay.co/problems/validation",
                      "title": "Validation failed",
                      "status": 422,
                      "detail": "Some fields need attention.",
                      "instance": "req_7f3c9a1e2b4d4e8a9c6f2d1b0a3e5f71",
                      "code": "validation",
                      "errors": [
                        {
                          "path": "name",
                          "message": "Name your product"
                        }
                      ]
                    }
                  },
                  "idempotency_mismatch_2": {
                    "summary": "This Idempotency-Key was already used with a different request body.",
                    "value": {
                      "type": "https://invoice.horizonpay.co/problems/idempotency-mismatch",
                      "title": "Idempotency-Key reused",
                      "status": 422,
                      "detail": "This Idempotency-Key was already used with a different request body.",
                      "instance": "req_7f3c9a1e2b4d4e8a9c6f2d1b0a3e5f71",
                      "code": "idempotency_mismatch",
                      "errors": [
                        {
                          "path": "Idempotency-Key",
                          "message": "Generate a new key per distinct request, not per retry loop."
                        }
                      ]
                    }
                  }
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/products/{id}": {
      "get": {
        "operationId": "retrieveProduct",
        "summary": "Retrieve a product",
        "tags": [
          "Products"
        ],
        "description": "Returns a product by `prod_…` id or UUID, active or archived.\n\n**Scope:** `products:read`",
        "x-required-scope": "products:read",
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "cURL",
            "source": "curl https://invoice.horizonpay.co/api/v1/products/prod_Hy7Rq2Lm9Xc4Vb8Nt3Kd6Pw1 \\\n  -H \"Authorization: Bearer $INVOICE_AI_API_KEY\""
          },
          {
            "lang": "node",
            "label": "Node.js",
            "source": "import InvoiceAI from '@horizonpay/invoice-ai'\n\nconst invoiceai = new InvoiceAI() // reads INVOICE_AI_API_KEY\n\nconst product = await invoiceai.products.retrieve('prod_Hy7Rq2Lm9Xc4Vb8Nt3Kd6Pw1')\nconsole.log(product.name, product.active)"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "from invoice_ai import InvoiceAI\n\nclient = InvoiceAI()  # reads INVOICE_AI_API_KEY\n\nproduct = client.products.retrieve(\"prod_Hy7Rq2Lm9Xc4Vb8Nt3Kd6Pw1\")\nprint(product.name, product.active)"
          }
        ],
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "schema": {
              "type": "string",
              "description": "The product, `prod_…` or UUID.",
              "examples": [
                "prod_Hy7Rq2Lm9Xc4Vb8Nt3Kd6Pw1"
              ]
            },
            "required": true,
            "description": "The product, `prod_…` or UUID."
          }
        ],
        "responses": {
          "200": {
            "description": "The product.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "example": {
                  "data": {
                    "id": "prod_Hy7Rq2Lm9Xc4Vb8Nt3Kd6Pw1",
                    "object": "product",
                    "name": "Consulting retainer",
                    "description": "Monthly advisory block.",
                    "images": [],
                    "active": true,
                    "created": "2026-09-22T09:30:00.000Z",
                    "updated": "2026-09-22T09:30:00.000Z"
                  }
                },
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "description": "The product.",
                      "$ref": "#/components/schemas/Product"
                    }
                  },
                  "required": [
                    "data"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "description": "No such product. Another account's resource is also a `404`, so ids cannot be probed. Codes: `not_found`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "not_found": {
                    "summary": "Product not found.",
                    "value": {
                      "type": "https://invoice.horizonpay.co/problems/not-found",
                      "title": "Not found",
                      "status": 404,
                      "detail": "Product not found.",
                      "instance": "req_7f3c9a1e2b4d4e8a9c6f2d1b0a3e5f71",
                      "code": "not_found"
                    }
                  }
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      },
      "patch": {
        "operationId": "updateProduct",
        "summary": "Update a product",
        "tags": [
          "Products"
        ],
        "description": "Updates the fields you send and leaves the rest unchanged. Send `active: true` to restore an archived product. Finalized invoices keep the line descriptions they were issued with.\n\n**Scope:** `products:write`",
        "x-required-scope": "products:write",
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "cURL",
            "source": "curl -X PATCH https://invoice.horizonpay.co/api/v1/products/prod_Hy7Rq2Lm9Xc4Vb8Nt3Kd6Pw1 \\\n  -H \"Authorization: Bearer $INVOICE_AI_API_KEY\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{ \"description\": \"Monthly advisory block, up to 10 hours.\" }'"
          },
          {
            "lang": "node",
            "label": "Node.js",
            "source": "import InvoiceAI from '@horizonpay/invoice-ai'\n\nconst invoiceai = new InvoiceAI() // reads INVOICE_AI_API_KEY\n\nconst product = await invoiceai.products.update('prod_Hy7Rq2Lm9Xc4Vb8Nt3Kd6Pw1', {\n  description: 'Monthly advisory block, up to 10 hours.',\n})\nconsole.log(product.description)"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "from invoice_ai import InvoiceAI\n\nclient = InvoiceAI()  # reads INVOICE_AI_API_KEY\n\nproduct = client.products.update(\n    \"prod_Hy7Rq2Lm9Xc4Vb8Nt3Kd6Pw1\",\n    description=\"Monthly advisory block, up to 10 hours.\",\n)\nprint(product.description)"
          }
        ],
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "schema": {
              "type": "string",
              "description": "The product, `prod_…` or UUID.",
              "examples": [
                "prod_Hy7Rq2Lm9Xc4Vb8Nt3Kd6Pw1"
              ]
            },
            "required": true,
            "description": "The product, `prod_…` or UUID."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "example": {
                "description": "Monthly advisory block, up to 10 hours."
              },
              "schema": {
                "$ref": "#/components/schemas/ProductUpdate"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The updated product.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "example": {
                  "data": {
                    "id": "prod_Hy7Rq2Lm9Xc4Vb8Nt3Kd6Pw1",
                    "object": "product",
                    "name": "Consulting retainer",
                    "description": "Monthly advisory block, up to 10 hours.",
                    "images": [],
                    "active": true,
                    "created": "2026-09-22T09:30:00.000Z",
                    "updated": "2026-09-22T09:45:00.000Z"
                  }
                },
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "description": "The updated product.",
                      "$ref": "#/components/schemas/Product"
                    }
                  },
                  "required": [
                    "data"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "description": "No such product. Another account's resource is also a `404`, so ids cannot be probed. Codes: `not_found`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "not_found": {
                    "summary": "Product not found.",
                    "value": {
                      "type": "https://invoice.horizonpay.co/problems/not-found",
                      "title": "Not found",
                      "status": 404,
                      "detail": "Product not found.",
                      "instance": "req_7f3c9a1e2b4d4e8a9c6f2d1b0a3e5f71",
                      "code": "not_found"
                    }
                  }
                }
              }
            }
          },
          "422": {
            "description": "The body failed validation. Codes: `validation`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "validation": {
                    "summary": "Some fields need attention.",
                    "value": {
                      "type": "https://invoice.horizonpay.co/problems/validation",
                      "title": "Validation failed",
                      "status": 422,
                      "detail": "Some fields need attention.",
                      "instance": "req_7f3c9a1e2b4d4e8a9c6f2d1b0a3e5f71",
                      "code": "validation",
                      "errors": [
                        {
                          "path": "images.0",
                          "message": "Enter a valid image URL"
                        }
                      ]
                    }
                  }
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      },
      "delete": {
        "operationId": "archiveProduct",
        "summary": "Archive a product",
        "tags": [
          "Products"
        ],
        "description": "Archives a product (`active: false`). Its prices and the invoice lines that use it stay intact; archiving twice changes nothing. Restore with `PATCH` and `active: true`.\n\n**Scope:** `products:write`",
        "x-required-scope": "products:write",
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "cURL",
            "source": "curl -X DELETE https://invoice.horizonpay.co/api/v1/products/prod_Hy7Rq2Lm9Xc4Vb8Nt3Kd6Pw1 \\\n  -H \"Authorization: Bearer $INVOICE_AI_API_KEY\""
          },
          {
            "lang": "node",
            "label": "Node.js",
            "source": "import InvoiceAI from '@horizonpay/invoice-ai'\n\nconst invoiceai = new InvoiceAI() // reads INVOICE_AI_API_KEY\n\nconst product = await invoiceai.products.archive('prod_Hy7Rq2Lm9Xc4Vb8Nt3Kd6Pw1')\nconsole.log(product.active)"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "from invoice_ai import InvoiceAI\n\nclient = InvoiceAI()  # reads INVOICE_AI_API_KEY\n\nproduct = client.products.archive(\"prod_Hy7Rq2Lm9Xc4Vb8Nt3Kd6Pw1\")\nprint(product.active)"
          }
        ],
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "schema": {
              "type": "string",
              "description": "The product, `prod_…` or UUID.",
              "examples": [
                "prod_Hy7Rq2Lm9Xc4Vb8Nt3Kd6Pw1"
              ]
            },
            "required": true,
            "description": "The product, `prod_…` or UUID."
          }
        ],
        "responses": {
          "200": {
            "description": "The archived product.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "example": {
                  "data": {
                    "id": "prod_Hy7Rq2Lm9Xc4Vb8Nt3Kd6Pw1",
                    "object": "product",
                    "name": "Consulting retainer",
                    "description": "Monthly advisory block.",
                    "images": [],
                    "active": false,
                    "created": "2026-09-22T09:30:00.000Z",
                    "updated": "2026-09-22T09:45:00.000Z"
                  }
                },
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "description": "The archived product.",
                      "$ref": "#/components/schemas/Product"
                    }
                  },
                  "required": [
                    "data"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "description": "No such product. Another account's resource is also a `404`, so ids cannot be probed. Codes: `not_found`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "not_found": {
                    "summary": "Product not found.",
                    "value": {
                      "type": "https://invoice.horizonpay.co/problems/not-found",
                      "title": "Not found",
                      "status": 404,
                      "detail": "Product not found.",
                      "instance": "req_7f3c9a1e2b4d4e8a9c6f2d1b0a3e5f71",
                      "code": "not_found"
                    }
                  }
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/prices": {
      "get": {
        "operationId": "listPrices",
        "summary": "List prices",
        "tags": [
          "Prices"
        ],
        "description": "Lists prices, newest first, optionally filtered by `product`, `active`, `currency` or `type`. An unknown `product` is a `404`, not an empty page.\n\n**Scope:** `products:read`",
        "x-required-scope": "products:read",
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "cURL",
            "source": "curl \"https://invoice.horizonpay.co/api/v1/prices?product=prod_Hy7Rq2Lm9Xc4Vb8Nt3Kd6Pw1\" \\\n  -H \"Authorization: Bearer $INVOICE_AI_API_KEY\""
          },
          {
            "lang": "node",
            "label": "Node.js",
            "source": "import InvoiceAI from '@horizonpay/invoice-ai'\n\nconst invoiceai = new InvoiceAI() // reads INVOICE_AI_API_KEY\n\nfor await (const price of invoiceai.prices.list({\n  product: 'prod_Hy7Rq2Lm9Xc4Vb8Nt3Kd6Pw1',\n})) {\n  console.log(price.id, price.unit_amount, price.currency)\n}"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "from invoice_ai import InvoiceAI\n\nclient = InvoiceAI()  # reads INVOICE_AI_API_KEY\n\nfor price in client.prices.list(product=\"prod_Hy7Rq2Lm9Xc4Vb8Nt3Kd6Pw1\"):\n    print(price.id, price.unit_amount, price.currency)"
          }
        ],
        "parameters": [
          {
            "in": "query",
            "name": "cursor",
            "schema": {
              "description": "The `next_cursor` from the previous page. Opaque — do not build it yourself.",
              "type": "string"
            },
            "description": "The `next_cursor` from the previous page. Opaque — do not build it yourself."
          },
          {
            "in": "query",
            "name": "limit",
            "schema": {
              "default": 25,
              "description": "Page size, 1–100. Defaults to 25.",
              "type": "integer",
              "minimum": 1,
              "maximum": 100
            },
            "description": "Page size, 1–100. Defaults to 25."
          },
          {
            "in": "query",
            "name": "product",
            "schema": {
              "description": "Only prices of this product, `prod_…` or UUID.",
              "examples": [
                "prod_Hy7Rq2Lm9Xc4Vb8Nt3Kd6Pw1"
              ],
              "type": "string"
            },
            "description": "Only prices of this product, `prod_…` or UUID."
          },
          {
            "in": "query",
            "name": "active",
            "schema": {
              "description": "`true` for active prices only, `false` for archived only. Omit for both.",
              "type": "boolean"
            },
            "description": "`true` for active prices only, `false` for archived only. Omit for both."
          },
          {
            "in": "query",
            "name": "currency",
            "schema": {
              "description": "ISO 4217 code, case-insensitive.",
              "examples": [
                "USD"
              ],
              "type": "string"
            },
            "description": "ISO 4217 code, case-insensitive."
          },
          {
            "in": "query",
            "name": "type",
            "schema": {
              "description": "Only prices of this type. Other values are ignored.",
              "type": "string",
              "enum": [
                "one_time",
                "recurring"
              ]
            },
            "description": "Only prices of this type. Other values are ignored."
          }
        ],
        "responses": {
          "200": {
            "description": "A page of prices.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "example": {
                  "data": [
                    {
                      "id": "price_Jc5Tn8Wq1Ze6Ra3Ym9Ub2Gs7",
                      "object": "price",
                      "product": "prod_Hy7Rq2Lm9Xc4Vb8Nt3Kd6Pw1",
                      "nickname": "Monthly",
                      "unit_amount": 2500000,
                      "currency": "USD",
                      "billing_scheme": "per_unit",
                      "type": "recurring",
                      "recurring": {
                        "interval": "month",
                        "interval_count": 1
                      },
                      "tax_rate": 0,
                      "active": true,
                      "created": "2026-09-22T09:30:00.000Z"
                    }
                  ],
                  "next_cursor": null
                },
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Price"
                      },
                      "description": "Prices, newest first."
                    },
                    "next_cursor": {
                      "anyOf": [
                        {
                          "type": "string"
                        },
                        {
                          "type": "null"
                        }
                      ],
                      "description": "Pass as `cursor` to fetch the next page. `null` on the last page.",
                      "examples": [
                        "MjAyNi0wOS0yMlQwOTozMDowMC4wMDBafDdmM2M"
                      ]
                    }
                  },
                  "required": [
                    "data",
                    "next_cursor"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "description": "The `product` filter names no product. Another account's resource is also a `404`, so ids cannot be probed. Codes: `not_found`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "not_found": {
                    "summary": "Product not found.",
                    "value": {
                      "type": "https://invoice.horizonpay.co/problems/not-found",
                      "title": "Not found",
                      "status": 404,
                      "detail": "Product not found.",
                      "instance": "req_7f3c9a1e2b4d4e8a9c6f2d1b0a3e5f71",
                      "code": "not_found"
                    }
                  }
                }
              }
            }
          },
          "422": {
            "description": "`cursor` is not a `next_cursor` this API returned. Codes: `validation`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "validation": {
                    "summary": "The cursor is not valid.",
                    "value": {
                      "type": "https://invoice.horizonpay.co/problems/validation",
                      "title": "Validation failed",
                      "status": 422,
                      "detail": "The cursor is not valid.",
                      "instance": "req_7f3c9a1e2b4d4e8a9c6f2d1b0a3e5f71",
                      "code": "validation",
                      "errors": [
                        {
                          "path": "cursor",
                          "message": "Pass the `next_cursor` from the previous page, unchanged."
                        }
                      ]
                    }
                  }
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      },
      "post": {
        "operationId": "createPrice",
        "summary": "Create a price",
        "tags": [
          "Prices"
        ],
        "description": "Adds a price to a product. `unit_amount` is in integer minor units. A `recurring` price needs `recurring.interval`; it is stored for reporting — nothing auto-bills yet.\n\n**Scope:** `products:write`\n\n**Idempotency:** `Idempotency-Key` optional. With one, a retry with the same key and body replays the first response (`Idempotent-Replayed: true`); the same key with a different body is a `422` `idempotency_mismatch`.",
        "x-required-scope": "products:write",
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "cURL",
            "source": "curl https://invoice.horizonpay.co/api/v1/prices \\\n  -H \"Authorization: Bearer $INVOICE_AI_API_KEY\" \\\n  -H \"Idempotency-Key: $(uuidgen)\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n    \"product\": \"prod_Hy7Rq2Lm9Xc4Vb8Nt3Kd6Pw1\",\n    \"nickname\": \"Monthly\",\n    \"unit_amount\": 2500000,\n    \"currency\": \"USD\",\n    \"type\": \"recurring\",\n    \"recurring\": { \"interval\": \"month\", \"interval_count\": 1 },\n    \"tax_rate\": 0\n  }'"
          },
          {
            "lang": "node",
            "label": "Node.js",
            "source": "import InvoiceAI from '@horizonpay/invoice-ai'\n\nconst invoiceai = new InvoiceAI() // reads INVOICE_AI_API_KEY\n\nconst price = await invoiceai.prices.create({\n  product: 'prod_Hy7Rq2Lm9Xc4Vb8Nt3Kd6Pw1',\n  nickname: 'Monthly',\n  unit_amount: 2500000,\n  currency: 'USD',\n  type: 'recurring',\n  recurring: { interval: 'month', interval_count: 1 },\n  tax_rate: 0,\n})\nconsole.log(price.id)"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "from invoice_ai import InvoiceAI\n\nclient = InvoiceAI()  # reads INVOICE_AI_API_KEY\n\nprice = client.prices.create(\n    product=\"prod_Hy7Rq2Lm9Xc4Vb8Nt3Kd6Pw1\",\n    nickname=\"Monthly\",\n    unit_amount=2500000,\n    currency=\"USD\",\n    type=\"recurring\",\n    recurring={\"interval\": \"month\", \"interval_count\": 1},\n    tax_rate=0,\n)\nprint(price.id)"
          }
        ],
        "parameters": [
          {
            "in": "header",
            "name": "Idempotency-Key",
            "schema": {
              "description": "A unique key per distinct operation (a UUID works), reused only when retrying that same request. Up to 255 characters; stored for 24 hours.",
              "examples": [
                "6f1c2d9e-8a4b-4c3f-9e7d-2b5a1c8f4e30"
              ],
              "type": "string",
              "maxLength": 255
            },
            "description": "A unique key per distinct operation (a UUID works), reused only when retrying that same request. Up to 255 characters; stored for 24 hours."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "example": {
                "product": "prod_Hy7Rq2Lm9Xc4Vb8Nt3Kd6Pw1",
                "nickname": "Monthly",
                "unit_amount": 2500000,
                "currency": "USD",
                "type": "recurring",
                "recurring": {
                  "interval": "month",
                  "interval_count": 1
                },
                "tax_rate": 0
              },
              "schema": {
                "$ref": "#/components/schemas/PriceCreate"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "The created price.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "Idempotent-Replayed": {
                "$ref": "#/components/headers/IdempotentReplayed"
              }
            },
            "content": {
              "application/json": {
                "example": {
                  "data": {
                    "id": "price_Jc5Tn8Wq1Ze6Ra3Ym9Ub2Gs7",
                    "object": "price",
                    "product": "prod_Hy7Rq2Lm9Xc4Vb8Nt3Kd6Pw1",
                    "nickname": "Monthly",
                    "unit_amount": 2500000,
                    "currency": "USD",
                    "billing_scheme": "per_unit",
                    "type": "recurring",
                    "recurring": {
                      "interval": "month",
                      "interval_count": 1
                    },
                    "tax_rate": 0,
                    "active": true,
                    "created": "2026-09-22T09:30:00.000Z"
                  }
                },
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "description": "The created price.",
                      "$ref": "#/components/schemas/Price"
                    }
                  },
                  "required": [
                    "data"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "description": "`product` names no product. Another account's resource is also a `404`, so ids cannot be probed. Codes: `not_found`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "not_found": {
                    "summary": "Product not found.",
                    "value": {
                      "type": "https://invoice.horizonpay.co/problems/not-found",
                      "title": "Not found",
                      "status": 404,
                      "detail": "Product not found.",
                      "instance": "req_7f3c9a1e2b4d4e8a9c6f2d1b0a3e5f71",
                      "code": "not_found"
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "A request with the same Idempotency-Key is still running. Codes: `conflict`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "conflict": {
                    "summary": "A request with this Idempotency-Key is still in flight. Retry in a moment.",
                    "value": {
                      "type": "https://invoice.horizonpay.co/problems/conflict",
                      "title": "Conflict",
                      "status": 409,
                      "detail": "A request with this Idempotency-Key is still in flight. Retry in a moment.",
                      "instance": "req_7f3c9a1e2b4d4e8a9c6f2d1b0a3e5f71",
                      "code": "conflict"
                    }
                  }
                }
              }
            }
          },
          "422": {
            "description": "The body failed validation, or the Idempotency-Key was reused with a different body. Codes: `validation`, `idempotency_mismatch`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "validation_1": {
                    "summary": "Some fields need attention.",
                    "value": {
                      "type": "https://invoice.horizonpay.co/problems/validation",
                      "title": "Validation failed",
                      "status": 422,
                      "detail": "Some fields need attention.",
                      "instance": "req_7f3c9a1e2b4d4e8a9c6f2d1b0a3e5f71",
                      "code": "validation",
                      "errors": [
                        {
                          "path": "recurring_interval",
                          "message": "Pick how often this price recurs"
                        }
                      ]
                    }
                  },
                  "idempotency_mismatch_2": {
                    "summary": "This Idempotency-Key was already used with a different request body.",
                    "value": {
                      "type": "https://invoice.horizonpay.co/problems/idempotency-mismatch",
                      "title": "Idempotency-Key reused",
                      "status": 422,
                      "detail": "This Idempotency-Key was already used with a different request body.",
                      "instance": "req_7f3c9a1e2b4d4e8a9c6f2d1b0a3e5f71",
                      "code": "idempotency_mismatch",
                      "errors": [
                        {
                          "path": "Idempotency-Key",
                          "message": "Generate a new key per distinct request, not per retry loop."
                        }
                      ]
                    }
                  }
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/prices/{id}": {
      "get": {
        "operationId": "retrievePrice",
        "summary": "Retrieve a price",
        "tags": [
          "Prices"
        ],
        "description": "Returns a price by `price_…` id or UUID, active or archived.\n\n**Scope:** `products:read`",
        "x-required-scope": "products:read",
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "cURL",
            "source": "curl https://invoice.horizonpay.co/api/v1/prices/price_Jc5Tn8Wq1Ze6Ra3Ym9Ub2Gs7 \\\n  -H \"Authorization: Bearer $INVOICE_AI_API_KEY\""
          },
          {
            "lang": "node",
            "label": "Node.js",
            "source": "import InvoiceAI from '@horizonpay/invoice-ai'\n\nconst invoiceai = new InvoiceAI() // reads INVOICE_AI_API_KEY\n\nconst price = await invoiceai.prices.retrieve('price_Jc5Tn8Wq1Ze6Ra3Ym9Ub2Gs7')\nconsole.log(price.unit_amount, price.currency)"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "from invoice_ai import InvoiceAI\n\nclient = InvoiceAI()  # reads INVOICE_AI_API_KEY\n\nprice = client.prices.retrieve(\"price_Jc5Tn8Wq1Ze6Ra3Ym9Ub2Gs7\")\nprint(price.unit_amount, price.currency)"
          }
        ],
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "schema": {
              "type": "string",
              "description": "The price, `price_…` or UUID.",
              "examples": [
                "price_Jc5Tn8Wq1Ze6Ra3Ym9Ub2Gs7"
              ]
            },
            "required": true,
            "description": "The price, `price_…` or UUID."
          }
        ],
        "responses": {
          "200": {
            "description": "The price.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "example": {
                  "data": {
                    "id": "price_Jc5Tn8Wq1Ze6Ra3Ym9Ub2Gs7",
                    "object": "price",
                    "product": "prod_Hy7Rq2Lm9Xc4Vb8Nt3Kd6Pw1",
                    "nickname": "Monthly",
                    "unit_amount": 2500000,
                    "currency": "USD",
                    "billing_scheme": "per_unit",
                    "type": "recurring",
                    "recurring": {
                      "interval": "month",
                      "interval_count": 1
                    },
                    "tax_rate": 0,
                    "active": true,
                    "created": "2026-09-22T09:30:00.000Z"
                  }
                },
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "description": "The price.",
                      "$ref": "#/components/schemas/Price"
                    }
                  },
                  "required": [
                    "data"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "description": "No such price. Another account's resource is also a `404`, so ids cannot be probed. Codes: `not_found`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "not_found": {
                    "summary": "Price not found.",
                    "value": {
                      "type": "https://invoice.horizonpay.co/problems/not-found",
                      "title": "Not found",
                      "status": 404,
                      "detail": "Price not found.",
                      "instance": "req_7f3c9a1e2b4d4e8a9c6f2d1b0a3e5f71",
                      "code": "not_found"
                    }
                  }
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      },
      "patch": {
        "operationId": "updatePrice",
        "summary": "Update a price",
        "tags": [
          "Prices"
        ],
        "description": "Updates the fields you send and leaves the rest unchanged. A price cannot move to another product (`422`) — create a new price instead. Finalized invoices keep the amount they were billed at; a draft picks up the change the next time it is saved.\n\n**Scope:** `products:write`",
        "x-required-scope": "products:write",
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "cURL",
            "source": "curl -X PATCH https://invoice.horizonpay.co/api/v1/prices/price_Jc5Tn8Wq1Ze6Ra3Ym9Ub2Gs7 \\\n  -H \"Authorization: Bearer $INVOICE_AI_API_KEY\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n    \"nickname\": \"Monthly (annual contract)\",\n    \"type\": \"recurring\",\n    \"recurring\": { \"interval\": \"month\", \"interval_count\": 1 }\n  }'"
          },
          {
            "lang": "node",
            "label": "Node.js",
            "source": "import InvoiceAI from '@horizonpay/invoice-ai'\n\nconst invoiceai = new InvoiceAI() // reads INVOICE_AI_API_KEY\n\nconst price = await invoiceai.prices.update('price_Jc5Tn8Wq1Ze6Ra3Ym9Ub2Gs7', {\n  nickname: 'Monthly (annual contract)',\n  type: 'recurring',\n  recurring: { interval: 'month', interval_count: 1 },\n})\nconsole.log(price.nickname)"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "from invoice_ai import InvoiceAI\n\nclient = InvoiceAI()  # reads INVOICE_AI_API_KEY\n\nprice = client.prices.update(\n    \"price_Jc5Tn8Wq1Ze6Ra3Ym9Ub2Gs7\",\n    nickname=\"Monthly (annual contract)\",\n    type=\"recurring\",\n    recurring={\"interval\": \"month\", \"interval_count\": 1},\n)\nprint(price.nickname)"
          }
        ],
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "schema": {
              "type": "string",
              "description": "The price, `price_…` or UUID.",
              "examples": [
                "price_Jc5Tn8Wq1Ze6Ra3Ym9Ub2Gs7"
              ]
            },
            "required": true,
            "description": "The price, `price_…` or UUID."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "example": {
                "nickname": "Monthly (annual contract)",
                "type": "recurring",
                "recurring": {
                  "interval": "month",
                  "interval_count": 1
                }
              },
              "schema": {
                "$ref": "#/components/schemas/PriceUpdate"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The updated price.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "example": {
                  "data": {
                    "id": "price_Jc5Tn8Wq1Ze6Ra3Ym9Ub2Gs7",
                    "object": "price",
                    "product": "prod_Hy7Rq2Lm9Xc4Vb8Nt3Kd6Pw1",
                    "nickname": "Monthly (annual contract)",
                    "unit_amount": 2500000,
                    "currency": "USD",
                    "billing_scheme": "per_unit",
                    "type": "recurring",
                    "recurring": {
                      "interval": "month",
                      "interval_count": 1
                    },
                    "tax_rate": 0,
                    "active": true,
                    "created": "2026-09-22T09:30:00.000Z"
                  }
                },
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "description": "The updated price.",
                      "$ref": "#/components/schemas/Price"
                    }
                  },
                  "required": [
                    "data"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "description": "No such price. Another account's resource is also a `404`, so ids cannot be probed. Codes: `not_found`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "not_found": {
                    "summary": "Price not found.",
                    "value": {
                      "type": "https://invoice.horizonpay.co/problems/not-found",
                      "title": "Not found",
                      "status": 404,
                      "detail": "Price not found.",
                      "instance": "req_7f3c9a1e2b4d4e8a9c6f2d1b0a3e5f71",
                      "code": "not_found"
                    }
                  }
                }
              }
            }
          },
          "422": {
            "description": "The body failed validation, or tried to move the price to another product. Codes: `validation`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "validation": {
                    "summary": "A price cannot move to another product.",
                    "value": {
                      "type": "https://invoice.horizonpay.co/problems/validation",
                      "title": "Validation failed",
                      "status": 422,
                      "detail": "A price cannot move to another product.",
                      "instance": "req_7f3c9a1e2b4d4e8a9c6f2d1b0a3e5f71",
                      "code": "validation",
                      "errors": [
                        {
                          "path": "product",
                          "message": "Create a new price on the other product instead."
                        }
                      ]
                    }
                  }
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      },
      "delete": {
        "operationId": "archivePrice",
        "summary": "Archive a price",
        "tags": [
          "Prices"
        ],
        "description": "Archives a price (`active: false`). It is kept because invoice lines may reference it; archiving twice changes nothing. Restore with `PATCH` and `active: true`.\n\n**Scope:** `products:write`",
        "x-required-scope": "products:write",
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "cURL",
            "source": "curl -X DELETE https://invoice.horizonpay.co/api/v1/prices/price_Jc5Tn8Wq1Ze6Ra3Ym9Ub2Gs7 \\\n  -H \"Authorization: Bearer $INVOICE_AI_API_KEY\""
          },
          {
            "lang": "node",
            "label": "Node.js",
            "source": "import InvoiceAI from '@horizonpay/invoice-ai'\n\nconst invoiceai = new InvoiceAI() // reads INVOICE_AI_API_KEY\n\nconst price = await invoiceai.prices.archive('price_Jc5Tn8Wq1Ze6Ra3Ym9Ub2Gs7')\nconsole.log(price.active)"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "from invoice_ai import InvoiceAI\n\nclient = InvoiceAI()  # reads INVOICE_AI_API_KEY\n\nprice = client.prices.archive(\"price_Jc5Tn8Wq1Ze6Ra3Ym9Ub2Gs7\")\nprint(price.active)"
          }
        ],
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "schema": {
              "type": "string",
              "description": "The price, `price_…` or UUID.",
              "examples": [
                "price_Jc5Tn8Wq1Ze6Ra3Ym9Ub2Gs7"
              ]
            },
            "required": true,
            "description": "The price, `price_…` or UUID."
          }
        ],
        "responses": {
          "200": {
            "description": "The archived price.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "example": {
                  "data": {
                    "id": "price_Jc5Tn8Wq1Ze6Ra3Ym9Ub2Gs7",
                    "object": "price",
                    "product": "prod_Hy7Rq2Lm9Xc4Vb8Nt3Kd6Pw1",
                    "nickname": "Monthly",
                    "unit_amount": 2500000,
                    "currency": "USD",
                    "billing_scheme": "per_unit",
                    "type": "recurring",
                    "recurring": {
                      "interval": "month",
                      "interval_count": 1
                    },
                    "tax_rate": 0,
                    "active": false,
                    "created": "2026-09-22T09:30:00.000Z"
                  }
                },
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "description": "The archived price.",
                      "$ref": "#/components/schemas/Price"
                    }
                  },
                  "required": [
                    "data"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "description": "No such price. Another account's resource is also a `404`, so ids cannot be probed. Codes: `not_found`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "not_found": {
                    "summary": "Price not found.",
                    "value": {
                      "type": "https://invoice.horizonpay.co/problems/not-found",
                      "title": "Not found",
                      "status": 404,
                      "detail": "Price not found.",
                      "instance": "req_7f3c9a1e2b4d4e8a9c6f2d1b0a3e5f71",
                      "code": "not_found"
                    }
                  }
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/invoices": {
      "get": {
        "operationId": "listInvoices",
        "summary": "List invoices",
        "tags": [
          "Invoices"
        ],
        "description": "Lists invoices, newest first, without `lines`. `status=overdue` returns open invoices whose `due_date` is before today (UTC); `status=open` includes them. An unknown `customer` filter is a `404`.\n\n**Scope:** `invoices:read` + `clients:read` (when filtering by `customer`)",
        "x-required-scope": "invoices:read",
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "cURL",
            "source": "curl \"https://invoice.horizonpay.co/api/v1/invoices?status=open\" \\\n  -H \"Authorization: Bearer $INVOICE_AI_API_KEY\""
          },
          {
            "lang": "node",
            "label": "Node.js",
            "source": "import InvoiceAI from '@horizonpay/invoice-ai'\n\nconst invoiceai = new InvoiceAI() // reads INVOICE_AI_API_KEY\n\nfor await (const invoice of invoiceai.invoices.list({ status: 'open' })) {\n  console.log(invoice.number, invoice.amount_due)\n}"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "from invoice_ai import InvoiceAI\n\nclient = InvoiceAI()  # reads INVOICE_AI_API_KEY\n\nfor invoice in client.invoices.list(status=\"open\"):\n    print(invoice.number, invoice.amount_due)"
          }
        ],
        "parameters": [
          {
            "in": "query",
            "name": "cursor",
            "schema": {
              "description": "The `next_cursor` from the previous page. Opaque — do not build it yourself.",
              "type": "string"
            },
            "description": "The `next_cursor` from the previous page. Opaque — do not build it yourself."
          },
          {
            "in": "query",
            "name": "limit",
            "schema": {
              "default": 25,
              "description": "Page size, 1–100. Defaults to 25.",
              "type": "integer",
              "minimum": 1,
              "maximum": 100
            },
            "description": "Page size, 1–100. Defaults to 25."
          },
          {
            "in": "query",
            "name": "status",
            "schema": {
              "description": "Only invoices in this status. Other values are ignored.",
              "type": "string",
              "enum": [
                "draft",
                "open",
                "paid",
                "overdue",
                "void"
              ]
            },
            "description": "Only invoices in this status. Other values are ignored."
          },
          {
            "in": "query",
            "name": "customer",
            "schema": {
              "description": "Only invoices billed to this customer, `cus_…` or UUID.",
              "examples": [
                "cus_Nf3kQ8pR2mX7vB1cT9wL4sZ6"
              ],
              "type": "string"
            },
            "description": "Only invoices billed to this customer, `cus_…` or UUID."
          },
          {
            "in": "query",
            "name": "from",
            "schema": {
              "description": "Only invoices issued on or after this date (`YYYY-MM-DD`).",
              "examples": [
                "2026-09-01"
              ],
              "type": "string",
              "format": "date",
              "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$"
            },
            "description": "Only invoices issued on or after this date (`YYYY-MM-DD`)."
          },
          {
            "in": "query",
            "name": "to",
            "schema": {
              "description": "Only invoices issued on or before this date (`YYYY-MM-DD`).",
              "examples": [
                "2026-09-30"
              ],
              "type": "string",
              "format": "date",
              "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$"
            },
            "description": "Only invoices issued on or before this date (`YYYY-MM-DD`)."
          }
        ],
        "responses": {
          "200": {
            "description": "A page of invoices (without lines).",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "example": {
                  "data": [
                    {
                      "id": "in_Pb2Xk7Mv4Qs9Lr1Wd6Tn3Fh8",
                      "object": "invoice",
                      "number": "INV-0042",
                      "status": "open",
                      "customer": "cus_Nf3kQ8pR2mX7vB1cT9wL4sZ6",
                      "currency": "USD",
                      "collection_method": "send_invoice",
                      "issue_date": "2026-09-22",
                      "due_date": "2026-10-22",
                      "description": "Consulting retainer.",
                      "footer": null,
                      "subtotal": 2550000,
                      "discount": 0,
                      "taxable": 2550000,
                      "tax": 0,
                      "total": 2550000,
                      "amount_due": 2550000,
                      "amount_in_words": "Twenty Five Thousand Five Hundred USD Only",
                      "public_url_token": "2b7e4c1a-9f3d-4e68-8a5b-0d1c7f3e9a46",
                      "finalized_at": "2026-09-22T10:00:00.000Z",
                      "paid_at": null,
                      "voided_at": null,
                      "void_reason": null,
                      "created": "2026-09-22T09:30:00.000Z",
                      "updated": "2026-09-22T10:00:00.000Z"
                    }
                  ],
                  "next_cursor": null
                },
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Invoice"
                      },
                      "description": "Invoices, newest first."
                    },
                    "next_cursor": {
                      "anyOf": [
                        {
                          "type": "string"
                        },
                        {
                          "type": "null"
                        }
                      ],
                      "description": "Pass as `cursor` to fetch the next page. `null` on the last page.",
                      "examples": [
                        "MjAyNi0wOS0yMlQwOTozMDowMC4wMDBafDdmM2M"
                      ]
                    }
                  },
                  "required": [
                    "data",
                    "next_cursor"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "description": "The `customer` filter names no customer. Another account's resource is also a `404`, so ids cannot be probed. Codes: `not_found`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "not_found": {
                    "summary": "Client not found.",
                    "value": {
                      "type": "https://invoice.horizonpay.co/problems/not-found",
                      "title": "Not found",
                      "status": 404,
                      "detail": "Client not found.",
                      "instance": "req_7f3c9a1e2b4d4e8a9c6f2d1b0a3e5f71",
                      "code": "not_found"
                    }
                  }
                }
              }
            }
          },
          "422": {
            "description": "`cursor` is not a `next_cursor` this API returned. Codes: `validation`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "validation": {
                    "summary": "The cursor is not valid.",
                    "value": {
                      "type": "https://invoice.horizonpay.co/problems/validation",
                      "title": "Validation failed",
                      "status": 422,
                      "detail": "The cursor is not valid.",
                      "instance": "req_7f3c9a1e2b4d4e8a9c6f2d1b0a3e5f71",
                      "code": "validation",
                      "errors": [
                        {
                          "path": "cursor",
                          "message": "Pass the `next_cursor` from the previous page, unchanged."
                        }
                      ]
                    }
                  }
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      },
      "post": {
        "operationId": "createInvoice",
        "summary": "Create a draft invoice",
        "tags": [
          "Invoices"
        ],
        "description": "Creates a `draft` invoice for an existing customer. Each line is either a catalog `price` (its name, amount and tax rate fill in) or an ad-hoc `description` + `unit_amount`. Totals are computed server-side; `currency` defaults to your business currency.\n\nA draft has no number until you finalize or send it. Emits `invoice.created`.\n\n**Scope:** `invoices:write` + `business:read` + `clients:read`\n\n**Idempotency:** `Idempotency-Key` **required** (`428` without it). A retry with the same key and body replays the first response (`Idempotent-Replayed: true`); the same key with a different body is a `422` `idempotency_mismatch`.",
        "x-required-scope": "invoices:write",
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "cURL",
            "source": "curl https://invoice.horizonpay.co/api/v1/invoices \\\n  -H \"Authorization: Bearer $INVOICE_AI_API_KEY\" \\\n  -H \"Idempotency-Key: $(uuidgen)\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n    \"customer\": \"cus_Nf3kQ8pR2mX7vB1cT9wL4sZ6\",\n    \"currency\": \"USD\",\n    \"due_date\": \"2026-10-22\",\n    \"description\": \"Consulting retainer.\",\n    \"items\": [\n      { \"price\": \"price_Jc5Tn8Wq1Ze6Ra3Ym9Ub2Gs7\", \"quantity\": 1 },\n      {\n        \"description\": \"Onboarding workshop\",\n        \"quantity\": 1,\n        \"unit\": \"NOS\",\n        \"unit_amount\": 50000,\n        \"tax_rate\": 0\n      }\n    ]\n  }'"
          },
          {
            "lang": "node",
            "label": "Node.js",
            "source": "import InvoiceAI from '@horizonpay/invoice-ai'\n\nconst invoiceai = new InvoiceAI() // reads INVOICE_AI_API_KEY\n\n// Retries reuse one Idempotency-Key; pass { idempotencyKey } to set your own.\nconst invoice = await invoiceai.invoices.create({\n  customer: 'cus_Nf3kQ8pR2mX7vB1cT9wL4sZ6',\n  currency: 'USD',\n  due_date: '2026-10-22',\n  description: 'Consulting retainer.',\n  items: [\n    { price: 'price_Jc5Tn8Wq1Ze6Ra3Ym9Ub2Gs7', quantity: 1 },\n    {\n      description: 'Onboarding workshop',\n      quantity: 1,\n      unit: 'NOS',\n      unit_amount: 50000,\n      tax_rate: 0,\n    },\n  ],\n})\nconsole.log(invoice.id, invoice.status)"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "from invoice_ai import InvoiceAI\n\nclient = InvoiceAI()  # reads INVOICE_AI_API_KEY\n\n# Retries reuse one Idempotency-Key; pass idempotency_key=... to set your own.\ninvoice = client.invoices.create(\n    customer=\"cus_Nf3kQ8pR2mX7vB1cT9wL4sZ6\",\n    currency=\"USD\",\n    due_date=\"2026-10-22\",\n    description=\"Consulting retainer.\",\n    items=[\n        {\"price\": \"price_Jc5Tn8Wq1Ze6Ra3Ym9Ub2Gs7\", \"quantity\": 1},\n        {\n            \"description\": \"Onboarding workshop\",\n            \"quantity\": 1,\n            \"unit\": \"NOS\",\n            \"unit_amount\": 50000,\n            \"tax_rate\": 0,\n        },\n    ],\n)\nprint(invoice.id, invoice.status)"
          }
        ],
        "parameters": [
          {
            "in": "header",
            "name": "Idempotency-Key",
            "schema": {
              "type": "string",
              "maxLength": 255,
              "description": "A unique key per distinct operation (a UUID works), reused only when retrying that same request. Up to 255 characters; stored for 24 hours.",
              "examples": [
                "6f1c2d9e-8a4b-4c3f-9e7d-2b5a1c8f4e30"
              ]
            },
            "required": true,
            "description": "A unique key per distinct operation (a UUID works), reused only when retrying that same request. Up to 255 characters; stored for 24 hours."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "example": {
                "customer": "cus_Nf3kQ8pR2mX7vB1cT9wL4sZ6",
                "currency": "USD",
                "due_date": "2026-10-22",
                "description": "Consulting retainer.",
                "items": [
                  {
                    "price": "price_Jc5Tn8Wq1Ze6Ra3Ym9Ub2Gs7",
                    "quantity": 1
                  },
                  {
                    "description": "Onboarding workshop",
                    "quantity": 1,
                    "unit": "NOS",
                    "unit_amount": 50000,
                    "tax_rate": 0
                  }
                ]
              },
              "schema": {
                "$ref": "#/components/schemas/InvoiceCreate"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "The created draft, with lines.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "Idempotent-Replayed": {
                "$ref": "#/components/headers/IdempotentReplayed"
              }
            },
            "content": {
              "application/json": {
                "example": {
                  "data": {
                    "id": "in_Pb2Xk7Mv4Qs9Lr1Wd6Tn3Fh8",
                    "object": "invoice",
                    "number": null,
                    "status": "draft",
                    "customer": "cus_Nf3kQ8pR2mX7vB1cT9wL4sZ6",
                    "currency": "USD",
                    "collection_method": "send_invoice",
                    "issue_date": "2026-09-22",
                    "due_date": "2026-10-22",
                    "description": "Consulting retainer.",
                    "footer": null,
                    "subtotal": 2550000,
                    "discount": 0,
                    "taxable": 2550000,
                    "tax": 0,
                    "total": 2550000,
                    "amount_due": 0,
                    "amount_in_words": "Twenty Five Thousand Five Hundred USD Only",
                    "public_url_token": "2b7e4c1a-9f3d-4e68-8a5b-0d1c7f3e9a46",
                    "finalized_at": null,
                    "paid_at": null,
                    "voided_at": null,
                    "void_reason": null,
                    "created": "2026-09-22T09:30:00.000Z",
                    "updated": "2026-09-22T09:30:00.000Z",
                    "lines": {
                      "data": [
                        {
                          "id": "ii_Da4Vq9Ns2Kx7Bm3Yt8Rc1Lp6",
                          "object": "invoiceitem",
                          "price": "price_Jc5Tn8Wq1Ze6Ra3Ym9Ub2Gs7",
                          "product": "prod_Hy7Rq2Lm9Xc4Vb8Nt3Kd6Pw1",
                          "description": "Consulting retainer",
                          "quantity": 1,
                          "unit": "NOS",
                          "unit_amount": 2500000,
                          "amount": 2500000,
                          "discount_percent": 0,
                          "tax_rate": 0,
                          "tax_amount": 0
                        },
                        {
                          "id": "ii_Ew8Hz3Jc6Tq1Ms5Nv9Kb2Xr4",
                          "object": "invoiceitem",
                          "price": null,
                          "product": null,
                          "description": "Onboarding workshop",
                          "quantity": 1,
                          "unit": "NOS",
                          "unit_amount": 50000,
                          "amount": 50000,
                          "discount_percent": 0,
                          "tax_rate": 0,
                          "tax_amount": 0
                        }
                      ]
                    }
                  }
                },
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "description": "The created draft.",
                      "$ref": "#/components/schemas/Invoice"
                    }
                  },
                  "required": [
                    "data"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "description": "`customer` names no customer, or the business profile is missing. Another account's resource is also a `404`, so ids cannot be probed. Codes: `not_found`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "not_found": {
                    "summary": "Client not found.",
                    "value": {
                      "type": "https://invoice.horizonpay.co/problems/not-found",
                      "title": "Not found",
                      "status": 404,
                      "detail": "Client not found.",
                      "instance": "req_7f3c9a1e2b4d4e8a9c6f2d1b0a3e5f71",
                      "code": "not_found"
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "A request with the same Idempotency-Key is still running. Codes: `conflict`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "conflict": {
                    "summary": "A request with this Idempotency-Key is still in flight. Retry in a moment.",
                    "value": {
                      "type": "https://invoice.horizonpay.co/problems/conflict",
                      "title": "Conflict",
                      "status": 409,
                      "detail": "A request with this Idempotency-Key is still in flight. Retry in a moment.",
                      "instance": "req_7f3c9a1e2b4d4e8a9c6f2d1b0a3e5f71",
                      "code": "conflict"
                    }
                  }
                }
              }
            }
          },
          "422": {
            "description": "The body failed validation (including an unknown price or a currency mismatch), or the Idempotency-Key was reused with a different body. Codes: `validation`, `idempotency_mismatch`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "validation_1": {
                    "summary": "Some fields need attention.",
                    "value": {
                      "type": "https://invoice.horizonpay.co/problems/validation",
                      "title": "Validation failed",
                      "status": 422,
                      "detail": "Some fields need attention.",
                      "instance": "req_7f3c9a1e2b4d4e8a9c6f2d1b0a3e5f71",
                      "code": "validation",
                      "errors": [
                        {
                          "path": "items.0.price",
                          "message": "This price is in EUR but the invoice is in USD."
                        }
                      ]
                    }
                  },
                  "idempotency_mismatch_2": {
                    "summary": "This Idempotency-Key was already used with a different request body.",
                    "value": {
                      "type": "https://invoice.horizonpay.co/problems/idempotency-mismatch",
                      "title": "Idempotency-Key reused",
                      "status": 422,
                      "detail": "This Idempotency-Key was already used with a different request body.",
                      "instance": "req_7f3c9a1e2b4d4e8a9c6f2d1b0a3e5f71",
                      "code": "idempotency_mismatch",
                      "errors": [
                        {
                          "path": "Idempotency-Key",
                          "message": "Generate a new key per distinct request, not per retry loop."
                        }
                      ]
                    }
                  }
                }
              }
            }
          },
          "428": {
            "$ref": "#/components/responses/IdempotencyKeyRequired"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/invoices/{id}": {
      "get": {
        "operationId": "retrieveInvoice",
        "summary": "Retrieve an invoice",
        "tags": [
          "Invoices"
        ],
        "description": "Returns an invoice by `in_…` id or UUID, with its `lines`. `status` reads `overdue` when an open invoice is past its due date.\n\n**Scope:** `invoices:read`",
        "x-required-scope": "invoices:read",
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "cURL",
            "source": "curl https://invoice.horizonpay.co/api/v1/invoices/in_Pb2Xk7Mv4Qs9Lr1Wd6Tn3Fh8 \\\n  -H \"Authorization: Bearer $INVOICE_AI_API_KEY\""
          },
          {
            "lang": "node",
            "label": "Node.js",
            "source": "import InvoiceAI from '@horizonpay/invoice-ai'\n\nconst invoiceai = new InvoiceAI() // reads INVOICE_AI_API_KEY\n\nconst invoice = await invoiceai.invoices.retrieve('in_Pb2Xk7Mv4Qs9Lr1Wd6Tn3Fh8')\nconsole.log(invoice.number, invoice.status)"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "from invoice_ai import InvoiceAI\n\nclient = InvoiceAI()  # reads INVOICE_AI_API_KEY\n\ninvoice = client.invoices.retrieve(\"in_Pb2Xk7Mv4Qs9Lr1Wd6Tn3Fh8\")\nprint(invoice.number, invoice.status)"
          }
        ],
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "schema": {
              "type": "string",
              "description": "The invoice, `in_…` or UUID.",
              "examples": [
                "in_Pb2Xk7Mv4Qs9Lr1Wd6Tn3Fh8"
              ]
            },
            "required": true,
            "description": "The invoice, `in_…` or UUID."
          }
        ],
        "responses": {
          "200": {
            "description": "The invoice, with lines.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "example": {
                  "data": {
                    "id": "in_Pb2Xk7Mv4Qs9Lr1Wd6Tn3Fh8",
                    "object": "invoice",
                    "number": "INV-0042",
                    "status": "open",
                    "customer": "cus_Nf3kQ8pR2mX7vB1cT9wL4sZ6",
                    "currency": "USD",
                    "collection_method": "send_invoice",
                    "issue_date": "2026-09-22",
                    "due_date": "2026-10-22",
                    "description": "Consulting retainer.",
                    "footer": null,
                    "subtotal": 2550000,
                    "discount": 0,
                    "taxable": 2550000,
                    "tax": 0,
                    "total": 2550000,
                    "amount_due": 2550000,
                    "amount_in_words": "Twenty Five Thousand Five Hundred USD Only",
                    "public_url_token": "2b7e4c1a-9f3d-4e68-8a5b-0d1c7f3e9a46",
                    "finalized_at": "2026-09-22T10:00:00.000Z",
                    "paid_at": null,
                    "voided_at": null,
                    "void_reason": null,
                    "created": "2026-09-22T09:30:00.000Z",
                    "updated": "2026-09-22T10:00:00.000Z",
                    "lines": {
                      "data": [
                        {
                          "id": "ii_Da4Vq9Ns2Kx7Bm3Yt8Rc1Lp6",
                          "object": "invoiceitem",
                          "price": "price_Jc5Tn8Wq1Ze6Ra3Ym9Ub2Gs7",
                          "product": "prod_Hy7Rq2Lm9Xc4Vb8Nt3Kd6Pw1",
                          "description": "Consulting retainer",
                          "quantity": 1,
                          "unit": "NOS",
                          "unit_amount": 2500000,
                          "amount": 2500000,
                          "discount_percent": 0,
                          "tax_rate": 0,
                          "tax_amount": 0
                        },
                        {
                          "id": "ii_Ew8Hz3Jc6Tq1Ms5Nv9Kb2Xr4",
                          "object": "invoiceitem",
                          "price": null,
                          "product": null,
                          "description": "Onboarding workshop",
                          "quantity": 1,
                          "unit": "NOS",
                          "unit_amount": 50000,
                          "amount": 50000,
                          "discount_percent": 0,
                          "tax_rate": 0,
                          "tax_amount": 0
                        }
                      ]
                    }
                  }
                },
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "description": "The invoice.",
                      "$ref": "#/components/schemas/Invoice"
                    }
                  },
                  "required": [
                    "data"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "description": "No such invoice. Another account's resource is also a `404`, so ids cannot be probed. Codes: `not_found`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "not_found": {
                    "summary": "Invoice not found.",
                    "value": {
                      "type": "https://invoice.horizonpay.co/problems/not-found",
                      "title": "Not found",
                      "status": 404,
                      "detail": "Invoice not found.",
                      "instance": "req_7f3c9a1e2b4d4e8a9c6f2d1b0a3e5f71",
                      "code": "not_found"
                    }
                  }
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      },
      "patch": {
        "operationId": "updateInvoice",
        "summary": "Update a draft invoice",
        "tags": [
          "Invoices"
        ],
        "description": "Updates a draft. Send only the fields to change; `items`, when sent, replaces every line (line ids change). Once finalized an invoice is frozen and this returns `409`. Emits `invoice.updated`.\n\n**Scope:** `invoices:write` + `business:read` + `clients:read`",
        "x-required-scope": "invoices:write",
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "cURL",
            "source": "curl -X PATCH https://invoice.horizonpay.co/api/v1/invoices/in_Pb2Xk7Mv4Qs9Lr1Wd6Tn3Fh8 \\\n  -H \"Authorization: Bearer $INVOICE_AI_API_KEY\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n    \"due_date\": \"2026-10-22\",\n    \"description\": \"Consulting retainer — net 30.\",\n    \"footer\": \"Thank you for your business.\"\n  }'"
          },
          {
            "lang": "node",
            "label": "Node.js",
            "source": "import InvoiceAI from '@horizonpay/invoice-ai'\n\nconst invoiceai = new InvoiceAI() // reads INVOICE_AI_API_KEY\n\nconst invoice = await invoiceai.invoices.update('in_Pb2Xk7Mv4Qs9Lr1Wd6Tn3Fh8', {\n  due_date: '2026-10-22',\n  description: 'Consulting retainer — net 30.',\n  footer: 'Thank you for your business.',\n})\nconsole.log(invoice.due_date, invoice.total)"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "from invoice_ai import InvoiceAI\n\nclient = InvoiceAI()  # reads INVOICE_AI_API_KEY\n\ninvoice = client.invoices.update(\n    \"in_Pb2Xk7Mv4Qs9Lr1Wd6Tn3Fh8\",\n    due_date=\"2026-10-22\",\n    description=\"Consulting retainer — net 30.\",\n    footer=\"Thank you for your business.\",\n)\nprint(invoice.due_date, invoice.total)"
          }
        ],
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "schema": {
              "type": "string",
              "description": "The draft, `in_…` or UUID.",
              "examples": [
                "in_Pb2Xk7Mv4Qs9Lr1Wd6Tn3Fh8"
              ]
            },
            "required": true,
            "description": "The draft, `in_…` or UUID."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "example": {
                "due_date": "2026-10-22",
                "description": "Consulting retainer — net 30.",
                "footer": "Thank you for your business."
              },
              "schema": {
                "$ref": "#/components/schemas/InvoiceUpdate"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The updated draft, with lines.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "example": {
                  "data": {
                    "id": "in_Pb2Xk7Mv4Qs9Lr1Wd6Tn3Fh8",
                    "object": "invoice",
                    "number": null,
                    "status": "draft",
                    "customer": "cus_Nf3kQ8pR2mX7vB1cT9wL4sZ6",
                    "currency": "USD",
                    "collection_method": "send_invoice",
                    "issue_date": "2026-09-22",
                    "due_date": "2026-10-22",
                    "description": "Consulting retainer — net 30.",
                    "footer": "Thank you for your business.",
                    "subtotal": 2550000,
                    "discount": 0,
                    "taxable": 2550000,
                    "tax": 0,
                    "total": 2550000,
                    "amount_due": 0,
                    "amount_in_words": "Twenty Five Thousand Five Hundred USD Only",
                    "public_url_token": "2b7e4c1a-9f3d-4e68-8a5b-0d1c7f3e9a46",
                    "finalized_at": null,
                    "paid_at": null,
                    "voided_at": null,
                    "void_reason": null,
                    "created": "2026-09-22T09:30:00.000Z",
                    "updated": "2026-09-22T09:45:00.000Z",
                    "lines": {
                      "data": [
                        {
                          "id": "ii_Da4Vq9Ns2Kx7Bm3Yt8Rc1Lp6",
                          "object": "invoiceitem",
                          "price": "price_Jc5Tn8Wq1Ze6Ra3Ym9Ub2Gs7",
                          "product": "prod_Hy7Rq2Lm9Xc4Vb8Nt3Kd6Pw1",
                          "description": "Consulting retainer",
                          "quantity": 1,
                          "unit": "NOS",
                          "unit_amount": 2500000,
                          "amount": 2500000,
                          "discount_percent": 0,
                          "tax_rate": 0,
                          "tax_amount": 0
                        },
                        {
                          "id": "ii_Ew8Hz3Jc6Tq1Ms5Nv9Kb2Xr4",
                          "object": "invoiceitem",
                          "price": null,
                          "product": null,
                          "description": "Onboarding workshop",
                          "quantity": 1,
                          "unit": "NOS",
                          "unit_amount": 50000,
                          "amount": 50000,
                          "discount_percent": 0,
                          "tax_rate": 0,
                          "tax_amount": 0
                        }
                      ]
                    }
                  }
                },
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "description": "The updated draft.",
                      "$ref": "#/components/schemas/Invoice"
                    }
                  },
                  "required": [
                    "data"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "description": "No such invoice or customer. Another account's resource is also a `404`, so ids cannot be probed. Codes: `not_found`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "not_found": {
                    "summary": "Invoice not found.",
                    "value": {
                      "type": "https://invoice.horizonpay.co/problems/not-found",
                      "title": "Not found",
                      "status": 404,
                      "detail": "Invoice not found.",
                      "instance": "req_7f3c9a1e2b4d4e8a9c6f2d1b0a3e5f71",
                      "code": "not_found"
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "The invoice is no longer a draft. Codes: `invalid_state`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "invalid_state": {
                    "summary": "This invoice has been finalized and can no longer be edited.",
                    "value": {
                      "type": "https://invoice.horizonpay.co/problems/invalid-state",
                      "title": "Invalid state for this operation",
                      "status": 409,
                      "detail": "This invoice has been finalized and can no longer be edited.",
                      "instance": "req_7f3c9a1e2b4d4e8a9c6f2d1b0a3e5f71",
                      "code": "invalid_state"
                    }
                  }
                }
              }
            }
          },
          "422": {
            "description": "The body failed validation. Codes: `validation`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "validation": {
                    "summary": "Some fields need attention.",
                    "value": {
                      "type": "https://invoice.horizonpay.co/problems/validation",
                      "title": "Validation failed",
                      "status": 422,
                      "detail": "Some fields need attention.",
                      "instance": "req_7f3c9a1e2b4d4e8a9c6f2d1b0a3e5f71",
                      "code": "validation",
                      "errors": [
                        {
                          "path": "due_date",
                          "message": "Invalid ISO date"
                        }
                      ]
                    }
                  }
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      },
      "delete": {
        "operationId": "deleteInvoice",
        "summary": "Delete a draft invoice",
        "tags": [
          "Invoices"
        ],
        "description": "Permanently deletes a draft. A finalized invoice cannot be deleted (`409`) — its number belongs to a gap-free series. Void it instead.\n\n**Scope:** `invoices:write`",
        "x-required-scope": "invoices:write",
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "cURL",
            "source": "curl -X DELETE https://invoice.horizonpay.co/api/v1/invoices/in_Pb2Xk7Mv4Qs9Lr1Wd6Tn3Fh8 \\\n  -H \"Authorization: Bearer $INVOICE_AI_API_KEY\""
          },
          {
            "lang": "node",
            "label": "Node.js",
            "source": "import InvoiceAI from '@horizonpay/invoice-ai'\n\nconst invoiceai = new InvoiceAI() // reads INVOICE_AI_API_KEY\n\nawait invoiceai.invoices.del('in_Pb2Xk7Mv4Qs9Lr1Wd6Tn3Fh8')"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "from invoice_ai import InvoiceAI\n\nclient = InvoiceAI()  # reads INVOICE_AI_API_KEY\n\nclient.invoices.delete(\"in_Pb2Xk7Mv4Qs9Lr1Wd6Tn3Fh8\")"
          }
        ],
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "schema": {
              "type": "string",
              "description": "The draft, `in_…` or UUID.",
              "examples": [
                "in_Pb2Xk7Mv4Qs9Lr1Wd6Tn3Fh8"
              ]
            },
            "required": true,
            "description": "The draft, `in_…` or UUID."
          }
        ],
        "responses": {
          "204": {
            "description": "Deleted. No body.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "description": "No such invoice. Another account's resource is also a `404`, so ids cannot be probed. Codes: `not_found`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "not_found": {
                    "summary": "Invoice not found.",
                    "value": {
                      "type": "https://invoice.horizonpay.co/problems/not-found",
                      "title": "Not found",
                      "status": 404,
                      "detail": "Invoice not found.",
                      "instance": "req_7f3c9a1e2b4d4e8a9c6f2d1b0a3e5f71",
                      "code": "not_found"
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "The invoice has been finalized. Codes: `invalid_state`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "invalid_state": {
                    "summary": "Invoice INV-0042 has been finalized and cannot be deleted. Void it instead.",
                    "value": {
                      "type": "https://invoice.horizonpay.co/problems/invalid-state",
                      "title": "Invalid state for this operation",
                      "status": 409,
                      "detail": "Invoice INV-0042 has been finalized and cannot be deleted. Void it instead.",
                      "instance": "req_7f3c9a1e2b4d4e8a9c6f2d1b0a3e5f71",
                      "code": "invalid_state"
                    }
                  }
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/invoices/{id}/finalize": {
      "post": {
        "operationId": "finalizeInvoice",
        "summary": "Finalize an invoice",
        "tags": [
          "Invoices"
        ],
        "description": "Issues a draft: assigns the next number in your series (e.g. `INV-0042`) and moves it to `open`. The draft needs at least one line. Finalizing an invoice that already has a number returns it unchanged, so a retry never spends a second number. Does not email the customer — see `/send`. Emits `invoice.finalized`.\n\n**Scope:** `invoices:finalize`\n\n**Idempotency:** `Idempotency-Key` **required** (`428` without it). A retry with the same key and body replays the first response (`Idempotent-Replayed: true`); the same key with a different body is a `422` `idempotency_mismatch`.",
        "x-required-scope": "invoices:finalize",
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "cURL",
            "source": "curl -X POST https://invoice.horizonpay.co/api/v1/invoices/in_Pb2Xk7Mv4Qs9Lr1Wd6Tn3Fh8/finalize \\\n  -H \"Authorization: Bearer $INVOICE_AI_API_KEY\" \\\n  -H \"Idempotency-Key: $(uuidgen)\""
          },
          {
            "lang": "node",
            "label": "Node.js",
            "source": "import InvoiceAI from '@horizonpay/invoice-ai'\n\nconst invoiceai = new InvoiceAI() // reads INVOICE_AI_API_KEY\n\n// Retries reuse one Idempotency-Key; pass { idempotencyKey } to set your own.\nconst invoice = await invoiceai.invoices.finalize('in_Pb2Xk7Mv4Qs9Lr1Wd6Tn3Fh8')\nconsole.log(invoice.number)"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "from invoice_ai import InvoiceAI\n\nclient = InvoiceAI()  # reads INVOICE_AI_API_KEY\n\n# Retries reuse one Idempotency-Key; pass idempotency_key=... to set your own.\ninvoice = client.invoices.finalize(\"in_Pb2Xk7Mv4Qs9Lr1Wd6Tn3Fh8\")\nprint(invoice.number)"
          }
        ],
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "schema": {
              "type": "string",
              "description": "The draft, `in_…` or UUID.",
              "examples": [
                "in_Pb2Xk7Mv4Qs9Lr1Wd6Tn3Fh8"
              ]
            },
            "required": true,
            "description": "The draft, `in_…` or UUID."
          },
          {
            "in": "header",
            "name": "Idempotency-Key",
            "schema": {
              "type": "string",
              "maxLength": 255,
              "description": "A unique key per distinct operation (a UUID works), reused only when retrying that same request. Up to 255 characters; stored for 24 hours.",
              "examples": [
                "6f1c2d9e-8a4b-4c3f-9e7d-2b5a1c8f4e30"
              ]
            },
            "required": true,
            "description": "A unique key per distinct operation (a UUID works), reused only when retrying that same request. Up to 255 characters; stored for 24 hours."
          }
        ],
        "responses": {
          "200": {
            "description": "The finalized invoice, with its number and lines.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "Idempotent-Replayed": {
                "$ref": "#/components/headers/IdempotentReplayed"
              }
            },
            "content": {
              "application/json": {
                "example": {
                  "data": {
                    "id": "in_Pb2Xk7Mv4Qs9Lr1Wd6Tn3Fh8",
                    "object": "invoice",
                    "number": "INV-0042",
                    "status": "open",
                    "customer": "cus_Nf3kQ8pR2mX7vB1cT9wL4sZ6",
                    "currency": "USD",
                    "collection_method": "send_invoice",
                    "issue_date": "2026-09-22",
                    "due_date": "2026-10-22",
                    "description": "Consulting retainer.",
                    "footer": null,
                    "subtotal": 2550000,
                    "discount": 0,
                    "taxable": 2550000,
                    "tax": 0,
                    "total": 2550000,
                    "amount_due": 2550000,
                    "amount_in_words": "Twenty Five Thousand Five Hundred USD Only",
                    "public_url_token": "2b7e4c1a-9f3d-4e68-8a5b-0d1c7f3e9a46",
                    "finalized_at": "2026-09-22T10:00:00.000Z",
                    "paid_at": null,
                    "voided_at": null,
                    "void_reason": null,
                    "created": "2026-09-22T09:30:00.000Z",
                    "updated": "2026-09-22T10:00:00.000Z",
                    "lines": {
                      "data": [
                        {
                          "id": "ii_Da4Vq9Ns2Kx7Bm3Yt8Rc1Lp6",
                          "object": "invoiceitem",
                          "price": "price_Jc5Tn8Wq1Ze6Ra3Ym9Ub2Gs7",
                          "product": "prod_Hy7Rq2Lm9Xc4Vb8Nt3Kd6Pw1",
                          "description": "Consulting retainer",
                          "quantity": 1,
                          "unit": "NOS",
                          "unit_amount": 2500000,
                          "amount": 2500000,
                          "discount_percent": 0,
                          "tax_rate": 0,
                          "tax_amount": 0
                        },
                        {
                          "id": "ii_Ew8Hz3Jc6Tq1Ms5Nv9Kb2Xr4",
                          "object": "invoiceitem",
                          "price": null,
                          "product": null,
                          "description": "Onboarding workshop",
                          "quantity": 1,
                          "unit": "NOS",
                          "unit_amount": 50000,
                          "amount": 50000,
                          "discount_percent": 0,
                          "tax_rate": 0,
                          "tax_amount": 0
                        }
                      ]
                    }
                  }
                },
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "description": "The finalized invoice.",
                      "$ref": "#/components/schemas/Invoice"
                    }
                  },
                  "required": [
                    "data"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "description": "No such invoice. Another account's resource is also a `404`, so ids cannot be probed. Codes: `not_found`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "not_found": {
                    "summary": "Invoice not found.",
                    "value": {
                      "type": "https://invoice.horizonpay.co/problems/not-found",
                      "title": "Not found",
                      "status": 404,
                      "detail": "Invoice not found.",
                      "instance": "req_7f3c9a1e2b4d4e8a9c6f2d1b0a3e5f71",
                      "code": "not_found"
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "The invoice has no lines or cannot be finalized from its state, or the same Idempotency-Key is still running. Codes: `invalid_state`, `conflict`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "invalid_state_1": {
                    "summary": "invalid_state",
                    "value": {
                      "type": "https://invoice.horizonpay.co/problems/invalid-state",
                      "title": "Invalid state for this operation",
                      "status": 409,
                      "detail": "invalid_state",
                      "instance": "req_7f3c9a1e2b4d4e8a9c6f2d1b0a3e5f71",
                      "code": "invalid_state"
                    }
                  },
                  "conflict_2": {
                    "summary": "A request with this Idempotency-Key is still in flight. Retry in a moment.",
                    "value": {
                      "type": "https://invoice.horizonpay.co/problems/conflict",
                      "title": "Conflict",
                      "status": 409,
                      "detail": "A request with this Idempotency-Key is still in flight. Retry in a moment.",
                      "instance": "req_7f3c9a1e2b4d4e8a9c6f2d1b0a3e5f71",
                      "code": "conflict"
                    }
                  }
                }
              }
            }
          },
          "422": {
            "description": "The Idempotency-Key was reused with a different request. Codes: `idempotency_mismatch`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "idempotency_mismatch": {
                    "summary": "This Idempotency-Key was already used with a different request body.",
                    "value": {
                      "type": "https://invoice.horizonpay.co/problems/idempotency-mismatch",
                      "title": "Idempotency-Key reused",
                      "status": 422,
                      "detail": "This Idempotency-Key was already used with a different request body.",
                      "instance": "req_7f3c9a1e2b4d4e8a9c6f2d1b0a3e5f71",
                      "code": "idempotency_mismatch",
                      "errors": [
                        {
                          "path": "Idempotency-Key",
                          "message": "Generate a new key per distinct request, not per retry loop."
                        }
                      ]
                    }
                  }
                }
              }
            }
          },
          "428": {
            "$ref": "#/components/responses/IdempotencyKeyRequired"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/invoices/{id}/send": {
      "post": {
        "operationId": "sendInvoice",
        "summary": "Send an invoice",
        "tags": [
          "Invoices"
        ],
        "description": "Emails the invoice PDF and a link to its public page to `to`, or else the customer email on the invoice. A draft is finalized first (no `invoices:finalize` scope needed). Open and paid invoices can be re-sent; void ones cannot.\n\n**Requires a verified account email** — until then this returns `409` `invalid_state`.\n\n**Rate limits:** 10 sends per hour per API key, and 50 per hour per account across every key and the dashboard (`429` `rate_limited`, with `Retry-After`).\n\nIf the email fails after finalizing, the response is `502` `upstream_failed` and the number stays spent; retry the send. Emits `invoice.emailed` (or `invoice.email_failed`), plus `invoice.finalized` when it finalized.\n\n**Scope:** `invoices:send`\n\n**Idempotency:** `Idempotency-Key` **required** (`428` without it). A retry with the same key and body replays the first response (`Idempotent-Replayed: true`); the same key with a different body is a `422` `idempotency_mismatch`.",
        "x-required-scope": "invoices:send",
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "cURL",
            "source": "curl https://invoice.horizonpay.co/api/v1/invoices/in_Pb2Xk7Mv4Qs9Lr1Wd6Tn3Fh8/send \\\n  -H \"Authorization: Bearer $INVOICE_AI_API_KEY\" \\\n  -H \"Idempotency-Key: $(uuidgen)\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{ \"to\": \"ap@acme.example\" }'"
          },
          {
            "lang": "node",
            "label": "Node.js",
            "source": "import InvoiceAI from '@horizonpay/invoice-ai'\n\nconst invoiceai = new InvoiceAI() // reads INVOICE_AI_API_KEY\n\n// Retries reuse one Idempotency-Key; pass { idempotencyKey } to set your own.\nconst sent = await invoiceai.invoices.send('in_Pb2Xk7Mv4Qs9Lr1Wd6Tn3Fh8', {\n  to: 'ap@acme.example',\n})\nconsole.log(sent.data.number, sent.emailed_to)"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "from invoice_ai import InvoiceAI\n\nclient = InvoiceAI()  # reads INVOICE_AI_API_KEY\n\n# Retries reuse one Idempotency-Key; pass idempotency_key=... to set your own.\nsent = client.invoices.send(\n    \"in_Pb2Xk7Mv4Qs9Lr1Wd6Tn3Fh8\",\n    to=\"ap@acme.example\",\n)\nprint(sent.data.number, sent.emailed_to)"
          }
        ],
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "schema": {
              "type": "string",
              "description": "The invoice, `in_…` or UUID.",
              "examples": [
                "in_Pb2Xk7Mv4Qs9Lr1Wd6Tn3Fh8"
              ]
            },
            "required": true,
            "description": "The invoice, `in_…` or UUID."
          },
          {
            "in": "header",
            "name": "Idempotency-Key",
            "schema": {
              "type": "string",
              "maxLength": 255,
              "description": "A unique key per distinct operation (a UUID works), reused only when retrying that same request. Up to 255 characters; stored for 24 hours.",
              "examples": [
                "6f1c2d9e-8a4b-4c3f-9e7d-2b5a1c8f4e30"
              ]
            },
            "required": true,
            "description": "A unique key per distinct operation (a UUID works), reused only when retrying that same request. Up to 255 characters; stored for 24 hours."
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "example": {
                "to": "ap@acme.example"
              },
              "schema": {
                "$ref": "#/components/schemas/InvoiceSend"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Sent. The invoice (finalized if it was a draft, with lines) plus the address it went to.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "Idempotent-Replayed": {
                "$ref": "#/components/headers/IdempotentReplayed"
              }
            },
            "content": {
              "application/json": {
                "example": {
                  "data": {
                    "id": "in_Pb2Xk7Mv4Qs9Lr1Wd6Tn3Fh8",
                    "object": "invoice",
                    "number": "INV-0042",
                    "status": "open",
                    "customer": "cus_Nf3kQ8pR2mX7vB1cT9wL4sZ6",
                    "currency": "USD",
                    "collection_method": "send_invoice",
                    "issue_date": "2026-09-22",
                    "due_date": "2026-10-22",
                    "description": "Consulting retainer.",
                    "footer": null,
                    "subtotal": 2550000,
                    "discount": 0,
                    "taxable": 2550000,
                    "tax": 0,
                    "total": 2550000,
                    "amount_due": 2550000,
                    "amount_in_words": "Twenty Five Thousand Five Hundred USD Only",
                    "public_url_token": "2b7e4c1a-9f3d-4e68-8a5b-0d1c7f3e9a46",
                    "finalized_at": "2026-09-22T10:00:00.000Z",
                    "paid_at": null,
                    "voided_at": null,
                    "void_reason": null,
                    "created": "2026-09-22T09:30:00.000Z",
                    "updated": "2026-09-22T10:00:00.000Z",
                    "lines": {
                      "data": [
                        {
                          "id": "ii_Da4Vq9Ns2Kx7Bm3Yt8Rc1Lp6",
                          "object": "invoiceitem",
                          "price": "price_Jc5Tn8Wq1Ze6Ra3Ym9Ub2Gs7",
                          "product": "prod_Hy7Rq2Lm9Xc4Vb8Nt3Kd6Pw1",
                          "description": "Consulting retainer",
                          "quantity": 1,
                          "unit": "NOS",
                          "unit_amount": 2500000,
                          "amount": 2500000,
                          "discount_percent": 0,
                          "tax_rate": 0,
                          "tax_amount": 0
                        },
                        {
                          "id": "ii_Ew8Hz3Jc6Tq1Ms5Nv9Kb2Xr4",
                          "object": "invoiceitem",
                          "price": null,
                          "product": null,
                          "description": "Onboarding workshop",
                          "quantity": 1,
                          "unit": "NOS",
                          "unit_amount": 50000,
                          "amount": 50000,
                          "discount_percent": 0,
                          "tax_rate": 0,
                          "tax_amount": 0
                        }
                      ]
                    }
                  },
                  "emailed_to": "ap@acme.example"
                },
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "description": "The invoice, finalized if it was a draft, with lines.",
                      "$ref": "#/components/schemas/Invoice"
                    },
                    "emailed_to": {
                      "type": "string",
                      "description": "The address the email was sent to: `to`, or the customer email.",
                      "examples": [
                        "ap@acme.example"
                      ]
                    }
                  },
                  "required": [
                    "data",
                    "emailed_to"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "description": "No such invoice. Another account's resource is also a `404`, so ids cannot be probed. Codes: `not_found`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "not_found": {
                    "summary": "Invoice not found.",
                    "value": {
                      "type": "https://invoice.horizonpay.co/problems/not-found",
                      "title": "Not found",
                      "status": 404,
                      "detail": "Invoice not found.",
                      "instance": "req_7f3c9a1e2b4d4e8a9c6f2d1b0a3e5f71",
                      "code": "not_found"
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "The account email is not verified yet, the invoice is void or has no lines, or the same Idempotency-Key is still running. Codes: `invalid_state`, `conflict`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "invalid_state_1": {
                    "summary": "Verify your email address before emailing invoices: use the link we sent you, or resend it from the dashboard.",
                    "value": {
                      "type": "https://invoice.horizonpay.co/problems/invalid-state",
                      "title": "Invalid state for this operation",
                      "status": 409,
                      "detail": "Verify your email address before emailing invoices: use the link we sent you, or resend it from the dashboard.",
                      "instance": "req_7f3c9a1e2b4d4e8a9c6f2d1b0a3e5f71",
                      "code": "invalid_state"
                    }
                  },
                  "invalid_state_2": {
                    "summary": "This invoice is void and cannot be sent.",
                    "value": {
                      "type": "https://invoice.horizonpay.co/problems/invalid-state",
                      "title": "Invalid state for this operation",
                      "status": 409,
                      "detail": "This invoice is void and cannot be sent.",
                      "instance": "req_7f3c9a1e2b4d4e8a9c6f2d1b0a3e5f71",
                      "code": "invalid_state"
                    }
                  },
                  "invalid_state_3": {
                    "summary": "Add at least one line item before sending.",
                    "value": {
                      "type": "https://invoice.horizonpay.co/problems/invalid-state",
                      "title": "Invalid state for this operation",
                      "status": 409,
                      "detail": "Add at least one line item before sending.",
                      "instance": "req_7f3c9a1e2b4d4e8a9c6f2d1b0a3e5f71",
                      "code": "invalid_state"
                    }
                  },
                  "conflict_4": {
                    "summary": "A request with this Idempotency-Key is still in flight. Retry in a moment.",
                    "value": {
                      "type": "https://invoice.horizonpay.co/problems/conflict",
                      "title": "Conflict",
                      "status": 409,
                      "detail": "A request with this Idempotency-Key is still in flight. Retry in a moment.",
                      "instance": "req_7f3c9a1e2b4d4e8a9c6f2d1b0a3e5f71",
                      "code": "conflict"
                    }
                  }
                }
              }
            }
          },
          "422": {
            "description": "No recipient: neither `to` nor a customer email. Or the Idempotency-Key was reused with a different body. Codes: `validation`, `idempotency_mismatch`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "validation_1": {
                    "summary": "No client email address to send to.",
                    "value": {
                      "type": "https://invoice.horizonpay.co/problems/validation",
                      "title": "Validation failed",
                      "status": 422,
                      "detail": "No client email address to send to.",
                      "instance": "req_7f3c9a1e2b4d4e8a9c6f2d1b0a3e5f71",
                      "code": "validation",
                      "errors": [
                        {
                          "path": "to",
                          "message": "Provide a recipient, or set an email on the client."
                        }
                      ]
                    }
                  },
                  "idempotency_mismatch_2": {
                    "summary": "This Idempotency-Key was already used with a different request body.",
                    "value": {
                      "type": "https://invoice.horizonpay.co/problems/idempotency-mismatch",
                      "title": "Idempotency-Key reused",
                      "status": 422,
                      "detail": "This Idempotency-Key was already used with a different request body.",
                      "instance": "req_7f3c9a1e2b4d4e8a9c6f2d1b0a3e5f71",
                      "code": "idempotency_mismatch",
                      "errors": [
                        {
                          "path": "Idempotency-Key",
                          "message": "Generate a new key per distinct request, not per retry loop."
                        }
                      ]
                    }
                  }
                }
              }
            }
          },
          "428": {
            "$ref": "#/components/responses/IdempotencyKeyRequired"
          },
          "429": {
            "description": "More than 10 sends in an hour for this key, or 50 for the whole account (dashboard included). Wait `Retry-After` seconds. Codes: `rate_limited`.",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/RetryAfter"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "rate_limited_1": {
                    "summary": "Rate limit of 10 per 3600s exceeded.",
                    "value": {
                      "type": "https://invoice.horizonpay.co/problems/rate-limited",
                      "title": "Too many requests",
                      "status": 429,
                      "detail": "Rate limit of 10 per 3600s exceeded.",
                      "instance": "req_7f3c9a1e2b4d4e8a9c6f2d1b0a3e5f71",
                      "code": "rate_limited"
                    }
                  },
                  "rate_limited_2": {
                    "summary": "Too many invoices emailed in the last hour. Try again in 20 min.",
                    "value": {
                      "type": "https://invoice.horizonpay.co/problems/rate-limited",
                      "title": "Too many requests",
                      "status": 429,
                      "detail": "Too many invoices emailed in the last hour. Try again in 20 min.",
                      "instance": "req_7f3c9a1e2b4d4e8a9c6f2d1b0a3e5f71",
                      "code": "rate_limited"
                    }
                  }
                }
              }
            }
          },
          "502": {
            "description": "The invoice was finalized but the email provider failed. The number is spent; retrying the send is safe. Codes: `upstream_failed`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "upstream_failed": {
                    "summary": "Invoice finalized, but the email failed: Service unavailable",
                    "value": {
                      "type": "https://invoice.horizonpay.co/problems/upstream-failed",
                      "title": "Upstream service failed",
                      "status": 502,
                      "detail": "Invoice finalized, but the email failed: Service unavailable",
                      "instance": "req_7f3c9a1e2b4d4e8a9c6f2d1b0a3e5f71",
                      "code": "upstream_failed"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/invoices/{id}/pay": {
      "post": {
        "operationId": "payInvoice",
        "summary": "Mark an invoice paid",
        "tags": [
          "Invoices"
        ],
        "description": "Marks an `open` (or overdue) invoice paid outside Invoice-AI — no money moves. `paid_on` is an ISO 8601 date or timestamp (defaults to now); `reference` is up to 200 characters. Drafts, void and already-paid invoices return `409`. The response omits `lines`. Emits `invoice.paid`, with `reference` in its meta.\n\n**Scope:** `payments:write`\n\n**Idempotency:** `Idempotency-Key` **required** (`428` without it). A retry with the same key and body replays the first response (`Idempotent-Replayed: true`); the same key with a different body is a `422` `idempotency_mismatch`.",
        "x-required-scope": "payments:write",
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "cURL",
            "source": "curl https://invoice.horizonpay.co/api/v1/invoices/in_Pb2Xk7Mv4Qs9Lr1Wd6Tn3Fh8/pay \\\n  -H \"Authorization: Bearer $INVOICE_AI_API_KEY\" \\\n  -H \"Idempotency-Key: $(uuidgen)\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{ \"paid_on\": \"2026-09-29\", \"reference\": \"chk_123456\" }'"
          },
          {
            "lang": "node",
            "label": "Node.js",
            "source": "import InvoiceAI from '@horizonpay/invoice-ai'\n\nconst invoiceai = new InvoiceAI() // reads INVOICE_AI_API_KEY\n\n// Retries reuse one Idempotency-Key; pass { idempotencyKey } to set your own.\nconst invoice = await invoiceai.invoices.pay('in_Pb2Xk7Mv4Qs9Lr1Wd6Tn3Fh8', {\n  paid_on: '2026-09-29',\n  reference: 'chk_123456',\n})\nconsole.log(invoice.status, invoice.paid_at)"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "from invoice_ai import InvoiceAI\n\nclient = InvoiceAI()  # reads INVOICE_AI_API_KEY\n\n# Retries reuse one Idempotency-Key; pass idempotency_key=... to set your own.\ninvoice = client.invoices.pay(\n    \"in_Pb2Xk7Mv4Qs9Lr1Wd6Tn3Fh8\",\n    paid_on=\"2026-09-29\",\n    reference=\"chk_123456\",\n)\nprint(invoice.status, invoice.paid_at)"
          }
        ],
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "schema": {
              "type": "string",
              "description": "The invoice, `in_…` or UUID.",
              "examples": [
                "in_Pb2Xk7Mv4Qs9Lr1Wd6Tn3Fh8"
              ]
            },
            "required": true,
            "description": "The invoice, `in_…` or UUID."
          },
          {
            "in": "header",
            "name": "Idempotency-Key",
            "schema": {
              "type": "string",
              "maxLength": 255,
              "description": "A unique key per distinct operation (a UUID works), reused only when retrying that same request. Up to 255 characters; stored for 24 hours.",
              "examples": [
                "6f1c2d9e-8a4b-4c3f-9e7d-2b5a1c8f4e30"
              ]
            },
            "required": true,
            "description": "A unique key per distinct operation (a UUID works), reused only when retrying that same request. Up to 255 characters; stored for 24 hours."
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "example": {
                "paid_on": "2026-09-29",
                "reference": "chk_123456"
              },
              "schema": {
                "$ref": "#/components/schemas/InvoicePay"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The paid invoice (without lines).",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "Idempotent-Replayed": {
                "$ref": "#/components/headers/IdempotentReplayed"
              }
            },
            "content": {
              "application/json": {
                "example": {
                  "data": {
                    "id": "in_Pb2Xk7Mv4Qs9Lr1Wd6Tn3Fh8",
                    "object": "invoice",
                    "number": "INV-0042",
                    "status": "paid",
                    "customer": "cus_Nf3kQ8pR2mX7vB1cT9wL4sZ6",
                    "currency": "USD",
                    "collection_method": "send_invoice",
                    "issue_date": "2026-09-22",
                    "due_date": "2026-10-22",
                    "description": "Consulting retainer.",
                    "footer": null,
                    "subtotal": 2550000,
                    "discount": 0,
                    "taxable": 2550000,
                    "tax": 0,
                    "total": 2550000,
                    "amount_due": 0,
                    "amount_in_words": "Twenty Five Thousand Five Hundred USD Only",
                    "public_url_token": "2b7e4c1a-9f3d-4e68-8a5b-0d1c7f3e9a46",
                    "finalized_at": "2026-09-22T10:00:00.000Z",
                    "paid_at": "2026-09-29T14:20:00.000Z",
                    "voided_at": null,
                    "void_reason": null,
                    "created": "2026-09-22T09:30:00.000Z",
                    "updated": "2026-09-29T14:20:00.000Z"
                  }
                },
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "description": "The paid invoice.",
                      "$ref": "#/components/schemas/Invoice"
                    }
                  },
                  "required": [
                    "data"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "description": "No such invoice. Another account's resource is also a `404`, so ids cannot be probed. Codes: `not_found`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "not_found": {
                    "summary": "Invoice not found.",
                    "value": {
                      "type": "https://invoice.horizonpay.co/problems/not-found",
                      "title": "Not found",
                      "status": 404,
                      "detail": "Invoice not found.",
                      "instance": "req_7f3c9a1e2b4d4e8a9c6f2d1b0a3e5f71",
                      "code": "not_found"
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "The invoice is not open, or the same Idempotency-Key is still running. Codes: `invalid_state`, `conflict`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "invalid_state_1": {
                    "summary": "Invoice is draft and cannot be marked paid.",
                    "value": {
                      "type": "https://invoice.horizonpay.co/problems/invalid-state",
                      "title": "Invalid state for this operation",
                      "status": 409,
                      "detail": "Invoice is draft and cannot be marked paid.",
                      "instance": "req_7f3c9a1e2b4d4e8a9c6f2d1b0a3e5f71",
                      "code": "invalid_state"
                    }
                  },
                  "conflict_2": {
                    "summary": "A request with this Idempotency-Key is still in flight. Retry in a moment.",
                    "value": {
                      "type": "https://invoice.horizonpay.co/problems/conflict",
                      "title": "Conflict",
                      "status": 409,
                      "detail": "A request with this Idempotency-Key is still in flight. Retry in a moment.",
                      "instance": "req_7f3c9a1e2b4d4e8a9c6f2d1b0a3e5f71",
                      "code": "conflict"
                    }
                  }
                }
              }
            }
          },
          "422": {
            "description": "The body is not valid JSON, or the Idempotency-Key was reused with a different body. Codes: `idempotency_mismatch`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "idempotency_mismatch": {
                    "summary": "This Idempotency-Key was already used with a different request body.",
                    "value": {
                      "type": "https://invoice.horizonpay.co/problems/idempotency-mismatch",
                      "title": "Idempotency-Key reused",
                      "status": 422,
                      "detail": "This Idempotency-Key was already used with a different request body.",
                      "instance": "req_7f3c9a1e2b4d4e8a9c6f2d1b0a3e5f71",
                      "code": "idempotency_mismatch",
                      "errors": [
                        {
                          "path": "Idempotency-Key",
                          "message": "Generate a new key per distinct request, not per retry loop."
                        }
                      ]
                    }
                  }
                }
              }
            }
          },
          "428": {
            "$ref": "#/components/responses/IdempotencyKeyRequired"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/invoices/{id}/void": {
      "post": {
        "operationId": "voidInvoice",
        "summary": "Void an invoice",
        "tags": [
          "Invoices"
        ],
        "description": "Voids an `open` (or overdue) invoice. `reason` is required, up to 500 characters. The number stays on record, so the series has no gaps. A paid invoice cannot be voided (it needs a credit note) and a draft should be deleted instead — both `409`. The response omits `lines`. Emits `invoice.voided`.\n\n**Scope:** `invoices:finalize`\n\n**Idempotency:** `Idempotency-Key` **required** (`428` without it). A retry with the same key and body replays the first response (`Idempotent-Replayed: true`); the same key with a different body is a `422` `idempotency_mismatch`.",
        "x-required-scope": "invoices:finalize",
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "cURL",
            "source": "curl https://invoice.horizonpay.co/api/v1/invoices/in_Pb2Xk7Mv4Qs9Lr1Wd6Tn3Fh8/void \\\n  -H \"Authorization: Bearer $INVOICE_AI_API_KEY\" \\\n  -H \"Idempotency-Key: $(uuidgen)\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{ \"reason\": \"Raised against the wrong customer.\" }'"
          },
          {
            "lang": "node",
            "label": "Node.js",
            "source": "import InvoiceAI from '@horizonpay/invoice-ai'\n\nconst invoiceai = new InvoiceAI() // reads INVOICE_AI_API_KEY\n\n// Retries reuse one Idempotency-Key; pass { idempotencyKey } to set your own.\nconst invoice = await invoiceai.invoices.void('in_Pb2Xk7Mv4Qs9Lr1Wd6Tn3Fh8', {\n  reason: 'Raised against the wrong customer.',\n})\nconsole.log(invoice.status, invoice.void_reason)"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "from invoice_ai import InvoiceAI\n\nclient = InvoiceAI()  # reads INVOICE_AI_API_KEY\n\n# Retries reuse one Idempotency-Key; pass idempotency_key=... to set your own.\ninvoice = client.invoices.void(\n    \"in_Pb2Xk7Mv4Qs9Lr1Wd6Tn3Fh8\",\n    reason=\"Raised against the wrong customer.\",\n)\nprint(invoice.status, invoice.void_reason)"
          }
        ],
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "schema": {
              "type": "string",
              "description": "The invoice, `in_…` or UUID.",
              "examples": [
                "in_Pb2Xk7Mv4Qs9Lr1Wd6Tn3Fh8"
              ]
            },
            "required": true,
            "description": "The invoice, `in_…` or UUID."
          },
          {
            "in": "header",
            "name": "Idempotency-Key",
            "schema": {
              "type": "string",
              "maxLength": 255,
              "description": "A unique key per distinct operation (a UUID works), reused only when retrying that same request. Up to 255 characters; stored for 24 hours.",
              "examples": [
                "6f1c2d9e-8a4b-4c3f-9e7d-2b5a1c8f4e30"
              ]
            },
            "required": true,
            "description": "A unique key per distinct operation (a UUID works), reused only when retrying that same request. Up to 255 characters; stored for 24 hours."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "example": {
                "reason": "Raised against the wrong customer."
              },
              "schema": {
                "$ref": "#/components/schemas/InvoiceVoid"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The voided invoice (without lines).",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "Idempotent-Replayed": {
                "$ref": "#/components/headers/IdempotentReplayed"
              }
            },
            "content": {
              "application/json": {
                "example": {
                  "data": {
                    "id": "in_Pb2Xk7Mv4Qs9Lr1Wd6Tn3Fh8",
                    "object": "invoice",
                    "number": "INV-0042",
                    "status": "void",
                    "customer": "cus_Nf3kQ8pR2mX7vB1cT9wL4sZ6",
                    "currency": "USD",
                    "collection_method": "send_invoice",
                    "issue_date": "2026-09-22",
                    "due_date": "2026-10-22",
                    "description": "Consulting retainer.",
                    "footer": null,
                    "subtotal": 2550000,
                    "discount": 0,
                    "taxable": 2550000,
                    "tax": 0,
                    "total": 2550000,
                    "amount_due": 0,
                    "amount_in_words": "Twenty Five Thousand Five Hundred USD Only",
                    "public_url_token": "2b7e4c1a-9f3d-4e68-8a5b-0d1c7f3e9a46",
                    "finalized_at": "2026-09-22T10:00:00.000Z",
                    "paid_at": null,
                    "voided_at": "2026-09-29T14:20:00.000Z",
                    "void_reason": "Raised against the wrong customer.",
                    "created": "2026-09-22T09:30:00.000Z",
                    "updated": "2026-09-29T14:20:00.000Z"
                  }
                },
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "description": "The voided invoice.",
                      "$ref": "#/components/schemas/Invoice"
                    }
                  },
                  "required": [
                    "data"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "description": "No such invoice. Another account's resource is also a `404`, so ids cannot be probed. Codes: `not_found`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "not_found": {
                    "summary": "Invoice not found.",
                    "value": {
                      "type": "https://invoice.horizonpay.co/problems/not-found",
                      "title": "Not found",
                      "status": 404,
                      "detail": "Invoice not found.",
                      "instance": "req_7f3c9a1e2b4d4e8a9c6f2d1b0a3e5f71",
                      "code": "not_found"
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "The invoice is not open, or the same Idempotency-Key is still running. Codes: `invalid_state`, `conflict`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "invalid_state_1": {
                    "summary": "A paid invoice needs a credit note, not a void.",
                    "value": {
                      "type": "https://invoice.horizonpay.co/problems/invalid-state",
                      "title": "Invalid state for this operation",
                      "status": 409,
                      "detail": "A paid invoice needs a credit note, not a void.",
                      "instance": "req_7f3c9a1e2b4d4e8a9c6f2d1b0a3e5f71",
                      "code": "invalid_state"
                    }
                  },
                  "conflict_2": {
                    "summary": "A request with this Idempotency-Key is still in flight. Retry in a moment.",
                    "value": {
                      "type": "https://invoice.horizonpay.co/problems/conflict",
                      "title": "Conflict",
                      "status": 409,
                      "detail": "A request with this Idempotency-Key is still in flight. Retry in a moment.",
                      "instance": "req_7f3c9a1e2b4d4e8a9c6f2d1b0a3e5f71",
                      "code": "conflict"
                    }
                  }
                }
              }
            }
          },
          "422": {
            "description": "`reason` is missing or blank, or the Idempotency-Key was reused with a different body. Codes: `validation`, `idempotency_mismatch`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "validation_1": {
                    "summary": "A void reason is required.",
                    "value": {
                      "type": "https://invoice.horizonpay.co/problems/validation",
                      "title": "Validation failed",
                      "status": 422,
                      "detail": "A void reason is required.",
                      "instance": "req_7f3c9a1e2b4d4e8a9c6f2d1b0a3e5f71",
                      "code": "validation",
                      "errors": [
                        {
                          "path": "reason",
                          "message": "Say why this invoice is void."
                        }
                      ]
                    }
                  },
                  "idempotency_mismatch_2": {
                    "summary": "This Idempotency-Key was already used with a different request body.",
                    "value": {
                      "type": "https://invoice.horizonpay.co/problems/idempotency-mismatch",
                      "title": "Idempotency-Key reused",
                      "status": 422,
                      "detail": "This Idempotency-Key was already used with a different request body.",
                      "instance": "req_7f3c9a1e2b4d4e8a9c6f2d1b0a3e5f71",
                      "code": "idempotency_mismatch",
                      "errors": [
                        {
                          "path": "Idempotency-Key",
                          "message": "Generate a new key per distinct request, not per retry loop."
                        }
                      ]
                    }
                  }
                }
              }
            }
          },
          "428": {
            "$ref": "#/components/responses/IdempotencyKeyRequired"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/invoices/{id}/pdf": {
      "get": {
        "operationId": "retrieveInvoicePdf",
        "summary": "Download an invoice PDF",
        "tags": [
          "Invoices"
        ],
        "description": "Returns the PDF bytes (not a link), rendered on demand from the current invoice — drafts too, without a number. Served inline; pass `download=1` for `Content-Disposition: attachment`. Not cacheable.\n\n**Scope:** `invoices:read`",
        "x-required-scope": "invoices:read",
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "cURL",
            "source": "curl https://invoice.horizonpay.co/api/v1/invoices/in_Pb2Xk7Mv4Qs9Lr1Wd6Tn3Fh8/pdf \\\n  -H \"Authorization: Bearer $INVOICE_AI_API_KEY\" \\\n  -o invoice.pdf"
          },
          {
            "lang": "node",
            "label": "Node.js",
            "source": "import { writeFile } from 'node:fs/promises'\nimport InvoiceAI from '@horizonpay/invoice-ai'\n\nconst invoiceai = new InvoiceAI() // reads INVOICE_AI_API_KEY\n\nconst pdf = await invoiceai.invoices.pdf('in_Pb2Xk7Mv4Qs9Lr1Wd6Tn3Fh8')\nawait writeFile('invoice.pdf', Buffer.from(pdf))"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "from invoice_ai import InvoiceAI\n\nclient = InvoiceAI()  # reads INVOICE_AI_API_KEY\n\npdf = client.invoices.pdf(\"in_Pb2Xk7Mv4Qs9Lr1Wd6Tn3Fh8\")\nwith open(\"invoice.pdf\", \"wb\") as f:\n    f.write(pdf)"
          }
        ],
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "schema": {
              "type": "string",
              "description": "The invoice, `in_…` or UUID.",
              "examples": [
                "in_Pb2Xk7Mv4Qs9Lr1Wd6Tn3Fh8"
              ]
            },
            "required": true,
            "description": "The invoice, `in_…` or UUID."
          },
          {
            "in": "query",
            "name": "download",
            "schema": {
              "description": "`1` to download as an attachment instead of displaying inline.",
              "type": "string",
              "enum": [
                "1"
              ]
            },
            "description": "`1` to download as an attachment instead of displaying inline."
          }
        ],
        "responses": {
          "200": {
            "description": "The PDF.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "Content-Disposition": {
                "description": "`inline` or `attachment`, with the file name.",
                "schema": {
                  "type": "string",
                  "examples": [
                    "inline; filename=\"INV-0042.pdf\""
                  ]
                }
              }
            },
            "content": {
              "application/pdf": {
                "schema": {
                  "type": "string",
                  "description": "PDF document bytes.",
                  "format": "binary"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "description": "No such invoice. Another account's resource is also a `404`, so ids cannot be probed. Codes: `not_found`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "not_found": {
                    "summary": "Invoice not found.",
                    "value": {
                      "type": "https://invoice.horizonpay.co/problems/not-found",
                      "title": "Not found",
                      "status": 404,
                      "detail": "Invoice not found.",
                      "instance": "req_7f3c9a1e2b4d4e8a9c6f2d1b0a3e5f71",
                      "code": "not_found"
                    }
                  }
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/invoices/{id}/events": {
      "get": {
        "operationId": "listInvoiceEvents",
        "summary": "List invoice events",
        "tags": [
          "Invoices"
        ],
        "description": "Lists one invoice’s history, newest first: created, updated, finalized, emailed, viewed, downloaded, paid, voided. `invoice.viewed` and `invoice.downloaded` mean the customer opened the public link; each is recorded at most once per invoice every 10 minutes.\n\n**Scope:** `invoices:read`",
        "x-required-scope": "invoices:read",
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "cURL",
            "source": "curl https://invoice.horizonpay.co/api/v1/invoices/in_Pb2Xk7Mv4Qs9Lr1Wd6Tn3Fh8/events \\\n  -H \"Authorization: Bearer $INVOICE_AI_API_KEY\""
          },
          {
            "lang": "node",
            "label": "Node.js",
            "source": "import InvoiceAI from '@horizonpay/invoice-ai'\n\nconst invoiceai = new InvoiceAI() // reads INVOICE_AI_API_KEY\n\nfor await (const event of invoiceai.invoices.events('in_Pb2Xk7Mv4Qs9Lr1Wd6Tn3Fh8')) {\n  console.log(event.type, event.created_at)\n}"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "from invoice_ai import InvoiceAI\n\nclient = InvoiceAI()  # reads INVOICE_AI_API_KEY\n\nfor event in client.invoices.events(\"in_Pb2Xk7Mv4Qs9Lr1Wd6Tn3Fh8\"):\n    print(event.type, event.created_at)"
          }
        ],
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "schema": {
              "type": "string",
              "description": "The invoice, `in_…` or UUID.",
              "examples": [
                "in_Pb2Xk7Mv4Qs9Lr1Wd6Tn3Fh8"
              ]
            },
            "required": true,
            "description": "The invoice, `in_…` or UUID."
          },
          {
            "in": "query",
            "name": "cursor",
            "schema": {
              "description": "The `next_cursor` from the previous page. Opaque — do not build it yourself.",
              "type": "string"
            },
            "description": "The `next_cursor` from the previous page. Opaque — do not build it yourself."
          },
          {
            "in": "query",
            "name": "limit",
            "schema": {
              "default": 25,
              "description": "Page size, 1–100. Defaults to 25.",
              "type": "integer",
              "minimum": 1,
              "maximum": 100
            },
            "description": "Page size, 1–100. Defaults to 25."
          }
        ],
        "responses": {
          "200": {
            "description": "A page of events, newest first.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "example": {
                  "data": [
                    {
                      "id": "9b1e5c7a-2d4f-4a86-b3e0-7c5d1f9a2e64",
                      "type": "invoice.paid",
                      "meta": {
                        "actor": "api_key",
                        "request_id": "req_7f3c9a1e2b4d4e8a9c6f2d1b0a3e5f71",
                        "api_key_id": "6d3a9f1c-8e2b-4c75-a0d4-1f7e3b9c5a28",
                        "reference": "chk_123456"
                      },
                      "created_at": "2026-09-29T14:20:00.000Z"
                    },
                    {
                      "id": "3e8d1a6c-5f2b-4c90-a7e3-8b4d2f1c6a95",
                      "type": "invoice.viewed",
                      "meta": null,
                      "created_at": "2026-09-23T08:12:00.000Z"
                    },
                    {
                      "id": "7a2c9e4f-1b6d-4f38-9e5a-2c8b6d4f1e07",
                      "type": "invoice.emailed",
                      "meta": {
                        "to": "ap@acme.example"
                      },
                      "created_at": "2026-09-22T10:00:05.000Z"
                    },
                    {
                      "id": "5c4f7b2e-9a1d-4e63-8f0b-6d3a2e9c7b18",
                      "type": "invoice.finalized",
                      "meta": {
                        "actor": "api_key",
                        "request_id": "req_7f3c9a1e2b4d4e8a9c6f2d1b0a3e5f71",
                        "api_key_id": "6d3a9f1c-8e2b-4c75-a0d4-1f7e3b9c5a28"
                      },
                      "created_at": "2026-09-22T10:00:00.000Z"
                    },
                    {
                      "id": "1d9b6e3a-4c7f-4a25-b8e1-9f2c5a7d3b60",
                      "type": "invoice.created",
                      "meta": {
                        "actor": "api_key",
                        "request_id": "req_7f3c9a1e2b4d4e8a9c6f2d1b0a3e5f71",
                        "api_key_id": "6d3a9f1c-8e2b-4c75-a0d4-1f7e3b9c5a28"
                      },
                      "created_at": "2026-09-22T09:30:00.000Z"
                    }
                  ],
                  "next_cursor": null
                },
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/InvoiceEvent"
                      },
                      "description": "Events, newest first."
                    },
                    "next_cursor": {
                      "anyOf": [
                        {
                          "type": "string"
                        },
                        {
                          "type": "null"
                        }
                      ],
                      "description": "Pass as `cursor` to fetch the next page. `null` on the last page.",
                      "examples": [
                        "MjAyNi0wOS0yMlQwOTozMDowMC4wMDBafDdmM2M"
                      ]
                    }
                  },
                  "required": [
                    "data",
                    "next_cursor"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "description": "No such invoice. Another account's resource is also a `404`, so ids cannot be probed. Codes: `not_found`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "not_found": {
                    "summary": "Invoice not found.",
                    "value": {
                      "type": "https://invoice.horizonpay.co/problems/not-found",
                      "title": "Not found",
                      "status": 404,
                      "detail": "Invoice not found.",
                      "instance": "req_7f3c9a1e2b4d4e8a9c6f2d1b0a3e5f71",
                      "code": "not_found"
                    }
                  }
                }
              }
            }
          },
          "422": {
            "description": "`cursor` is not a `next_cursor` this API returned. Codes: `validation`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "validation": {
                    "summary": "The cursor is not valid.",
                    "value": {
                      "type": "https://invoice.horizonpay.co/problems/validation",
                      "title": "Validation failed",
                      "status": 422,
                      "detail": "The cursor is not valid.",
                      "instance": "req_7f3c9a1e2b4d4e8a9c6f2d1b0a3e5f71",
                      "code": "validation",
                      "errors": [
                        {
                          "path": "cursor",
                          "message": "Pass the `next_cursor` from the previous page, unchanged."
                        }
                      ]
                    }
                  }
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/invoice-items": {
      "get": {
        "operationId": "listInvoiceItems",
        "summary": "List invoice items",
        "tags": [
          "Invoice items"
        ],
        "description": "Returns every line of one invoice, in order. `invoice` is required; the result is not paginated.\n\n**Scope:** `invoices:read`",
        "x-required-scope": "invoices:read",
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "cURL",
            "source": "curl \"https://invoice.horizonpay.co/api/v1/invoice-items?invoice=in_Pb2Xk7Mv4Qs9Lr1Wd6Tn3Fh8\" \\\n  -H \"Authorization: Bearer $INVOICE_AI_API_KEY\""
          },
          {
            "lang": "node",
            "label": "Node.js",
            "source": "import InvoiceAI from '@horizonpay/invoice-ai'\n\nconst invoiceai = new InvoiceAI() // reads INVOICE_AI_API_KEY\n\nfor await (const item of invoiceai.invoiceItems.list({\n  invoice: 'in_Pb2Xk7Mv4Qs9Lr1Wd6Tn3Fh8',\n})) {\n  console.log(item.description, item.amount)\n}"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "from invoice_ai import InvoiceAI\n\nclient = InvoiceAI()  # reads INVOICE_AI_API_KEY\n\nfor item in client.invoice_items.list(invoice=\"in_Pb2Xk7Mv4Qs9Lr1Wd6Tn3Fh8\"):\n    print(item.description, item.amount)"
          }
        ],
        "parameters": [
          {
            "in": "query",
            "name": "invoice",
            "schema": {
              "type": "string",
              "description": "The invoice, `in_…` or UUID.",
              "examples": [
                "in_Pb2Xk7Mv4Qs9Lr1Wd6Tn3Fh8"
              ]
            },
            "required": true,
            "description": "The invoice, `in_…` or UUID."
          }
        ],
        "responses": {
          "200": {
            "description": "The invoice lines.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "example": {
                  "data": [
                    {
                      "id": "ii_Da4Vq9Ns2Kx7Bm3Yt8Rc1Lp6",
                      "object": "invoiceitem",
                      "price": "price_Jc5Tn8Wq1Ze6Ra3Ym9Ub2Gs7",
                      "product": "prod_Hy7Rq2Lm9Xc4Vb8Nt3Kd6Pw1",
                      "description": "Consulting retainer",
                      "quantity": 1,
                      "unit": "NOS",
                      "unit_amount": 2500000,
                      "amount": 2500000,
                      "discount_percent": 0,
                      "tax_rate": 0,
                      "tax_amount": 0
                    },
                    {
                      "id": "ii_Ew8Hz3Jc6Tq1Ms5Nv9Kb2Xr4",
                      "object": "invoiceitem",
                      "price": null,
                      "product": null,
                      "description": "Onboarding workshop",
                      "quantity": 1,
                      "unit": "NOS",
                      "unit_amount": 50000,
                      "amount": 50000,
                      "discount_percent": 0,
                      "tax_rate": 0,
                      "tax_amount": 0
                    }
                  ]
                },
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/InvoiceItem"
                      },
                      "description": "The lines, in order."
                    }
                  },
                  "required": [
                    "data"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "description": "No such invoice. Another account's resource is also a `404`, so ids cannot be probed. Codes: `not_found`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "not_found": {
                    "summary": "Invoice not found.",
                    "value": {
                      "type": "https://invoice.horizonpay.co/problems/not-found",
                      "title": "Not found",
                      "status": 404,
                      "detail": "Invoice not found.",
                      "instance": "req_7f3c9a1e2b4d4e8a9c6f2d1b0a3e5f71",
                      "code": "not_found"
                    }
                  }
                }
              }
            }
          },
          "422": {
            "description": "`invoice` is missing. Codes: `validation`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "validation": {
                    "summary": "Some fields need attention.",
                    "value": {
                      "type": "https://invoice.horizonpay.co/problems/validation",
                      "title": "Validation failed",
                      "status": 422,
                      "detail": "Some fields need attention.",
                      "instance": "req_7f3c9a1e2b4d4e8a9c6f2d1b0a3e5f71",
                      "code": "validation",
                      "errors": [
                        {
                          "path": "invoice",
                          "message": "Pick an invoice"
                        }
                      ]
                    }
                  }
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      },
      "post": {
        "operationId": "createInvoiceItem",
        "summary": "Add an invoice item",
        "tags": [
          "Invoice items"
        ],
        "description": "Appends a line to a draft: a `price`, or `description` + `unit_amount`. Returns the whole recomputed invoice; every line gets a new id. Finalized invoices return `409`. Emits `invoice.updated`.\n\n**Scope:** `invoices:write` + `business:read`\n\n**Idempotency:** `Idempotency-Key` **required** (`428` without it). A retry with the same key and body replays the first response (`Idempotent-Replayed: true`); the same key with a different body is a `422` `idempotency_mismatch`.",
        "x-required-scope": "invoices:write",
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "cURL",
            "source": "curl https://invoice.horizonpay.co/api/v1/invoice-items \\\n  -H \"Authorization: Bearer $INVOICE_AI_API_KEY\" \\\n  -H \"Idempotency-Key: $(uuidgen)\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n    \"invoice\": \"in_Pb2Xk7Mv4Qs9Lr1Wd6Tn3Fh8\",\n    \"description\": \"Extra review round\",\n    \"quantity\": 1,\n    \"unit_amount\": 10000\n  }'"
          },
          {
            "lang": "node",
            "label": "Node.js",
            "source": "import InvoiceAI from '@horizonpay/invoice-ai'\n\nconst invoiceai = new InvoiceAI() // reads INVOICE_AI_API_KEY\n\n// Retries reuse one Idempotency-Key; pass { idempotencyKey } to set your own.\nconst invoice = await invoiceai.invoiceItems.create({\n  invoice: 'in_Pb2Xk7Mv4Qs9Lr1Wd6Tn3Fh8',\n  description: 'Extra review round',\n  quantity: 1,\n  unit_amount: 10000,\n})\nconsole.log(invoice.total)"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "from invoice_ai import InvoiceAI\n\nclient = InvoiceAI()  # reads INVOICE_AI_API_KEY\n\n# Retries reuse one Idempotency-Key; pass idempotency_key=... to set your own.\ninvoice = client.invoice_items.create(\n    invoice=\"in_Pb2Xk7Mv4Qs9Lr1Wd6Tn3Fh8\",\n    description=\"Extra review round\",\n    quantity=1,\n    unit_amount=10000,\n)\nprint(invoice.total)"
          }
        ],
        "parameters": [
          {
            "in": "header",
            "name": "Idempotency-Key",
            "schema": {
              "type": "string",
              "maxLength": 255,
              "description": "A unique key per distinct operation (a UUID works), reused only when retrying that same request. Up to 255 characters; stored for 24 hours.",
              "examples": [
                "6f1c2d9e-8a4b-4c3f-9e7d-2b5a1c8f4e30"
              ]
            },
            "required": true,
            "description": "A unique key per distinct operation (a UUID works), reused only when retrying that same request. Up to 255 characters; stored for 24 hours."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "example": {
                "invoice": "in_Pb2Xk7Mv4Qs9Lr1Wd6Tn3Fh8",
                "description": "Extra review round",
                "quantity": 1,
                "unit_amount": 10000
              },
              "schema": {
                "$ref": "#/components/schemas/InvoiceItemCreate"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "The whole draft, with the new line last.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "Idempotent-Replayed": {
                "$ref": "#/components/headers/IdempotentReplayed"
              }
            },
            "content": {
              "application/json": {
                "example": {
                  "data": {
                    "id": "in_Pb2Xk7Mv4Qs9Lr1Wd6Tn3Fh8",
                    "object": "invoice",
                    "number": null,
                    "status": "draft",
                    "customer": "cus_Nf3kQ8pR2mX7vB1cT9wL4sZ6",
                    "currency": "USD",
                    "collection_method": "send_invoice",
                    "issue_date": "2026-09-22",
                    "due_date": "2026-10-22",
                    "description": "Consulting retainer.",
                    "footer": null,
                    "subtotal": 2560000,
                    "discount": 0,
                    "taxable": 2560000,
                    "tax": 0,
                    "total": 2560000,
                    "amount_due": 0,
                    "amount_in_words": "Twenty Five Thousand Six Hundred USD Only",
                    "public_url_token": "2b7e4c1a-9f3d-4e68-8a5b-0d1c7f3e9a46",
                    "finalized_at": null,
                    "paid_at": null,
                    "voided_at": null,
                    "void_reason": null,
                    "created": "2026-09-22T09:30:00.000Z",
                    "updated": "2026-09-22T09:45:00.000Z",
                    "lines": {
                      "data": [
                        {
                          "id": "ii_Da4Vq9Ns2Kx7Bm3Yt8Rc1Lp6",
                          "object": "invoiceitem",
                          "price": "price_Jc5Tn8Wq1Ze6Ra3Ym9Ub2Gs7",
                          "product": "prod_Hy7Rq2Lm9Xc4Vb8Nt3Kd6Pw1",
                          "description": "Consulting retainer",
                          "quantity": 1,
                          "unit": "NOS",
                          "unit_amount": 2500000,
                          "amount": 2500000,
                          "discount_percent": 0,
                          "tax_rate": 0,
                          "tax_amount": 0
                        },
                        {
                          "id": "ii_Ew8Hz3Jc6Tq1Ms5Nv9Kb2Xr4",
                          "object": "invoiceitem",
                          "price": null,
                          "product": null,
                          "description": "Onboarding workshop",
                          "quantity": 1,
                          "unit": "NOS",
                          "unit_amount": 50000,
                          "amount": 50000,
                          "discount_percent": 0,
                          "tax_rate": 0,
                          "tax_amount": 0
                        },
                        {
                          "id": "ii_Gk2Rw7Lq4Zt9Xn1Vb6Mc3Hs8",
                          "object": "invoiceitem",
                          "price": null,
                          "product": null,
                          "description": "Extra review round",
                          "quantity": 1,
                          "unit": "NOS",
                          "unit_amount": 10000,
                          "amount": 10000,
                          "discount_percent": 0,
                          "tax_rate": 0,
                          "tax_amount": 0
                        }
                      ]
                    }
                  }
                },
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "description": "The updated draft.",
                      "$ref": "#/components/schemas/Invoice"
                    }
                  },
                  "required": [
                    "data"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "description": "No such invoice. Another account's resource is also a `404`, so ids cannot be probed. Codes: `not_found`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "not_found": {
                    "summary": "Invoice not found.",
                    "value": {
                      "type": "https://invoice.horizonpay.co/problems/not-found",
                      "title": "Not found",
                      "status": 404,
                      "detail": "Invoice not found.",
                      "instance": "req_7f3c9a1e2b4d4e8a9c6f2d1b0a3e5f71",
                      "code": "not_found"
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "The invoice has been finalized, or the same Idempotency-Key is still running. Codes: `invalid_state`, `conflict`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "invalid_state_1": {
                    "summary": "This invoice has been finalized and can no longer be edited.",
                    "value": {
                      "type": "https://invoice.horizonpay.co/problems/invalid-state",
                      "title": "Invalid state for this operation",
                      "status": 409,
                      "detail": "This invoice has been finalized and can no longer be edited.",
                      "instance": "req_7f3c9a1e2b4d4e8a9c6f2d1b0a3e5f71",
                      "code": "invalid_state"
                    }
                  },
                  "conflict_2": {
                    "summary": "A request with this Idempotency-Key is still in flight. Retry in a moment.",
                    "value": {
                      "type": "https://invoice.horizonpay.co/problems/conflict",
                      "title": "Conflict",
                      "status": 409,
                      "detail": "A request with this Idempotency-Key is still in flight. Retry in a moment.",
                      "instance": "req_7f3c9a1e2b4d4e8a9c6f2d1b0a3e5f71",
                      "code": "conflict"
                    }
                  }
                }
              }
            }
          },
          "422": {
            "description": "The body failed validation, or the Idempotency-Key was reused with a different body. Codes: `validation`, `idempotency_mismatch`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "validation_1": {
                    "summary": "Some fields need attention.",
                    "value": {
                      "type": "https://invoice.horizonpay.co/problems/validation",
                      "title": "Validation failed",
                      "status": 422,
                      "detail": "Some fields need attention.",
                      "instance": "req_7f3c9a1e2b4d4e8a9c6f2d1b0a3e5f71",
                      "code": "validation",
                      "errors": [
                        {
                          "path": "items.2.description",
                          "message": "Describe what you are billing for"
                        }
                      ]
                    }
                  },
                  "idempotency_mismatch_2": {
                    "summary": "This Idempotency-Key was already used with a different request body.",
                    "value": {
                      "type": "https://invoice.horizonpay.co/problems/idempotency-mismatch",
                      "title": "Idempotency-Key reused",
                      "status": 422,
                      "detail": "This Idempotency-Key was already used with a different request body.",
                      "instance": "req_7f3c9a1e2b4d4e8a9c6f2d1b0a3e5f71",
                      "code": "idempotency_mismatch",
                      "errors": [
                        {
                          "path": "Idempotency-Key",
                          "message": "Generate a new key per distinct request, not per retry loop."
                        }
                      ]
                    }
                  }
                }
              }
            }
          },
          "428": {
            "$ref": "#/components/responses/IdempotencyKeyRequired"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/invoice-items/{id}": {
      "get": {
        "operationId": "retrieveInvoiceItem",
        "summary": "Retrieve an invoice item",
        "tags": [
          "Invoice items"
        ],
        "description": "Returns one invoice line by `ii_…` id or UUID.\n\n**Scope:** `invoices:read`",
        "x-required-scope": "invoices:read",
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "cURL",
            "source": "curl https://invoice.horizonpay.co/api/v1/invoice-items/ii_Da4Vq9Ns2Kx7Bm3Yt8Rc1Lp6 \\\n  -H \"Authorization: Bearer $INVOICE_AI_API_KEY\""
          },
          {
            "lang": "node",
            "label": "Node.js",
            "source": "import InvoiceAI from '@horizonpay/invoice-ai'\n\nconst invoiceai = new InvoiceAI() // reads INVOICE_AI_API_KEY\n\nconst item = await invoiceai.invoiceItems.retrieve('ii_Da4Vq9Ns2Kx7Bm3Yt8Rc1Lp6')\nconsole.log(item.description, item.amount)"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "from invoice_ai import InvoiceAI\n\nclient = InvoiceAI()  # reads INVOICE_AI_API_KEY\n\nitem = client.invoice_items.retrieve(\"ii_Da4Vq9Ns2Kx7Bm3Yt8Rc1Lp6\")\nprint(item.description, item.amount)"
          }
        ],
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "schema": {
              "type": "string",
              "description": "The line, `ii_…` or UUID.",
              "examples": [
                "ii_Da4Vq9Ns2Kx7Bm3Yt8Rc1Lp6"
              ]
            },
            "required": true,
            "description": "The line, `ii_…` or UUID."
          }
        ],
        "responses": {
          "200": {
            "description": "The line.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "example": {
                  "data": {
                    "id": "ii_Da4Vq9Ns2Kx7Bm3Yt8Rc1Lp6",
                    "object": "invoiceitem",
                    "price": "price_Jc5Tn8Wq1Ze6Ra3Ym9Ub2Gs7",
                    "product": "prod_Hy7Rq2Lm9Xc4Vb8Nt3Kd6Pw1",
                    "description": "Consulting retainer",
                    "quantity": 1,
                    "unit": "NOS",
                    "unit_amount": 2500000,
                    "amount": 2500000,
                    "discount_percent": 0,
                    "tax_rate": 0,
                    "tax_amount": 0
                  }
                },
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "description": "The line.",
                      "$ref": "#/components/schemas/InvoiceItem"
                    }
                  },
                  "required": [
                    "data"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "description": "No such line. Another account's resource is also a `404`, so ids cannot be probed. Codes: `not_found`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "not_found": {
                    "summary": "Invoice item not found.",
                    "value": {
                      "type": "https://invoice.horizonpay.co/problems/not-found",
                      "title": "Not found",
                      "status": 404,
                      "detail": "Invoice item not found.",
                      "instance": "req_7f3c9a1e2b4d4e8a9c6f2d1b0a3e5f71",
                      "code": "not_found"
                    }
                  }
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      },
      "delete": {
        "operationId": "deleteInvoiceItem",
        "summary": "Remove an invoice item",
        "tags": [
          "Invoice items"
        ],
        "description": "Removes a line from a draft and returns the recomputed invoice. A draft keeps at least one line, and finalized invoices are frozen — both `409`. Pass `invoice` to speed up the lookup. Emits `invoice.updated`.\n\n**Scope:** `invoices:write` + `business:read`",
        "x-required-scope": "invoices:write",
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "cURL",
            "source": "curl -X DELETE https://invoice.horizonpay.co/api/v1/invoice-items/ii_Gk2Rw7Lq4Zt9Xn1Vb6Mc3Hs8 \\\n  -H \"Authorization: Bearer $INVOICE_AI_API_KEY\""
          },
          {
            "lang": "node",
            "label": "Node.js",
            "source": "import InvoiceAI from '@horizonpay/invoice-ai'\n\nconst invoiceai = new InvoiceAI() // reads INVOICE_AI_API_KEY\n\nconst invoice = await invoiceai.invoiceItems.del('ii_Gk2Rw7Lq4Zt9Xn1Vb6Mc3Hs8')\nconsole.log(invoice.total)"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "from invoice_ai import InvoiceAI\n\nclient = InvoiceAI()  # reads INVOICE_AI_API_KEY\n\ninvoice = client.invoice_items.delete(\"ii_Gk2Rw7Lq4Zt9Xn1Vb6Mc3Hs8\")\nprint(invoice.total)"
          }
        ],
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "schema": {
              "type": "string",
              "description": "The line, `ii_…` or UUID.",
              "examples": [
                "ii_Gk2Rw7Lq4Zt9Xn1Vb6Mc3Hs8"
              ]
            },
            "required": true,
            "description": "The line, `ii_…` or UUID."
          },
          {
            "in": "query",
            "name": "invoice",
            "schema": {
              "description": "The invoice the line belongs to, `in_…` or UUID. Speeds up the lookup.",
              "examples": [
                "in_Pb2Xk7Mv4Qs9Lr1Wd6Tn3Fh8"
              ],
              "type": "string"
            },
            "description": "The invoice the line belongs to, `in_…` or UUID. Speeds up the lookup."
          }
        ],
        "responses": {
          "200": {
            "description": "The updated draft, without the removed line.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "example": {
                  "data": {
                    "id": "in_Pb2Xk7Mv4Qs9Lr1Wd6Tn3Fh8",
                    "object": "invoice",
                    "number": null,
                    "status": "draft",
                    "customer": "cus_Nf3kQ8pR2mX7vB1cT9wL4sZ6",
                    "currency": "USD",
                    "collection_method": "send_invoice",
                    "issue_date": "2026-09-22",
                    "due_date": "2026-10-22",
                    "description": "Consulting retainer.",
                    "footer": null,
                    "subtotal": 2550000,
                    "discount": 0,
                    "taxable": 2550000,
                    "tax": 0,
                    "total": 2550000,
                    "amount_due": 0,
                    "amount_in_words": "Twenty Five Thousand Five Hundred USD Only",
                    "public_url_token": "2b7e4c1a-9f3d-4e68-8a5b-0d1c7f3e9a46",
                    "finalized_at": null,
                    "paid_at": null,
                    "voided_at": null,
                    "void_reason": null,
                    "created": "2026-09-22T09:30:00.000Z",
                    "updated": "2026-09-22T09:45:00.000Z",
                    "lines": {
                      "data": [
                        {
                          "id": "ii_Da4Vq9Ns2Kx7Bm3Yt8Rc1Lp6",
                          "object": "invoiceitem",
                          "price": "price_Jc5Tn8Wq1Ze6Ra3Ym9Ub2Gs7",
                          "product": "prod_Hy7Rq2Lm9Xc4Vb8Nt3Kd6Pw1",
                          "description": "Consulting retainer",
                          "quantity": 1,
                          "unit": "NOS",
                          "unit_amount": 2500000,
                          "amount": 2500000,
                          "discount_percent": 0,
                          "tax_rate": 0,
                          "tax_amount": 0
                        },
                        {
                          "id": "ii_Ew8Hz3Jc6Tq1Ms5Nv9Kb2Xr4",
                          "object": "invoiceitem",
                          "price": null,
                          "product": null,
                          "description": "Onboarding workshop",
                          "quantity": 1,
                          "unit": "NOS",
                          "unit_amount": 50000,
                          "amount": 50000,
                          "discount_percent": 0,
                          "tax_rate": 0,
                          "tax_amount": 0
                        }
                      ]
                    }
                  }
                },
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "description": "The updated draft.",
                      "$ref": "#/components/schemas/Invoice"
                    }
                  },
                  "required": [
                    "data"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "description": "No such line (or invoice). Another account's resource is also a `404`, so ids cannot be probed. Codes: `not_found`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "not_found": {
                    "summary": "Invoice item not found.",
                    "value": {
                      "type": "https://invoice.horizonpay.co/problems/not-found",
                      "title": "Not found",
                      "status": 404,
                      "detail": "Invoice item not found.",
                      "instance": "req_7f3c9a1e2b4d4e8a9c6f2d1b0a3e5f71",
                      "code": "not_found"
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "The invoice has been finalized, or this is its only line. Codes: `invalid_state`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "invalid_state_1": {
                    "summary": "This invoice has been finalized and can no longer be edited.",
                    "value": {
                      "type": "https://invoice.horizonpay.co/problems/invalid-state",
                      "title": "Invalid state for this operation",
                      "status": 409,
                      "detail": "This invoice has been finalized and can no longer be edited.",
                      "instance": "req_7f3c9a1e2b4d4e8a9c6f2d1b0a3e5f71",
                      "code": "invalid_state"
                    }
                  },
                  "invalid_state_2": {
                    "summary": "An invoice needs at least one line item.",
                    "value": {
                      "type": "https://invoice.horizonpay.co/problems/invalid-state",
                      "title": "Invalid state for this operation",
                      "status": 409,
                      "detail": "An invoice needs at least one line item.",
                      "instance": "req_7f3c9a1e2b4d4e8a9c6f2d1b0a3e5f71",
                      "code": "invalid_state"
                    }
                  }
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/webhook-endpoints": {
      "get": {
        "operationId": "listWebhookEndpoints",
        "summary": "List webhook endpoints",
        "tags": [
          "Webhook endpoints"
        ],
        "description": "Lists your webhook endpoints, newest first. Signing secrets are never included.\n\n**Scope:** `webhooks:manage`",
        "x-required-scope": "webhooks:manage",
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "cURL",
            "source": "curl https://invoice.horizonpay.co/api/v1/webhook-endpoints \\\n  -H \"Authorization: Bearer $INVOICE_AI_API_KEY\""
          },
          {
            "lang": "node",
            "label": "Node.js",
            "source": "import InvoiceAI from '@horizonpay/invoice-ai'\n\nconst invoiceai = new InvoiceAI() // reads INVOICE_AI_API_KEY\n\nfor await (const endpoint of invoiceai.webhookEndpoints.list()) {\n  console.log(endpoint.url, endpoint.active)\n}"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "from invoice_ai import InvoiceAI\n\nclient = InvoiceAI()  # reads INVOICE_AI_API_KEY\n\nfor endpoint in client.webhook_endpoints.list():\n    print(endpoint.url, endpoint.active)"
          }
        ],
        "parameters": [
          {
            "in": "query",
            "name": "cursor",
            "schema": {
              "description": "The `next_cursor` from the previous page. Opaque — do not build it yourself.",
              "type": "string"
            },
            "description": "The `next_cursor` from the previous page. Opaque — do not build it yourself."
          },
          {
            "in": "query",
            "name": "limit",
            "schema": {
              "default": 25,
              "description": "Page size, 1–100. Defaults to 25.",
              "type": "integer",
              "minimum": 1,
              "maximum": 100
            },
            "description": "Page size, 1–100. Defaults to 25."
          }
        ],
        "responses": {
          "200": {
            "description": "A page of endpoints.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "example": {
                  "data": [
                    {
                      "id": "4f9c2a1e-7b3d-4e8a-9c6f-2d1b0a3e5f71",
                      "url": "https://example.com/webhooks/invoice-ai",
                      "events": [
                        "invoice.finalized",
                        "invoice.paid"
                      ],
                      "active": true,
                      "disabled_at": null,
                      "failure_count": 0,
                      "created_at": "2026-09-22T09:30:00.000Z"
                    }
                  ],
                  "next_cursor": null
                },
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/WebhookEndpoint"
                      },
                      "description": "Webhook endpoints, newest first."
                    },
                    "next_cursor": {
                      "anyOf": [
                        {
                          "type": "string"
                        },
                        {
                          "type": "null"
                        }
                      ],
                      "description": "Pass as `cursor` to fetch the next page. `null` on the last page.",
                      "examples": [
                        "MjAyNi0wOS0yMlQwOTozMDowMC4wMDBafDdmM2M"
                      ]
                    }
                  },
                  "required": [
                    "data",
                    "next_cursor"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "422": {
            "description": "`cursor` is not a `next_cursor` this API returned. Codes: `validation`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "validation": {
                    "summary": "The cursor is not valid.",
                    "value": {
                      "type": "https://invoice.horizonpay.co/problems/validation",
                      "title": "Validation failed",
                      "status": 422,
                      "detail": "The cursor is not valid.",
                      "instance": "req_7f3c9a1e2b4d4e8a9c6f2d1b0a3e5f71",
                      "code": "validation",
                      "errors": [
                        {
                          "path": "cursor",
                          "message": "Pass the `next_cursor` from the previous page, unchanged."
                        }
                      ]
                    }
                  }
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      },
      "post": {
        "operationId": "createWebhookEndpoint",
        "summary": "Create a webhook endpoint",
        "tags": [
          "Webhook endpoints"
        ],
        "description": "Registers a URL to receive signed invoice events. The response carries the signing `secret` (`whsec_…`) — the only time it is returned, so store it.\n\n**URL rules:** `https` only, at most 2048 characters, no username or password, and every address it resolves to must be public — private, loopback, link-local and IPv4-embedding IPv6 ranges (NAT64, 6to4, Teredo) are rejected. The check runs again at every delivery, and redirects are not followed.\n\n**Scope:** `webhooks:manage`\n\n**Idempotency:** `Idempotency-Key` optional. With one, a retry with the same key and body replays the first response (`Idempotent-Replayed: true`); the same key with a different body is a `422` `idempotency_mismatch`.",
        "x-required-scope": "webhooks:manage",
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "cURL",
            "source": "curl https://invoice.horizonpay.co/api/v1/webhook-endpoints \\\n  -H \"Authorization: Bearer $INVOICE_AI_API_KEY\" \\\n  -H \"Idempotency-Key: $(uuidgen)\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n    \"url\": \"https://example.com/webhooks/invoice-ai\",\n    \"events\": [\"invoice.finalized\", \"invoice.paid\"]\n  }'"
          },
          {
            "lang": "node",
            "label": "Node.js",
            "source": "import InvoiceAI from '@horizonpay/invoice-ai'\n\nconst invoiceai = new InvoiceAI() // reads INVOICE_AI_API_KEY\n\nconst endpoint = await invoiceai.webhookEndpoints.create({\n  url: 'https://example.com/webhooks/invoice-ai',\n  events: ['invoice.finalized', 'invoice.paid'],\n})\nconsole.log(endpoint.secret) // returned only once — store it"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "from invoice_ai import InvoiceAI\n\nclient = InvoiceAI()  # reads INVOICE_AI_API_KEY\n\nendpoint = client.webhook_endpoints.create(\n    url=\"https://example.com/webhooks/invoice-ai\",\n    events=[\"invoice.finalized\", \"invoice.paid\"],\n)\nprint(endpoint.secret)  # returned only once — store it"
          }
        ],
        "parameters": [
          {
            "in": "header",
            "name": "Idempotency-Key",
            "schema": {
              "description": "A unique key per distinct operation (a UUID works), reused only when retrying that same request. Up to 255 characters; stored for 24 hours.",
              "examples": [
                "6f1c2d9e-8a4b-4c3f-9e7d-2b5a1c8f4e30"
              ],
              "type": "string",
              "maxLength": 255
            },
            "description": "A unique key per distinct operation (a UUID works), reused only when retrying that same request. Up to 255 characters; stored for 24 hours."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "example": {
                "url": "https://example.com/webhooks/invoice-ai",
                "events": [
                  "invoice.finalized",
                  "invoice.paid"
                ]
              },
              "schema": {
                "$ref": "#/components/schemas/WebhookEndpointCreate"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "The endpoint, with its signing secret.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "Idempotent-Replayed": {
                "$ref": "#/components/headers/IdempotentReplayed"
              }
            },
            "content": {
              "application/json": {
                "example": {
                  "data": {
                    "id": "4f9c2a1e-7b3d-4e8a-9c6f-2d1b0a3e5f71",
                    "url": "https://example.com/webhooks/invoice-ai",
                    "events": [
                      "invoice.finalized",
                      "invoice.paid"
                    ],
                    "active": true,
                    "disabled_at": null,
                    "failure_count": 0,
                    "created_at": "2026-09-22T09:30:00.000Z",
                    "secret": "whsec_Zm9vYmFyYmF6cXV4cXV1eGNvcmdl"
                  }
                },
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "object",
                      "properties": {
                        "id": {
                          "type": "string",
                          "description": "Endpoint id (UUID).",
                          "examples": [
                            "4f9c2a1e-7b3d-4e8a-9c6f-2d1b0a3e5f71"
                          ]
                        },
                        "url": {
                          "type": "string",
                          "description": "The https URL deliveries are POSTed to.",
                          "examples": [
                            "https://example.com/webhooks/invoice-ai"
                          ]
                        },
                        "events": {
                          "type": "array",
                          "items": {
                            "type": "string",
                            "enum": [
                              "invoice.created",
                              "invoice.updated",
                              "invoice.finalized",
                              "invoice.emailed",
                              "invoice.email_failed",
                              "invoice.viewed",
                              "invoice.downloaded",
                              "invoice.paid",
                              "invoice.voided"
                            ]
                          },
                          "description": "Subscribed event types. An endpoint registered with no events receives every type, and lists them all here."
                        },
                        "active": {
                          "type": "boolean",
                          "description": "`false` once deliveries are disabled: after 20 deliveries in a row used up every retry. A successful delivery resets the count."
                        },
                        "disabled_at": {
                          "anyOf": [
                            {
                              "type": "string",
                              "format": "date-time"
                            },
                            {
                              "type": "null"
                            }
                          ],
                          "description": "When deliveries were disabled, or `null`."
                        },
                        "failure_count": {
                          "type": "integer",
                          "minimum": -9007199254740991,
                          "maximum": 9007199254740991,
                          "description": "Deliveries in a row that used up every retry. Resets to 0 on any successful delivery.",
                          "examples": [
                            0
                          ]
                        },
                        "created_at": {
                          "type": "string",
                          "description": "When the endpoint was registered (ISO 8601).",
                          "format": "date-time"
                        },
                        "secret": {
                          "type": "string",
                          "description": "Signing secret for verifying `webhook-signature`: `whsec_` followed by standard base64 (Standard Webhooks). Returned only in this response.",
                          "examples": [
                            "whsec_Zm9vYmFyYmF6cXV4cXV1eGNvcmdl"
                          ]
                        }
                      },
                      "required": [
                        "id",
                        "url",
                        "events",
                        "active",
                        "disabled_at",
                        "failure_count",
                        "created_at",
                        "secret"
                      ],
                      "additionalProperties": false,
                      "description": "The created endpoint, including its secret."
                    }
                  },
                  "required": [
                    "data"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "409": {
            "description": "A request with the same Idempotency-Key is still running. Codes: `conflict`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "conflict": {
                    "summary": "A request with this Idempotency-Key is still in flight. Retry in a moment.",
                    "value": {
                      "type": "https://invoice.horizonpay.co/problems/conflict",
                      "title": "Conflict",
                      "status": 409,
                      "detail": "A request with this Idempotency-Key is still in flight. Retry in a moment.",
                      "instance": "req_7f3c9a1e2b4d4e8a9c6f2d1b0a3e5f71",
                      "code": "conflict"
                    }
                  }
                }
              }
            }
          },
          "422": {
            "description": "The URL breaks a rule above (not https, too long, has credentials, or resolves to a non-public address), or an event type is unknown. Codes: `validation`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "validation_1": {
                    "summary": "Webhook URLs must use https.",
                    "value": {
                      "type": "https://invoice.horizonpay.co/problems/validation",
                      "title": "Validation failed",
                      "status": 422,
                      "detail": "Webhook URLs must use https.",
                      "instance": "req_7f3c9a1e2b4d4e8a9c6f2d1b0a3e5f71",
                      "code": "validation",
                      "errors": [
                        {
                          "path": "url",
                          "message": "Webhook URLs must use https."
                        }
                      ]
                    }
                  },
                  "validation_2": {
                    "summary": "Unknown event type: invoice.overdue.",
                    "value": {
                      "type": "https://invoice.horizonpay.co/problems/validation",
                      "title": "Validation failed",
                      "status": 422,
                      "detail": "Unknown event type: invoice.overdue.",
                      "instance": "req_7f3c9a1e2b4d4e8a9c6f2d1b0a3e5f71",
                      "code": "validation",
                      "errors": [
                        {
                          "path": "events",
                          "message": "Valid types are invoice.created, invoice.updated, invoice.finalized, invoice.emailed, invoice.email_failed, invoice.viewed, invoice.downloaded, invoice.paid, invoice.voided."
                        }
                      ]
                    }
                  }
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/webhook-endpoints/{id}": {
      "delete": {
        "operationId": "deleteWebhookEndpoint",
        "summary": "Delete a webhook endpoint",
        "tags": [
          "Webhook endpoints"
        ],
        "description": "Permanently deletes an endpoint; no further deliveries are made to it. Deleting it again is a `404`.\n\n**Scope:** `webhooks:manage`",
        "x-required-scope": "webhooks:manage",
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "cURL",
            "source": "curl -X DELETE https://invoice.horizonpay.co/api/v1/webhook-endpoints/4f9c2a1e-7b3d-4e8a-9c6f-2d1b0a3e5f71 \\\n  -H \"Authorization: Bearer $INVOICE_AI_API_KEY\""
          },
          {
            "lang": "node",
            "label": "Node.js",
            "source": "import InvoiceAI from '@horizonpay/invoice-ai'\n\nconst invoiceai = new InvoiceAI() // reads INVOICE_AI_API_KEY\n\nawait invoiceai.webhookEndpoints.del('4f9c2a1e-7b3d-4e8a-9c6f-2d1b0a3e5f71')"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "from invoice_ai import InvoiceAI\n\nclient = InvoiceAI()  # reads INVOICE_AI_API_KEY\n\nclient.webhook_endpoints.delete(\"4f9c2a1e-7b3d-4e8a-9c6f-2d1b0a3e5f71\")"
          }
        ],
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "schema": {
              "type": "string",
              "description": "The endpoint id (UUID).",
              "examples": [
                "4f9c2a1e-7b3d-4e8a-9c6f-2d1b0a3e5f71"
              ]
            },
            "required": true,
            "description": "The endpoint id (UUID)."
          }
        ],
        "responses": {
          "204": {
            "description": "Deleted. No body.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "description": "No such endpoint. Another account's resource is also a `404`, so ids cannot be probed. Codes: `not_found`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "not_found": {
                    "summary": "Webhook endpoint not found.",
                    "value": {
                      "type": "https://invoice.horizonpay.co/problems/not-found",
                      "title": "Not found",
                      "status": 404,
                      "detail": "Webhook endpoint not found.",
                      "instance": "req_7f3c9a1e2b4d4e8a9c6f2d1b0a3e5f71",
                      "code": "not_found"
                    }
                  }
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "CustomerCreate": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "minLength": 1,
            "description": "Full name or legal business name.",
            "examples": [
              "Acme Industries"
            ]
          },
          "email": {
            "description": "Billing email. `POST /invoices/{id}/send` delivers here unless you pass `to`. `\"\"` clears it.",
            "examples": [
              "ap@acme.example"
            ],
            "anyOf": [
              {
                "type": "string",
                "format": "email",
                "pattern": "^(?!\\.)(?!.*\\.\\.)([A-Za-z0-9_'+\\-\\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$"
              },
              {
                "type": "string",
                "const": ""
              }
            ]
          },
          "phone": {
            "description": "Phone number, free text.",
            "type": "string"
          },
          "tax_id": {
            "description": "Tax registration number (VAT, EIN, GSTIN…), free text — no format check.",
            "type": "string"
          },
          "address": {
            "description": "Billing address. Every field is optional.",
            "type": "object",
            "properties": {
              "line1": {
                "description": "Street address.",
                "type": "string"
              },
              "line2": {
                "description": "Apartment, suite, unit.",
                "type": "string"
              },
              "city": {
                "description": "City or locality.",
                "type": "string"
              },
              "state": {
                "description": "State, province or region.",
                "type": "string"
              },
              "postal_code": {
                "description": "ZIP or postal code.",
                "type": "string"
              },
              "country": {
                "description": "ISO 3166-1 alpha-2 country code (uppercased for you).",
                "examples": [
                  "US"
                ],
                "type": "string",
                "minLength": 2,
                "maxLength": 2
              }
            }
          }
        },
        "required": [
          "name"
        ]
      },
      "CustomerUpdate": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "minLength": 1,
            "description": "Full name or legal business name.",
            "examples": [
              "Acme Industries"
            ]
          },
          "email": {
            "description": "Billing email. `POST /invoices/{id}/send` delivers here unless you pass `to`. `\"\"` clears it.",
            "examples": [
              "ap@acme.example"
            ],
            "anyOf": [
              {
                "type": "string",
                "format": "email",
                "pattern": "^(?!\\.)(?!.*\\.\\.)([A-Za-z0-9_'+\\-\\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$"
              },
              {
                "type": "string",
                "const": ""
              }
            ]
          },
          "phone": {
            "description": "Phone number, free text.",
            "type": "string"
          },
          "tax_id": {
            "description": "Tax registration number (VAT, EIN, GSTIN…), free text — no format check.",
            "type": "string"
          },
          "address": {
            "description": "Billing address. Every field is optional.",
            "type": "object",
            "properties": {
              "line1": {
                "description": "Street address.",
                "type": "string"
              },
              "line2": {
                "description": "Apartment, suite, unit.",
                "type": "string"
              },
              "city": {
                "description": "City or locality.",
                "type": "string"
              },
              "state": {
                "description": "State, province or region.",
                "type": "string"
              },
              "postal_code": {
                "description": "ZIP or postal code.",
                "type": "string"
              },
              "country": {
                "description": "ISO 3166-1 alpha-2 country code (uppercased for you).",
                "examples": [
                  "US"
                ],
                "type": "string",
                "minLength": 2,
                "maxLength": 2
              }
            }
          }
        },
        "description": "Any subset of the create fields. Omitted fields are left unchanged."
      },
      "ProductCreate": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 200,
            "description": "Product name, 1–200 characters. Becomes the default line description.",
            "examples": [
              "Consulting retainer"
            ]
          },
          "description": {
            "description": "Longer description.",
            "type": "string"
          },
          "images": {
            "default": [],
            "description": "Up to 8 image URLs.",
            "examples": [
              []
            ],
            "maxItems": 8,
            "type": "array",
            "items": {
              "type": "string",
              "format": "uri"
            }
          },
          "active": {
            "default": true,
            "description": "Whether the product is available. Defaults to `true` on create.",
            "examples": [
              true
            ],
            "type": "boolean"
          }
        },
        "required": [
          "name"
        ]
      },
      "ProductUpdate": {
        "type": "object",
        "properties": {
          "name": {
            "description": "Product name, 1–200 characters. Becomes the default line description.",
            "examples": [
              "Consulting retainer"
            ],
            "type": "string",
            "minLength": 1,
            "maxLength": 200
          },
          "description": {
            "description": "Longer description. `null` or `\"\"` clears it.",
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ]
          },
          "images": {
            "description": "Up to 8 image URLs.",
            "examples": [
              []
            ],
            "maxItems": 8,
            "type": "array",
            "items": {
              "type": "string",
              "format": "uri"
            }
          },
          "active": {
            "description": "`false` archives, `true` restores.",
            "examples": [
              true
            ],
            "type": "boolean"
          }
        },
        "description": "Any subset of fields. Omitted fields are left unchanged."
      },
      "PriceCreate": {
        "type": "object",
        "properties": {
          "product": {
            "type": "string",
            "minLength": 1,
            "description": "The parent product, `prod_…` or UUID.",
            "examples": [
              "prod_Hy7Rq2Lm9Xc4Vb8Nt3Kd6Pw1"
            ]
          },
          "nickname": {
            "description": "Internal label, e.g. \"Monthly\".",
            "type": "string"
          },
          "unit_amount": {
            "type": "integer",
            "minimum": 0,
            "maximum": 9007199254740991,
            "description": "Price per unit in integer minor units (`2500000` is $25,000.00).",
            "examples": [
              2500000
            ]
          },
          "currency": {
            "type": "string",
            "minLength": 3,
            "maxLength": 3,
            "pattern": "^[A-Z]{3}$",
            "description": "ISO 4217 code, three letters (uppercased for you). Must match the invoice currency when billed.",
            "examples": [
              "USD"
            ]
          },
          "type": {
            "default": "one_time",
            "description": "`one_time` (default) or `recurring`. `recurring` requires `recurring.interval`.",
            "examples": [
              "recurring"
            ],
            "type": "string",
            "enum": [
              "one_time",
              "recurring"
            ]
          },
          "recurring": {
            "description": "Required when `type` is `recurring`; must be omitted for `one_time`.",
            "type": "object",
            "properties": {
              "interval": {
                "type": "string",
                "enum": [
                  "day",
                  "week",
                  "month",
                  "year"
                ],
                "description": "Billing interval: `day`, `week`, `month`, `year`.",
                "examples": [
                  "month"
                ]
              },
              "interval_count": {
                "default": 1,
                "description": "Intervals between bills, 1–52. Defaults to 1.",
                "examples": [
                  1
                ],
                "type": "integer",
                "minimum": 1,
                "maximum": 52
              }
            },
            "required": [
              "interval"
            ]
          },
          "tax_rate": {
            "default": 0,
            "description": "Default tax percentage, 0–100, for lines billed from this price. Defaults to 0.",
            "examples": [
              0
            ],
            "type": "number",
            "minimum": 0,
            "maximum": 100
          },
          "active": {
            "default": true,
            "description": "Whether the price is available. Defaults to `true`.",
            "examples": [
              true
            ],
            "type": "boolean"
          }
        },
        "required": [
          "product",
          "unit_amount",
          "currency"
        ]
      },
      "PriceUpdate": {
        "type": "object",
        "properties": {
          "product": {
            "description": "Not updatable — sending it is a `422`. Create a new price on the other product instead.",
            "type": "string",
            "minLength": 1
          },
          "nickname": {
            "description": "Internal label. `null` or `\"\"` clears it.",
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ]
          },
          "unit_amount": {
            "description": "Price per unit in integer minor units (`2500000` is $25,000.00).",
            "examples": [
              2500000
            ],
            "type": "integer",
            "minimum": 0,
            "maximum": 9007199254740991
          },
          "currency": {
            "description": "ISO 4217 code, three letters (uppercased for you). Must match the invoice currency when billed.",
            "examples": [
              "USD"
            ],
            "type": "string",
            "minLength": 3,
            "maxLength": 3,
            "pattern": "^[A-Z]{3}$"
          },
          "type": {
            "description": "Switching to `one_time` clears the interval; switching to `recurring` needs `recurring.interval` unless one is stored.",
            "examples": [
              "recurring"
            ],
            "type": "string",
            "enum": [
              "one_time",
              "recurring"
            ]
          },
          "recurring": {
            "description": "Required when `type` is `recurring`; must be omitted for `one_time`.",
            "type": "object",
            "properties": {
              "interval": {
                "type": "string",
                "enum": [
                  "day",
                  "week",
                  "month",
                  "year"
                ],
                "description": "Billing interval: `day`, `week`, `month`, `year`.",
                "examples": [
                  "month"
                ]
              },
              "interval_count": {
                "default": 1,
                "description": "Intervals between bills, 1–52. Defaults to 1.",
                "examples": [
                  1
                ],
                "type": "integer",
                "minimum": 1,
                "maximum": 52
              }
            },
            "required": [
              "interval"
            ]
          },
          "tax_rate": {
            "description": "Default tax percentage, 0–100, for lines billed from this price. Defaults to 0.",
            "examples": [
              0
            ],
            "type": "number",
            "minimum": 0,
            "maximum": 100
          },
          "active": {
            "description": "`false` archives, `true` restores.",
            "examples": [
              true
            ],
            "type": "boolean"
          }
        },
        "description": "Any subset of fields. Omitted fields are left unchanged."
      },
      "InvoiceCreate": {
        "type": "object",
        "properties": {
          "customer": {
            "type": "string",
            "minLength": 1,
            "description": "The customer to bill, `cus_…` or UUID. Must already exist (`POST /customers`).",
            "examples": [
              "cus_Nf3kQ8pR2mX7vB1cT9wL4sZ6"
            ]
          },
          "currency": {
            "description": "ISO 4217 code. Defaults to your business currency.",
            "examples": [
              "USD"
            ],
            "type": "string",
            "minLength": 3,
            "maxLength": 3,
            "pattern": "^[A-Z]{3}$"
          },
          "collection_method": {
            "description": "Defaults to `send_invoice`. Informational today.",
            "examples": [
              "send_invoice"
            ],
            "type": "string",
            "enum": [
              "charge_automatically",
              "send_invoice"
            ]
          },
          "due_date": {
            "description": "Due date, `YYYY-MM-DD`. `\"\"` clears it.",
            "examples": [
              "2026-10-22"
            ],
            "anyOf": [
              {
                "type": "string",
                "format": "date",
                "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$"
              },
              {
                "type": "string",
                "const": ""
              }
            ]
          },
          "days_until_due": {
            "description": "Alternative to `due_date` on create only: issue date + N days (0–365). Ignored on update.",
            "examples": [
              30
            ],
            "type": "integer",
            "minimum": 0,
            "maximum": 365
          },
          "description": {
            "description": "Notes printed on the invoice.",
            "type": "string"
          },
          "footer": {
            "description": "Terms printed at the foot of the invoice.",
            "type": "string"
          },
          "items": {
            "description": "The lines, at least one. On update, replaces every existing line; omit to keep them.",
            "minItems": 1,
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/InvoiceLineInput"
            }
          }
        },
        "required": [
          "customer"
        ]
      },
      "InvoiceLineInput": {
        "type": "object",
        "properties": {
          "price": {
            "description": "A catalog price, `price_…` or UUID. Its product name, unit amount and tax rate fill any of `description`, `unit_amount`, `tax_rate` you omit. Its currency must match the invoice.",
            "examples": [
              "price_Jc5Tn8Wq1Ze6Ra3Ym9Ub2Gs7"
            ],
            "type": "string"
          },
          "description": {
            "default": "",
            "description": "What you are billing for. Required unless `price` is given.",
            "examples": [
              "Onboarding workshop"
            ],
            "type": "string"
          },
          "quantity": {
            "default": 1,
            "description": "Quantity, greater than zero. Defaults to 1.",
            "examples": [
              1
            ],
            "type": "number",
            "exclusiveMinimum": 0
          },
          "unit": {
            "default": "NOS",
            "description": "Unit of measure. Defaults to `NOS` (numbers).",
            "examples": [
              "NOS"
            ],
            "type": "string",
            "enum": [
              "NOS",
              "PCS",
              "KGS",
              "GMS",
              "LTR",
              "MTR",
              "SQF",
              "SQM",
              "HRS",
              "DAY",
              "MON",
              "BOX",
              "SET",
              "OTH"
            ]
          },
          "unit_amount": {
            "description": "Price per unit in integer minor units of the invoice currency. Required unless `price` is given.",
            "examples": [
              50000
            ],
            "type": "integer",
            "minimum": 0,
            "maximum": 9007199254740991
          },
          "discount_percent": {
            "default": 0,
            "description": "Discount percentage, 0–100, applied before tax. Defaults to 0.",
            "examples": [
              0
            ],
            "type": "number",
            "minimum": 0,
            "maximum": 100
          },
          "tax_rate": {
            "description": "Tax percentage, 0–100, added on top. Defaults to the price’s rate, or 0 on ad-hoc lines.",
            "examples": [
              0
            ],
            "type": "number",
            "minimum": 0,
            "maximum": 100
          }
        },
        "description": "Either `price`, or `description` + `unit_amount`."
      },
      "InvoiceUpdate": {
        "type": "object",
        "properties": {
          "customer": {
            "description": "Bill a different customer, `cus_…` or UUID. Omit to keep the current one.",
            "examples": [
              "cus_Nf3kQ8pR2mX7vB1cT9wL4sZ6"
            ],
            "type": "string",
            "minLength": 1
          },
          "currency": {
            "description": "ISO 4217 code. Defaults to your business currency.",
            "examples": [
              "USD"
            ],
            "type": "string",
            "minLength": 3,
            "maxLength": 3,
            "pattern": "^[A-Z]{3}$"
          },
          "collection_method": {
            "description": "Defaults to `send_invoice`. Informational today.",
            "examples": [
              "send_invoice"
            ],
            "type": "string",
            "enum": [
              "charge_automatically",
              "send_invoice"
            ]
          },
          "due_date": {
            "description": "Due date, `YYYY-MM-DD`. `\"\"` clears it.",
            "examples": [
              "2026-10-22"
            ],
            "anyOf": [
              {
                "type": "string",
                "format": "date",
                "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$"
              },
              {
                "type": "string",
                "const": ""
              }
            ]
          },
          "days_until_due": {
            "description": "Alternative to `due_date` on create only: issue date + N days (0–365). Ignored on update.",
            "examples": [
              30
            ],
            "type": "integer",
            "minimum": 0,
            "maximum": 365
          },
          "description": {
            "description": "Notes printed on the invoice.",
            "type": "string"
          },
          "footer": {
            "description": "Terms printed at the foot of the invoice.",
            "type": "string"
          },
          "items": {
            "description": "The lines, at least one. On update, replaces every existing line; omit to keep them.",
            "minItems": 1,
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/InvoiceLineInput"
            }
          }
        },
        "description": "Any subset of fields. Omitted fields keep their stored value; omit `items` to keep the lines."
      },
      "InvoiceSend": {
        "type": "object",
        "properties": {
          "to": {
            "description": "Recipient email. Defaults to the customer email recorded on the invoice; one of the two is required.",
            "examples": [
              "ap@acme.example"
            ],
            "type": "string"
          }
        }
      },
      "InvoicePay": {
        "type": "object",
        "properties": {
          "paid_on": {
            "description": "When payment was received: an ISO 8601 date or timestamp. Defaults to now.",
            "examples": [
              "2026-09-29"
            ],
            "type": "string"
          },
          "reference": {
            "description": "Your payment reference (cheque number, bank transfer id), up to 200 characters. Recorded on the `invoice.paid` event.",
            "examples": [
              "chk_123456"
            ],
            "type": "string"
          }
        }
      },
      "InvoiceVoid": {
        "type": "object",
        "properties": {
          "reason": {
            "type": "string",
            "minLength": 1,
            "description": "Why the invoice is void: required, non-blank, up to 500 characters. Stored as `void_reason`.",
            "examples": [
              "Raised against the wrong customer."
            ]
          }
        },
        "required": [
          "reason"
        ]
      },
      "InvoiceItemCreate": {
        "type": "object",
        "properties": {
          "price": {
            "description": "A catalog price, `price_…` or UUID. Its product name, unit amount and tax rate fill any of `description`, `unit_amount`, `tax_rate` you omit. Its currency must match the invoice.",
            "examples": [
              "price_Jc5Tn8Wq1Ze6Ra3Ym9Ub2Gs7"
            ],
            "type": "string"
          },
          "description": {
            "default": "",
            "description": "What you are billing for. Required unless `price` is given.",
            "examples": [
              "Onboarding workshop"
            ],
            "type": "string"
          },
          "quantity": {
            "default": 1,
            "description": "Quantity, greater than zero. Defaults to 1.",
            "examples": [
              1
            ],
            "type": "number",
            "exclusiveMinimum": 0
          },
          "unit": {
            "default": "NOS",
            "description": "Unit of measure. Defaults to `NOS` (numbers).",
            "examples": [
              "NOS"
            ],
            "type": "string",
            "enum": [
              "NOS",
              "PCS",
              "KGS",
              "GMS",
              "LTR",
              "MTR",
              "SQF",
              "SQM",
              "HRS",
              "DAY",
              "MON",
              "BOX",
              "SET",
              "OTH"
            ]
          },
          "unit_amount": {
            "description": "Price per unit in integer minor units of the invoice currency. Required unless `price` is given.",
            "examples": [
              50000
            ],
            "type": "integer",
            "minimum": 0,
            "maximum": 9007199254740991
          },
          "discount_percent": {
            "default": 0,
            "description": "Discount percentage, 0–100, applied before tax. Defaults to 0.",
            "examples": [
              0
            ],
            "type": "number",
            "minimum": 0,
            "maximum": 100
          },
          "tax_rate": {
            "description": "Tax percentage, 0–100, added on top. Defaults to the price’s rate, or 0 on ad-hoc lines.",
            "examples": [
              0
            ],
            "type": "number",
            "minimum": 0,
            "maximum": 100
          },
          "invoice": {
            "type": "string",
            "minLength": 1,
            "description": "The draft to append to, `in_…` or UUID.",
            "examples": [
              "in_Pb2Xk7Mv4Qs9Lr1Wd6Tn3Fh8"
            ]
          }
        },
        "required": [
          "invoice"
        ],
        "description": "Either `price`, or `description` + `unit_amount`."
      },
      "WebhookEndpointCreate": {
        "type": "object",
        "properties": {
          "url": {
            "type": "string",
            "description": "An `https://` URL of up to 2048 characters, without a username or password, that resolves only to public addresses. Redirects are not followed.",
            "examples": [
              "https://example.com/webhooks/invoice-ai"
            ]
          },
          "events": {
            "description": "Event types to receive. Omit or send `[]` to receive every type, including ones added later.",
            "examples": [
              [
                "invoice.finalized",
                "invoice.paid"
              ]
            ],
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "invoice.created",
                "invoice.updated",
                "invoice.finalized",
                "invoice.emailed",
                "invoice.email_failed",
                "invoice.viewed",
                "invoice.downloaded",
                "invoice.paid",
                "invoice.voided"
              ]
            }
          }
        },
        "required": [
          "url"
        ]
      },
      "Business": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Business id (UUID).",
            "examples": [
              "0c6f2d8e-3a41-4b9e-8f17-5d2a9c4e1b73"
            ]
          },
          "legal_name": {
            "type": "string",
            "description": "Registered legal name, printed as the invoice issuer.",
            "examples": [
              "Horizon Consulting LLC"
            ]
          },
          "trade_name": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Trading name, if different.",
            "examples": [
              "Horizon"
            ]
          },
          "country_code": {
            "type": "string",
            "description": "ISO 3166-1 alpha-2 country code.",
            "examples": [
              "US"
            ]
          },
          "currency": {
            "type": "string",
            "description": "Default invoice currency (ISO 4217).",
            "examples": [
              "USD"
            ]
          },
          "tax_id": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Your tax registration number, free text.",
            "examples": [
              "US-EIN 98-7654321"
            ]
          },
          "address": {
            "type": "object",
            "properties": {
              "line1": {
                "anyOf": [
                  {
                    "type": "string"
                  },
                  {
                    "type": "null"
                  }
                ],
                "description": "Street address.",
                "examples": [
                  "500 Congress Ave"
                ]
              },
              "line2": {
                "anyOf": [
                  {
                    "type": "string"
                  },
                  {
                    "type": "null"
                  }
                ],
                "description": "Suite, floor, unit."
              },
              "city": {
                "anyOf": [
                  {
                    "type": "string"
                  },
                  {
                    "type": "null"
                  }
                ],
                "description": "City.",
                "examples": [
                  "Austin"
                ]
              },
              "region": {
                "anyOf": [
                  {
                    "type": "string"
                  },
                  {
                    "type": "null"
                  }
                ],
                "description": "State, province or region.",
                "examples": [
                  "TX"
                ]
              },
              "postal_code": {
                "anyOf": [
                  {
                    "type": "string"
                  },
                  {
                    "type": "null"
                  }
                ],
                "description": "ZIP or postal code.",
                "examples": [
                  "78701"
                ]
              },
              "country_code": {
                "anyOf": [
                  {
                    "type": "string"
                  },
                  {
                    "type": "null"
                  }
                ],
                "description": "ISO 3166-1 alpha-2 country code.",
                "examples": [
                  "US"
                ]
              },
              "country": {
                "anyOf": [
                  {
                    "type": "string"
                  },
                  {
                    "type": "null"
                  }
                ],
                "description": "Country name.",
                "examples": [
                  "United States"
                ]
              }
            },
            "required": [
              "line1",
              "line2",
              "city",
              "region",
              "postal_code",
              "country_code",
              "country"
            ],
            "additionalProperties": false,
            "description": "Registered address."
          },
          "email": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Contact email printed on invoices.",
            "examples": [
              "billing@horizon.example"
            ]
          },
          "phone": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Contact phone.",
            "examples": [
              "+1 512 555 0199"
            ]
          },
          "bank": {
            "type": "object",
            "properties": {
              "bank_name": {
                "anyOf": [
                  {
                    "type": "string"
                  },
                  {
                    "type": "null"
                  }
                ],
                "description": "Bank name.",
                "examples": [
                  "First Austin Bank"
                ]
              },
              "account_name": {
                "anyOf": [
                  {
                    "type": "string"
                  },
                  {
                    "type": "null"
                  }
                ],
                "description": "Account holder name.",
                "examples": [
                  "Horizon Consulting LLC"
                ]
              },
              "account_number": {
                "anyOf": [
                  {
                    "type": "string"
                  },
                  {
                    "type": "null"
                  }
                ],
                "description": "Account number (or IBAN).",
                "examples": [
                  "000123456789"
                ]
              },
              "routing_number": {
                "anyOf": [
                  {
                    "type": "string"
                  },
                  {
                    "type": "null"
                  }
                ],
                "description": "Routing number, sort code, IFSC or SWIFT.",
                "examples": [
                  "111000025"
                ]
              }
            },
            "required": [
              "bank_name",
              "account_name",
              "account_number",
              "routing_number"
            ],
            "additionalProperties": false,
            "description": "Payment details printed on invoices."
          },
          "invoice_prefix": {
            "type": "string",
            "description": "Prefix of every invoice number, e.g. `INV` in `INV-0042`.",
            "examples": [
              "INV"
            ]
          },
          "created_at": {
            "type": "string",
            "description": "When the business profile was created (ISO 8601).",
            "format": "date-time"
          }
        },
        "required": [
          "id",
          "legal_name",
          "trade_name",
          "country_code",
          "currency",
          "tax_id",
          "address",
          "email",
          "phone",
          "bank",
          "invoice_prefix",
          "created_at"
        ],
        "additionalProperties": false,
        "description": "Your business profile — the \"From\" side of every invoice."
      },
      "Problem": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "description": "A URI identifying the problem type: `https://invoice.horizonpay.co/problems/<code>` with underscores as hyphens.",
            "examples": [
              "https://invoice.horizonpay.co/problems/invalid-state"
            ]
          },
          "title": {
            "type": "string",
            "description": "Short, human-readable summary of the problem type.",
            "examples": [
              "Invalid state for this operation"
            ]
          },
          "status": {
            "type": "integer",
            "minimum": -9007199254740991,
            "maximum": 9007199254740991,
            "description": "The HTTP status code, repeated for convenience.",
            "examples": [
              409
            ]
          },
          "detail": {
            "type": "string",
            "description": "Human-readable explanation of this occurrence. Wording may change — do not parse it.",
            "examples": [
              "This invoice has been finalized and can no longer be edited."
            ]
          },
          "instance": {
            "type": "string",
            "description": "The request id (also sent as `X-Request-Id`), for correlating with our logs.",
            "examples": [
              "req_7f3c9a1e2b4d4e8a9c6f2d1b0a3e5f71"
            ]
          },
          "code": {
            "type": "string",
            "description": "Stable machine-readable code. Branch on this, never on `detail`. One of: `validation`, `idempotency_mismatch`, `unauthorized`, `forbidden`, `not_found`, `invalid_state`, `conflict`, `idempotency_key_required`, `rate_limited`, `upstream_failed`, `internal_error`.",
            "examples": [
              "invalid_state"
            ]
          },
          "errors": {
            "description": "Field-level problems. Present on `validation` errors only.",
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "path": {
                  "type": "string",
                  "description": "Dot-path of the offending field, e.g. `items.0.unit_amount`.",
                  "examples": [
                    "email"
                  ]
                },
                "message": {
                  "type": "string",
                  "description": "What is wrong with it.",
                  "examples": [
                    "Enter a valid email"
                  ]
                }
              },
              "required": [
                "path",
                "message"
              ],
              "additionalProperties": false
            }
          }
        },
        "required": [
          "type",
          "title",
          "status",
          "detail",
          "instance",
          "code"
        ],
        "additionalProperties": false,
        "description": "An RFC 9457 problem details object, served as `application/problem+json`. Every non-2xx response uses this shape."
      },
      "Customer": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Unique identifier, `cus_…`.",
            "examples": [
              "cus_Nf3kQ8pR2mX7vB1cT9wL4sZ6"
            ]
          },
          "object": {
            "type": "string",
            "const": "customer",
            "description": "Always `customer`."
          },
          "name": {
            "type": "string",
            "description": "Full name or legal business name.",
            "examples": [
              "Acme Industries"
            ]
          },
          "email": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Billing email, copied onto invoices for this customer — where `POST /invoices/{id}/send` delivers by default.",
            "examples": [
              "ap@acme.example"
            ]
          },
          "phone": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Phone number, free text.",
            "examples": [
              "+1 512 555 0100"
            ]
          },
          "tax_id": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Tax registration number (VAT, EIN, GSTIN, ABN…), free text. Printed on invoices.",
            "examples": [
              "US-EIN 12-3456789"
            ]
          },
          "address": {
            "type": "object",
            "properties": {
              "line1": {
                "anyOf": [
                  {
                    "type": "string"
                  },
                  {
                    "type": "null"
                  }
                ],
                "description": "Street address.",
                "examples": [
                  "4th Floor, Market Tower"
                ]
              },
              "line2": {
                "anyOf": [
                  {
                    "type": "string"
                  },
                  {
                    "type": "null"
                  }
                ],
                "description": "Apartment, suite, unit."
              },
              "city": {
                "anyOf": [
                  {
                    "type": "string"
                  },
                  {
                    "type": "null"
                  }
                ],
                "description": "City or locality.",
                "examples": [
                  "Austin"
                ]
              },
              "state": {
                "anyOf": [
                  {
                    "type": "string"
                  },
                  {
                    "type": "null"
                  }
                ],
                "description": "State, province or region.",
                "examples": [
                  "TX"
                ]
              },
              "postal_code": {
                "anyOf": [
                  {
                    "type": "string"
                  },
                  {
                    "type": "null"
                  }
                ],
                "description": "ZIP or postal code.",
                "examples": [
                  "73301"
                ]
              },
              "country": {
                "anyOf": [
                  {
                    "type": "string"
                  },
                  {
                    "type": "null"
                  }
                ],
                "description": "ISO 3166-1 alpha-2 country code.",
                "examples": [
                  "US"
                ]
              }
            },
            "required": [
              "line1",
              "line2",
              "city",
              "state",
              "postal_code",
              "country"
            ],
            "additionalProperties": false,
            "description": "Billing address. Every field may be null."
          },
          "deleted": {
            "type": "boolean",
            "description": "True once archived with `DELETE /customers/{id}`. Archived customers stay readable."
          },
          "created": {
            "type": "string",
            "description": "When the customer was created (ISO 8601).",
            "format": "date-time"
          }
        },
        "required": [
          "id",
          "object",
          "name",
          "email",
          "phone",
          "tax_id",
          "address",
          "deleted",
          "created"
        ],
        "additionalProperties": false,
        "description": "Someone you bill. Customers are archived, never hard-deleted."
      },
      "Product": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Unique identifier, `prod_…`.",
            "examples": [
              "prod_Hy7Rq2Lm9Xc4Vb8Nt3Kd6Pw1"
            ]
          },
          "object": {
            "type": "string",
            "const": "product",
            "description": "Always `product`."
          },
          "name": {
            "type": "string",
            "description": "Shown as the line description when a price of this product is billed.",
            "examples": [
              "Consulting retainer"
            ]
          },
          "description": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Longer description for your own reference.",
            "examples": [
              "Monthly advisory block."
            ]
          },
          "images": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Up to 8 image URLs.",
            "examples": [
              []
            ]
          },
          "active": {
            "type": "boolean",
            "description": "`false` once archived. Archived products keep their prices and history."
          },
          "created": {
            "type": "string",
            "description": "When the product was created (ISO 8601).",
            "format": "date-time"
          },
          "updated": {
            "type": "string",
            "description": "When the product was last changed (ISO 8601).",
            "format": "date-time"
          }
        },
        "required": [
          "id",
          "object",
          "name",
          "description",
          "images",
          "active",
          "created",
          "updated"
        ],
        "additionalProperties": false,
        "description": "Something you sell. Money lives on its prices, not on the product."
      },
      "Price": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Unique identifier, `price_…`.",
            "examples": [
              "price_Jc5Tn8Wq1Ze6Ra3Ym9Ub2Gs7"
            ]
          },
          "object": {
            "type": "string",
            "const": "price",
            "description": "Always `price`."
          },
          "product": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "The parent product, `prod_…`. Cannot change after creation.",
            "examples": [
              "prod_Hy7Rq2Lm9Xc4Vb8Nt3Kd6Pw1"
            ]
          },
          "nickname": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Internal label, e.g. \"Monthly\".",
            "examples": [
              "Monthly"
            ]
          },
          "unit_amount": {
            "type": "integer",
            "minimum": -9007199254740991,
            "maximum": 9007199254740991,
            "description": "Price per unit. Integer minor units of the currency (`250000` is $2,500.00; ¥5,000 is `5000`).",
            "examples": [
              2500000
            ]
          },
          "currency": {
            "type": "string",
            "description": "ISO 4217 currency code, uppercase.",
            "examples": [
              "USD"
            ]
          },
          "billing_scheme": {
            "type": "string",
            "const": "per_unit",
            "description": "Always `per_unit`."
          },
          "type": {
            "type": "string",
            "enum": [
              "one_time",
              "recurring"
            ],
            "description": "`recurring` prices carry `recurring`; nothing auto-bills them yet."
          },
          "recurring": {
            "anyOf": [
              {
                "type": "object",
                "properties": {
                  "interval": {
                    "anyOf": [
                      {
                        "type": "string"
                      },
                      {
                        "type": "null"
                      }
                    ],
                    "description": "`day`, `week`, `month` or `year`.",
                    "examples": [
                      "month"
                    ]
                  },
                  "interval_count": {
                    "type": "integer",
                    "minimum": -9007199254740991,
                    "maximum": 9007199254740991,
                    "description": "Number of intervals between bills (1–52).",
                    "examples": [
                      1
                    ]
                  }
                },
                "required": [
                  "interval",
                  "interval_count"
                ],
                "additionalProperties": false
              },
              {
                "type": "null"
              }
            ],
            "description": "Billing cadence. `null` on one-time prices."
          },
          "tax_rate": {
            "type": "number",
            "description": "Default tax percentage (0–100) for lines billed from this price.",
            "examples": [
              0
            ]
          },
          "active": {
            "type": "boolean",
            "description": "`false` once archived. Archived prices cannot be chosen for new lines in the app."
          },
          "created": {
            "type": "string",
            "description": "When the price was created (ISO 8601).",
            "format": "date-time"
          }
        },
        "required": [
          "id",
          "object",
          "product",
          "nickname",
          "unit_amount",
          "currency",
          "billing_scheme",
          "type",
          "recurring",
          "tax_rate",
          "active",
          "created"
        ],
        "additionalProperties": false,
        "description": "One way to charge for a product: an amount in a currency, one-time or recurring."
      },
      "Invoice": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Unique identifier, `in_…`.",
            "examples": [
              "in_Pb2Xk7Mv4Qs9Lr1Wd6Tn3Fh8"
            ]
          },
          "object": {
            "type": "string",
            "const": "invoice",
            "description": "Always `invoice`."
          },
          "number": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "The invoice number, e.g. `INV-0042` (your prefix + a zero-padded counter). `null` until finalized — a draft has no number because none was spent on it.",
            "examples": [
              "INV-0042"
            ]
          },
          "status": {
            "type": "string",
            "enum": [
              "draft",
              "open",
              "paid",
              "overdue",
              "void"
            ],
            "description": "`draft` → `open` (finalize) → `paid` (pay) or `void`. `overdue` is an open invoice past `due_date`; it is derived at read time and never stored.",
            "examples": [
              "open"
            ]
          },
          "customer": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "The billed customer, `cus_…`.",
            "examples": [
              "cus_Nf3kQ8pR2mX7vB1cT9wL4sZ6"
            ]
          },
          "currency": {
            "type": "string",
            "description": "ISO 4217 currency code. Defaults to your business currency.",
            "examples": [
              "USD"
            ]
          },
          "collection_method": {
            "type": "string",
            "enum": [
              "charge_automatically",
              "send_invoice"
            ],
            "description": "How you intend to collect. Informational today; defaults to `send_invoice`."
          },
          "issue_date": {
            "type": "string",
            "description": "Issue date (ISO 8601 date). Set to the creation date.",
            "format": "date",
            "examples": [
              "2026-09-22"
            ]
          },
          "due_date": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Due date (ISO 8601 date), or `null`.",
            "format": "date",
            "examples": [
              "2026-10-22"
            ]
          },
          "description": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Notes printed on the invoice.",
            "examples": [
              "Consulting retainer."
            ]
          },
          "footer": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Terms printed at the foot of the invoice.",
            "examples": [
              "Thank you for your business."
            ]
          },
          "subtotal": {
            "type": "integer",
            "minimum": -9007199254740991,
            "maximum": 9007199254740991,
            "description": "Sum of quantity × unit_amount over all lines, before discount and tax. Integer minor units of the currency (`250000` is $2,500.00; ¥5,000 is `5000`).",
            "examples": [
              2550000
            ]
          },
          "discount": {
            "type": "integer",
            "minimum": -9007199254740991,
            "maximum": 9007199254740991,
            "description": "Total discount across lines. Integer minor units of the currency (`250000` is $2,500.00; ¥5,000 is `5000`).",
            "examples": [
              0
            ]
          },
          "taxable": {
            "type": "integer",
            "minimum": -9007199254740991,
            "maximum": 9007199254740991,
            "description": "`subtotal` − `discount`. Integer minor units of the currency (`250000` is $2,500.00; ¥5,000 is `5000`).",
            "examples": [
              2550000
            ]
          },
          "tax": {
            "type": "integer",
            "minimum": -9007199254740991,
            "maximum": 9007199254740991,
            "description": "Total tax across lines. Integer minor units of the currency (`250000` is $2,500.00; ¥5,000 is `5000`).",
            "examples": [
              0
            ]
          },
          "total": {
            "type": "integer",
            "minimum": -9007199254740991,
            "maximum": 9007199254740991,
            "description": "`taxable` + `tax`. Integer minor units of the currency (`250000` is $2,500.00; ¥5,000 is `5000`).",
            "examples": [
              2550000
            ]
          },
          "amount_due": {
            "type": "integer",
            "minimum": -9007199254740991,
            "maximum": 9007199254740991,
            "description": "What is still owed: `total` while `open` or `overdue`, otherwise 0. Integer minor units of the currency (`250000` is $2,500.00; ¥5,000 is `5000`).",
            "examples": [
              2550000
            ]
          },
          "amount_in_words": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "The total spelled out, as printed on the PDF.",
            "examples": [
              "Twenty Five Thousand Five Hundred USD Only"
            ]
          },
          "public_url_token": {
            "type": "string",
            "description": "Token of the public share link (`/i/{token}`). Anyone with it can view the invoice.",
            "examples": [
              "2b7e4c1a-9f3d-4e68-8a5b-0d1c7f3e9a46"
            ]
          },
          "finalized_at": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ],
            "description": "When the invoice was finalized, or `null`."
          },
          "paid_at": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ],
            "description": "When the invoice was marked paid, or `null`."
          },
          "voided_at": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ],
            "description": "When the invoice was voided, or `null`."
          },
          "void_reason": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "The reason given to `POST /invoices/{id}/void`."
          },
          "created": {
            "type": "string",
            "description": "When the invoice was created (ISO 8601).",
            "format": "date-time"
          },
          "updated": {
            "type": "string",
            "description": "When the invoice was last changed (ISO 8601).",
            "format": "date-time"
          },
          "lines": {
            "description": "The invoice lines. Included when reading or writing a single invoice; omitted from list results and from the pay and void responses.",
            "type": "object",
            "properties": {
              "data": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/InvoiceItem"
                },
                "description": "The lines, in order."
              }
            },
            "required": [
              "data"
            ],
            "additionalProperties": false
          }
        },
        "required": [
          "id",
          "object",
          "number",
          "status",
          "customer",
          "currency",
          "collection_method",
          "issue_date",
          "due_date",
          "description",
          "footer",
          "subtotal",
          "discount",
          "taxable",
          "tax",
          "total",
          "amount_due",
          "amount_in_words",
          "public_url_token",
          "finalized_at",
          "paid_at",
          "voided_at",
          "void_reason",
          "created",
          "updated"
        ],
        "additionalProperties": false,
        "description": "An invoice: a draft, or a numbered document once finalized."
      },
      "InvoiceItem": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Unique identifier, `ii_…`. Lines get new ids whenever the draft is re-saved.",
            "examples": [
              "ii_Da4Vq9Ns2Kx7Bm3Yt8Rc1Lp6"
            ]
          },
          "object": {
            "type": "string",
            "const": "invoiceitem",
            "description": "Always `invoiceitem`."
          },
          "price": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "The `price_…` this line was billed from, or `null` for an ad-hoc line.",
            "examples": [
              "price_Jc5Tn8Wq1Ze6Ra3Ym9Ub2Gs7"
            ]
          },
          "product": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "The price's product, `prod_…`, or `null`.",
            "examples": [
              "prod_Hy7Rq2Lm9Xc4Vb8Nt3Kd6Pw1"
            ]
          },
          "description": {
            "type": "string",
            "description": "What is being billed. Defaults to the product name on priced lines.",
            "examples": [
              "Consulting retainer"
            ]
          },
          "quantity": {
            "type": "number",
            "description": "Quantity, greater than zero. May be fractional.",
            "examples": [
              1
            ]
          },
          "unit": {
            "type": "string",
            "description": "Unit of measure: `NOS`, `PCS`, `KGS`, `GMS`, `LTR`, `MTR`, `SQF`, `SQM`, `HRS`, `DAY`, `MON`, `BOX`, `SET`, `OTH`.",
            "examples": [
              "NOS"
            ]
          },
          "unit_amount": {
            "type": "integer",
            "minimum": -9007199254740991,
            "maximum": 9007199254740991,
            "description": "Price per unit. Integer minor units of the currency (`250000` is $2,500.00; ¥5,000 is `5000`).",
            "examples": [
              2500000
            ]
          },
          "amount": {
            "type": "integer",
            "minimum": -9007199254740991,
            "maximum": 9007199254740991,
            "description": "Line total after discount, including tax. Integer minor units of the currency (`250000` is $2,500.00; ¥5,000 is `5000`).",
            "examples": [
              2500000
            ]
          },
          "discount_percent": {
            "type": "number",
            "description": "Discount percentage (0–100) applied before tax.",
            "examples": [
              0
            ]
          },
          "tax_rate": {
            "type": "number",
            "description": "Tax percentage (0–100), exclusive — added on top of the discounted amount.",
            "examples": [
              0
            ]
          },
          "tax_amount": {
            "type": "integer",
            "minimum": -9007199254740991,
            "maximum": 9007199254740991,
            "description": "Tax on this line. Integer minor units of the currency (`250000` is $2,500.00; ¥5,000 is `5000`).",
            "examples": [
              0
            ]
          }
        },
        "required": [
          "id",
          "object",
          "price",
          "product",
          "description",
          "quantity",
          "unit",
          "unit_amount",
          "amount",
          "discount_percent",
          "tax_rate",
          "tax_amount"
        ],
        "additionalProperties": false,
        "description": "One line of an invoice. Totals are always recomputed server-side from the lines."
      },
      "InvoiceEvent": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Event id (UUID).",
            "examples": [
              "9b1e5c7a-2d4f-4a86-b3e0-7c5d1f9a2e64"
            ]
          },
          "type": {
            "type": "string",
            "enum": [
              "invoice.created",
              "invoice.updated",
              "invoice.finalized",
              "invoice.emailed",
              "invoice.email_failed",
              "invoice.viewed",
              "invoice.downloaded",
              "invoice.paid",
              "invoice.voided"
            ],
            "description": "What happened. `invoice.viewed` and `invoice.downloaded` are recorded when the customer opens the public share link, at most once per type per invoice every 10 minutes.",
            "examples": [
              "invoice.finalized"
            ]
          },
          "meta": {
            "anyOf": [
              {
                "type": "object",
                "propertyNames": {
                  "type": "string"
                },
                "additionalProperties": {}
              },
              {
                "type": "null"
              }
            ],
            "description": "Context: `actor`, `request_id`, `api_key_id`, and event-specific fields such as `to`, `reason` or `reference`.",
            "examples": [
              {
                "actor": "api_key",
                "request_id": "req_7f3c9a1e2b4d4e8a9c6f2d1b0a3e5f71",
                "api_key_id": "6d3a9f1c-8e2b-4c75-a0d4-1f7e3b9c5a28"
              }
            ]
          },
          "created_at": {
            "type": "string",
            "description": "When it happened (ISO 8601).",
            "format": "date-time"
          }
        },
        "required": [
          "id",
          "type",
          "meta",
          "created_at"
        ],
        "additionalProperties": false,
        "description": "One entry in an invoice’s history. The same names are used for webhook events."
      },
      "WebhookEndpoint": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Endpoint id (UUID).",
            "examples": [
              "4f9c2a1e-7b3d-4e8a-9c6f-2d1b0a3e5f71"
            ]
          },
          "url": {
            "type": "string",
            "description": "The https URL deliveries are POSTed to.",
            "examples": [
              "https://example.com/webhooks/invoice-ai"
            ]
          },
          "events": {
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "invoice.created",
                "invoice.updated",
                "invoice.finalized",
                "invoice.emailed",
                "invoice.email_failed",
                "invoice.viewed",
                "invoice.downloaded",
                "invoice.paid",
                "invoice.voided"
              ]
            },
            "description": "Subscribed event types. An endpoint registered with no events receives every type, and lists them all here."
          },
          "active": {
            "type": "boolean",
            "description": "`false` once deliveries are disabled: after 20 deliveries in a row used up every retry. A successful delivery resets the count."
          },
          "disabled_at": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ],
            "description": "When deliveries were disabled, or `null`."
          },
          "failure_count": {
            "type": "integer",
            "minimum": -9007199254740991,
            "maximum": 9007199254740991,
            "description": "Deliveries in a row that used up every retry. Resets to 0 on any successful delivery.",
            "examples": [
              0
            ]
          },
          "created_at": {
            "type": "string",
            "description": "When the endpoint was registered (ISO 8601).",
            "format": "date-time"
          }
        },
        "required": [
          "id",
          "url",
          "events",
          "active",
          "disabled_at",
          "failure_count",
          "created_at"
        ],
        "additionalProperties": false,
        "description": "A URL that receives signed invoice events (Standard Webhooks format)."
      }
    },
    "headers": {
      "RequestId": {
        "required": true,
        "description": "The request id: yours, if you sent `X-Request-Id` (up to 200 characters), otherwise one we generated. Quote it to support.",
        "schema": {
          "type": "string",
          "description": "The request id: yours, if you sent `X-Request-Id` (up to 200 characters), otherwise one we generated. Quote it to support.",
          "examples": [
            "req_7f3c9a1e2b4d4e8a9c6f2d1b0a3e5f71"
          ]
        }
      },
      "RateLimitLimit": {
        "required": true,
        "description": "Requests allowed in the current window for this key and bucket.",
        "schema": {
          "type": "integer",
          "minimum": -9007199254740991,
          "maximum": 9007199254740991,
          "description": "Requests allowed in the current window for this key and bucket.",
          "examples": [
            120
          ]
        }
      },
      "RateLimitRemaining": {
        "required": true,
        "description": "Requests left in the current window.",
        "schema": {
          "type": "integer",
          "minimum": -9007199254740991,
          "maximum": 9007199254740991,
          "description": "Requests left in the current window.",
          "examples": [
            119
          ]
        }
      },
      "RateLimitReset": {
        "required": true,
        "description": "Unix time (seconds) at which the window resets.",
        "schema": {
          "type": "integer",
          "minimum": -9007199254740991,
          "maximum": 9007199254740991,
          "description": "Unix time (seconds) at which the window resets.",
          "examples": [
            1789371294
          ]
        }
      },
      "RetryAfter": {
        "required": true,
        "description": "Seconds to wait before retrying.",
        "schema": {
          "type": "integer",
          "minimum": -9007199254740991,
          "maximum": 9007199254740991,
          "description": "Seconds to wait before retrying.",
          "examples": [
            42
          ]
        }
      },
      "IdempotentReplayed": {
        "description": "Present and `true` when this response is a replay of the first response stored under the same `Idempotency-Key` — the operation did not run again.",
        "schema": {
          "description": "Present and `true` when this response is a replay of the first response stored under the same `Idempotency-Key` — the operation did not run again.",
          "type": "string",
          "enum": [
            "true"
          ]
        }
      }
    },
    "responses": {
      "Unauthorized": {
        "description": "The API key is missing, malformed, unknown, revoked or expired. The response carries `WWW-Authenticate: Bearer`. Codes: `unauthorized`.",
        "content": {
          "application/problem+json": {
            "schema": {
              "$ref": "#/components/schemas/Problem"
            },
            "examples": {
              "unauthorized": {
                "summary": "Send your API key as `Authorization: Bearer inv_live_…`.",
                "value": {
                  "type": "https://invoice.horizonpay.co/problems/unauthorized",
                  "title": "Unauthorized",
                  "status": 401,
                  "detail": "Send your API key as `Authorization: Bearer inv_live_…`.",
                  "instance": "req_7f3c9a1e2b4d4e8a9c6f2d1b0a3e5f71",
                  "code": "unauthorized"
                }
              }
            }
          }
        }
      },
      "Forbidden": {
        "description": "The key is valid but lacks a scope this operation needs (see `x-required-scope`). Codes: `forbidden`.",
        "content": {
          "application/problem+json": {
            "schema": {
              "$ref": "#/components/schemas/Problem"
            },
            "examples": {
              "forbidden": {
                "summary": "This credential is missing the invoices:write scope.",
                "value": {
                  "type": "https://invoice.horizonpay.co/problems/forbidden",
                  "title": "Insufficient scope",
                  "status": 403,
                  "detail": "This credential is missing the invoices:write scope.",
                  "instance": "req_7f3c9a1e2b4d4e8a9c6f2d1b0a3e5f71",
                  "code": "forbidden"
                }
              }
            }
          }
        }
      },
      "RateLimited": {
        "description": "Rate limit exceeded for this API key. Wait the number of seconds in `Retry-After` before retrying. Codes: `rate_limited`.",
        "headers": {
          "Retry-After": {
            "$ref": "#/components/headers/RetryAfter"
          },
          "X-Request-Id": {
            "$ref": "#/components/headers/RequestId"
          }
        },
        "content": {
          "application/problem+json": {
            "schema": {
              "$ref": "#/components/schemas/Problem"
            },
            "examples": {
              "rate_limited": {
                "summary": "Rate limit of 120 per 60s exceeded.",
                "value": {
                  "type": "https://invoice.horizonpay.co/problems/rate-limited",
                  "title": "Too many requests",
                  "status": 429,
                  "detail": "Rate limit of 120 per 60s exceeded.",
                  "instance": "req_7f3c9a1e2b4d4e8a9c6f2d1b0a3e5f71",
                  "code": "rate_limited"
                }
              }
            }
          }
        }
      },
      "IdempotencyKeyRequired": {
        "description": "No `Idempotency-Key` header was sent. This operation refuses to run without one. Codes: `idempotency_key_required`.",
        "content": {
          "application/problem+json": {
            "schema": {
              "$ref": "#/components/schemas/Problem"
            },
            "examples": {
              "idempotency_key_required": {
                "summary": "This operation assigns or spends an invoice number. Send an Idempotency-Key header so a retry cannot do it twice.",
                "value": {
                  "type": "https://invoice.horizonpay.co/problems/idempotency-key-required",
                  "title": "Idempotency-Key required",
                  "status": 428,
                  "detail": "This operation assigns or spends an invoice number. Send an Idempotency-Key header so a retry cannot do it twice.",
                  "instance": "req_7f3c9a1e2b4d4e8a9c6f2d1b0a3e5f71",
                  "code": "idempotency_key_required"
                }
              }
            }
          }
        }
      }
    },
    "securitySchemes": {
      "apiKey": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "inv_live_<id>_<secret>",
        "description": "An Invoice-AI API key sent as `Authorization: Bearer inv_live_…`.\n\nCreate keys in **Settings → API keys**; the secret is shown once. Each key carries scopes, and every operation lists the scope it needs (`x-required-scope`):\n\n- `business:read` — Read your business profile, tax ID and bank details\n- `clients:read` — List and read your clients\n- `clients:write` — Create, update and archive clients\n- `products:read` — List and read products and prices\n- `products:write` — Create, update and archive products and prices\n- `invoices:read` — List and read invoices, including PDFs\n- `invoices:write` — Create, edit and delete drafts\n- `invoices:finalize` — Finalize invoices and void them\n- `invoices:send` — Email invoices to your clients\n- `payments:write` — Mark invoices as paid\n- `webhooks:manage` — Manage webhook endpoints\n\nKeys cannot be created or revoked through the API, so a leaked key cannot mint more keys."
      }
    }
  }
}