{
  "openapi": "3.1.0",
  "info": {
    "title": "QuoteBill API",
    "version": "1.1.0",
    "summary": "Make quotations and invoices in a QuoteBill account, read them, and work out document totals by country.",
    "description": "The personal API of QuoteBill (https://quotebill.com). A member makes a key in Company settings; it reaches only that member's own documents.\n\nAuthentication: send the key as \"Authorization: Bearer qbk_...\" and nowhere else. A missing, wrong, revoked or expired key gets the same 401.\n\nLimits: Each key may make 60 requests a minute and 5,000 a day (UTC days), whichever endpoint it calls; one account may make 500 documents a day through the API. A request over a limit gets 429 with Retry-After (seconds). There are no other rate-limit headers.\n\nBodies: JSON with Content-Type: application/json, at most 256 KB. Every answer is JSON and Cache-Control: no-store. There are no CORS headers: call the API from a server, a script or an automation tool, not from a web page.\n\nIdempotency: POST /v1/documents takes an Idempotency-Key header; a retry of the same request within 24 hours returns the same document.\n\nVersioning: v1 changes only by addition: new endpoints, new optional request fields and new fields in answers. A change that could break a working integration (a field or endpoint removed or renamed, a type or meaning changed, a field made required) is made only in a new version, /v2, announced in the changelog at least six months before v1 changes or stops. Only a security problem or a legal obligation could make a change sooner, and the changelog would say so and why.\n\nTerms: The API is free for QuoteBill members, within the limits above. To ask about higher limits, write through the contact page: https://quotebill.com/en/contact/.\n\nGuide, changelog and examples: https://quotebill.com/en/developers/",
    "termsOfService": "https://quotebill.com/en/terms/",
    "contact": {
      "name": "QuoteBill",
      "url": "https://quotebill.com/en/contact/"
    }
  },
  "servers": [
    {
      "url": "https://quotebill.com/functions/v1/api",
      "description": "QuoteBill"
    }
  ],
  "security": [
    {
      "bearerAuth": []
    }
  ],
  "tags": [
    {
      "name": "Account",
      "description": "The key."
    },
    {
      "name": "Catalogue",
      "description": "What the site publishes: kinds, templates, countries and their tax rates."
    },
    {
      "name": "Documents",
      "description": "The member's own documents."
    },
    {
      "name": "Calculation",
      "description": "Figures worked out as a document's are, saved nowhere."
    }
  ],
  "paths": {
    "/v1/ping": {
      "get": {
        "operationId": "ping",
        "tags": [
          "Account"
        ],
        "summary": "Check the key",
        "description": "Answers {\"ok\": true} for a key that works. Any key.",
        "responses": {
          "200": {
            "description": "The key works.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Ping"
                },
                "examples": {
                  "ping": {
                    "summary": "The key works",
                    "value": {
                      "ok": true
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        }
      }
    },
    "/v1/templates": {
      "get": {
        "operationId": "listTemplates",
        "tags": [
          "Catalogue"
        ],
        "summary": "List the kinds and templates",
        "description": "The kinds of document the API makes and the templates of those kinds. Any key. The example shows the first three templates.",
        "responses": {
          "200": {
            "description": "The kinds and templates.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Templates"
                },
                "examples": {
                  "templates": {
                    "summary": "Kinds and the first templates",
                    "value": {
                      "kinds": [
                        {
                          "kind": "quotation",
                          "name": "Quotation",
                          "default_columns": "priced",
                          "second_date": "valid_until"
                        },
                        {
                          "kind": "invoice",
                          "name": "Invoice",
                          "default_columns": "priced",
                          "second_date": "due_date"
                        },
                        {
                          "kind": "proforma",
                          "name": "Proforma invoice",
                          "default_columns": "priced",
                          "second_date": "valid_until"
                        },
                        {
                          "kind": "receipt",
                          "name": "Receipt",
                          "default_columns": "priced",
                          "second_date": null
                        },
                        {
                          "kind": "creditNote",
                          "name": "Credit note",
                          "default_columns": "priced",
                          "second_date": null
                        },
                        {
                          "kind": "purchaseOrder",
                          "name": "Purchase order",
                          "default_columns": "priced",
                          "second_date": null
                        },
                        {
                          "kind": "deliveryNote",
                          "name": "Delivery note",
                          "default_columns": "quantity",
                          "second_date": null
                        },
                        {
                          "kind": "workOrder",
                          "name": "Work order",
                          "default_columns": "priced",
                          "second_date": null
                        },
                        {
                          "kind": "commercialInvoice",
                          "name": "Commercial invoice",
                          "default_columns": "priced",
                          "second_date": "due_date"
                        }
                      ],
                      "templates": [
                        {
                          "slug": "free-invoice-generator",
                          "kind": "invoice",
                          "name": "Free invoice generator",
                          "category": "generators",
                          "layout": "figures"
                        },
                        {
                          "slug": "free-quotation-generator",
                          "kind": "quotation",
                          "name": "Free quotation generator",
                          "category": "generators",
                          "layout": "stripe"
                        },
                        {
                          "slug": "free-pdf-invoice-generator",
                          "kind": "invoice",
                          "name": "Free PDF invoice generator",
                          "category": "generators",
                          "layout": "modern"
                        }
                      ]
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        }
      }
    },
    "/v1/documents": {
      "get": {
        "operationId": "listDocuments",
        "tags": [
          "Documents"
        ],
        "summary": "List your documents",
        "description": "Your own documents, however they were made, newest first: metadata only. Scope documents:read. Any other parameter is refused.",
        "parameters": [
          {
            "$ref": "#/components/parameters/ListKind"
          },
          {
            "$ref": "#/components/parameters/ListStatus"
          },
          {
            "$ref": "#/components/parameters/ListLimit"
          },
          {
            "$ref": "#/components/parameters/ListCursor"
          }
        ],
        "responses": {
          "200": {
            "description": "A page of documents.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentList"
                },
                "examples": {
                  "listDocuments": {
                    "summary": "One page",
                    "value": {
                      "data": [
                        {
                          "id": "doc-7c0b8a4e-3f1d-4a52-9d6e-0b2f5c1e8a77",
                          "kind": "invoice",
                          "status": "draft",
                          "number": "INVOICE-20261004-1-9F3A1C",
                          "name": "Invoice · Acme Ltd",
                          "customer": "Acme Ltd",
                          "language": "en",
                          "country": "KR",
                          "currency": "KRW",
                          "issue_date": "2026-10-04",
                          "created_at": "2026-10-04T09:30:00.000000Z",
                          "updated_at": "2026-10-04T09:30:00.000Z",
                          "editor_url": "https://quotebill.com/en/editor/doc-7c0b8a4e-3f1d-4a52-9d6e-0b2f5c1e8a77"
                        }
                      ],
                      "next_cursor": null
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "invalid_query: A parameter of the list is not one the endpoint has, or has a wrong value.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "insufficient_scope: The key does not have the scope the endpoint needs.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        }
      },
      "post": {
        "operationId": "createDocument",
        "tags": [
          "Documents"
        ],
        "summary": "Make a document",
        "description": "Makes a draft in your cloud, the way the editor makes one, with your company details as the sender. It counts against your cloud document limit. Scope documents:create.",
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/DocumentRequest"
              },
              "examples": {
                "invoice": {
                  "summary": "An invoice in Korea",
                  "value": {
                    "kind": "invoice",
                    "country": "KR",
                    "issue_date": "2026-10-04",
                    "due_date": "2026-11-03",
                    "customer": {
                      "name": "Acme Ltd",
                      "email": "billing@acme.example",
                      "address": "12 Harbour Road, Rotterdam",
                      "tax_id": "NL123456789B01"
                    },
                    "items": [
                      {
                        "description": "Website design",
                        "quantity": 1,
                        "unit_price": 1500000
                      },
                      {
                        "description": "Hosting (12 months)",
                        "quantity": 12,
                        "unit_price": 10000
                      }
                    ],
                    "notes": "Thank you for your business."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "A retry of a request already made with this Idempotency-Key in the last 24 hours: the same document, made once.",
            "headers": {
              "Idempotent-Replayed": {
                "$ref": "#/components/headers/IdempotentReplayed"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentCreated"
                }
              }
            }
          },
          "201": {
            "description": "Made.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentCreated"
                },
                "examples": {
                  "createDocument": {
                    "summary": "The invoice made",
                    "value": {
                      "id": "doc-7c0b8a4e-3f1d-4a52-9d6e-0b2f5c1e8a77",
                      "editor_url": "https://quotebill.com/en/editor/doc-7c0b8a4e-3f1d-4a52-9d6e-0b2f5c1e8a77",
                      "number": "INVOICE-20261004-1-9F3A1C",
                      "totals": {
                        "currency": "KRW",
                        "subtotal": 1620000,
                        "tax_name": "VAT",
                        "tax_rate": 10,
                        "tax_amount": 162000,
                        "total": 1782000,
                        "tax_status": "calculated"
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "invalid_json: The body is not valid JSON or not valid UTF-8 text. invalid_idempotency_key: The Idempotency-Key header is not 1 to 255 letters, digits, dots, dashes, underscores or colons.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "insufficient_scope: The key does not have the scope the endpoint needs. document_limit_reached: Your QuoteBill cloud is full.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "document_number_taken: Another of your documents has this document_number. idempotency_key_reused: The Idempotency-Key was used for a different request in the last 24 hours.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "$ref": "#/components/responses/PayloadTooLarge"
          },
          "415": {
            "$ref": "#/components/responses/UnsupportedMediaType"
          },
          "422": {
            "$ref": "#/components/responses/InvalidRequest"
          },
          "429": {
            "description": "rate_limited: A key made too many requests; wait Retry-After seconds. daily_document_limit: The account has made 500 documents through the API today.",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/RetryAfter"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        }
      }
    },
    "/v1/documents/{id}": {
      "get": {
        "operationId": "getDocument",
        "tags": [
          "Documents"
        ],
        "summary": "Read one of your documents",
        "description": "The customer, the lines, the notes and the totals. A document that is not yours is a 404, as one that does not exist. Scope documents:read.",
        "parameters": [
          {
            "$ref": "#/components/parameters/DocumentId"
          }
        ],
        "responses": {
          "200": {
            "description": "The document.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Document"
                },
                "examples": {
                  "getDocument": {
                    "summary": "The invoice made above",
                    "value": {
                      "id": "doc-7c0b8a4e-3f1d-4a52-9d6e-0b2f5c1e8a77",
                      "kind": "invoice",
                      "status": "draft",
                      "number": "INVOICE-20261004-1-9F3A1C",
                      "name": "Invoice · Acme Ltd",
                      "language": "en",
                      "country": "KR",
                      "currency": "KRW",
                      "issue_date": "2026-10-04",
                      "due_date": "2026-11-03",
                      "customer": {
                        "name": "Acme Ltd",
                        "email": "billing@acme.example",
                        "address": "12 Harbour Road, Rotterdam",
                        "tax_id": "NL123456789B01"
                      },
                      "items": [
                        {
                          "description": "Website design",
                          "quantity": 1,
                          "unit_price": 1500000
                        },
                        {
                          "description": "Hosting (12 months)",
                          "quantity": 12,
                          "unit_price": 10000
                        }
                      ],
                      "notes": "Thank you for your business.",
                      "totals": {
                        "currency": "KRW",
                        "subtotal": 1620000,
                        "tax_name": "VAT",
                        "tax_rate": 10,
                        "tax_amount": 162000,
                        "total": 1782000,
                        "tax_status": "calculated"
                      },
                      "editor_url": "https://quotebill.com/en/editor/doc-7c0b8a4e-3f1d-4a52-9d6e-0b2f5c1e8a77",
                      "created_at": "2026-10-04T09:30:00.000000Z",
                      "updated_at": "2026-10-04T09:30:00.000Z"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "insufficient_scope: The key does not have the scope the endpoint needs.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "not_found: No such endpoint, or no such document of yours.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "notFound": {
                    "summary": "No such document of yours",
                    "value": {
                      "error": {
                        "code": "not_found",
                        "message": "There is no such document."
                      }
                    }
                  }
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        }
      }
    },
    "/v1/calculate": {
      "post": {
        "operationId": "calculate",
        "tags": [
          "Calculation"
        ],
        "summary": "Work out a document's figures without saving it",
        "description": "The subtotal, the line discounts, the tax and the total that a document of this body would show, worked out by the code that works out a saved document's: the totals equal the totals POST /v1/documents answers with for the same body. Fields the request leaves out come from your account's settings, as for a document; send country, currency and tax_rate for an answer that does not depend on them. Nothing is saved. Any key; it counts against the key's limits. Prices are before tax.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CalculateRequest"
              },
              "examples": {
                "germany": {
                  "summary": "Two lines in Germany, one with a discount",
                  "value": {
                    "country": "DE",
                    "currency": "EUR",
                    "items": [
                      {
                        "description": "Design work",
                        "quantity": 3,
                        "unit_price": 33.33,
                        "discount": {
                          "type": "percent",
                          "value": 10
                        }
                      },
                      {
                        "description": "Printing",
                        "quantity": 0.5,
                        "unit_price": 19.99
                      }
                    ]
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The figures.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Calculation"
                },
                "examples": {
                  "calculate": {
                    "summary": "VAT at 19% on two lines",
                    "value": {
                      "kind": "invoice",
                      "country": "DE",
                      "region": null,
                      "currency": "EUR",
                      "currency_decimals": 2,
                      "lines": [
                        {
                          "quantity": 3,
                          "unit_price": 33.33,
                          "discount": {
                            "type": "percent",
                            "value": 10
                          },
                          "gross": 99.99,
                          "discount_amount": 10,
                          "amount": 89.99
                        },
                        {
                          "quantity": 0.5,
                          "unit_price": 19.99,
                          "discount": null,
                          "gross": 10,
                          "discount_amount": 0,
                          "amount": 10
                        }
                      ],
                      "subtotal_before_discounts": 109.99,
                      "discount_total": 10,
                      "totals": {
                        "currency": "EUR",
                        "subtotal": 99.99,
                        "tax_name": "VAT",
                        "tax_rate": 19,
                        "tax_amount": 19,
                        "total": 118.99,
                        "tax_status": "calculated"
                      },
                      "tax": {
                        "components": [
                          {
                            "name": "VAT",
                            "rate": 19,
                            "amount": 19
                          }
                        ],
                        "rate_from": "published",
                        "status": "standard-rate-estimate",
                        "review_reasons": [
                          "confirm-registration-supply-place-date-and-tax-treatment"
                        ],
                        "source": {
                          "title": "European Commission: VAT rates",
                          "url": "https://europa.eu/youreurope/business/finance-and-tax/vat/vat-rules-rates/index_en.htm",
                          "checked_on": "2026-09-06"
                        },
                        "effective_from": null
                      },
                      "defaults": {
                        "country": "request",
                        "currency": "request"
                      },
                      "rounding": "half-up; currency-rounded base; each tax component rounded separately"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "invalid_json: The body is not valid JSON or not valid UTF-8 text.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "413": {
            "$ref": "#/components/responses/PayloadTooLarge"
          },
          "415": {
            "$ref": "#/components/responses/UnsupportedMediaType"
          },
          "422": {
            "$ref": "#/components/responses/InvalidRequest"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        }
      }
    },
    "/v1/countries": {
      "get": {
        "operationId": "listCountries",
        "tags": [
          "Catalogue"
        ],
        "summary": "List the countries, their currencies and published tax rates",
        "description": "Every country a document may name, with the currency and decimals its money is rounded to and the tax rate QuoteBill applies by default, from the catalogue the site publishes. A rate is a published rate to confirm, not tax advice. Any key. The example shows three countries.",
        "responses": {
          "200": {
            "description": "The countries.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Countries"
                },
                "examples": {
                  "countries": {
                    "summary": "Canada, Germany and Korea",
                    "value": {
                      "tax_reviewed_on": "2026-09-06",
                      "rounding": "half-up; currency-rounded base; each tax component rounded separately",
                      "countries": [
                        {
                          "code": "CA",
                          "currency": "CAD",
                          "currency_decimals": 2,
                          "tax_name": "GST/HST/PST",
                          "standard_rate": null,
                          "status": "jurisdiction-required",
                          "review_reasons": [
                            "place-of-supply-jurisdiction-required"
                          ],
                          "source": {
                            "title": "CRA: GST/HST and provincial rates",
                            "url": "https://www.canada.ca/en/revenue-agency/services/tax/businesses/topics/gst-hst-businesses/charge-collect-which-rate/calculator.html",
                            "checked_on": "2026-09-06"
                          },
                          "effective_from": null,
                          "e_invoicing": null,
                          "e_invoicing_kind": null,
                          "regions": [
                            {
                              "code": "BC",
                              "tax_name": "GST + PST",
                              "rate": 12,
                              "components": [
                                {
                                  "name": "GST",
                                  "rate": 5
                                },
                                {
                                  "name": "PST",
                                  "rate": 7
                                }
                              ],
                              "source": {
                                "title": "CRA: GST/HST and provincial rates",
                                "url": "https://www.canada.ca/en/revenue-agency/services/tax/businesses/topics/gst-hst-businesses/charge-collect-which-rate/calculator.html",
                                "checked_on": "2026-09-06"
                              }
                            },
                            {
                              "code": "ON",
                              "tax_name": "HST",
                              "rate": 13,
                              "components": [
                                {
                                  "name": "HST",
                                  "rate": 13
                                }
                              ],
                              "source": {
                                "title": "CRA: GST/HST and provincial rates",
                                "url": "https://www.canada.ca/en/revenue-agency/services/tax/businesses/topics/gst-hst-businesses/charge-collect-which-rate/calculator.html",
                                "checked_on": "2026-09-06"
                              }
                            }
                          ]
                        },
                        {
                          "code": "DE",
                          "currency": "EUR",
                          "currency_decimals": 2,
                          "tax_name": "VAT",
                          "standard_rate": 19,
                          "status": "standard-rate-estimate",
                          "review_reasons": [
                            "confirm-registration-supply-place-date-and-tax-treatment"
                          ],
                          "source": {
                            "title": "European Commission: VAT rates",
                            "url": "https://europa.eu/youreurope/business/finance-and-tax/vat/vat-rules-rates/index_en.htm",
                            "checked_on": "2026-09-06"
                          },
                          "effective_from": null,
                          "e_invoicing": "XRechnung or ZUGFeRD",
                          "e_invoicing_kind": "invoice"
                        },
                        {
                          "code": "KR",
                          "currency": "KRW",
                          "currency_decimals": 0,
                          "tax_name": "VAT",
                          "standard_rate": 10,
                          "status": "standard-rate-estimate",
                          "review_reasons": [
                            "confirm-registration-supply-place-date-and-tax-treatment"
                          ],
                          "source": {
                            "title": "National Tax Service: VAT overview",
                            "url": "https://b.nts.go.kr/nts/cm/cntnts/cntntsView.do?cntntsId=7693&mi=2272",
                            "checked_on": "2026-09-06"
                          },
                          "effective_from": null,
                          "e_invoicing": "NTS e-tax invoice",
                          "e_invoicing_kind": "invoice"
                        }
                      ]
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "qbk_ followed by 32 characters a-z and 2-7",
        "description": "A personal API key from QuoteBill Company settings. Scopes: documents:create, documents:read."
      }
    },
    "parameters": {
      "IdempotencyKey": {
        "name": "Idempotency-Key",
        "in": "header",
        "required": false,
        "description": "Remembered for 24 hours. The same key with a different request is refused (409 idempotency_key_reused).",
        "schema": {
          "type": "string",
          "pattern": "^[A-Za-z0-9._:-]{1,255}$"
        }
      },
      "DocumentId": {
        "name": "id",
        "in": "path",
        "required": true,
        "schema": {
          "type": "string",
          "pattern": "^[A-Za-z0-9_-]{1,100}$"
        },
        "example": "doc-7c0b8a4e-3f1d-4a52-9d6e-0b2f5c1e8a77"
      },
      "ListKind": {
        "name": "kind",
        "in": "query",
        "required": false,
        "schema": {
          "type": "string",
          "enum": [
            "quotation",
            "invoice",
            "proforma",
            "receipt",
            "creditNote",
            "purchaseOrder",
            "deliveryNote",
            "workOrder",
            "statement",
            "commercialInvoice"
          ]
        }
      },
      "ListStatus": {
        "name": "status",
        "in": "query",
        "required": false,
        "description": "Such as draft, sent or paid.",
        "schema": {
          "type": "string",
          "pattern": "^[A-Za-z0-9_-]{1,40}$"
        }
      },
      "ListLimit": {
        "name": "limit",
        "in": "query",
        "required": false,
        "schema": {
          "type": "integer",
          "minimum": 1,
          "maximum": 100,
          "default": 25
        }
      },
      "ListCursor": {
        "name": "cursor",
        "in": "query",
        "required": false,
        "description": "The next_cursor of the page before, unchanged.",
        "schema": {
          "type": "string",
          "pattern": "^[A-Za-z0-9_-]{1,200}$"
        }
      }
    },
    "headers": {
      "RetryAfter": {
        "description": "Seconds to wait before trying again.",
        "schema": {
          "type": "integer",
          "minimum": 1
        }
      },
      "IdempotentReplayed": {
        "description": "true when the answer is the replay of an earlier request with the same Idempotency-Key.",
        "schema": {
          "type": "string",
          "enum": [
            "true"
          ]
        }
      },
      "WWWAuthenticate": {
        "schema": {
          "type": "string"
        }
      }
    },
    "responses": {
      "Unauthorized": {
        "description": "invalid_api_key: The key is missing, wrong, revoked or expired.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "examples": {
              "invalidKey": {
                "summary": "A missing, wrong, revoked or expired key",
                "value": {
                  "error": {
                    "code": "invalid_api_key",
                    "message": "The API key is missing, not valid, revoked or expired. Send a key from QuoteBill Settings as \"Authorization: Bearer <key>\"."
                  }
                }
              }
            }
          }
        },
        "headers": {
          "WWW-Authenticate": {
            "$ref": "#/components/headers/WWWAuthenticate"
          }
        }
      },
      "InvalidRequest": {
        "description": "invalid_request: A field is missing, unknown or out of range, or a text holds characters that cannot be stored; the fields list says which.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "examples": {
              "invalid": {
                "summary": "A quantity sent as text",
                "value": {
                  "error": {
                    "code": "invalid_request",
                    "message": "items[0].quantity must be a JSON number (not text such as \"10\")",
                    "fields": [
                      {
                        "path": "items[0].quantity",
                        "message": "must be a JSON number (not text such as \"10\")"
                      }
                    ]
                  }
                }
              }
            }
          }
        }
      },
      "PayloadTooLarge": {
        "description": "payload_too_large: The body is over 256 KB.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "UnsupportedMediaType": {
        "description": "unsupported_media_type: The body is not sent as application/json.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "TooManyRequests": {
        "description": "rate_limited: A key made too many requests; wait Retry-After seconds.",
        "headers": {
          "Retry-After": {
            "$ref": "#/components/headers/RetryAfter"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "InternalError": {
        "description": "internal_error: Something went wrong on QuoteBill's side. Retry; if it persists, contact support.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "ServiceUnavailable": {
        "description": "service_unavailable: QuoteBill could not answer just now. Retry after a few seconds.",
        "headers": {
          "Retry-After": {
            "$ref": "#/components/headers/RetryAfter"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      }
    },
    "schemas": {
      "Error": {
        "type": "object",
        "properties": {
          "error": {
            "type": "object",
            "properties": {
              "code": {
                "type": "string",
                "description": "One of the codes in x-error-codes."
              },
              "message": {
                "type": "string",
                "description": "Plain words for a person; do not parse it."
              },
              "fields": {
                "type": "array",
                "maxItems": 20,
                "items": {
                  "$ref": "#/components/schemas/Problem"
                },
                "description": "Only with invalid_request (422) and invalid_query (400)."
              }
            },
            "required": [
              "code",
              "message"
            ],
            "additionalProperties": false
          }
        },
        "required": [
          "error"
        ],
        "additionalProperties": false
      },
      "Problem": {
        "type": "object",
        "properties": {
          "path": {
            "type": "string",
            "description": "The field, such as items[0].unit_price; empty for the body as a whole."
          },
          "message": {
            "type": "string"
          }
        },
        "required": [
          "path",
          "message"
        ],
        "additionalProperties": false
      },
      "Discount": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "enum": [
              "percent",
              "amount"
            ]
          },
          "value": {
            "type": "number",
            "minimum": 0,
            "maximum": 100000000000,
            "description": "percent: 0 to 100. amount: in the document's currency, at most quantity x unit_price."
          }
        },
        "required": [
          "type",
          "value"
        ],
        "additionalProperties": false,
        "description": "A line's discount (V 1.38 on requests; read back since V 1.28)."
      },
      "Customer": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 200,
            "description": "Required."
          },
          "email": {
            "anyOf": [
              {
                "type": "string",
                "maxLength": 254,
                "pattern": "^[^\\s@]{1,64}@[^\\s@]{1,255}$"
              },
              {
                "type": "null"
              }
            ],
            "description": "An e-mail address. Optional: null or an empty string counts as left out."
          },
          "address": {
            "anyOf": [
              {
                "type": "string",
                "maxLength": 500
              },
              {
                "type": "null"
              }
            ],
            "description": "Up to 500 characters; may hold line breaks. Optional: null or an empty string counts as left out."
          },
          "tax_id": {
            "anyOf": [
              {
                "type": "string",
                "maxLength": 60
              },
              {
                "type": "null"
              }
            ],
            "description": "Up to 60 characters. Optional: null or an empty string counts as left out."
          }
        },
        "required": [
          "name"
        ],
        "additionalProperties": false
      },
      "DocumentRequest": {
        "type": "object",
        "properties": {
          "kind": {
            "type": "string",
            "enum": [
              "quotation",
              "invoice",
              "proforma",
              "receipt",
              "creditNote",
              "purchaseOrder",
              "deliveryNote",
              "workOrder",
              "commercialInvoice"
            ],
            "description": "Required. A statement of account is not made through the API."
          },
          "template": {
            "anyOf": [
              {
                "type": "string",
                "pattern": "^[a-z0-9][a-z0-9._-]{0,80}$"
              },
              {
                "type": "null"
              }
            ],
            "description": "A template slug from GET /v1/templates, of the same kind. Optional: null or an empty string counts as left out."
          },
          "language": {
            "anyOf": [
              {
                "type": "string",
                "enum": [
                  "en",
                  "ko",
                  "ja",
                  "zh",
                  "de",
                  "fr",
                  "es",
                  "vi",
                  "ar",
                  "ru",
                  "pt",
                  "it",
                  "nl",
                  "pl",
                  "tr",
                  "sv",
                  "th",
                  "id",
                  "ms",
                  "da",
                  "fi",
                  "nb",
                  "el",
                  "cs",
                  "hu",
                  "ro",
                  "bg",
                  "hr",
                  "lt",
                  "lv",
                  "et",
                  "sl",
                  "sk"
                ]
              },
              {
                "type": "null"
              }
            ],
            "description": "The language the document is written in. Default: the account's, else en. Optional: null or an empty string counts as left out."
          },
          "country": {
            "anyOf": [
              {
                "type": "string",
                "pattern": "^[A-Z]{2}$"
              },
              {
                "type": "null"
              }
            ],
            "description": "A country of GET /v1/countries. The tax follows it. Default: the template's own country (a regional template), else the account's, else US. Optional: null or an empty string counts as left out."
          },
          "region": {
            "anyOf": [
              {
                "type": "string",
                "pattern": "^[A-Z]{2}$"
              },
              {
                "type": "null"
              }
            ],
            "description": "A Canadian province or territory of GET /v1/countries (CA regions), only with country CA: its GST, HST, PST or QST, each rounded on its own. Optional: null or an empty string counts as left out."
          },
          "currency": {
            "anyOf": [
              {
                "type": "string",
                "pattern": "^[A-Z]{3}$"
              },
              {
                "type": "null"
              }
            ],
            "description": "A currency of GET /v1/countries. Default: the account's, else the country's. Amounts round to its decimals. Optional: null or an empty string counts as left out."
          },
          "issue_date": {
            "anyOf": [
              {
                "type": "string",
                "format": "date",
                "pattern": "^\\d{4}-\\d{2}-\\d{2}$"
              },
              {
                "type": "null"
              }
            ],
            "description": "A day from 2000 to 2100. Default: today (UTC). Optional: null or an empty string counts as left out."
          },
          "due_date": {
            "anyOf": [
              {
                "type": "string",
                "format": "date",
                "pattern": "^\\d{4}-\\d{2}-\\d{2}$"
              },
              {
                "type": "null"
              }
            ],
            "description": "For an invoice or commercial invoice. Default: 30 days after the issue date. Optional: null or an empty string counts as left out."
          },
          "valid_until": {
            "anyOf": [
              {
                "type": "string",
                "format": "date",
                "pattern": "^\\d{4}-\\d{2}-\\d{2}$"
              },
              {
                "type": "null"
              }
            ],
            "description": "For a quotation or proforma invoice. Default: 30 days after the issue date. Optional: null or an empty string counts as left out."
          },
          "document_number": {
            "anyOf": [
              {
                "type": "string",
                "maxLength": 100
              },
              {
                "type": "null"
              }
            ],
            "description": "Default: made as the account's numbering setting says. Optional: null or an empty string counts as left out."
          },
          "tax_rate": {
            "anyOf": [
              {
                "type": "number",
                "minimum": 0,
                "maximum": 100
              },
              {
                "type": "null"
              }
            ],
            "description": "A percentage for the whole document. Default: the kind's own (0 for a commercial invoice), else the template's own (0 for a template made for someone not registered for VAT or GST), else the account's saved rate when the document is for the account's own country, else the country's or region's published rate. Optional: null or an empty string counts as left out."
          },
          "customer": {
            "$ref": "#/components/schemas/Customer"
          },
          "items": {
            "type": "array",
            "minItems": 1,
            "maxItems": 200,
            "items": {
              "type": "object",
              "properties": {
                "description": {
                  "type": "string",
                  "minLength": 1,
                  "maxLength": 500,
                  "description": "Up to 500 characters, one line. Required."
                },
                "quantity": {
                  "type": "number",
                  "exclusiveMinimum": 0,
                  "maximum": 1000000000,
                  "description": "A JSON number above 0. Hours on an hours template."
                },
                "unit_price": {
                  "type": "number",
                  "minimum": 0,
                  "maximum": 100000000000,
                  "description": "A JSON number from 0, before tax. Required, except on a kind or template whose lines are quantities only. quantity x unit_price may not pass 100000000000."
                },
                "tax_rate": {
                  "anyOf": [
                    {
                      "type": "number",
                      "minimum": 0,
                      "maximum": 100
                    },
                    {
                      "type": "null"
                    }
                  ],
                  "description": "A percentage. A document has one tax rate, so it must equal the document's tax_rate and every other item's. Optional: null or an empty string counts as left out."
                },
                "discount": {
                  "anyOf": [
                    {
                      "$ref": "#/components/schemas/Discount"
                    },
                    {
                      "type": "null"
                    }
                  ],
                  "description": "Taken off the line before tax, as the editor's discount column does. Optional: null or an empty string counts as left out."
                }
              },
              "required": [
                "description",
                "quantity"
              ],
              "additionalProperties": false
            },
            "description": "1 to 200 lines."
          },
          "notes": {
            "anyOf": [
              {
                "type": "string",
                "maxLength": 2000
              },
              {
                "type": "null"
              }
            ],
            "description": "Up to 2,000 characters, printed on the document. Optional: null or an empty string counts as left out."
          }
        },
        "required": [
          "kind",
          "customer",
          "items"
        ],
        "additionalProperties": false,
        "description": "A document to make. A field the API does not know is refused (422). Numbers are JSON numbers, not text. Prices are before tax: QuoteBill documents have no tax-inclusive prices."
      },
      "CalculateRequest": {
        "type": "object",
        "properties": {
          "kind": {
            "type": "string",
            "enum": [
              "quotation",
              "invoice",
              "proforma",
              "receipt",
              "creditNote",
              "purchaseOrder",
              "deliveryNote",
              "workOrder",
              "commercialInvoice"
            ],
            "description": "Default: the template's kind, else invoice."
          },
          "template": {
            "anyOf": [
              {
                "type": "string",
                "pattern": "^[a-z0-9][a-z0-9._-]{0,80}$"
              },
              {
                "type": "null"
              }
            ],
            "description": "A template slug from GET /v1/templates, of the same kind. Optional: null or an empty string counts as left out."
          },
          "language": {
            "anyOf": [
              {
                "type": "string",
                "enum": [
                  "en",
                  "ko",
                  "ja",
                  "zh",
                  "de",
                  "fr",
                  "es",
                  "vi",
                  "ar",
                  "ru",
                  "pt",
                  "it",
                  "nl",
                  "pl",
                  "tr",
                  "sv",
                  "th",
                  "id",
                  "ms",
                  "da",
                  "fi",
                  "nb",
                  "el",
                  "cs",
                  "hu",
                  "ro",
                  "bg",
                  "hr",
                  "lt",
                  "lv",
                  "et",
                  "sl",
                  "sk"
                ]
              },
              {
                "type": "null"
              }
            ],
            "description": "The language the document is written in. Default: the account's, else en. Optional: null or an empty string counts as left out."
          },
          "country": {
            "anyOf": [
              {
                "type": "string",
                "pattern": "^[A-Z]{2}$"
              },
              {
                "type": "null"
              }
            ],
            "description": "A country of GET /v1/countries. The tax follows it. Default: the template's own country (a regional template), else the account's, else US. Optional: null or an empty string counts as left out."
          },
          "region": {
            "anyOf": [
              {
                "type": "string",
                "pattern": "^[A-Z]{2}$"
              },
              {
                "type": "null"
              }
            ],
            "description": "A Canadian province or territory of GET /v1/countries (CA regions), only with country CA: its GST, HST, PST or QST, each rounded on its own. Optional: null or an empty string counts as left out."
          },
          "currency": {
            "anyOf": [
              {
                "type": "string",
                "pattern": "^[A-Z]{3}$"
              },
              {
                "type": "null"
              }
            ],
            "description": "A currency of GET /v1/countries. Default: the account's, else the country's. Amounts round to its decimals. Optional: null or an empty string counts as left out."
          },
          "issue_date": {
            "anyOf": [
              {
                "type": "string",
                "format": "date",
                "pattern": "^\\d{4}-\\d{2}-\\d{2}$"
              },
              {
                "type": "null"
              }
            ],
            "description": "A day from 2000 to 2100. Default: today (UTC). Optional: null or an empty string counts as left out."
          },
          "due_date": {
            "anyOf": [
              {
                "type": "string",
                "format": "date",
                "pattern": "^\\d{4}-\\d{2}-\\d{2}$"
              },
              {
                "type": "null"
              }
            ],
            "description": "For an invoice or commercial invoice. Default: 30 days after the issue date. Optional: null or an empty string counts as left out."
          },
          "valid_until": {
            "anyOf": [
              {
                "type": "string",
                "format": "date",
                "pattern": "^\\d{4}-\\d{2}-\\d{2}$"
              },
              {
                "type": "null"
              }
            ],
            "description": "For a quotation or proforma invoice. Default: 30 days after the issue date. Optional: null or an empty string counts as left out."
          },
          "document_number": {
            "anyOf": [
              {
                "type": "string",
                "maxLength": 100
              },
              {
                "type": "null"
              }
            ],
            "description": "Default: made as the account's numbering setting says. Optional: null or an empty string counts as left out."
          },
          "tax_rate": {
            "anyOf": [
              {
                "type": "number",
                "minimum": 0,
                "maximum": 100
              },
              {
                "type": "null"
              }
            ],
            "description": "A percentage for the whole document. Default: the kind's own (0 for a commercial invoice), else the template's own (0 for a template made for someone not registered for VAT or GST), else the account's saved rate when the document is for the account's own country, else the country's or region's published rate. Optional: null or an empty string counts as left out."
          },
          "customer": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/Customer"
              },
              {
                "type": "null"
              }
            ],
            "description": "Not used by the calculation; checked as for a document. Optional: null or an empty string counts as left out."
          },
          "items": {
            "type": "array",
            "minItems": 1,
            "maxItems": 200,
            "items": {
              "type": "object",
              "properties": {
                "description": {
                  "anyOf": [
                    {
                      "type": "string",
                      "minLength": 1,
                      "maxLength": 500
                    },
                    {
                      "type": "null"
                    }
                  ],
                  "description": "Up to 500 characters, one line. Optional: null or an empty string counts as left out."
                },
                "quantity": {
                  "type": "number",
                  "exclusiveMinimum": 0,
                  "maximum": 1000000000,
                  "description": "A JSON number above 0. Hours on an hours template."
                },
                "unit_price": {
                  "type": "number",
                  "minimum": 0,
                  "maximum": 100000000000,
                  "description": "A JSON number from 0, before tax. Required, except on a kind or template whose lines are quantities only. quantity x unit_price may not pass 100000000000."
                },
                "tax_rate": {
                  "anyOf": [
                    {
                      "type": "number",
                      "minimum": 0,
                      "maximum": 100
                    },
                    {
                      "type": "null"
                    }
                  ],
                  "description": "A percentage. A document has one tax rate, so it must equal the document's tax_rate and every other item's. Optional: null or an empty string counts as left out."
                },
                "discount": {
                  "anyOf": [
                    {
                      "$ref": "#/components/schemas/Discount"
                    },
                    {
                      "type": "null"
                    }
                  ],
                  "description": "Taken off the line before tax, as the editor's discount column does. Optional: null or an empty string counts as left out."
                }
              },
              "required": [
                "quantity"
              ],
              "additionalProperties": false
            },
            "description": "1 to 200 lines."
          },
          "notes": {
            "anyOf": [
              {
                "type": "string",
                "maxLength": 2000
              },
              {
                "type": "null"
              }
            ],
            "description": "Up to 2,000 characters, printed on the document. Optional: null or an empty string counts as left out."
          }
        },
        "required": [
          "items"
        ],
        "additionalProperties": false,
        "description": "The body of POST /v1/documents, read the same way; kind, customer and the items' descriptions may be left out. A field the API does not know is refused (422). Numbers are JSON numbers, not text. Prices are before tax: QuoteBill documents have no tax-inclusive prices."
      },
      "Totals": {
        "type": "object",
        "properties": {
          "currency": {
            "type": "string",
            "pattern": "^[A-Z]{3}$"
          },
          "subtotal": {
            "type": "number",
            "description": "The lines, each rounded to the currency, added up."
          },
          "tax_name": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ]
          },
          "tax_rate": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "description": "A percentage: 19 is 19%."
          },
          "tax_amount": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ]
          },
          "total": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ]
          },
          "tax_status": {
            "type": "string",
            "enum": [
              "calculated",
              "rate_needed"
            ],
            "description": "rate_needed: the country has no single national rate (the United States, Canada without a region). No tax and no total until tax_rate is sent."
          },
          "total_hours": {
            "type": "number",
            "description": "Only on an hours template: the quantities added up."
          }
        },
        "required": [
          "currency",
          "subtotal",
          "tax_name",
          "tax_rate",
          "tax_amount",
          "total",
          "tax_status"
        ],
        "additionalProperties": false,
        "description": "What the editor shows under the lines."
      },
      "Ping": {
        "type": "object",
        "properties": {
          "ok": {
            "const": true
          }
        },
        "required": [
          "ok"
        ],
        "additionalProperties": false
      },
      "Templates": {
        "type": "object",
        "properties": {
          "kinds": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "kind": {
                  "type": "string",
                  "enum": [
                    "quotation",
                    "invoice",
                    "proforma",
                    "receipt",
                    "creditNote",
                    "purchaseOrder",
                    "deliveryNote",
                    "workOrder",
                    "commercialInvoice"
                  ]
                },
                "name": {
                  "type": "string"
                },
                "default_columns": {
                  "type": "string",
                  "enum": [
                    "priced",
                    "hours",
                    "quantity"
                  ]
                },
                "second_date": {
                  "anyOf": [
                    {
                      "type": "string",
                      "enum": [
                        "due_date",
                        "valid_until"
                      ]
                    },
                    {
                      "type": "null"
                    }
                  ]
                }
              },
              "required": [
                "kind",
                "name",
                "default_columns",
                "second_date"
              ],
              "additionalProperties": false
            }
          },
          "templates": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "slug": {
                  "type": "string",
                  "pattern": "^[a-z0-9][a-z0-9._-]{0,80}$"
                },
                "kind": {
                  "type": "string",
                  "enum": [
                    "quotation",
                    "invoice",
                    "proforma",
                    "receipt",
                    "creditNote",
                    "purchaseOrder",
                    "deliveryNote",
                    "workOrder",
                    "commercialInvoice"
                  ]
                },
                "name": {
                  "type": "string"
                },
                "category": {
                  "type": "string"
                },
                "layout": {
                  "type": "string"
                },
                "columns": {
                  "type": "string"
                },
                "language": {
                  "type": "string"
                }
              },
              "required": [
                "slug",
                "kind",
                "name",
                "category",
                "layout"
              ],
              "additionalProperties": false
            }
          }
        },
        "required": [
          "kinds",
          "templates"
        ],
        "additionalProperties": false
      },
      "DocumentCreated": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "editor_url": {
            "type": "string",
            "format": "uri",
            "description": "Opens the document in the editor, for the member."
          },
          "number": {
            "type": "string"
          },
          "totals": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/Totals"
              },
              {
                "type": "null"
              }
            ],
            "description": "null for a document whose lines carry no prices."
          }
        },
        "required": [
          "id",
          "editor_url",
          "number",
          "totals"
        ],
        "additionalProperties": false
      },
      "DocumentSummary": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "kind": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ]
          },
          "status": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ]
          },
          "number": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ]
          },
          "name": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ]
          },
          "customer": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ]
          },
          "language": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ]
          },
          "country": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ]
          },
          "currency": {
            "type": "string"
          },
          "issue_date": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ]
          },
          "created_at": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ]
          },
          "updated_at": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ]
          },
          "editor_url": {
            "type": "string",
            "format": "uri"
          }
        },
        "required": [
          "id",
          "kind",
          "status",
          "number",
          "name",
          "customer",
          "language",
          "country",
          "currency",
          "issue_date",
          "created_at",
          "updated_at",
          "editor_url"
        ],
        "additionalProperties": false
      },
      "DocumentList": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "maxItems": 100,
            "items": {
              "$ref": "#/components/schemas/DocumentSummary"
            }
          },
          "next_cursor": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Send it back as cursor for the next page; null on the last."
          }
        },
        "required": [
          "data",
          "next_cursor"
        ],
        "additionalProperties": false
      },
      "Document": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "kind": {
            "anyOf": [
              {
                "type": "string",
                "enum": [
                  "quotation",
                  "invoice",
                  "proforma",
                  "receipt",
                  "creditNote",
                  "purchaseOrder",
                  "deliveryNote",
                  "workOrder",
                  "statement",
                  "commercialInvoice"
                ]
              },
              {
                "type": "null"
              }
            ]
          },
          "status": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ]
          },
          "number": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ]
          },
          "name": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ]
          },
          "language": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ]
          },
          "country": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ]
          },
          "currency": {
            "type": "string"
          },
          "issue_date": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ]
          },
          "due_date": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ]
          },
          "valid_until": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ]
          },
          "customer": {
            "type": "object",
            "properties": {
              "name": {
                "anyOf": [
                  {
                    "type": "string"
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "email": {
                "anyOf": [
                  {
                    "type": "string"
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "address": {
                "anyOf": [
                  {
                    "type": "string"
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "tax_id": {
                "anyOf": [
                  {
                    "type": "string"
                  },
                  {
                    "type": "null"
                  }
                ]
              }
            },
            "required": [
              "name",
              "email",
              "address",
              "tax_id"
            ],
            "additionalProperties": false
          },
          "items": {
            "type": "array",
            "items": {
              "oneOf": [
                {
                  "type": "object",
                  "properties": {
                    "section": {
                      "anyOf": [
                        {
                          "type": "string"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    }
                  },
                  "required": [
                    "section"
                  ],
                  "additionalProperties": false,
                  "description": "A section heading between lines."
                },
                {
                  "type": "object",
                  "properties": {
                    "description": {
                      "anyOf": [
                        {
                          "type": "string"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "quantity": {
                      "anyOf": [
                        {
                          "type": "number"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "unit_price": {
                      "anyOf": [
                        {
                          "type": "number"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "discount": {
                      "$ref": "#/components/schemas/Discount"
                    }
                  },
                  "required": [
                    "description",
                    "quantity",
                    "unit_price"
                  ],
                  "additionalProperties": false
                }
              ]
            }
          },
          "notes": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ]
          },
          "totals": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/Totals"
              },
              {
                "type": "null"
              }
            ]
          },
          "editor_url": {
            "type": "string",
            "format": "uri"
          },
          "created_at": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ]
          },
          "updated_at": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ]
          }
        },
        "required": [
          "id",
          "kind",
          "status",
          "number",
          "name",
          "language",
          "country",
          "currency",
          "issue_date",
          "customer",
          "items",
          "notes",
          "totals",
          "editor_url",
          "created_at",
          "updated_at"
        ],
        "additionalProperties": false,
        "description": "Any document of the member's, however it was made. The sender's details, logo and stamp are not part of it. due_date is there for a kind that has one, valid_until likewise."
      },
      "Calculation": {
        "type": "object",
        "properties": {
          "kind": {
            "type": "string",
            "enum": [
              "quotation",
              "invoice",
              "proforma",
              "receipt",
              "creditNote",
              "purchaseOrder",
              "deliveryNote",
              "workOrder",
              "commercialInvoice"
            ]
          },
          "country": {
            "type": "string"
          },
          "region": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ]
          },
          "currency": {
            "type": "string",
            "pattern": "^[A-Z]{3}$"
          },
          "currency_decimals": {
            "type": "integer",
            "minimum": 0,
            "maximum": 4
          },
          "lines": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "quantity": {
                  "type": "number"
                },
                "unit_price": {
                  "type": "number"
                },
                "discount": {
                  "anyOf": [
                    {
                      "$ref": "#/components/schemas/Discount"
                    },
                    {
                      "type": "null"
                    }
                  ]
                },
                "gross": {
                  "type": "number",
                  "description": "quantity x unit_price, rounded to the currency."
                },
                "discount_amount": {
                  "type": "number",
                  "description": "gross less amount."
                },
                "amount": {
                  "type": "number",
                  "description": "The line as the document prints it: after its discount, rounded to the currency."
                }
              },
              "required": [
                "quantity",
                "unit_price",
                "discount",
                "gross",
                "discount_amount",
                "amount"
              ],
              "additionalProperties": false
            }
          },
          "subtotal_before_discounts": {
            "type": "number"
          },
          "discount_total": {
            "type": "number"
          },
          "totals": {
            "$ref": "#/components/schemas/Totals"
          },
          "tax": {
            "type": "object",
            "properties": {
              "components": {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "name": {
                      "type": "string"
                    },
                    "rate": {
                      "type": "number"
                    },
                    "amount": {
                      "type": "number"
                    }
                  },
                  "required": [
                    "name",
                    "rate",
                    "amount"
                  ],
                  "additionalProperties": false
                },
                "description": "Each tax, rounded on its own: two for a Canadian province with GST and PST."
              },
              "rate_from": {
                "anyOf": [
                  {
                    "type": "string",
                    "enum": [
                      "request",
                      "kind",
                      "template",
                      "account",
                      "published"
                    ]
                  },
                  {
                    "type": "null"
                  }
                ],
                "description": "Where the rate came from: the request's tax_rate, the kind's own (0 for a commercial invoice), the template's own (0 for a template made for someone not registered for VAT or GST), the account's default, or the published rate of the country or region. null when there is none."
              },
              "status": {
                "type": "string",
                "description": "The catalogue's note on the rate, such as standard-rate-estimate or jurisdiction-required."
              },
              "review_reasons": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              },
              "source": {
                "anyOf": [
                  {
                    "type": "object",
                    "properties": {
                      "title": {
                        "type": "string"
                      },
                      "url": {
                        "anyOf": [
                          {
                            "type": "string",
                            "format": "uri"
                          },
                          {
                            "type": "null"
                          }
                        ]
                      },
                      "checked_on": {
                        "anyOf": [
                          {
                            "type": "string",
                            "format": "date",
                            "pattern": "^\\d{4}-\\d{2}-\\d{2}$"
                          },
                          {
                            "type": "null"
                          }
                        ]
                      }
                    },
                    "required": [
                      "title",
                      "url",
                      "checked_on"
                    ],
                    "additionalProperties": false
                  },
                  {
                    "type": "null"
                  }
                ],
                "description": "Where the rate was read, and when."
              },
              "effective_from": {
                "anyOf": [
                  {
                    "type": "string",
                    "format": "date",
                    "pattern": "^\\d{4}-\\d{2}-\\d{2}$"
                  },
                  {
                    "type": "null"
                  }
                ]
              }
            },
            "required": [
              "components",
              "rate_from",
              "status",
              "review_reasons",
              "source",
              "effective_from"
            ],
            "additionalProperties": false
          },
          "defaults": {
            "type": "object",
            "properties": {
              "country": {
                "type": "string",
                "enum": [
                  "request",
                  "template",
                  "account",
                  "fallback"
                ]
              },
              "currency": {
                "type": "string",
                "enum": [
                  "request",
                  "account",
                  "country"
                ]
              }
            },
            "required": [
              "country",
              "currency"
            ],
            "additionalProperties": false,
            "description": "Which fields the request left to the template (its country), to the account's settings (as for a document), or to the fallbacks: US, and the country's currency."
          },
          "rounding": {
            "type": "string",
            "description": "How the figures are rounded, in the catalogue's words."
          }
        },
        "required": [
          "kind",
          "country",
          "region",
          "currency",
          "currency_decimals",
          "lines",
          "subtotal_before_discounts",
          "discount_total",
          "totals",
          "tax",
          "defaults",
          "rounding"
        ],
        "additionalProperties": false
      },
      "Countries": {
        "type": "object",
        "properties": {
          "tax_reviewed_on": {
            "anyOf": [
              {
                "type": "string",
                "format": "date",
                "pattern": "^\\d{4}-\\d{2}-\\d{2}$"
              },
              {
                "type": "null"
              }
            ]
          },
          "rounding": {
            "type": "string"
          },
          "countries": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Country"
            }
          }
        },
        "required": [
          "tax_reviewed_on",
          "rounding",
          "countries"
        ],
        "additionalProperties": false
      },
      "Country": {
        "type": "object",
        "properties": {
          "code": {
            "type": "string",
            "pattern": "^[A-Z]{2}$"
          },
          "currency": {
            "type": "string",
            "pattern": "^[A-Z]{3}$"
          },
          "currency_decimals": {
            "type": "integer",
            "minimum": 0,
            "maximum": 4
          },
          "tax_name": {
            "type": "string"
          },
          "standard_rate": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "description": "A percentage; null where there is no single national rate."
          },
          "status": {
            "type": "string"
          },
          "review_reasons": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "source": {
            "anyOf": [
              {
                "type": "object",
                "properties": {
                  "title": {
                    "type": "string"
                  },
                  "url": {
                    "anyOf": [
                      {
                        "type": "string",
                        "format": "uri"
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "checked_on": {
                    "anyOf": [
                      {
                        "type": "string",
                        "format": "date",
                        "pattern": "^\\d{4}-\\d{2}-\\d{2}$"
                      },
                      {
                        "type": "null"
                      }
                    ]
                  }
                },
                "required": [
                  "title",
                  "url",
                  "checked_on"
                ],
                "additionalProperties": false
              },
              {
                "type": "null"
              }
            ],
            "description": "Where the rate was read, and when."
          },
          "effective_from": {
            "anyOf": [
              {
                "type": "string",
                "format": "date",
                "pattern": "^\\d{4}-\\d{2}-\\d{2}$"
              },
              {
                "type": "null"
              }
            ]
          },
          "e_invoicing": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "The e-invoicing system invoices there may have to go through. QuoteBill does not send to it."
          },
          "e_invoicing_kind": {
            "anyOf": [
              {
                "type": "string",
                "enum": [
                  "invoice",
                  "software"
                ]
              },
              {
                "type": "null"
              }
            ],
            "description": "invoice: invoices may have to be issued as e-invoices through that system. software: the duty is on the invoicing software (Spain, Portugal), and QuoteBill is not a certified or registered invoicing system. null where e_invoicing is null."
          },
          "regions": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "code": {
                  "type": "string",
                  "pattern": "^[A-Z]{2}$"
                },
                "tax_name": {
                  "type": "string"
                },
                "rate": {
                  "type": "number"
                },
                "components": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "rate": {
                        "type": "number"
                      }
                    },
                    "required": [
                      "name",
                      "rate"
                    ],
                    "additionalProperties": false
                  }
                },
                "source": {
                  "anyOf": [
                    {
                      "type": "object",
                      "properties": {
                        "title": {
                          "type": "string"
                        },
                        "url": {
                          "anyOf": [
                            {
                              "type": "string",
                              "format": "uri"
                            },
                            {
                              "type": "null"
                            }
                          ]
                        },
                        "checked_on": {
                          "anyOf": [
                            {
                              "type": "string",
                              "format": "date",
                              "pattern": "^\\d{4}-\\d{2}-\\d{2}$"
                            },
                            {
                              "type": "null"
                            }
                          ]
                        }
                      },
                      "required": [
                        "title",
                        "url",
                        "checked_on"
                      ],
                      "additionalProperties": false
                    },
                    {
                      "type": "null"
                    }
                  ],
                  "description": "Where the rate was read, and when."
                }
              },
              "required": [
                "code",
                "tax_name",
                "rate",
                "components",
                "source"
              ],
              "additionalProperties": false
            },
            "description": "Canada only: the provinces and territories, for the region field."
          }
        },
        "required": [
          "code",
          "currency",
          "currency_decimals",
          "tax_name",
          "standard_rate",
          "status",
          "review_reasons",
          "source",
          "effective_from",
          "e_invoicing",
          "e_invoicing_kind"
        ],
        "additionalProperties": false
      }
    }
  },
  "x-error-codes": [
    {
      "status": 400,
      "code": "invalid_json",
      "meaning": "The body is not valid JSON or not valid UTF-8 text."
    },
    {
      "status": 400,
      "code": "invalid_query",
      "meaning": "A parameter of the list is not one the endpoint has, or has a wrong value."
    },
    {
      "status": 400,
      "code": "invalid_idempotency_key",
      "meaning": "The Idempotency-Key header is not 1 to 255 letters, digits, dots, dashes, underscores or colons."
    },
    {
      "status": 401,
      "code": "invalid_api_key",
      "meaning": "The key is missing, wrong, revoked or expired."
    },
    {
      "status": 403,
      "code": "insufficient_scope",
      "meaning": "The key does not have the scope the endpoint needs."
    },
    {
      "status": 403,
      "code": "document_limit_reached",
      "meaning": "Your QuoteBill cloud is full."
    },
    {
      "status": 404,
      "code": "not_found",
      "meaning": "No such endpoint, or no such document of yours."
    },
    {
      "status": 405,
      "code": "method_not_allowed",
      "meaning": "The endpoint does not have that method (the Allow header lists them)."
    },
    {
      "status": 409,
      "code": "document_number_taken",
      "meaning": "Another of your documents has this document_number."
    },
    {
      "status": 409,
      "code": "idempotency_key_reused",
      "meaning": "The Idempotency-Key was used for a different request in the last 24 hours."
    },
    {
      "status": 413,
      "code": "payload_too_large",
      "meaning": "The body is over 256 KB."
    },
    {
      "status": 415,
      "code": "unsupported_media_type",
      "meaning": "The body is not sent as application/json."
    },
    {
      "status": 422,
      "code": "invalid_request",
      "meaning": "A field is missing, unknown or out of range, or a text holds characters that cannot be stored; the fields list says which."
    },
    {
      "status": 429,
      "code": "rate_limited",
      "meaning": "A key made too many requests; wait Retry-After seconds."
    },
    {
      "status": 429,
      "code": "daily_document_limit",
      "meaning": "The account has made 500 documents through the API today."
    },
    {
      "status": 500,
      "code": "internal_error",
      "meaning": "Something went wrong on QuoteBill's side. Retry; if it persists, contact support."
    },
    {
      "status": 503,
      "code": "service_unavailable",
      "meaning": "QuoteBill could not answer just now. Retry after a few seconds."
    }
  ]
}
