{
  "openapi": "3.1.0",
  "info": {
    "title": "SLF Data API: integration guide and reference",
    "version": "0.9.2-draft",
    "summary": "Draft integration guide and reference for the planned SLF Data API, which is not live: through it, a company's own system would send the documents it has already issued or received to SLF Accounting for recording in its books.",
    "description": "Draft specification, version 0.9.2-draft (4 November 2026). The SLF Data API is in preparation and not live yet: until launch, every request to the base URLs below gets a `503 service_unavailable` error, and no keys are issued. It is planned to open in two releases, with supplier bills and supplier payments in the second (see [Two releases](https://slf-accounting.co/developers/reference#guide-overview)). Names, fields and behaviour may change before launch. Companies interested in early access can register interest at [https://slf-accounting.co/contact?topic=api-access](https://slf-accounting.co/contact?topic=api-access). This reference describes data, not tax treatment. Nothing here is tax or legal advice; SLF Accounting reviews what you send.\n\nFull integration guide and reference: https://slf-accounting.co/developers/reference",
    "contact": {
      "name": "SLF Accounting Co., Ltd.",
      "url": "https://slf-accounting.co/contact?topic=api-access"
    },
    "x-status": "draft"
  },
  "servers": [
    {
      "url": "https://api.slf-accounting.co/v1",
      "description": "Production, for live keys (planned — not live)"
    },
    {
      "url": "https://api-sandbox.slf-accounting.co/v1",
      "description": "Sandbox, for test keys (planned — not live)"
    }
  ],
  "security": [
    {
      "bearerAuth": []
    }
  ],
  "tags": [
    {
      "name": "Company",
      "description": "Not live yet (draft specification). The company your key belongs to."
    },
    {
      "name": "Bank accounts",
      "description": "Not live yet (draft specification). Your company's bank accounts as SLF has recorded them. The API only reads them: accounts are added, edited and deleted by SLF or in your company's client portal."
    },
    {
      "name": "Customers",
      "description": "Not live yet (draft specification). The customers your sales documents are issued to. Create each customer once and refer to it by `id` (or your `external_id`) on sales documents."
    },
    {
      "name": "Sales documents",
      "description": "Not live yet (draft specification). Documents you issued to customers: quotations, invoices, tax invoices, cash-sale tax invoice/receipts, credit notes and debit notes. You record them as printed; SLF does not number, print or send them."
    },
    {
      "name": "Receipts",
      "description": "Not live yet (draft specification). Payments your customers made against an invoice, tax invoice or debit note, including any tax they withheld."
    },
    {
      "name": "Supplier bills",
      "description": "Not live yet (draft specification). Second release (see [Two releases](https://slf-accounting.co/developers/reference#guide-overview)): once the first release is live, these paths answer 404 `not_found` until the second opens. Documents you received from suppliers, and the credit and debit notes suppliers issued against them."
    },
    {
      "name": "Supplier payments",
      "description": "Not live yet (draft specification). Second release (see [Two releases](https://slf-accounting.co/developers/reference#guide-overview)): once the first release is live, these paths answer 404 `not_found` until the second opens. Payments you made to suppliers, allocated to bills, with the tax you withheld and the withholding tax certificates (50 ทวิ) you issued."
    },
    {
      "name": "Attachments",
      "description": "Not live yet (draft specification). PDFs and scans attached to sales documents and receipts, and from the second release to bills and payments. Only files uploaded through the API are listed and returned."
    },
    {
      "name": "Periods",
      "description": "Not live yet (draft specification). A month's figures as SLF has recorded them, for reconciliation with your own system."
    }
  ],
  "paths": {
    "/company": {
      "get": {
        "operationId": "getCompany",
        "tags": [
          "Company"
        ],
        "summary": "Get your company",
        "x-release": 1,
        "description": "Draft specification: not live yet. Returns the company the key belongs to. Use it to check that your key works and belongs to the company you expect. `vat_registered` is the VAT setting of your company's profile at SLF, which someone at your company can also change in the client portal. If it is `false`, every line's `vat_category` is recorded as `none`. Every write is refused with 403 `forbidden` unless this setting and SLF's own record of your company's VAT registration are both set and agree; they can disagree, for example, after the setting is changed in the client portal. Reads, including this one, keep working. Keep the refused records, contact SLF, and send them again once SLF tells you the two agree.",
        "parameters": [],
        "responses": {
          "200": {
            "description": "Your company.",
            "headers": {
              "Request-Id": {
                "description": "SLF's id for the request: an opaque string of up to 64 characters. Quote it when you contact SLF. A replayed response carries the id of the first request.",
                "schema": {
                  "type": "string",
                  "maxLength": 64
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Company"
                },
                "example": {
                  "name": "Example Trading Co., Ltd.",
                  "name_local": "บริษัท ตัวอย่าง จำกัด",
                  "tax_id": "0999000000019",
                  "branch_no": "00000",
                  "vat_registered": true
                }
              }
            }
          },
          "default": {
            "description": "Error. See the error codes in the reference.",
            "headers": {
              "Request-Id": {
                "description": "SLF's id for the request: an opaque string of up to 64 characters. Quote it when you contact SLF. A replayed response carries the id of the first request.",
                "schema": {
                  "type": "string",
                  "maxLength": 64
                }
              },
              "Retry-After": {
                "description": "Seconds to wait before retrying.",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/bank-accounts": {
      "get": {
        "operationId": "listBankAccounts",
        "tags": [
          "Bank accounts"
        ],
        "summary": "List bank accounts",
        "x-release": 1,
        "description": "Draft specification: not live yet. Returns the accounts SLF has on record for your company. Use an account's `id` as `bank_account_id` on sales documents, receipts and payments. Only the last four digits of each account number are returned. The list can change between two reads: an account deleted by SLF or in your client portal is no longer listed and its `id` is gone, and an account edited there keeps its `id` with the new details. Read the list again before you use an id, and check that `bank_name` and `account_number_last4` still show the account you mean. An id that is no longer listed is refused on writes with 422 `reference_not_found`.",
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Number of records per page: a whole number from 1 to 100. Default 25. For the refusals, see Pagination in [Conventions](https://slf-accounting.co/developers/reference#guide-conventions).",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 25
            },
            "example": 25
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "description": "The `next_cursor` value from the previous page, unchanged. Omit it for the first page; an empty value is refused. For the refusals, see Pagination in [Conventions](https://slf-accounting.co/developers/reference#guide-conventions).",
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 512
            },
            "example": "cur_8Tn3XqL5Vd"
          }
        ],
        "responses": {
          "200": {
            "description": "A page of bank accounts.",
            "headers": {
              "Request-Id": {
                "description": "SLF's id for the request: an opaque string of up to 64 characters. Quote it when you contact SLF. A replayed response carries the id of the first request.",
                "schema": {
                  "type": "string",
                  "maxLength": 64
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/BankAccount"
                      }
                    },
                    "next_cursor": {
                      "type": [
                        "string",
                        "null"
                      ]
                    }
                  },
                  "required": [
                    "data",
                    "next_cursor"
                  ]
                },
                "example": {
                  "data": [
                    {
                      "id": "bnk_5Qm2Rk8Lt3Vw",
                      "bank_name": "Example Bank Public Company Limited",
                      "account_name": "Example Trading Co., Ltd.",
                      "account_number_last4": "4821",
                      "currency": "THB",
                      "type": null
                    },
                    {
                      "id": "bnk_9Ze3Lp6Qr2Dn",
                      "bank_name": "Example Bank Public Company Limited",
                      "account_name": "Example Trading Co., Ltd.",
                      "account_number_last4": "7730",
                      "currency": "USD",
                      "type": null
                    }
                  ],
                  "next_cursor": null
                }
              }
            }
          },
          "default": {
            "description": "Error. See the error codes in the reference.",
            "headers": {
              "Request-Id": {
                "description": "SLF's id for the request: an opaque string of up to 64 characters. Quote it when you contact SLF. A replayed response carries the id of the first request.",
                "schema": {
                  "type": "string",
                  "maxLength": 64
                }
              },
              "Retry-After": {
                "description": "Seconds to wait before retrying.",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/customers": {
      "post": {
        "operationId": "createCustomer",
        "tags": [
          "Customers"
        ],
        "summary": "Create a customer",
        "x-release": 1,
        "description": "Draft specification: not live yet. Creates a customer. Only `external_id` and `name` are required. For a customer in Thailand (`country` `TH`) with a `tax_id`, the tax ID's check digit is validated and `branch_no` defaults to `00000`. A customer with the same `tax_id` and `branch_no` as an existing one is refused with 409 `customer_exists`, and `existing_id` points to the customer already recorded. For a customer outside Thailand, `tax_id` is optional and its format is not checked.\n\nErrors specific to this endpoint: duplicate_external_id, customer_exists.",
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": true,
            "description": "Required on every POST. A unique value for this request, 1 to 255 visible ASCII characters; a UUID works well. Reuse it only to retry this exact request after a network error, a timeout, 429 or a 5xx. After any other 4xx, fix the request and send it with a new value. See [Idempotency and duplicates](https://slf-accounting.co/developers/reference#guide-idempotency).",
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 255,
              "pattern": "^[\\x21-\\x7E]+$"
            },
            "example": "5f0c2b8e-3d4a-4c1e-9b7f-2a6d8e1c0f93"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/Customer"
              },
              "example": {
                "external_id": "CUST-00412",
                "name": "Sample Retail Co., Ltd.",
                "name_local": "บริษัท ตัวอย่างค้าปลีก จำกัด",
                "country": "TH",
                "tax_id": "0999000000027",
                "branch_no": "00000",
                "address": "88 Example Road, Pathum Wan, Bangkok 10330",
                "email": "accounts@sample-retail.example",
                "phone": "+66 2 000 0000",
                "notes": "Send statements to the accounts team."
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "The customer was created.",
            "headers": {
              "Request-Id": {
                "description": "SLF's id for the request: an opaque string of up to 64 characters. Quote it when you contact SLF. A replayed response carries the id of the first request.",
                "schema": {
                  "type": "string",
                  "maxLength": 64
                }
              },
              "Idempotent-Replayed": {
                "description": "`true` when the response is the stored response of an earlier request with the same `Idempotency-Key`; nothing new was recorded.",
                "schema": {
                  "type": "string",
                  "enum": [
                    "true"
                  ]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Customer"
                },
                "example": {
                  "id": "cus_7Hc4Nf2Pq9Xz",
                  "external_id": "CUST-00412",
                  "name": "Sample Retail Co., Ltd.",
                  "name_local": "บริษัท ตัวอย่างค้าปลีก จำกัด",
                  "country": "TH",
                  "tax_id": "0999000000027",
                  "branch_no": "00000",
                  "address": "88 Example Road, Pathum Wan, Bangkok 10330",
                  "email": "accounts@sample-retail.example",
                  "phone": "+66 2 000 0000",
                  "notes": "Send statements to the accounts team.",
                  "created_at": "2026-10-15T09:12:44+07:00"
                }
              }
            }
          },
          "409": {
            "description": "A customer with this `tax_id` and `branch_no`, or this `external_id`, already exists.",
            "headers": {
              "Request-Id": {
                "description": "SLF's id for the request: an opaque string of up to 64 characters. Quote it when you contact SLF. A replayed response carries the id of the first request.",
                "schema": {
                  "type": "string",
                  "maxLength": 64
                }
              },
              "Idempotent-Replayed": {
                "description": "`true` when the response is the stored response of an earlier request with the same `Idempotency-Key`; nothing new was recorded.",
                "schema": {
                  "type": "string",
                  "enum": [
                    "true"
                  ]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "customer_exists",
                    "message": "A customer with tax ID 0999000000027, branch 00000 already exists.",
                    "param": "/tax_id",
                    "details": [],
                    "request_id": "req_7d1a4c8e2f6b9a35",
                    "existing_id": "cus_7Hc4Nf2Pq9Xz"
                  }
                }
              }
            }
          },
          "422": {
            "description": "One or more fields are invalid.",
            "headers": {
              "Request-Id": {
                "description": "SLF's id for the request: an opaque string of up to 64 characters. Quote it when you contact SLF. A replayed response carries the id of the first request.",
                "schema": {
                  "type": "string",
                  "maxLength": 64
                }
              },
              "Idempotent-Replayed": {
                "description": "`true` when the response is the stored response of an earlier request with the same `Idempotency-Key`; nothing new was recorded.",
                "schema": {
                  "type": "string",
                  "enum": [
                    "true"
                  ]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "validation_failed",
                    "message": "2 fields are invalid.",
                    "param": null,
                    "details": [
                      {
                        "param": "/tax_id",
                        "code": "invalid_tax_id",
                        "message": "The check digit does not match.",
                        "expected": null,
                        "received": null
                      },
                      {
                        "param": "/email",
                        "code": "invalid_format",
                        "message": "Not an email address.",
                        "expected": null,
                        "received": null
                      }
                    ],
                    "request_id": "req_3c9e1f7a2b5d8c04",
                    "existing_id": null
                  }
                }
              }
            }
          },
          "default": {
            "description": "Error. See the error codes in the reference.",
            "headers": {
              "Request-Id": {
                "description": "SLF's id for the request: an opaque string of up to 64 characters. Quote it when you contact SLF. A replayed response carries the id of the first request.",
                "schema": {
                  "type": "string",
                  "maxLength": 64
                }
              },
              "Idempotent-Replayed": {
                "description": "`true` when the response is the stored response of an earlier request with the same `Idempotency-Key`; nothing new was recorded.",
                "schema": {
                  "type": "string",
                  "enum": [
                    "true"
                  ]
                }
              },
              "Retry-After": {
                "description": "Seconds to wait before retrying.",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "get": {
        "operationId": "listCustomers",
        "tags": [
          "Customers"
        ],
        "summary": "List customers",
        "x-release": 1,
        "description": "Draft specification: not live yet. Returns your customers, newest first. Filter by tax ID and branch, or by your own `external_id`, to find a customer you may have created before.",
        "parameters": [
          {
            "name": "tax_id",
            "in": "query",
            "required": false,
            "description": "Only customers with this tax ID.",
            "schema": {
              "type": "string"
            },
            "example": "0999000000027"
          },
          {
            "name": "branch_no",
            "in": "query",
            "required": false,
            "description": "Only customers with this branch number. Use together with `tax_id`.",
            "schema": {
              "type": "string"
            },
            "example": "00000"
          },
          {
            "name": "external_id",
            "in": "query",
            "required": false,
            "description": "Only the customer with this `external_id`.",
            "schema": {
              "type": "string"
            },
            "example": "CUST-00412"
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Number of records per page: a whole number from 1 to 100. Default 25. For the refusals, see Pagination in [Conventions](https://slf-accounting.co/developers/reference#guide-conventions).",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 25
            },
            "example": 25
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "description": "The `next_cursor` value from the previous page, unchanged. Omit it for the first page; an empty value is refused. For the refusals, see Pagination in [Conventions](https://slf-accounting.co/developers/reference#guide-conventions).",
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 512
            },
            "example": "cur_8Tn3XqL5Vd"
          }
        ],
        "responses": {
          "200": {
            "description": "A page of customers.",
            "headers": {
              "Request-Id": {
                "description": "SLF's id for the request: an opaque string of up to 64 characters. Quote it when you contact SLF. A replayed response carries the id of the first request.",
                "schema": {
                  "type": "string",
                  "maxLength": 64
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Customer"
                      }
                    },
                    "next_cursor": {
                      "type": [
                        "string",
                        "null"
                      ]
                    }
                  },
                  "required": [
                    "data",
                    "next_cursor"
                  ]
                },
                "example": {
                  "data": [
                    {
                      "id": "cus_3Wd8Lm5Tb2Kr",
                      "external_id": "CUST-00977",
                      "name": "Example Imports Pte. Ltd.",
                      "name_local": null,
                      "country": "SG",
                      "tax_id": null,
                      "branch_no": null,
                      "address": "10 Example Street, Singapore 000000",
                      "email": "finance@example-imports.example",
                      "phone": null,
                      "notes": null,
                      "created_at": "2026-10-26T16:40:03+07:00"
                    },
                    {
                      "id": "cus_7Hc4Nf2Pq9Xz",
                      "external_id": "CUST-00412",
                      "name": "Sample Retail Co., Ltd.",
                      "name_local": "บริษัท ตัวอย่างค้าปลีก จำกัด",
                      "country": "TH",
                      "tax_id": "0999000000027",
                      "branch_no": "00000",
                      "address": "88 Example Road, Pathum Wan, Bangkok 10330",
                      "email": "accounts@sample-retail.example",
                      "phone": "+66 2 000 0000",
                      "notes": "Send statements to the accounts team.",
                      "created_at": "2026-10-15T09:12:44+07:00"
                    }
                  ],
                  "next_cursor": null
                }
              }
            }
          },
          "default": {
            "description": "Error. See the error codes in the reference.",
            "headers": {
              "Request-Id": {
                "description": "SLF's id for the request: an opaque string of up to 64 characters. Quote it when you contact SLF. A replayed response carries the id of the first request.",
                "schema": {
                  "type": "string",
                  "maxLength": 64
                }
              },
              "Retry-After": {
                "description": "Seconds to wait before retrying.",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/customers/{id}": {
      "get": {
        "operationId": "getCustomer",
        "tags": [
          "Customers"
        ],
        "summary": "Get a customer",
        "x-release": 1,
        "description": "Draft specification: not live yet. Returns one customer.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "The customer's id (`cus_`).",
            "schema": {
              "type": "string"
            },
            "example": "cus_…"
          }
        ],
        "responses": {
          "200": {
            "description": "The customer.",
            "headers": {
              "Request-Id": {
                "description": "SLF's id for the request: an opaque string of up to 64 characters. Quote it when you contact SLF. A replayed response carries the id of the first request.",
                "schema": {
                  "type": "string",
                  "maxLength": 64
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Customer"
                },
                "example": {
                  "id": "cus_7Hc4Nf2Pq9Xz",
                  "external_id": "CUST-00412",
                  "name": "Sample Retail Co., Ltd.",
                  "name_local": "บริษัท ตัวอย่างค้าปลีก จำกัด",
                  "country": "TH",
                  "tax_id": "0999000000027",
                  "branch_no": "00000",
                  "address": "88 Example Road, Pathum Wan, Bangkok 10330",
                  "email": "accounts@sample-retail.example",
                  "phone": "+66 2 000 0000",
                  "notes": "Send statements to the accounts team.",
                  "created_at": "2026-10-15T09:12:44+07:00"
                }
              }
            }
          },
          "default": {
            "description": "Error. See the error codes in the reference.",
            "headers": {
              "Request-Id": {
                "description": "SLF's id for the request: an opaque string of up to 64 characters. Quote it when you contact SLF. A replayed response carries the id of the first request.",
                "schema": {
                  "type": "string",
                  "maxLength": 64
                }
              },
              "Retry-After": {
                "description": "Seconds to wait before retrying.",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "patch": {
        "operationId": "updateCustomer",
        "tags": [
          "Customers"
        ],
        "summary": "Update a customer",
        "x-release": 1,
        "description": "Draft specification: not live yet. Changes a customer's `name`, `name_local`, `address`, `email`, `phone` or `notes`, and adds a `tax_id` and `branch_no` to a customer that has none. Send only the fields you change; `null` clears an optional field. `tax_id` and `branch_no` cannot change once set: sending a different value is refused with `immutable_field` (contact SLF if a tax ID was recorded wrongly). A `tax_id` and `branch_no` already used by another customer are refused with `customer_exists`. `country` and `external_id` cannot be changed, and other fields in the body are ignored. Documents already recorded keep the details printed on them.\n\nErrors specific to this endpoint: immutable_field, customer_exists.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "The customer's id (`cus_`).",
            "schema": {
              "type": "string"
            },
            "example": "cus_…"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CustomerUpdate"
              },
              "example": {
                "email": "ap@sample-retail.example",
                "phone": "+66 2 000 0001"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The updated customer.",
            "headers": {
              "Request-Id": {
                "description": "SLF's id for the request: an opaque string of up to 64 characters. Quote it when you contact SLF. A replayed response carries the id of the first request.",
                "schema": {
                  "type": "string",
                  "maxLength": 64
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Customer"
                },
                "example": {
                  "id": "cus_7Hc4Nf2Pq9Xz",
                  "external_id": "CUST-00412",
                  "name": "Sample Retail Co., Ltd.",
                  "name_local": "บริษัท ตัวอย่างค้าปลีก จำกัด",
                  "country": "TH",
                  "tax_id": "0999000000027",
                  "branch_no": "00000",
                  "address": "88 Example Road, Pathum Wan, Bangkok 10330",
                  "email": "ap@sample-retail.example",
                  "phone": "+66 2 000 0001",
                  "notes": "Send statements to the accounts team.",
                  "created_at": "2026-10-15T09:12:44+07:00"
                }
              }
            }
          },
          "409": {
            "description": "Another customer already has this `tax_id` and `branch_no`.",
            "headers": {
              "Request-Id": {
                "description": "SLF's id for the request: an opaque string of up to 64 characters. Quote it when you contact SLF. A replayed response carries the id of the first request.",
                "schema": {
                  "type": "string",
                  "maxLength": 64
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "customer_exists",
                    "message": "A customer with tax ID 0999000000027, branch 00000 already exists.",
                    "param": "/tax_id",
                    "details": [],
                    "request_id": "req_7d1a4c8e2f6b9a35",
                    "existing_id": "cus_7Hc4Nf2Pq9Xz"
                  }
                }
              }
            }
          },
          "422": {
            "description": "A field is invalid or cannot be changed.",
            "headers": {
              "Request-Id": {
                "description": "SLF's id for the request: an opaque string of up to 64 characters. Quote it when you contact SLF. A replayed response carries the id of the first request.",
                "schema": {
                  "type": "string",
                  "maxLength": 64
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "immutable_field",
                    "message": "tax_id cannot be changed once set.",
                    "param": "/tax_id",
                    "details": [],
                    "request_id": "req_0e5a2c8d4f7b1e93",
                    "existing_id": null
                  }
                }
              }
            }
          },
          "default": {
            "description": "Error. See the error codes in the reference.",
            "headers": {
              "Request-Id": {
                "description": "SLF's id for the request: an opaque string of up to 64 characters. Quote it when you contact SLF. A replayed response carries the id of the first request.",
                "schema": {
                  "type": "string",
                  "maxLength": 64
                }
              },
              "Retry-After": {
                "description": "Seconds to wait before retrying.",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/sales-documents": {
      "post": {
        "operationId": "createSalesDocument",
        "tags": [
          "Sales documents"
        ],
        "summary": "Record a sales document",
        "x-release": 1,
        "description": "Draft specification: not live yet. Records a sales document your system has already issued. Send it exactly as printed: your `number`, the `issue_date`, the lines and the totals. The API computes the line amounts and totals and refuses a difference beyond its tolerance (`totals_mismatch`); within it, the `vat_total` you printed is recorded (see [How the API checks totals](https://slf-accounting.co/developers/reference#guide-conventions)). A document whose VAT does not pass SLF's arithmetic check is recorded with the warning `vat_arithmetic_review`. Disbursement lines (`charge_role: disbursement`) are recorded as printed and never split; a line priced above its `pass_through_cost` is refused with `disbursement_marked_up`, unless your company is not VAT-registered or the document is not in THB. If your company is VAT-registered, a document in which no line carries VAT or says why it does not is refused with `vat_category_unexplained`. Credit and debit notes also need `original_document_ids`, `reason_code`, `reason_text`, `original_value` and `correct_value` (see [Corrections](https://slf-accounting.co/developers/reference#guide-corrections)); an original that is voided or belongs to another customer is refused with `validation_failed`. A `tax_invoice_receipt` is its own receipt and is recorded as paid. A document dated before your start date is refused with `validation_failed` (`out_of_range`), and so is a `tax_invoice` or `tax_invoice_receipt` dated after today or before the VAT registration date SLF has on record for your company. A tax invoice or cash sale that SLF already entered by hand is refused with `recorded_by_slf`, and one that repeats the VAT of a receipt with `tax_invoice_duplicates_receipt` (see [Idempotency and duplicates](https://slf-accounting.co/developers/reference#guide-idempotency)); a foreign-currency one may be refused with `fx_basis_unavailable` (see [Conventions](https://slf-accounting.co/developers/reference#guide-conventions)). Tax invoices, cash sales and adjustment notes dated in a month whose VAT return SLF has filed are refused with `period_filed` (see [Filed periods](https://slf-accounting.co/developers/reference#guide-filed-periods)). The example records an invoice with a disbursement line. Its withholding rates (3% on the service lines, none on the disbursement) are only example values, not rules; SLF reviews the rates.\n\nErrors specific to this endpoint: duplicate_external_id, duplicate_number, recorded_by_slf, reference_not_found, totals_mismatch, note_difference_mismatch, note_original_not_tax_invoice, note_exceeds_original, disbursement_vat_category, disbursement_marked_up, vat_category_unexplained, tax_invoice_duplicates_receipt, period_filed, period_closed, foreign_currency_tax_invoice_not_allowed, fx_basis_unavailable, fx_rate_required, account_code_unknown.",
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": true,
            "description": "Required on every POST. A unique value for this request, 1 to 255 visible ASCII characters; a UUID works well. Reuse it only to retry this exact request after a network error, a timeout, 429 or a 5xx. After any other 4xx, fix the request and send it with a new value. See [Idempotency and duplicates](https://slf-accounting.co/developers/reference#guide-idempotency).",
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 255,
              "pattern": "^[\\x21-\\x7E]+$"
            },
            "example": "5f0c2b8e-3d4a-4c1e-9b7f-2a6d8e1c0f93"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SalesDocument"
              },
              "example": {
                "type": "invoice",
                "external_id": "SO-2026-10-0187",
                "number": "INV-2026-0187",
                "issue_date": "2026-10-15",
                "due_date": "2026-11-14",
                "customer_id": "cus_7Hc4Nf2Pq9Xz",
                "currency": "THB",
                "bank_account_id": "bnk_5Qm2Rk8Lt3Vw",
                "remark": "Please pay by bank transfer within 30 days.",
                "reference": "PRJ-2026-031",
                "lines": [
                  {
                    "name": "Accounting system setup",
                    "description": "Chart of accounts, opening balances and user training",
                    "quantity": "1",
                    "unit_price": "12500.00",
                    "vat_category": "standard",
                    "wht_rate": "3",
                    "item_code": "SVC-SETUP",
                    "charge_role": "own_supply"
                  },
                  {
                    "name": "Monthly support",
                    "description": "October to December 2026",
                    "quantity": "3",
                    "unit_price": "2150.75",
                    "vat_category": "standard",
                    "wht_rate": "3",
                    "item_code": "SVC-SUPPORT",
                    "charge_role": "own_supply"
                  },
                  {
                    "name": "Government registration fee paid on your behalf",
                    "quantity": "1",
                    "unit_price": "1500.00",
                    "vat_category": "none",
                    "wht_rate": "0",
                    "charge_role": "disbursement",
                    "supplier_invoice_billed_to": "customer",
                    "pass_through_cost": "1500.00"
                  }
                ],
                "totals": {
                  "subtotal": "20452.25",
                  "vat_total": "1326.66",
                  "total": "21778.91",
                  "wht_total": "568.57",
                  "net_to_pay": "21210.34"
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "The document was recorded. Check `warnings`.",
            "headers": {
              "Request-Id": {
                "description": "SLF's id for the request: an opaque string of up to 64 characters. Quote it when you contact SLF. A replayed response carries the id of the first request.",
                "schema": {
                  "type": "string",
                  "maxLength": 64
                }
              },
              "Idempotent-Replayed": {
                "description": "`true` when the response is the stored response of an earlier request with the same `Idempotency-Key`; nothing new was recorded.",
                "schema": {
                  "type": "string",
                  "enum": [
                    "true"
                  ]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SalesDocument"
                },
                "example": {
                  "id": "doc_4Fp9Km2Qx7Ld",
                  "type": "invoice",
                  "external_id": "SO-2026-10-0187",
                  "number": "INV-2026-0187",
                  "issue_date": "2026-10-15",
                  "due_date": "2026-11-14",
                  "valid_until": null,
                  "customer_id": "cus_7Hc4Nf2Pq9Xz",
                  "bill_to_address": null,
                  "currency": "THB",
                  "fx_rate": null,
                  "fx_date": null,
                  "payment_terms": null,
                  "bank_account_id": "bnk_5Qm2Rk8Lt3Vw",
                  "remark": "Please pay by bank transfer within 30 days.",
                  "reference": "PRJ-2026-031",
                  "related_invoice_id": null,
                  "replaces_id": null,
                  "original_document_ids": null,
                  "reason_code": null,
                  "reason_text": null,
                  "original_value": null,
                  "correct_value": null,
                  "lines": [
                    {
                      "name": "Accounting system setup",
                      "description": "Chart of accounts, opening balances and user training",
                      "quantity": "1",
                      "unit_price": "12500.00",
                      "vat_category": "standard",
                      "wht_rate": "3",
                      "item_code": "SVC-SETUP",
                      "account_code": null,
                      "charge_role": "own_supply",
                      "supplier_invoice_billed_to": null,
                      "pass_through_cost": null,
                      "pre_vat_amount": "12500.00",
                      "vat_rate": "7",
                      "vat_amount": "875.00",
                      "wht_amount": "375.00"
                    },
                    {
                      "name": "Monthly support",
                      "description": "October to December 2026",
                      "quantity": "3",
                      "unit_price": "2150.75",
                      "vat_category": "standard",
                      "wht_rate": "3",
                      "item_code": "SVC-SUPPORT",
                      "account_code": null,
                      "charge_role": "own_supply",
                      "supplier_invoice_billed_to": null,
                      "pass_through_cost": null,
                      "pre_vat_amount": "6452.25",
                      "vat_rate": "7",
                      "vat_amount": "451.66",
                      "wht_amount": "193.57"
                    },
                    {
                      "name": "Government registration fee paid on your behalf",
                      "description": null,
                      "quantity": "1",
                      "unit_price": "1500.00",
                      "vat_category": "none",
                      "wht_rate": "0",
                      "item_code": null,
                      "account_code": null,
                      "charge_role": "disbursement",
                      "supplier_invoice_billed_to": "customer",
                      "pass_through_cost": "1500.00",
                      "pre_vat_amount": "1500.00",
                      "vat_rate": "0",
                      "vat_amount": "0.00",
                      "wht_amount": "0.00"
                    }
                  ],
                  "totals": {
                    "subtotal": "20452.25",
                    "vat_total": "1326.66",
                    "total": "21778.91",
                    "wht_total": "568.57",
                    "net_to_pay": "21210.34"
                  },
                  "attachments": [],
                  "status": "open",
                  "paid_amount": "0.00",
                  "credited_amount": "0.00",
                  "outstanding": "21778.91",
                  "voided_at": null,
                  "void_reason": null,
                  "replaced_by_id": null,
                  "warnings": [],
                  "created_at": "2026-10-15T14:02:11+07:00"
                }
              }
            }
          },
          "409": {
            "description": "A document with this `external_id` or this `number` already exists, or SLF already entered this tax invoice or cash sale by hand (`recorded_by_slf`).",
            "headers": {
              "Request-Id": {
                "description": "SLF's id for the request: an opaque string of up to 64 characters. Quote it when you contact SLF. A replayed response carries the id of the first request.",
                "schema": {
                  "type": "string",
                  "maxLength": 64
                }
              },
              "Idempotent-Replayed": {
                "description": "`true` when the response is the stored response of an earlier request with the same `Idempotency-Key`; nothing new was recorded.",
                "schema": {
                  "type": "string",
                  "enum": [
                    "true"
                  ]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "duplicate_number",
                    "message": "An invoice numbered INV-2026-0187 already exists.",
                    "param": "/number",
                    "details": [],
                    "request_id": "req_1e6c3a9d7b2f5c81",
                    "existing_id": "doc_4Fp9Km2Qx7Ld"
                  }
                }
              }
            }
          },
          "422": {
            "description": "The document is invalid, its totals do not match its lines, one of the rules above refuses it, or its month is filed or closed.",
            "headers": {
              "Request-Id": {
                "description": "SLF's id for the request: an opaque string of up to 64 characters. Quote it when you contact SLF. A replayed response carries the id of the first request.",
                "schema": {
                  "type": "string",
                  "maxLength": 64
                }
              },
              "Idempotent-Replayed": {
                "description": "`true` when the response is the stored response of an earlier request with the same `Idempotency-Key`; nothing new was recorded.",
                "schema": {
                  "type": "string",
                  "enum": [
                    "true"
                  ]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "totals_mismatch",
                    "message": "Totals do not match the lines.",
                    "param": "/totals",
                    "details": [
                      {
                        "param": "/totals/vat_total",
                        "code": "mismatch",
                        "message": "VAT total differs from the sum of line VAT.",
                        "expected": "1326.66",
                        "received": "1431.66"
                      },
                      {
                        "param": "/totals/total",
                        "code": "mismatch",
                        "message": "Total differs from subtotal plus VAT total.",
                        "expected": "21778.91",
                        "received": "21883.91"
                      }
                    ],
                    "request_id": "req_9a4f7c2e5d8b1a36",
                    "existing_id": null
                  }
                }
              }
            }
          },
          "default": {
            "description": "Error. See the error codes in the reference.",
            "headers": {
              "Request-Id": {
                "description": "SLF's id for the request: an opaque string of up to 64 characters. Quote it when you contact SLF. A replayed response carries the id of the first request.",
                "schema": {
                  "type": "string",
                  "maxLength": 64
                }
              },
              "Idempotent-Replayed": {
                "description": "`true` when the response is the stored response of an earlier request with the same `Idempotency-Key`; nothing new was recorded.",
                "schema": {
                  "type": "string",
                  "enum": [
                    "true"
                  ]
                }
              },
              "Retry-After": {
                "description": "Seconds to wait before retrying.",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "get": {
        "operationId": "listSalesDocuments",
        "tags": [
          "Sales documents"
        ],
        "summary": "List sales documents",
        "x-release": 1,
        "description": "Draft specification: not live yet. Returns your sales documents, newest first, with optional filters. Documents SLF entered itself are included, such as credit and debit notes; pro-forma documents SLF recorded are not.",
        "parameters": [
          {
            "name": "type",
            "in": "query",
            "required": false,
            "description": "Only documents of this type.",
            "schema": {
              "$ref": "#/components/schemas/sales_document_type"
            },
            "example": "tax_invoice"
          },
          {
            "name": "customer_id",
            "in": "query",
            "required": false,
            "description": "Only documents for this customer.",
            "schema": {
              "type": "string"
            },
            "example": "cus_7Hc4Nf2Pq9Xz"
          },
          {
            "name": "external_id",
            "in": "query",
            "required": false,
            "description": "Only the document with this `external_id`.",
            "schema": {
              "type": "string"
            },
            "example": "SO-2026-10-0412"
          },
          {
            "name": "number",
            "in": "query",
            "required": false,
            "description": "Only documents with this printed number.",
            "schema": {
              "type": "string"
            },
            "example": "TIV-2026-0412"
          },
          {
            "name": "reference",
            "in": "query",
            "required": false,
            "description": "Only documents with this `reference`.",
            "schema": {
              "type": "string"
            },
            "example": "PRJ-2026-031"
          },
          {
            "name": "status",
            "in": "query",
            "required": false,
            "description": "Only documents with this status, such as `open` to find what is still owed.",
            "schema": {
              "$ref": "#/components/schemas/sales_document_status"
            },
            "example": "open"
          },
          {
            "name": "issue_date_from",
            "in": "query",
            "required": false,
            "description": "Only documents issued on or after this date.",
            "schema": {
              "type": "string",
              "format": "date"
            },
            "example": "2026-10-01"
          },
          {
            "name": "issue_date_to",
            "in": "query",
            "required": false,
            "description": "Only documents issued on or before this date.",
            "schema": {
              "type": "string",
              "format": "date"
            },
            "example": "2026-10-31"
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Number of records per page: a whole number from 1 to 100. Default 25. For the refusals, see Pagination in [Conventions](https://slf-accounting.co/developers/reference#guide-conventions).",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 25
            },
            "example": 25
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "description": "The `next_cursor` value from the previous page, unchanged. Omit it for the first page; an empty value is refused. For the refusals, see Pagination in [Conventions](https://slf-accounting.co/developers/reference#guide-conventions).",
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 512
            },
            "example": "cur_8Tn3XqL5Vd"
          }
        ],
        "responses": {
          "200": {
            "description": "A page of sales documents. The example holds a foreign-currency invoice, a credit note and the tax invoice it adjusts, whose `outstanding` the credit note reduced.",
            "headers": {
              "Request-Id": {
                "description": "SLF's id for the request: an opaque string of up to 64 characters. Quote it when you contact SLF. A replayed response carries the id of the first request.",
                "schema": {
                  "type": "string",
                  "maxLength": 64
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/SalesDocument"
                      }
                    },
                    "next_cursor": {
                      "type": [
                        "string",
                        "null"
                      ]
                    }
                  },
                  "required": [
                    "data",
                    "next_cursor"
                  ]
                },
                "example": {
                  "data": [
                    {
                      "id": "doc_6Xn1Bq5Ty3Gv",
                      "type": "invoice",
                      "external_id": "SO-2026-10-0192",
                      "number": "INV-2026-0192",
                      "issue_date": "2026-10-27",
                      "due_date": "2026-11-26",
                      "valid_until": null,
                      "customer_id": "cus_3Wd8Lm5Tb2Kr",
                      "bill_to_address": null,
                      "currency": "USD",
                      "fx_rate": "32.4512",
                      "fx_date": "2026-10-27",
                      "payment_terms": "tt",
                      "bank_account_id": "bnk_9Ze3Lp6Qr2Dn",
                      "remark": null,
                      "reference": null,
                      "related_invoice_id": null,
                      "replaces_id": null,
                      "original_document_ids": null,
                      "reason_code": null,
                      "reason_text": null,
                      "original_value": null,
                      "correct_value": null,
                      "lines": [
                        {
                          "name": "Teak serving tray, large",
                          "description": null,
                          "quantity": "120",
                          "unit_price": "18.75",
                          "vat_category": "zero",
                          "wht_rate": "0",
                          "item_code": "TRAY-L",
                          "account_code": null,
                          "charge_role": null,
                          "supplier_invoice_billed_to": null,
                          "pass_through_cost": null,
                          "pre_vat_amount": "2250.00",
                          "vat_rate": "0",
                          "vat_amount": "0.00",
                          "wht_amount": "0.00"
                        },
                        {
                          "name": "Teak serving tray, small",
                          "description": null,
                          "quantity": "200",
                          "unit_price": "9.40",
                          "vat_category": "zero",
                          "wht_rate": "0",
                          "item_code": "TRAY-S",
                          "account_code": null,
                          "charge_role": null,
                          "supplier_invoice_billed_to": null,
                          "pass_through_cost": null,
                          "pre_vat_amount": "1880.00",
                          "vat_rate": "0",
                          "vat_amount": "0.00",
                          "wht_amount": "0.00"
                        }
                      ],
                      "totals": {
                        "subtotal": "4130.00",
                        "vat_total": "0.00",
                        "total": "4130.00",
                        "wht_total": null,
                        "net_to_pay": null
                      },
                      "attachments": [],
                      "status": "open",
                      "paid_amount": "0.00",
                      "credited_amount": "0.00",
                      "outstanding": "4130.00",
                      "voided_at": null,
                      "void_reason": null,
                      "replaced_by_id": null,
                      "warnings": [
                        {
                          "code": "zero_rated_review",
                          "message": "Line 1 uses the 0% rate. SLF will check that the conditions for it are met.",
                          "param": "/lines/0/vat_category"
                        },
                        {
                          "code": "zero_rated_review",
                          "message": "Line 2 uses the 0% rate. SLF will check that the conditions for it are met.",
                          "param": "/lines/1/vat_category"
                        }
                      ],
                      "created_at": "2026-10-27T15:20:48+07:00"
                    },
                    {
                      "id": "doc_2Lk7Pw4Mc8Jq",
                      "type": "credit_note",
                      "external_id": "SO-CN-2026-10-0031",
                      "number": "CN-2026-0031",
                      "issue_date": "2026-10-22",
                      "due_date": null,
                      "valid_until": null,
                      "customer_id": "cus_7Hc4Nf2Pq9Xz",
                      "bill_to_address": null,
                      "currency": "THB",
                      "fx_rate": null,
                      "fx_date": null,
                      "payment_terms": null,
                      "bank_account_id": null,
                      "remark": null,
                      "reference": null,
                      "related_invoice_id": null,
                      "replaces_id": null,
                      "original_document_ids": [
                        "doc_9Rt3Vb6Nz1Hs"
                      ],
                      "reason_code": "goods_returned",
                      "reason_text": "2 chairs returned: gas lift defective",
                      "original_value": "29168.00",
                      "correct_value": "24268.00",
                      "lines": [
                        {
                          "name": "Office chair, model A (returned)",
                          "description": null,
                          "quantity": "2",
                          "unit_price": "2450.00",
                          "vat_category": "standard",
                          "wht_rate": "0",
                          "item_code": "CH-A",
                          "account_code": null,
                          "charge_role": null,
                          "supplier_invoice_billed_to": null,
                          "pass_through_cost": null,
                          "pre_vat_amount": "4900.00",
                          "vat_rate": "7",
                          "vat_amount": "343.00",
                          "wht_amount": "0.00"
                        }
                      ],
                      "totals": {
                        "subtotal": "4900.00",
                        "vat_total": "343.00",
                        "total": "5243.00",
                        "wht_total": null,
                        "net_to_pay": null
                      },
                      "attachments": [],
                      "status": "open",
                      "paid_amount": "0.00",
                      "credited_amount": "0.00",
                      "outstanding": "0.00",
                      "voided_at": null,
                      "void_reason": null,
                      "replaced_by_id": null,
                      "warnings": [],
                      "created_at": "2026-10-22T10:31:09+07:00"
                    },
                    {
                      "id": "doc_9Rt3Vb6Nz1Hs",
                      "type": "tax_invoice",
                      "external_id": "SO-2026-10-0412",
                      "number": "TIV-2026-0412",
                      "issue_date": "2026-10-08",
                      "due_date": "2026-11-07",
                      "valid_until": null,
                      "customer_id": "cus_7Hc4Nf2Pq9Xz",
                      "bill_to_address": null,
                      "currency": "THB",
                      "fx_rate": null,
                      "fx_date": null,
                      "payment_terms": null,
                      "bank_account_id": "bnk_5Qm2Rk8Lt3Vw",
                      "remark": null,
                      "reference": null,
                      "related_invoice_id": null,
                      "replaces_id": null,
                      "original_document_ids": null,
                      "reason_code": null,
                      "reason_text": null,
                      "original_value": null,
                      "correct_value": null,
                      "lines": [
                        {
                          "name": "Office chair, model A",
                          "description": null,
                          "quantity": "10",
                          "unit_price": "2450.00",
                          "vat_category": "standard",
                          "wht_rate": "0",
                          "item_code": "CH-A",
                          "account_code": null,
                          "charge_role": null,
                          "supplier_invoice_billed_to": null,
                          "pass_through_cost": null,
                          "pre_vat_amount": "24500.00",
                          "vat_rate": "7",
                          "vat_amount": "1715.00",
                          "wht_amount": "0.00"
                        },
                        {
                          "name": "Desk lamp, LED",
                          "description": null,
                          "quantity": "12",
                          "unit_price": "389.00",
                          "vat_category": "standard",
                          "wht_rate": "0",
                          "item_code": "LAMP-LED",
                          "account_code": null,
                          "charge_role": null,
                          "supplier_invoice_billed_to": null,
                          "pass_through_cost": null,
                          "pre_vat_amount": "4668.00",
                          "vat_rate": "7",
                          "vat_amount": "326.76",
                          "wht_amount": "0.00"
                        }
                      ],
                      "totals": {
                        "subtotal": "29168.00",
                        "vat_total": "2041.76",
                        "total": "31209.76",
                        "wht_total": null,
                        "net_to_pay": null
                      },
                      "attachments": [
                        {
                          "id": "att_2Bh5Rx8Fk3Wq",
                          "object_type": "sales_document",
                          "object_id": "doc_9Rt3Vb6Nz1Hs",
                          "kind": "document_copy",
                          "file_name": "TIV-2026-0412.pdf",
                          "content_type": "application/pdf",
                          "size": 184233,
                          "sha256": "9f2b5c1e7a4d8f0c3b6e9a2d5c8f1b4e7a0d3c6f9b2e5a8d1c4f7b0e3a6d9c2f",
                          "created_at": "2026-10-08T11:05:37+07:00"
                        }
                      ],
                      "status": "open",
                      "paid_amount": "0.00",
                      "credited_amount": "5243.00",
                      "outstanding": "25966.76",
                      "voided_at": null,
                      "void_reason": null,
                      "replaced_by_id": null,
                      "warnings": [],
                      "created_at": "2026-10-08T11:04:52+07:00"
                    }
                  ],
                  "next_cursor": null
                }
              }
            }
          },
          "default": {
            "description": "Error. See the error codes in the reference.",
            "headers": {
              "Request-Id": {
                "description": "SLF's id for the request: an opaque string of up to 64 characters. Quote it when you contact SLF. A replayed response carries the id of the first request.",
                "schema": {
                  "type": "string",
                  "maxLength": 64
                }
              },
              "Retry-After": {
                "description": "Seconds to wait before retrying.",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/sales-documents/{id}": {
      "get": {
        "operationId": "getSalesDocument",
        "tags": [
          "Sales documents"
        ],
        "summary": "Get a sales document",
        "x-release": 1,
        "description": "Draft specification: not live yet. Returns one sales document, with its lines, totals, attachments, payment status and warnings. A pro-forma document SLF recorded answers 404 `not_found`.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "The sales document's id (`doc_`).",
            "schema": {
              "type": "string"
            },
            "example": "doc_…"
          }
        ],
        "responses": {
          "200": {
            "description": "The sales document.",
            "headers": {
              "Request-Id": {
                "description": "SLF's id for the request: an opaque string of up to 64 characters. Quote it when you contact SLF. A replayed response carries the id of the first request.",
                "schema": {
                  "type": "string",
                  "maxLength": 64
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SalesDocument"
                },
                "example": {
                  "id": "doc_9Rt3Vb6Nz1Hs",
                  "type": "tax_invoice",
                  "external_id": "SO-2026-10-0412",
                  "number": "TIV-2026-0412",
                  "issue_date": "2026-10-08",
                  "due_date": "2026-11-07",
                  "valid_until": null,
                  "customer_id": "cus_7Hc4Nf2Pq9Xz",
                  "bill_to_address": null,
                  "currency": "THB",
                  "fx_rate": null,
                  "fx_date": null,
                  "payment_terms": null,
                  "bank_account_id": "bnk_5Qm2Rk8Lt3Vw",
                  "remark": null,
                  "reference": null,
                  "related_invoice_id": null,
                  "replaces_id": null,
                  "original_document_ids": null,
                  "reason_code": null,
                  "reason_text": null,
                  "original_value": null,
                  "correct_value": null,
                  "lines": [
                    {
                      "name": "Office chair, model A",
                      "description": null,
                      "quantity": "10",
                      "unit_price": "2450.00",
                      "vat_category": "standard",
                      "wht_rate": "0",
                      "item_code": "CH-A",
                      "account_code": null,
                      "charge_role": null,
                      "supplier_invoice_billed_to": null,
                      "pass_through_cost": null,
                      "pre_vat_amount": "24500.00",
                      "vat_rate": "7",
                      "vat_amount": "1715.00",
                      "wht_amount": "0.00"
                    },
                    {
                      "name": "Desk lamp, LED",
                      "description": null,
                      "quantity": "12",
                      "unit_price": "389.00",
                      "vat_category": "standard",
                      "wht_rate": "0",
                      "item_code": "LAMP-LED",
                      "account_code": null,
                      "charge_role": null,
                      "supplier_invoice_billed_to": null,
                      "pass_through_cost": null,
                      "pre_vat_amount": "4668.00",
                      "vat_rate": "7",
                      "vat_amount": "326.76",
                      "wht_amount": "0.00"
                    }
                  ],
                  "totals": {
                    "subtotal": "29168.00",
                    "vat_total": "2041.76",
                    "total": "31209.76",
                    "wht_total": null,
                    "net_to_pay": null
                  },
                  "attachments": [
                    {
                      "id": "att_2Bh5Rx8Fk3Wq",
                      "object_type": "sales_document",
                      "object_id": "doc_9Rt3Vb6Nz1Hs",
                      "kind": "document_copy",
                      "file_name": "TIV-2026-0412.pdf",
                      "content_type": "application/pdf",
                      "size": 184233,
                      "sha256": "9f2b5c1e7a4d8f0c3b6e9a2d5c8f1b4e7a0d3c6f9b2e5a8d1c4f7b0e3a6d9c2f",
                      "created_at": "2026-10-08T11:05:37+07:00"
                    }
                  ],
                  "status": "open",
                  "paid_amount": "0.00",
                  "credited_amount": "5243.00",
                  "outstanding": "25966.76",
                  "voided_at": null,
                  "void_reason": null,
                  "replaced_by_id": null,
                  "warnings": [],
                  "created_at": "2026-10-08T11:04:52+07:00"
                }
              }
            }
          },
          "default": {
            "description": "Error. See the error codes in the reference.",
            "headers": {
              "Request-Id": {
                "description": "SLF's id for the request: an opaque string of up to 64 characters. Quote it when you contact SLF. A replayed response carries the id of the first request.",
                "schema": {
                  "type": "string",
                  "maxLength": 64
                }
              },
              "Retry-After": {
                "description": "Seconds to wait before retrying.",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/sales-documents/{id}/void": {
      "post": {
        "operationId": "voidSalesDocument",
        "tags": [
          "Sales documents"
        ],
        "summary": "Void a sales document",
        "x-release": 1,
        "description": "Draft specification: not live yet. Voids a sales document. For a `quotation` or `invoice`, this records your cancellation. To cancel and reissue a `tax_invoice` or `tax_invoice_receipt`, first record the replacement (new `number`, `issue_date` equal to the original's, `replaces_id` set to the original), then void the original with `replacement_id`; see [Corrections](https://slf-accounting.co/developers/reference#guide-corrections) for the Revenue Department procedure. Credit and debit notes cannot be voided through the API (`note_cannot_be_voided`). A voided document keeps its number and is returned with `status: void`. Voiding a tax invoice, cash sale or note dated in a filed month is refused with `period_filed`, and one dated in a closed period with `period_closed`. A document cannot be voided while receipts recorded against it are not voided (void them first), while a credit or debit note is recorded against it, or once SLF has posted it to your books (`void_not_allowed`).\n\nErrors specific to this endpoint: already_voided, void_not_allowed, note_cannot_be_voided, reference_not_found, period_filed, period_closed.",
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": true,
            "description": "Required on every POST. A unique value for this request, 1 to 255 visible ASCII characters; a UUID works well. Reuse it only to retry this exact request after a network error, a timeout, 429 or a 5xx. After any other 4xx, fix the request and send it with a new value. See [Idempotency and duplicates](https://slf-accounting.co/developers/reference#guide-idempotency).",
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 255,
              "pattern": "^[\\x21-\\x7E]+$"
            },
            "example": "5f0c2b8e-3d4a-4c1e-9b7f-2a6d8e1c0f93"
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "The sales document's id (`doc_`).",
            "schema": {
              "type": "string"
            },
            "example": "doc_…"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SalesDocumentVoidRequest"
              },
              "example": {
                "reason": "Buyer's address was wrong. Replaced by TIV-2026-0415.",
                "replacement_id": "doc_8Jd2Sv6Wm4Pa"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The voided document.",
            "headers": {
              "Request-Id": {
                "description": "SLF's id for the request: an opaque string of up to 64 characters. Quote it when you contact SLF. A replayed response carries the id of the first request.",
                "schema": {
                  "type": "string",
                  "maxLength": 64
                }
              },
              "Idempotent-Replayed": {
                "description": "`true` when the response is the stored response of an earlier request with the same `Idempotency-Key`; nothing new was recorded.",
                "schema": {
                  "type": "string",
                  "enum": [
                    "true"
                  ]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SalesDocument"
                },
                "example": {
                  "id": "doc_1Gh6Tc9Rw2Ne",
                  "type": "tax_invoice",
                  "external_id": "SO-2026-10-0398",
                  "number": "TIV-2026-0398",
                  "issue_date": "2026-10-05",
                  "due_date": null,
                  "valid_until": null,
                  "customer_id": "cus_7Hc4Nf2Pq9Xz",
                  "bill_to_address": "8 Example Road, Pathum Wan, Bangkok 10330",
                  "currency": "THB",
                  "fx_rate": null,
                  "fx_date": null,
                  "payment_terms": null,
                  "bank_account_id": null,
                  "remark": null,
                  "reference": null,
                  "related_invoice_id": null,
                  "replaces_id": null,
                  "original_document_ids": null,
                  "reason_code": null,
                  "reason_text": null,
                  "original_value": null,
                  "correct_value": null,
                  "lines": [
                    {
                      "name": "Bookkeeping software licence, 12 months",
                      "description": null,
                      "quantity": "1",
                      "unit_price": "18000.00",
                      "vat_category": "standard",
                      "wht_rate": "0",
                      "item_code": "LIC-12M",
                      "account_code": null,
                      "charge_role": null,
                      "supplier_invoice_billed_to": null,
                      "pass_through_cost": null,
                      "pre_vat_amount": "18000.00",
                      "vat_rate": "7",
                      "vat_amount": "1260.00",
                      "wht_amount": "0.00"
                    }
                  ],
                  "totals": {
                    "subtotal": "18000.00",
                    "vat_total": "1260.00",
                    "total": "19260.00",
                    "wht_total": null,
                    "net_to_pay": null
                  },
                  "attachments": [],
                  "status": "void",
                  "paid_amount": "0.00",
                  "credited_amount": "0.00",
                  "outstanding": "0.00",
                  "voided_at": "2026-10-29T13:47:20+07:00",
                  "void_reason": "Buyer's address was wrong. Replaced by TIV-2026-0415.",
                  "replaced_by_id": "doc_8Jd2Sv6Wm4Pa",
                  "warnings": [],
                  "created_at": "2026-10-05T10:15:02+07:00"
                }
              }
            }
          },
          "409": {
            "description": "The document is already voided (`already_voided`), or it cannot be voided now (`void_not_allowed`).",
            "headers": {
              "Request-Id": {
                "description": "SLF's id for the request: an opaque string of up to 64 characters. Quote it when you contact SLF. A replayed response carries the id of the first request.",
                "schema": {
                  "type": "string",
                  "maxLength": 64
                }
              },
              "Idempotent-Replayed": {
                "description": "`true` when the response is the stored response of an earlier request with the same `Idempotency-Key`; nothing new was recorded.",
                "schema": {
                  "type": "string",
                  "enum": [
                    "true"
                  ]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "void_not_allowed",
                    "message": "Receipt RE-2026-0233 is recorded against this invoice. Void the receipt first.",
                    "param": null,
                    "details": [],
                    "request_id": "req_8d4f2b7e1a6c9d53",
                    "existing_id": null
                  }
                }
              }
            }
          },
          "422": {
            "description": "The document cannot be voided through the API, or its month is filed or closed.",
            "headers": {
              "Request-Id": {
                "description": "SLF's id for the request: an opaque string of up to 64 characters. Quote it when you contact SLF. A replayed response carries the id of the first request.",
                "schema": {
                  "type": "string",
                  "maxLength": 64
                }
              },
              "Idempotent-Replayed": {
                "description": "`true` when the response is the stored response of an earlier request with the same `Idempotency-Key`; nothing new was recorded.",
                "schema": {
                  "type": "string",
                  "enum": [
                    "true"
                  ]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "period_filed",
                    "message": "This tax invoice is dated in 2026-09, whose VAT return SLF has already filed. Contact SLF.",
                    "param": null,
                    "details": [],
                    "request_id": "req_3e8b1d6a9c2f5e47",
                    "existing_id": null
                  }
                }
              }
            }
          },
          "default": {
            "description": "Error. See the error codes in the reference.",
            "headers": {
              "Request-Id": {
                "description": "SLF's id for the request: an opaque string of up to 64 characters. Quote it when you contact SLF. A replayed response carries the id of the first request.",
                "schema": {
                  "type": "string",
                  "maxLength": 64
                }
              },
              "Idempotent-Replayed": {
                "description": "`true` when the response is the stored response of an earlier request with the same `Idempotency-Key`; nothing new was recorded.",
                "schema": {
                  "type": "string",
                  "enum": [
                    "true"
                  ]
                }
              },
              "Retry-After": {
                "description": "Seconds to wait before retrying.",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/receipts": {
      "post": {
        "operationId": "createReceipt",
        "tags": [
          "Receipts"
        ],
        "summary": "Record a receipt",
        "x-release": 1,
        "description": "Draft specification: not live yet. Records a payment received against an `invoice`, `tax_invoice` or `debit_note`. `amount_received` is the money that arrived; `wht_amount` is the tax the customer withheld. Their sum, `gross_amount`, reduces the document's `outstanding` and may not exceed it (`receipt_exceeds_outstanding`). `wht_amount` may not exceed the withholding still expected from the document lines' `wht_rate` (`wht_exceeds_expected`); if it implies a different rate, the receipt is recorded with the warning `wht_rate_review`. A quotation, a `tax_invoice_receipt` (it is its own receipt), a credit note or a voided document cannot be receipted (`receipt_not_allowed`). The receipt takes the document's currency and exchange rate. A receipt that books VAT is checked against the month of its `payment_date` (`period_filed`), and any receipt dated in a closed period is refused (`period_closed`). A `payment_date` after today or before your start date is refused with `validation_failed` (`out_of_range`). Your receipt `number` must be unique among your receipts that are not voided (`duplicate_number`). A receipt for less than the document still owes is recorded with the warning `short_payment`, and your `remark` is stored unchanged. If SLF had entered by hand the VAT of the document being paid (an entry with its `number` and total), a receipt that books VAT depends on that entry's month. In a month whose VAT return SLF has filed, the receipt is recorded with the warning `recorded_by_slf_filed`, whether or not the entry is posted. In a month not yet filed, the receipt takes the entry's place, unless SLF has posted the entry to your books: then the receipt is refused with 409 `recorded_by_slf_posted`. A receipt that books VAT for a customer who has a `tax_invoice` that is not voided, of the same amount, without `related_invoice_id`, dated in the month of the receipt's `payment_date`, is recorded with the warning `possible_double_vat`.\n\nErrors specific to this endpoint: duplicate_external_id, duplicate_number, recorded_by_slf_posted, reference_not_found, receipt_not_allowed, receipt_exceeds_outstanding, wht_exceeds_expected, period_filed, period_closed.",
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": true,
            "description": "Required on every POST. A unique value for this request, 1 to 255 visible ASCII characters; a UUID works well. Reuse it only to retry this exact request after a network error, a timeout, 429 or a 5xx. After any other 4xx, fix the request and send it with a new value. See [Idempotency and duplicates](https://slf-accounting.co/developers/reference#guide-idempotency).",
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 255,
              "pattern": "^[\\x21-\\x7E]+$"
            },
            "example": "5f0c2b8e-3d4a-4c1e-9b7f-2a6d8e1c0f93"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/Receipt"
              },
              "example": {
                "external_id": "RCV-2026-10-0233",
                "number": "RE-2026-0233",
                "document_id": "doc_4Fp9Km2Qx7Ld",
                "payment_date": "2026-10-30",
                "amount_received": "21210.34",
                "wht_amount": "568.57",
                "bank_account_id": "bnk_5Qm2Rk8Lt3Vw",
                "remark": "Customer withheld 3% on the service lines; 50 ทวิ certificate received."
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "The receipt was recorded. Check `warnings`.",
            "headers": {
              "Request-Id": {
                "description": "SLF's id for the request: an opaque string of up to 64 characters. Quote it when you contact SLF. A replayed response carries the id of the first request.",
                "schema": {
                  "type": "string",
                  "maxLength": 64
                }
              },
              "Idempotent-Replayed": {
                "description": "`true` when the response is the stored response of an earlier request with the same `Idempotency-Key`; nothing new was recorded.",
                "schema": {
                  "type": "string",
                  "enum": [
                    "true"
                  ]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Receipt"
                },
                "example": {
                  "id": "rcp_3Np8Gz5Kd1Vt",
                  "external_id": "RCV-2026-10-0233",
                  "number": "RE-2026-0233",
                  "document_id": "doc_4Fp9Km2Qx7Ld",
                  "payment_date": "2026-10-30",
                  "amount_received": "21210.34",
                  "wht_amount": "568.57",
                  "bank_account_id": "bnk_5Qm2Rk8Lt3Vw",
                  "remark": "Customer withheld 3% on the service lines; 50 ทวิ certificate received.",
                  "gross_amount": "21778.91",
                  "vat_amount": "1326.66",
                  "currency": "THB",
                  "fx_rate": null,
                  "attachments": [],
                  "warnings": [],
                  "voided_at": null,
                  "void_reason": null,
                  "created_at": "2026-10-30T17:08:26+07:00"
                }
              }
            }
          },
          "409": {
            "description": "A receipt with this `external_id` or `number` already exists, or SLF has posted its own hand entry for this document's VAT in a month it has not filed (`recorded_by_slf_posted`).",
            "headers": {
              "Request-Id": {
                "description": "SLF's id for the request: an opaque string of up to 64 characters. Quote it when you contact SLF. A replayed response carries the id of the first request.",
                "schema": {
                  "type": "string",
                  "maxLength": 64
                }
              },
              "Idempotent-Replayed": {
                "description": "`true` when the response is the stored response of an earlier request with the same `Idempotency-Key`; nothing new was recorded.",
                "schema": {
                  "type": "string",
                  "enum": [
                    "true"
                  ]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "duplicate_external_id",
                    "message": "A receipt with external_id RCV-2026-10-0233 already exists.",
                    "param": "/external_id",
                    "details": [],
                    "request_id": "req_7a3e9c1d5b8f2a64",
                    "existing_id": "rcp_3Np8Gz5Kd1Vt"
                  }
                }
              }
            }
          },
          "422": {
            "description": "The receipt is invalid or not allowed for this document.",
            "headers": {
              "Request-Id": {
                "description": "SLF's id for the request: an opaque string of up to 64 characters. Quote it when you contact SLF. A replayed response carries the id of the first request.",
                "schema": {
                  "type": "string",
                  "maxLength": 64
                }
              },
              "Idempotent-Replayed": {
                "description": "`true` when the response is the stored response of an earlier request with the same `Idempotency-Key`; nothing new was recorded.",
                "schema": {
                  "type": "string",
                  "enum": [
                    "true"
                  ]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "receipt_exceeds_outstanding",
                    "message": "amount_received plus wht_amount (21778.91) is more than the outstanding 10000.00.",
                    "param": "/amount_received",
                    "details": [],
                    "request_id": "req_2d7a5c9f3e1b8d42",
                    "existing_id": null
                  }
                }
              }
            }
          },
          "default": {
            "description": "Error. See the error codes in the reference.",
            "headers": {
              "Request-Id": {
                "description": "SLF's id for the request: an opaque string of up to 64 characters. Quote it when you contact SLF. A replayed response carries the id of the first request.",
                "schema": {
                  "type": "string",
                  "maxLength": 64
                }
              },
              "Idempotent-Replayed": {
                "description": "`true` when the response is the stored response of an earlier request with the same `Idempotency-Key`; nothing new was recorded.",
                "schema": {
                  "type": "string",
                  "enum": [
                    "true"
                  ]
                }
              },
              "Retry-After": {
                "description": "Seconds to wait before retrying.",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "get": {
        "operationId": "listReceipts",
        "tags": [
          "Receipts"
        ],
        "summary": "List receipts",
        "x-release": 1,
        "description": "Draft specification: not live yet. Returns your receipts, newest first.",
        "parameters": [
          {
            "name": "document_id",
            "in": "query",
            "required": false,
            "description": "Only receipts against this sales document.",
            "schema": {
              "type": "string"
            },
            "example": "doc_4Fp9Km2Qx7Ld"
          },
          {
            "name": "external_id",
            "in": "query",
            "required": false,
            "description": "Only the receipt with this `external_id`.",
            "schema": {
              "type": "string"
            },
            "example": "RCV-2026-10-0233"
          },
          {
            "name": "payment_date_from",
            "in": "query",
            "required": false,
            "description": "Only receipts with a `payment_date` on or after this date.",
            "schema": {
              "type": "string",
              "format": "date"
            },
            "example": "2026-10-01"
          },
          {
            "name": "payment_date_to",
            "in": "query",
            "required": false,
            "description": "Only receipts with a `payment_date` on or before this date.",
            "schema": {
              "type": "string",
              "format": "date"
            },
            "example": "2026-10-31"
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Number of records per page: a whole number from 1 to 100. Default 25. For the refusals, see Pagination in [Conventions](https://slf-accounting.co/developers/reference#guide-conventions).",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 25
            },
            "example": 25
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "description": "The `next_cursor` value from the previous page, unchanged. Omit it for the first page; an empty value is refused. For the refusals, see Pagination in [Conventions](https://slf-accounting.co/developers/reference#guide-conventions).",
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 512
            },
            "example": "cur_8Tn3XqL5Vd"
          }
        ],
        "responses": {
          "200": {
            "description": "A page of receipts.",
            "headers": {
              "Request-Id": {
                "description": "SLF's id for the request: an opaque string of up to 64 characters. Quote it when you contact SLF. A replayed response carries the id of the first request.",
                "schema": {
                  "type": "string",
                  "maxLength": 64
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Receipt"
                      }
                    },
                    "next_cursor": {
                      "type": [
                        "string",
                        "null"
                      ]
                    }
                  },
                  "required": [
                    "data",
                    "next_cursor"
                  ]
                },
                "example": {
                  "data": [
                    {
                      "id": "rcp_3Np8Gz5Kd1Vt",
                      "external_id": "RCV-2026-10-0233",
                      "number": "RE-2026-0233",
                      "document_id": "doc_4Fp9Km2Qx7Ld",
                      "payment_date": "2026-10-30",
                      "amount_received": "21210.34",
                      "wht_amount": "568.57",
                      "bank_account_id": "bnk_5Qm2Rk8Lt3Vw",
                      "remark": "Customer withheld 3% on the service lines; 50 ทวิ certificate received.",
                      "gross_amount": "21778.91",
                      "vat_amount": "1326.66",
                      "currency": "THB",
                      "fx_rate": null,
                      "attachments": [],
                      "warnings": [],
                      "voided_at": null,
                      "void_reason": null,
                      "created_at": "2026-10-30T17:08:26+07:00"
                    }
                  ],
                  "next_cursor": null
                }
              }
            }
          },
          "default": {
            "description": "Error. See the error codes in the reference.",
            "headers": {
              "Request-Id": {
                "description": "SLF's id for the request: an opaque string of up to 64 characters. Quote it when you contact SLF. A replayed response carries the id of the first request.",
                "schema": {
                  "type": "string",
                  "maxLength": 64
                }
              },
              "Retry-After": {
                "description": "Seconds to wait before retrying.",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/receipts/{id}": {
      "get": {
        "operationId": "getReceipt",
        "tags": [
          "Receipts"
        ],
        "summary": "Get a receipt",
        "x-release": 1,
        "description": "Draft specification: not live yet. Returns one receipt.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "The receipt's id (`rcp_`).",
            "schema": {
              "type": "string"
            },
            "example": "rcp_…"
          }
        ],
        "responses": {
          "200": {
            "description": "The receipt.",
            "headers": {
              "Request-Id": {
                "description": "SLF's id for the request: an opaque string of up to 64 characters. Quote it when you contact SLF. A replayed response carries the id of the first request.",
                "schema": {
                  "type": "string",
                  "maxLength": 64
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Receipt"
                },
                "example": {
                  "id": "rcp_3Np8Gz5Kd1Vt",
                  "external_id": "RCV-2026-10-0233",
                  "number": "RE-2026-0233",
                  "document_id": "doc_4Fp9Km2Qx7Ld",
                  "payment_date": "2026-10-30",
                  "amount_received": "21210.34",
                  "wht_amount": "568.57",
                  "bank_account_id": "bnk_5Qm2Rk8Lt3Vw",
                  "remark": "Customer withheld 3% on the service lines; 50 ทวิ certificate received.",
                  "gross_amount": "21778.91",
                  "vat_amount": "1326.66",
                  "currency": "THB",
                  "fx_rate": null,
                  "attachments": [],
                  "warnings": [],
                  "voided_at": null,
                  "void_reason": null,
                  "created_at": "2026-10-30T17:08:26+07:00"
                }
              }
            }
          },
          "default": {
            "description": "Error. See the error codes in the reference.",
            "headers": {
              "Request-Id": {
                "description": "SLF's id for the request: an opaque string of up to 64 characters. Quote it when you contact SLF. A replayed response carries the id of the first request.",
                "schema": {
                  "type": "string",
                  "maxLength": 64
                }
              },
              "Retry-After": {
                "description": "Seconds to wait before retrying.",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/receipts/{id}/void": {
      "post": {
        "operationId": "voidReceipt",
        "tags": [
          "Receipts"
        ],
        "summary": "Void a receipt",
        "x-release": 1,
        "description": "Draft specification: not live yet. Voids a receipt recorded by mistake. The document's `outstanding` goes back up by the receipt's `gross_amount`. A receipt that booked VAT cannot be voided once its month is filed (`period_filed`), and no receipt can be voided once its `payment_date` falls in a closed period (`period_closed`). It is also refused with `void_not_allowed` once SLF has posted it to your books, while a credit or debit note is recorded against it or a credit note depends on it, and while a `tax_invoice` with `related_invoice_id` stands on its invoice. If the receipt took the place of a VAT entry SLF had made by hand, voiding it restores that entry.\n\nErrors specific to this endpoint: already_voided, void_not_allowed, period_filed, period_closed.",
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": true,
            "description": "Required on every POST. A unique value for this request, 1 to 255 visible ASCII characters; a UUID works well. Reuse it only to retry this exact request after a network error, a timeout, 429 or a 5xx. After any other 4xx, fix the request and send it with a new value. See [Idempotency and duplicates](https://slf-accounting.co/developers/reference#guide-idempotency).",
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 255,
              "pattern": "^[\\x21-\\x7E]+$"
            },
            "example": "5f0c2b8e-3d4a-4c1e-9b7f-2a6d8e1c0f93"
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "The receipt's id (`rcp_`).",
            "schema": {
              "type": "string"
            },
            "example": "rcp_…"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/VoidRequest"
              },
              "example": {
                "reason": "Recorded against the wrong invoice."
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The voided receipt.",
            "headers": {
              "Request-Id": {
                "description": "SLF's id for the request: an opaque string of up to 64 characters. Quote it when you contact SLF. A replayed response carries the id of the first request.",
                "schema": {
                  "type": "string",
                  "maxLength": 64
                }
              },
              "Idempotent-Replayed": {
                "description": "`true` when the response is the stored response of an earlier request with the same `Idempotency-Key`; nothing new was recorded.",
                "schema": {
                  "type": "string",
                  "enum": [
                    "true"
                  ]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Receipt"
                },
                "example": {
                  "id": "rcp_3Np8Gz5Kd1Vt",
                  "external_id": "RCV-2026-10-0233",
                  "number": "RE-2026-0233",
                  "document_id": "doc_4Fp9Km2Qx7Ld",
                  "payment_date": "2026-10-30",
                  "amount_received": "21210.34",
                  "wht_amount": "568.57",
                  "bank_account_id": "bnk_5Qm2Rk8Lt3Vw",
                  "remark": "Customer withheld 3% on the service lines; 50 ทวิ certificate received.",
                  "gross_amount": "21778.91",
                  "vat_amount": "1326.66",
                  "currency": "THB",
                  "fx_rate": null,
                  "attachments": [],
                  "warnings": [],
                  "voided_at": "2026-10-31T09:03:12+07:00",
                  "void_reason": "Recorded against the wrong invoice.",
                  "created_at": "2026-10-30T17:08:26+07:00"
                }
              }
            }
          },
          "409": {
            "description": "The receipt is already voided (`already_voided`), or it cannot be voided now (`void_not_allowed`).",
            "headers": {
              "Request-Id": {
                "description": "SLF's id for the request: an opaque string of up to 64 characters. Quote it when you contact SLF. A replayed response carries the id of the first request.",
                "schema": {
                  "type": "string",
                  "maxLength": 64
                }
              },
              "Idempotent-Replayed": {
                "description": "`true` when the response is the stored response of an earlier request with the same `Idempotency-Key`; nothing new was recorded.",
                "schema": {
                  "type": "string",
                  "enum": [
                    "true"
                  ]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "already_voided",
                    "message": "This record is already voided.",
                    "param": null,
                    "details": [],
                    "request_id": "req_5c9a1e7d3b6f2a48",
                    "existing_id": null
                  }
                }
              }
            }
          },
          "422": {
            "description": "The receipt is dated in a filed month or a closed period.",
            "headers": {
              "Request-Id": {
                "description": "SLF's id for the request: an opaque string of up to 64 characters. Quote it when you contact SLF. A replayed response carries the id of the first request.",
                "schema": {
                  "type": "string",
                  "maxLength": 64
                }
              },
              "Idempotent-Replayed": {
                "description": "`true` when the response is the stored response of an earlier request with the same `Idempotency-Key`; nothing new was recorded.",
                "schema": {
                  "type": "string",
                  "enum": [
                    "true"
                  ]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "period_filed",
                    "message": "This receipt booked VAT in a month whose VAT return SLF has already filed. Contact SLF.",
                    "param": null,
                    "details": [],
                    "request_id": "req_9b2e6c4a8d1f3e75",
                    "existing_id": null
                  }
                }
              }
            }
          },
          "default": {
            "description": "Error. See the error codes in the reference.",
            "headers": {
              "Request-Id": {
                "description": "SLF's id for the request: an opaque string of up to 64 characters. Quote it when you contact SLF. A replayed response carries the id of the first request.",
                "schema": {
                  "type": "string",
                  "maxLength": 64
                }
              },
              "Idempotent-Replayed": {
                "description": "`true` when the response is the stored response of an earlier request with the same `Idempotency-Key`; nothing new was recorded.",
                "schema": {
                  "type": "string",
                  "enum": [
                    "true"
                  ]
                }
              },
              "Retry-After": {
                "description": "Seconds to wait before retrying.",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/bills": {
      "post": {
        "operationId": "createBill",
        "tags": [
          "Supplier bills"
        ],
        "summary": "Record a supplier bill",
        "x-release": 2,
        "description": "Draft specification: not live yet. Second release (see [Two releases](https://slf-accounting.co/developers/reference#guide-overview)): once the first release is live, this path answers 404 `not_found` until the second opens. Records a document you received from a supplier. Amounts are typed from the printed document and are not recomputed; the API only checks that `total` equals `subtotal` plus `vat_amount` (`totals_mismatch`). Lines are optional and help SLF classify the cost; their amounts are not added up against the header. A second bill with the same supplier `tax_id` (or, for a supplier without one, the same supplier `name`) and `bill_number` is refused with 409 `duplicate_bill`. If the bill is a cost you paid on a customer's behalf and is addressed to that customer, set `on_behalf_of_customer_id`.\n\nErrors specific to this endpoint: duplicate_external_id, duplicate_bill, reference_not_found, totals_mismatch, fx_rate_required, account_code_unknown.",
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": true,
            "description": "Required on every POST. A unique value for this request, 1 to 255 visible ASCII characters; a UUID works well. Reuse it only to retry this exact request after a network error, a timeout, 429 or a 5xx. After any other 4xx, fix the request and send it with a new value. See [Idempotency and duplicates](https://slf-accounting.co/developers/reference#guide-idempotency).",
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 255,
              "pattern": "^[\\x21-\\x7E]+$"
            },
            "example": "5f0c2b8e-3d4a-4c1e-9b7f-2a6d8e1c0f93"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/Bill"
              },
              "example": {
                "external_id": "AP-2026-10-0058",
                "document_type": "tax_invoice",
                "supplier": {
                  "name": "Demo Services Co., Ltd.",
                  "tax_id": "0999000000035",
                  "branch_no": "00000",
                  "country": "TH"
                },
                "bill_number": "DS-2610-0058",
                "bill_date": "2026-10-25",
                "due_date": "2026-11-24",
                "currency": "THB",
                "subtotal": "15000.00",
                "vat_amount": "1050.00",
                "total": "16050.00",
                "lines": [
                  {
                    "description": "IT support, October 2026",
                    "quantity": "1",
                    "unit_price": "15000.00",
                    "amount": "15000.00",
                    "item_code": "DS-ITS-01"
                  }
                ],
                "remark": "Monthly IT support contract",
                "reference": null
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "The bill was recorded.",
            "headers": {
              "Request-Id": {
                "description": "SLF's id for the request: an opaque string of up to 64 characters. Quote it when you contact SLF. A replayed response carries the id of the first request.",
                "schema": {
                  "type": "string",
                  "maxLength": 64
                }
              },
              "Idempotent-Replayed": {
                "description": "`true` when the response is the stored response of an earlier request with the same `Idempotency-Key`; nothing new was recorded.",
                "schema": {
                  "type": "string",
                  "enum": [
                    "true"
                  ]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Bill"
                },
                "example": {
                  "id": "bil_5Tg9Hw2Lr6Mx",
                  "external_id": "AP-2026-10-0058",
                  "document_type": "tax_invoice",
                  "supplier": {
                    "name": "Demo Services Co., Ltd.",
                    "tax_id": "0999000000035",
                    "branch_no": "00000",
                    "country": "TH"
                  },
                  "bill_number": "DS-2610-0058",
                  "bill_date": "2026-10-25",
                  "due_date": "2026-11-24",
                  "currency": "THB",
                  "fx_rate": null,
                  "fx_date": null,
                  "subtotal": "15000.00",
                  "vat_amount": "1050.00",
                  "total": "16050.00",
                  "lines": [
                    {
                      "description": "IT support, October 2026",
                      "quantity": "1",
                      "unit_price": "15000.00",
                      "amount": "15000.00",
                      "item_code": "DS-ITS-01",
                      "account_code": null
                    }
                  ],
                  "on_behalf_of_customer_id": null,
                  "remark": "Monthly IT support contract",
                  "reference": null,
                  "status": "open",
                  "paid_amount": "0.00",
                  "outstanding": "16050.00",
                  "notes": [],
                  "attachments": [],
                  "voided_at": null,
                  "void_reason": null,
                  "created_at": "2026-10-26T09:41:15+07:00"
                }
              }
            }
          },
          "409": {
            "description": "A bill with this `external_id`, or this supplier `tax_id` and `bill_number`, already exists.",
            "headers": {
              "Request-Id": {
                "description": "SLF's id for the request: an opaque string of up to 64 characters. Quote it when you contact SLF. A replayed response carries the id of the first request.",
                "schema": {
                  "type": "string",
                  "maxLength": 64
                }
              },
              "Idempotent-Replayed": {
                "description": "`true` when the response is the stored response of an earlier request with the same `Idempotency-Key`; nothing new was recorded.",
                "schema": {
                  "type": "string",
                  "enum": [
                    "true"
                  ]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "duplicate_bill",
                    "message": "A bill DS-2610-0058 from supplier 0999000000035 already exists.",
                    "param": "/bill_number",
                    "details": [],
                    "request_id": "req_8c2e6a4f1d9b3c75",
                    "existing_id": "bil_5Tg9Hw2Lr6Mx"
                  }
                }
              }
            }
          },
          "422": {
            "description": "The bill is invalid.",
            "headers": {
              "Request-Id": {
                "description": "SLF's id for the request: an opaque string of up to 64 characters. Quote it when you contact SLF. A replayed response carries the id of the first request.",
                "schema": {
                  "type": "string",
                  "maxLength": 64
                }
              },
              "Idempotent-Replayed": {
                "description": "`true` when the response is the stored response of an earlier request with the same `Idempotency-Key`; nothing new was recorded.",
                "schema": {
                  "type": "string",
                  "enum": [
                    "true"
                  ]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "validation_failed",
                    "message": "2 fields are invalid.",
                    "param": null,
                    "details": [
                      {
                        "param": "/tax_id",
                        "code": "invalid_tax_id",
                        "message": "The check digit does not match.",
                        "expected": null,
                        "received": null
                      },
                      {
                        "param": "/email",
                        "code": "invalid_format",
                        "message": "Not an email address.",
                        "expected": null,
                        "received": null
                      }
                    ],
                    "request_id": "req_3c9e1f7a2b5d8c04",
                    "existing_id": null
                  }
                }
              }
            }
          },
          "default": {
            "description": "Error. See the error codes in the reference.",
            "headers": {
              "Request-Id": {
                "description": "SLF's id for the request: an opaque string of up to 64 characters. Quote it when you contact SLF. A replayed response carries the id of the first request.",
                "schema": {
                  "type": "string",
                  "maxLength": 64
                }
              },
              "Idempotent-Replayed": {
                "description": "`true` when the response is the stored response of an earlier request with the same `Idempotency-Key`; nothing new was recorded.",
                "schema": {
                  "type": "string",
                  "enum": [
                    "true"
                  ]
                }
              },
              "Retry-After": {
                "description": "Seconds to wait before retrying.",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "get": {
        "operationId": "listBills",
        "tags": [
          "Supplier bills"
        ],
        "summary": "List supplier bills",
        "x-release": 2,
        "description": "Draft specification: not live yet. Second release (see [Two releases](https://slf-accounting.co/developers/reference#guide-overview)): once the first release is live, this path answers 404 `not_found` until the second opens. Returns your supplier bills, newest first.",
        "parameters": [
          {
            "name": "external_id",
            "in": "query",
            "required": false,
            "description": "Only the bill with this `external_id`.",
            "schema": {
              "type": "string"
            },
            "example": "AP-2026-10-0058"
          },
          {
            "name": "supplier_tax_id",
            "in": "query",
            "required": false,
            "description": "Only bills from the supplier with this tax ID.",
            "schema": {
              "type": "string"
            },
            "example": "0999000000035"
          },
          {
            "name": "reference",
            "in": "query",
            "required": false,
            "description": "Only bills with this `reference`.",
            "schema": {
              "type": "string"
            },
            "example": "PRJ-2026-031"
          },
          {
            "name": "status",
            "in": "query",
            "required": false,
            "description": "Only bills with this status, such as `open` to find what you still owe.",
            "schema": {
              "$ref": "#/components/schemas/bill_status"
            },
            "example": "open"
          },
          {
            "name": "bill_date_from",
            "in": "query",
            "required": false,
            "description": "Only bills with a `bill_date` on or after this date.",
            "schema": {
              "type": "string",
              "format": "date"
            },
            "example": "2026-10-01"
          },
          {
            "name": "bill_date_to",
            "in": "query",
            "required": false,
            "description": "Only bills with a `bill_date` on or before this date.",
            "schema": {
              "type": "string",
              "format": "date"
            },
            "example": "2026-10-31"
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Number of records per page: a whole number from 1 to 100. Default 25. For the refusals, see Pagination in [Conventions](https://slf-accounting.co/developers/reference#guide-conventions).",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 25
            },
            "example": 25
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "description": "The `next_cursor` value from the previous page, unchanged. Omit it for the first page; an empty value is refused. For the refusals, see Pagination in [Conventions](https://slf-accounting.co/developers/reference#guide-conventions).",
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 512
            },
            "example": "cur_8Tn3XqL5Vd"
          }
        ],
        "responses": {
          "200": {
            "description": "A page of bills.",
            "headers": {
              "Request-Id": {
                "description": "SLF's id for the request: an opaque string of up to 64 characters. Quote it when you contact SLF. A replayed response carries the id of the first request.",
                "schema": {
                  "type": "string",
                  "maxLength": 64
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Bill"
                      }
                    },
                    "next_cursor": {
                      "type": [
                        "string",
                        "null"
                      ]
                    }
                  },
                  "required": [
                    "data",
                    "next_cursor"
                  ]
                },
                "example": {
                  "data": [
                    {
                      "id": "bil_5Tg9Hw2Lr6Mx",
                      "external_id": "AP-2026-10-0058",
                      "document_type": "tax_invoice",
                      "supplier": {
                        "name": "Demo Services Co., Ltd.",
                        "tax_id": "0999000000035",
                        "branch_no": "00000",
                        "country": "TH"
                      },
                      "bill_number": "DS-2610-0058",
                      "bill_date": "2026-10-25",
                      "due_date": "2026-11-24",
                      "currency": "THB",
                      "fx_rate": null,
                      "fx_date": null,
                      "subtotal": "15000.00",
                      "vat_amount": "1050.00",
                      "total": "16050.00",
                      "lines": [
                        {
                          "description": "IT support, October 2026",
                          "quantity": "1",
                          "unit_price": "15000.00",
                          "amount": "15000.00",
                          "item_code": "DS-ITS-01",
                          "account_code": null
                        }
                      ],
                      "on_behalf_of_customer_id": null,
                      "remark": "Monthly IT support contract",
                      "reference": null,
                      "status": "open",
                      "paid_amount": "0.00",
                      "outstanding": "16050.00",
                      "notes": [],
                      "attachments": [],
                      "voided_at": null,
                      "void_reason": null,
                      "created_at": "2026-10-26T09:41:15+07:00"
                    }
                  ],
                  "next_cursor": null
                }
              }
            }
          },
          "default": {
            "description": "Error. See the error codes in the reference.",
            "headers": {
              "Request-Id": {
                "description": "SLF's id for the request: an opaque string of up to 64 characters. Quote it when you contact SLF. A replayed response carries the id of the first request.",
                "schema": {
                  "type": "string",
                  "maxLength": 64
                }
              },
              "Retry-After": {
                "description": "Seconds to wait before retrying.",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/bills/{id}": {
      "get": {
        "operationId": "getBill",
        "tags": [
          "Supplier bills"
        ],
        "summary": "Get a supplier bill",
        "x-release": 2,
        "description": "Draft specification: not live yet. Second release (see [Two releases](https://slf-accounting.co/developers/reference#guide-overview)): once the first release is live, this path answers 404 `not_found` until the second opens. Returns one bill, with its payment status and any supplier notes recorded against it.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "The bill's id (`bil_`).",
            "schema": {
              "type": "string"
            },
            "example": "bil_…"
          }
        ],
        "responses": {
          "200": {
            "description": "The bill.",
            "headers": {
              "Request-Id": {
                "description": "SLF's id for the request: an opaque string of up to 64 characters. Quote it when you contact SLF. A replayed response carries the id of the first request.",
                "schema": {
                  "type": "string",
                  "maxLength": 64
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Bill"
                },
                "example": {
                  "id": "bil_5Tg9Hw2Lr6Mx",
                  "external_id": "AP-2026-10-0058",
                  "document_type": "tax_invoice",
                  "supplier": {
                    "name": "Demo Services Co., Ltd.",
                    "tax_id": "0999000000035",
                    "branch_no": "00000",
                    "country": "TH"
                  },
                  "bill_number": "DS-2610-0058",
                  "bill_date": "2026-10-25",
                  "due_date": "2026-11-24",
                  "currency": "THB",
                  "fx_rate": null,
                  "fx_date": null,
                  "subtotal": "15000.00",
                  "vat_amount": "1050.00",
                  "total": "16050.00",
                  "lines": [
                    {
                      "description": "IT support, October 2026",
                      "quantity": "1",
                      "unit_price": "15000.00",
                      "amount": "15000.00",
                      "item_code": "DS-ITS-01",
                      "account_code": null
                    }
                  ],
                  "on_behalf_of_customer_id": null,
                  "remark": "Monthly IT support contract",
                  "reference": null,
                  "status": "open",
                  "paid_amount": "0.00",
                  "outstanding": "16050.00",
                  "notes": [],
                  "attachments": [],
                  "voided_at": null,
                  "void_reason": null,
                  "created_at": "2026-10-26T09:41:15+07:00"
                }
              }
            }
          },
          "default": {
            "description": "Error. See the error codes in the reference.",
            "headers": {
              "Request-Id": {
                "description": "SLF's id for the request: an opaque string of up to 64 characters. Quote it when you contact SLF. A replayed response carries the id of the first request.",
                "schema": {
                  "type": "string",
                  "maxLength": 64
                }
              },
              "Retry-After": {
                "description": "Seconds to wait before retrying.",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/bills/{id}/void": {
      "post": {
        "operationId": "voidBill",
        "tags": [
          "Supplier bills"
        ],
        "summary": "Void a supplier bill",
        "x-release": 2,
        "description": "Draft specification: not live yet. Second release (see [Two releases](https://slf-accounting.co/developers/reference#guide-overview)): once the first release is live, this path answers 404 `not_found` until the second opens. Voids a bill recorded by mistake. It stays visible with `status: void`. A bill cannot be voided while payments allocated to it are not reversed (reverse them first), or while a supplier note on it has been posted by SLF to your books (`void_not_allowed`).\n\nErrors specific to this endpoint: already_voided, void_not_allowed.",
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": true,
            "description": "Required on every POST. A unique value for this request, 1 to 255 visible ASCII characters; a UUID works well. Reuse it only to retry this exact request after a network error, a timeout, 429 or a 5xx. After any other 4xx, fix the request and send it with a new value. See [Idempotency and duplicates](https://slf-accounting.co/developers/reference#guide-idempotency).",
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 255,
              "pattern": "^[\\x21-\\x7E]+$"
            },
            "example": "5f0c2b8e-3d4a-4c1e-9b7f-2a6d8e1c0f93"
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "The bill's id (`bil_`).",
            "schema": {
              "type": "string"
            },
            "example": "bil_…"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/VoidRequest"
              },
              "example": {
                "reason": "The supplier withdrew this bill."
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The voided bill.",
            "headers": {
              "Request-Id": {
                "description": "SLF's id for the request: an opaque string of up to 64 characters. Quote it when you contact SLF. A replayed response carries the id of the first request.",
                "schema": {
                  "type": "string",
                  "maxLength": 64
                }
              },
              "Idempotent-Replayed": {
                "description": "`true` when the response is the stored response of an earlier request with the same `Idempotency-Key`; nothing new was recorded.",
                "schema": {
                  "type": "string",
                  "enum": [
                    "true"
                  ]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Bill"
                },
                "example": {
                  "id": "bil_8Kd3Wq6Ln1Rz",
                  "external_id": "AP-2026-10-0057",
                  "document_type": "tax_invoice",
                  "supplier": {
                    "name": "Demo Services Co., Ltd.",
                    "tax_id": "0999000000035",
                    "branch_no": "00000",
                    "country": "TH"
                  },
                  "bill_number": "DS-2610-0057",
                  "bill_date": "2026-10-25",
                  "due_date": "2026-11-24",
                  "currency": "THB",
                  "fx_rate": null,
                  "fx_date": null,
                  "subtotal": "15000.00",
                  "vat_amount": "1050.00",
                  "total": "16050.00",
                  "lines": [
                    {
                      "description": "IT support, October 2026",
                      "quantity": "1",
                      "unit_price": "15000.00",
                      "amount": "15000.00",
                      "item_code": "DS-ITS-01",
                      "account_code": null
                    }
                  ],
                  "on_behalf_of_customer_id": null,
                  "remark": "Monthly IT support contract",
                  "reference": null,
                  "status": "void",
                  "paid_amount": "0.00",
                  "outstanding": "0.00",
                  "notes": [],
                  "attachments": [],
                  "voided_at": "2026-10-27T08:30:00+07:00",
                  "void_reason": "The supplier withdrew this bill.",
                  "created_at": "2026-10-26T09:41:15+07:00"
                }
              }
            }
          },
          "409": {
            "description": "The bill is already voided (`already_voided`), or it cannot be voided now (`void_not_allowed`).",
            "headers": {
              "Request-Id": {
                "description": "SLF's id for the request: an opaque string of up to 64 characters. Quote it when you contact SLF. A replayed response carries the id of the first request.",
                "schema": {
                  "type": "string",
                  "maxLength": 64
                }
              },
              "Idempotent-Replayed": {
                "description": "`true` when the response is the stored response of an earlier request with the same `Idempotency-Key`; nothing new was recorded.",
                "schema": {
                  "type": "string",
                  "enum": [
                    "true"
                  ]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "already_voided",
                    "message": "This record is already voided.",
                    "param": null,
                    "details": [],
                    "request_id": "req_5c9a1e7d3b6f2a48",
                    "existing_id": null
                  }
                }
              }
            }
          },
          "default": {
            "description": "Error. See the error codes in the reference.",
            "headers": {
              "Request-Id": {
                "description": "SLF's id for the request: an opaque string of up to 64 characters. Quote it when you contact SLF. A replayed response carries the id of the first request.",
                "schema": {
                  "type": "string",
                  "maxLength": 64
                }
              },
              "Idempotent-Replayed": {
                "description": "`true` when the response is the stored response of an earlier request with the same `Idempotency-Key`; nothing new was recorded.",
                "schema": {
                  "type": "string",
                  "enum": [
                    "true"
                  ]
                }
              },
              "Retry-After": {
                "description": "Seconds to wait before retrying.",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/bills/{id}/notes": {
      "post": {
        "operationId": "createBillNote",
        "tags": [
          "Supplier bills"
        ],
        "summary": "Record a supplier credit or debit note",
        "x-release": 2,
        "description": "Draft specification: not live yet. Second release (see [Two releases](https://slf-accounting.co/developers/reference#guide-overview)): once the first release is live, this path answers 404 `not_found` until the second opens. Records a credit or debit note your supplier issued against a bill. `amount` is the change before VAT and `vat_amount` the VAT on it, both as printed; `reason` is the supplier's reason, as free text. The note changes the bill's `outstanding`. A credit note may not be more than the bill's `total` less the supplier credit notes already recorded against it (`validation_failed`, `out_of_range`), and no note is accepted on a voided bill.\n\nErrors specific to this endpoint: duplicate_external_id.",
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": true,
            "description": "Required on every POST. A unique value for this request, 1 to 255 visible ASCII characters; a UUID works well. Reuse it only to retry this exact request after a network error, a timeout, 429 or a 5xx. After any other 4xx, fix the request and send it with a new value. See [Idempotency and duplicates](https://slf-accounting.co/developers/reference#guide-idempotency).",
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 255,
              "pattern": "^[\\x21-\\x7E]+$"
            },
            "example": "5f0c2b8e-3d4a-4c1e-9b7f-2a6d8e1c0f93"
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "The bill's id (`bil_`).",
            "schema": {
              "type": "string"
            },
            "example": "bil_…"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/BillNote"
              },
              "example": {
                "external_id": "AP-CN-2026-11-0007",
                "type": "credit_note",
                "number": "DS-CN-0007",
                "date": "2026-11-02",
                "amount": "1000.00",
                "vat_amount": "70.00",
                "reason": "Two support visits were not provided"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "The note was recorded.",
            "headers": {
              "Request-Id": {
                "description": "SLF's id for the request: an opaque string of up to 64 characters. Quote it when you contact SLF. A replayed response carries the id of the first request.",
                "schema": {
                  "type": "string",
                  "maxLength": 64
                }
              },
              "Idempotent-Replayed": {
                "description": "`true` when the response is the stored response of an earlier request with the same `Idempotency-Key`; nothing new was recorded.",
                "schema": {
                  "type": "string",
                  "enum": [
                    "true"
                  ]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BillNote"
                },
                "example": {
                  "id": "bnt_1Qz6Ck3Pv8Ys",
                  "bill_id": "bil_2Cw8Np4Vs7Kf",
                  "external_id": "AP-CN-2026-11-0007",
                  "type": "credit_note",
                  "number": "DS-CN-0007",
                  "date": "2026-11-02",
                  "amount": "1000.00",
                  "vat_amount": "70.00",
                  "reason": "Two support visits were not provided",
                  "created_at": "2026-11-02T14:22:40+07:00"
                }
              }
            }
          },
          "409": {
            "description": "A supplier note with this `external_id` already exists.",
            "headers": {
              "Request-Id": {
                "description": "SLF's id for the request: an opaque string of up to 64 characters. Quote it when you contact SLF. A replayed response carries the id of the first request.",
                "schema": {
                  "type": "string",
                  "maxLength": 64
                }
              },
              "Idempotent-Replayed": {
                "description": "`true` when the response is the stored response of an earlier request with the same `Idempotency-Key`; nothing new was recorded.",
                "schema": {
                  "type": "string",
                  "enum": [
                    "true"
                  ]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "duplicate_external_id",
                    "message": "A supplier note with external_id AP-CN-2026-11-0007 already exists.",
                    "param": "/external_id",
                    "details": [],
                    "request_id": "req_6a2d9f4c1e8b3a70",
                    "existing_id": "bnt_1Qz6Ck3Pv8Ys"
                  }
                }
              }
            }
          },
          "422": {
            "description": "The note is invalid.",
            "headers": {
              "Request-Id": {
                "description": "SLF's id for the request: an opaque string of up to 64 characters. Quote it when you contact SLF. A replayed response carries the id of the first request.",
                "schema": {
                  "type": "string",
                  "maxLength": 64
                }
              },
              "Idempotent-Replayed": {
                "description": "`true` when the response is the stored response of an earlier request with the same `Idempotency-Key`; nothing new was recorded.",
                "schema": {
                  "type": "string",
                  "enum": [
                    "true"
                  ]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "validation_failed",
                    "message": "2 fields are invalid.",
                    "param": null,
                    "details": [
                      {
                        "param": "/tax_id",
                        "code": "invalid_tax_id",
                        "message": "The check digit does not match.",
                        "expected": null,
                        "received": null
                      },
                      {
                        "param": "/email",
                        "code": "invalid_format",
                        "message": "Not an email address.",
                        "expected": null,
                        "received": null
                      }
                    ],
                    "request_id": "req_3c9e1f7a2b5d8c04",
                    "existing_id": null
                  }
                }
              }
            }
          },
          "default": {
            "description": "Error. See the error codes in the reference.",
            "headers": {
              "Request-Id": {
                "description": "SLF's id for the request: an opaque string of up to 64 characters. Quote it when you contact SLF. A replayed response carries the id of the first request.",
                "schema": {
                  "type": "string",
                  "maxLength": 64
                }
              },
              "Idempotent-Replayed": {
                "description": "`true` when the response is the stored response of an earlier request with the same `Idempotency-Key`; nothing new was recorded.",
                "schema": {
                  "type": "string",
                  "enum": [
                    "true"
                  ]
                }
              },
              "Retry-After": {
                "description": "Seconds to wait before retrying.",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/payments": {
      "post": {
        "operationId": "createPayment",
        "tags": [
          "Supplier payments"
        ],
        "summary": "Record a supplier payment",
        "x-release": 2,
        "description": "Draft specification: not live yet. Second release (see [Two releases](https://slf-accounting.co/developers/reference#guide-overview)): once the first release is live, this path answers 404 `not_found` until the second opens. Records a payment you made. Each allocation gives the cash paid towards one bill and the tax you withheld from it, in the bill's currency; together they reduce the bill's `outstanding`, and an allocation larger than the outstanding is refused with `validation_failed` (`out_of_range`). When you withheld tax, list it in `withholding`, one entry per payee and income type, as on your 50 ทวิ certificate. Withholding entries are in THB, so a payment with withholding may be allocated only to bills in THB (`validation_failed`, `invalid_value`). The withheld amounts in `allocations` and in `withholding` must add up to the same total (`withholding_mismatch`), and each entry's `wht_amount` must equal `round2(gross_amount × rate / 100)` (`totals_mismatch`). `return_form` is set from `payee_type`, and SLF confirms it on review. A payment with withholding dated in a month whose withholding return of that `return_form` SLF has filed is refused with `period_filed`; any payment dated in a closed period with `period_closed`. Rates are what you actually withheld; the API does not check them against income types, and SLF reviews them. The example withholds 3% on a service fee; the number is only an example, not a rule.\n\nErrors specific to this endpoint: duplicate_external_id, reference_not_found, withholding_mismatch, totals_mismatch, period_filed, period_closed.",
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": true,
            "description": "Required on every POST. A unique value for this request, 1 to 255 visible ASCII characters; a UUID works well. Reuse it only to retry this exact request after a network error, a timeout, 429 or a 5xx. After any other 4xx, fix the request and send it with a new value. See [Idempotency and duplicates](https://slf-accounting.co/developers/reference#guide-idempotency).",
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 255,
              "pattern": "^[\\x21-\\x7E]+$"
            },
            "example": "5f0c2b8e-3d4a-4c1e-9b7f-2a6d8e1c0f93"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/Payment"
              },
              "example": {
                "external_id": "AP-PAY-2026-10-0031",
                "pay_date": "2026-10-31",
                "method": "transfer",
                "bank_account_id": "bnk_5Qm2Rk8Lt3Vw",
                "reference": "TRF-20261031-0007",
                "allocations": [
                  {
                    "bill_id": "bil_5Tg9Hw2Lr6Mx",
                    "amount": "15600.00",
                    "wht_amount": "450.00"
                  }
                ],
                "withholding": [
                  {
                    "payee_name": "Demo Services Co., Ltd.",
                    "payee_tax_id": "0999000000035",
                    "payee_branch_no": "00000",
                    "payee_address": "1 Example Road, Khlong Toei, Bangkok 10110",
                    "payee_type": "company",
                    "income_type": "service",
                    "income_description": null,
                    "gross_amount": "15000.00",
                    "rate": "3",
                    "wht_amount": "450.00",
                    "certificate_number": "WHT-2026-0101"
                  }
                ]
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "The payment was recorded.",
            "headers": {
              "Request-Id": {
                "description": "SLF's id for the request: an opaque string of up to 64 characters. Quote it when you contact SLF. A replayed response carries the id of the first request.",
                "schema": {
                  "type": "string",
                  "maxLength": 64
                }
              },
              "Idempotent-Replayed": {
                "description": "`true` when the response is the stored response of an earlier request with the same `Idempotency-Key`; nothing new was recorded.",
                "schema": {
                  "type": "string",
                  "enum": [
                    "true"
                  ]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Payment"
                },
                "example": {
                  "id": "pay_7Mv4Ys1Jn9Bc",
                  "external_id": "AP-PAY-2026-10-0031",
                  "pay_date": "2026-10-31",
                  "method": "transfer",
                  "bank_account_id": "bnk_5Qm2Rk8Lt3Vw",
                  "reference": "TRF-20261031-0007",
                  "allocations": [
                    {
                      "bill_id": "bil_5Tg9Hw2Lr6Mx",
                      "amount": "15600.00",
                      "wht_amount": "450.00"
                    }
                  ],
                  "withholding": [
                    {
                      "payee_name": "Demo Services Co., Ltd.",
                      "payee_tax_id": "0999000000035",
                      "payee_branch_no": "00000",
                      "payee_address": "1 Example Road, Khlong Toei, Bangkok 10110",
                      "payee_type": "company",
                      "income_type": "service",
                      "income_description": null,
                      "gross_amount": "15000.00",
                      "rate": "3",
                      "wht_amount": "450.00",
                      "certificate_number": "WHT-2026-0101",
                      "return_form": "pnd53"
                    }
                  ],
                  "attachments": [],
                  "state": "recorded",
                  "reversed_at": null,
                  "reverse_reason": null,
                  "created_at": "2026-10-31T16:55:02+07:00"
                }
              }
            }
          },
          "409": {
            "description": "A payment with this `external_id` already exists.",
            "headers": {
              "Request-Id": {
                "description": "SLF's id for the request: an opaque string of up to 64 characters. Quote it when you contact SLF. A replayed response carries the id of the first request.",
                "schema": {
                  "type": "string",
                  "maxLength": 64
                }
              },
              "Idempotent-Replayed": {
                "description": "`true` when the response is the stored response of an earlier request with the same `Idempotency-Key`; nothing new was recorded.",
                "schema": {
                  "type": "string",
                  "enum": [
                    "true"
                  ]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "duplicate_external_id",
                    "message": "A payment with external_id AP-PAY-2026-10-0031 already exists.",
                    "param": "/external_id",
                    "details": [],
                    "request_id": "req_1c7e4a9d2f6b8e53",
                    "existing_id": "pay_7Mv4Ys1Jn9Bc"
                  }
                }
              }
            }
          },
          "422": {
            "description": "The payment is invalid, its withholding does not add up, or its month is filed or closed.",
            "headers": {
              "Request-Id": {
                "description": "SLF's id for the request: an opaque string of up to 64 characters. Quote it when you contact SLF. A replayed response carries the id of the first request.",
                "schema": {
                  "type": "string",
                  "maxLength": 64
                }
              },
              "Idempotent-Replayed": {
                "description": "`true` when the response is the stored response of an earlier request with the same `Idempotency-Key`; nothing new was recorded.",
                "schema": {
                  "type": "string",
                  "enum": [
                    "true"
                  ]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "withholding_mismatch",
                    "message": "allocations withhold 450.00 in total but withholding lists 405.00.",
                    "param": "/withholding",
                    "details": [
                      {
                        "param": "/withholding",
                        "code": "mismatch",
                        "message": "Sum of withholding[].wht_amount.",
                        "expected": "450.00",
                        "received": "405.00"
                      }
                    ],
                    "request_id": "req_4b1d8f3a6c2e9d17",
                    "existing_id": null
                  }
                }
              }
            }
          },
          "default": {
            "description": "Error. See the error codes in the reference.",
            "headers": {
              "Request-Id": {
                "description": "SLF's id for the request: an opaque string of up to 64 characters. Quote it when you contact SLF. A replayed response carries the id of the first request.",
                "schema": {
                  "type": "string",
                  "maxLength": 64
                }
              },
              "Idempotent-Replayed": {
                "description": "`true` when the response is the stored response of an earlier request with the same `Idempotency-Key`; nothing new was recorded.",
                "schema": {
                  "type": "string",
                  "enum": [
                    "true"
                  ]
                }
              },
              "Retry-After": {
                "description": "Seconds to wait before retrying.",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "get": {
        "operationId": "listPayments",
        "tags": [
          "Supplier payments"
        ],
        "summary": "List supplier payments",
        "x-release": 2,
        "description": "Draft specification: not live yet. Second release (see [Two releases](https://slf-accounting.co/developers/reference#guide-overview)): once the first release is live, this path answers 404 `not_found` until the second opens. Returns your supplier payments, newest first.",
        "parameters": [
          {
            "name": "external_id",
            "in": "query",
            "required": false,
            "description": "Only the payment with this `external_id`.",
            "schema": {
              "type": "string"
            },
            "example": "AP-PAY-2026-10-0031"
          },
          {
            "name": "bill_id",
            "in": "query",
            "required": false,
            "description": "Only payments with an allocation to this bill.",
            "schema": {
              "type": "string"
            },
            "example": "bil_5Tg9Hw2Lr6Mx"
          },
          {
            "name": "pay_date_from",
            "in": "query",
            "required": false,
            "description": "Only payments with a `pay_date` on or after this date.",
            "schema": {
              "type": "string",
              "format": "date"
            },
            "example": "2026-10-01"
          },
          {
            "name": "pay_date_to",
            "in": "query",
            "required": false,
            "description": "Only payments with a `pay_date` on or before this date.",
            "schema": {
              "type": "string",
              "format": "date"
            },
            "example": "2026-10-31"
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Number of records per page: a whole number from 1 to 100. Default 25. For the refusals, see Pagination in [Conventions](https://slf-accounting.co/developers/reference#guide-conventions).",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 25
            },
            "example": 25
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "description": "The `next_cursor` value from the previous page, unchanged. Omit it for the first page; an empty value is refused. For the refusals, see Pagination in [Conventions](https://slf-accounting.co/developers/reference#guide-conventions).",
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 512
            },
            "example": "cur_8Tn3XqL5Vd"
          }
        ],
        "responses": {
          "200": {
            "description": "A page of payments.",
            "headers": {
              "Request-Id": {
                "description": "SLF's id for the request: an opaque string of up to 64 characters. Quote it when you contact SLF. A replayed response carries the id of the first request.",
                "schema": {
                  "type": "string",
                  "maxLength": 64
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Payment"
                      }
                    },
                    "next_cursor": {
                      "type": [
                        "string",
                        "null"
                      ]
                    }
                  },
                  "required": [
                    "data",
                    "next_cursor"
                  ]
                },
                "example": {
                  "data": [
                    {
                      "id": "pay_7Mv4Ys1Jn9Bc",
                      "external_id": "AP-PAY-2026-10-0031",
                      "pay_date": "2026-10-31",
                      "method": "transfer",
                      "bank_account_id": "bnk_5Qm2Rk8Lt3Vw",
                      "reference": "TRF-20261031-0007",
                      "allocations": [
                        {
                          "bill_id": "bil_5Tg9Hw2Lr6Mx",
                          "amount": "15600.00",
                          "wht_amount": "450.00"
                        }
                      ],
                      "withholding": [
                        {
                          "payee_name": "Demo Services Co., Ltd.",
                          "payee_tax_id": "0999000000035",
                          "payee_branch_no": "00000",
                          "payee_address": "1 Example Road, Khlong Toei, Bangkok 10110",
                          "payee_type": "company",
                          "income_type": "service",
                          "income_description": null,
                          "gross_amount": "15000.00",
                          "rate": "3",
                          "wht_amount": "450.00",
                          "certificate_number": "WHT-2026-0101",
                          "return_form": "pnd53"
                        }
                      ],
                      "attachments": [],
                      "state": "recorded",
                      "reversed_at": null,
                      "reverse_reason": null,
                      "created_at": "2026-10-31T16:55:02+07:00"
                    }
                  ],
                  "next_cursor": null
                }
              }
            }
          },
          "default": {
            "description": "Error. See the error codes in the reference.",
            "headers": {
              "Request-Id": {
                "description": "SLF's id for the request: an opaque string of up to 64 characters. Quote it when you contact SLF. A replayed response carries the id of the first request.",
                "schema": {
                  "type": "string",
                  "maxLength": 64
                }
              },
              "Retry-After": {
                "description": "Seconds to wait before retrying.",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/payments/{id}": {
      "get": {
        "operationId": "getPayment",
        "tags": [
          "Supplier payments"
        ],
        "summary": "Get a supplier payment",
        "x-release": 2,
        "description": "Draft specification: not live yet. Second release (see [Two releases](https://slf-accounting.co/developers/reference#guide-overview)): once the first release is live, this path answers 404 `not_found` until the second opens. Returns one payment, with its allocations and withholding.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "The payment's id (`pay_`).",
            "schema": {
              "type": "string"
            },
            "example": "pay_…"
          }
        ],
        "responses": {
          "200": {
            "description": "The payment.",
            "headers": {
              "Request-Id": {
                "description": "SLF's id for the request: an opaque string of up to 64 characters. Quote it when you contact SLF. A replayed response carries the id of the first request.",
                "schema": {
                  "type": "string",
                  "maxLength": 64
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Payment"
                },
                "example": {
                  "id": "pay_7Mv4Ys1Jn9Bc",
                  "external_id": "AP-PAY-2026-10-0031",
                  "pay_date": "2026-10-31",
                  "method": "transfer",
                  "bank_account_id": "bnk_5Qm2Rk8Lt3Vw",
                  "reference": "TRF-20261031-0007",
                  "allocations": [
                    {
                      "bill_id": "bil_5Tg9Hw2Lr6Mx",
                      "amount": "15600.00",
                      "wht_amount": "450.00"
                    }
                  ],
                  "withholding": [
                    {
                      "payee_name": "Demo Services Co., Ltd.",
                      "payee_tax_id": "0999000000035",
                      "payee_branch_no": "00000",
                      "payee_address": "1 Example Road, Khlong Toei, Bangkok 10110",
                      "payee_type": "company",
                      "income_type": "service",
                      "income_description": null,
                      "gross_amount": "15000.00",
                      "rate": "3",
                      "wht_amount": "450.00",
                      "certificate_number": "WHT-2026-0101",
                      "return_form": "pnd53"
                    }
                  ],
                  "attachments": [],
                  "state": "recorded",
                  "reversed_at": null,
                  "reverse_reason": null,
                  "created_at": "2026-10-31T16:55:02+07:00"
                }
              }
            }
          },
          "default": {
            "description": "Error. See the error codes in the reference.",
            "headers": {
              "Request-Id": {
                "description": "SLF's id for the request: an opaque string of up to 64 characters. Quote it when you contact SLF. A replayed response carries the id of the first request.",
                "schema": {
                  "type": "string",
                  "maxLength": 64
                }
              },
              "Retry-After": {
                "description": "Seconds to wait before retrying.",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/payments/{id}/reverse": {
      "post": {
        "operationId": "reversePayment",
        "tags": [
          "Supplier payments"
        ],
        "summary": "Reverse a supplier payment",
        "x-release": 2,
        "description": "Draft specification: not live yet. Second release (see [Two releases](https://slf-accounting.co/developers/reference#guide-overview)): once the first release is live, this path answers 404 `not_found` until the second opens. Reverses a payment recorded by mistake. The bills it was allocated to owe the allocated amounts again, and its withholding entries no longer count. The payment stays visible with `state: reversed`. A payment dated in a closed period cannot be reversed (`period_closed`), nor one whose settlement SLF has already posted to your books (`void_not_allowed`). Withholding already in a return SLF has filed stays there; SLF handles that with you.\n\nErrors specific to this endpoint: already_voided, void_not_allowed, period_closed.",
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": true,
            "description": "Required on every POST. A unique value for this request, 1 to 255 visible ASCII characters; a UUID works well. Reuse it only to retry this exact request after a network error, a timeout, 429 or a 5xx. After any other 4xx, fix the request and send it with a new value. See [Idempotency and duplicates](https://slf-accounting.co/developers/reference#guide-idempotency).",
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 255,
              "pattern": "^[\\x21-\\x7E]+$"
            },
            "example": "5f0c2b8e-3d4a-4c1e-9b7f-2a6d8e1c0f93"
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "The payment's id (`pay_`).",
            "schema": {
              "type": "string"
            },
            "example": "pay_…"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/VoidRequest"
              },
              "example": {
                "reason": "Transfer was rejected by the bank."
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The reversed payment.",
            "headers": {
              "Request-Id": {
                "description": "SLF's id for the request: an opaque string of up to 64 characters. Quote it when you contact SLF. A replayed response carries the id of the first request.",
                "schema": {
                  "type": "string",
                  "maxLength": 64
                }
              },
              "Idempotent-Replayed": {
                "description": "`true` when the response is the stored response of an earlier request with the same `Idempotency-Key`; nothing new was recorded.",
                "schema": {
                  "type": "string",
                  "enum": [
                    "true"
                  ]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Payment"
                },
                "example": {
                  "id": "pay_7Mv4Ys1Jn9Bc",
                  "external_id": "AP-PAY-2026-10-0031",
                  "pay_date": "2026-10-31",
                  "method": "transfer",
                  "bank_account_id": "bnk_5Qm2Rk8Lt3Vw",
                  "reference": "TRF-20261031-0007",
                  "allocations": [
                    {
                      "bill_id": "bil_5Tg9Hw2Lr6Mx",
                      "amount": "15600.00",
                      "wht_amount": "450.00"
                    }
                  ],
                  "withholding": [
                    {
                      "payee_name": "Demo Services Co., Ltd.",
                      "payee_tax_id": "0999000000035",
                      "payee_branch_no": "00000",
                      "payee_address": "1 Example Road, Khlong Toei, Bangkok 10110",
                      "payee_type": "company",
                      "income_type": "service",
                      "income_description": null,
                      "gross_amount": "15000.00",
                      "rate": "3",
                      "wht_amount": "450.00",
                      "certificate_number": "WHT-2026-0101",
                      "return_form": "pnd53"
                    }
                  ],
                  "attachments": [],
                  "state": "reversed",
                  "reversed_at": "2026-11-01T10:12:45+07:00",
                  "reverse_reason": "Transfer was rejected by the bank.",
                  "created_at": "2026-10-31T16:55:02+07:00"
                }
              }
            }
          },
          "409": {
            "description": "The payment is already reversed (`already_voided`), or it cannot be reversed now (`void_not_allowed`).",
            "headers": {
              "Request-Id": {
                "description": "SLF's id for the request: an opaque string of up to 64 characters. Quote it when you contact SLF. A replayed response carries the id of the first request.",
                "schema": {
                  "type": "string",
                  "maxLength": 64
                }
              },
              "Idempotent-Replayed": {
                "description": "`true` when the response is the stored response of an earlier request with the same `Idempotency-Key`; nothing new was recorded.",
                "schema": {
                  "type": "string",
                  "enum": [
                    "true"
                  ]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "already_voided",
                    "message": "This payment is already reversed.",
                    "param": null,
                    "details": [],
                    "request_id": "req_2f7c4a9e1d5b8c36",
                    "existing_id": null
                  }
                }
              }
            }
          },
          "default": {
            "description": "Error. See the error codes in the reference.",
            "headers": {
              "Request-Id": {
                "description": "SLF's id for the request: an opaque string of up to 64 characters. Quote it when you contact SLF. A replayed response carries the id of the first request.",
                "schema": {
                  "type": "string",
                  "maxLength": 64
                }
              },
              "Idempotent-Replayed": {
                "description": "`true` when the response is the stored response of an earlier request with the same `Idempotency-Key`; nothing new was recorded.",
                "schema": {
                  "type": "string",
                  "enum": [
                    "true"
                  ]
                }
              },
              "Retry-After": {
                "description": "Seconds to wait before retrying.",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/attachments": {
      "post": {
        "operationId": "createAttachment",
        "tags": [
          "Attachments"
        ],
        "summary": "Upload an attachment",
        "x-release": 1,
        "description": "Draft specification: not live yet. Uploads a file and attaches it to a sales document or receipt (to a bill or payment from the second release; until then `reference_not_found`). Send `multipart/form-data` with the fields of `AttachmentUpload` and one file; form fields the API does not know are ignored, and a second file is refused with `validation_failed`. The file's type is read from its content, not from its name or the media type you declare. Allowed types: PDF, JPEG, PNG and WebP, up to 10 MB; anything else is refused with 415 `unsupported_media_type` or 413 `payload_too_large`. HEIC is not accepted: convert such photos to JPEG first. A voided record takes no new attachments (`validation_failed`, `invalid_value` on `/object_id`). Your company may upload up to 1 GB or 1,000 files per day, Bangkok time; above that, uploads are refused with 429 `rate_limited` and `Retry-After` until midnight. If the same file (by SHA-256) is already attached to the same record, the existing attachment is returned with 200 instead of 201.\n\nErrors specific to this endpoint: reference_not_found.",
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": true,
            "description": "Required on every POST. A unique value for this request, 1 to 255 visible ASCII characters; a UUID works well. Reuse it only to retry this exact request after a network error, a timeout, 429 or a 5xx. After any other 4xx, fix the request and send it with a new value. See [Idempotency and duplicates](https://slf-accounting.co/developers/reference#guide-idempotency).",
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 255,
              "pattern": "^[\\x21-\\x7E]+$"
            },
            "example": "5f0c2b8e-3d4a-4c1e-9b7f-2a6d8e1c0f93"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "multipart/form-data": {
              "schema": {
                "$ref": "#/components/schemas/AttachmentUpload"
              },
              "encoding": {
                "file": {
                  "contentType": "application/pdf, image/jpeg, image/png, image/webp"
                }
              },
              "example": {
                "file": "(binary content of TIV-2026-0412.pdf)",
                "object_type": "sales_document",
                "object_id": "doc_9Rt3Vb6Nz1Hs",
                "kind": "document_copy"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The same file was already attached to this record; the existing attachment is returned.",
            "headers": {
              "Request-Id": {
                "description": "SLF's id for the request: an opaque string of up to 64 characters. Quote it when you contact SLF. A replayed response carries the id of the first request.",
                "schema": {
                  "type": "string",
                  "maxLength": 64
                }
              },
              "Idempotent-Replayed": {
                "description": "`true` when the response is the stored response of an earlier request with the same `Idempotency-Key`; nothing new was recorded.",
                "schema": {
                  "type": "string",
                  "enum": [
                    "true"
                  ]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Attachment"
                },
                "example": {
                  "id": "att_2Bh5Rx8Fk3Wq",
                  "object_type": "sales_document",
                  "object_id": "doc_9Rt3Vb6Nz1Hs",
                  "kind": "document_copy",
                  "file_name": "TIV-2026-0412.pdf",
                  "content_type": "application/pdf",
                  "size": 184233,
                  "sha256": "9f2b5c1e7a4d8f0c3b6e9a2d5c8f1b4e7a0d3c6f9b2e5a8d1c4f7b0e3a6d9c2f",
                  "created_at": "2026-10-08T11:05:37+07:00"
                }
              }
            }
          },
          "201": {
            "description": "The file was stored and attached.",
            "headers": {
              "Request-Id": {
                "description": "SLF's id for the request: an opaque string of up to 64 characters. Quote it when you contact SLF. A replayed response carries the id of the first request.",
                "schema": {
                  "type": "string",
                  "maxLength": 64
                }
              },
              "Idempotent-Replayed": {
                "description": "`true` when the response is the stored response of an earlier request with the same `Idempotency-Key`; nothing new was recorded.",
                "schema": {
                  "type": "string",
                  "enum": [
                    "true"
                  ]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Attachment"
                },
                "example": {
                  "id": "att_2Bh5Rx8Fk3Wq",
                  "object_type": "sales_document",
                  "object_id": "doc_9Rt3Vb6Nz1Hs",
                  "kind": "document_copy",
                  "file_name": "TIV-2026-0412.pdf",
                  "content_type": "application/pdf",
                  "size": 184233,
                  "sha256": "9f2b5c1e7a4d8f0c3b6e9a2d5c8f1b4e7a0d3c6f9b2e5a8d1c4f7b0e3a6d9c2f",
                  "created_at": "2026-10-08T11:05:37+07:00"
                }
              }
            }
          },
          "413": {
            "description": "The file is larger than 10 MB.",
            "headers": {
              "Request-Id": {
                "description": "SLF's id for the request: an opaque string of up to 64 characters. Quote it when you contact SLF. A replayed response carries the id of the first request.",
                "schema": {
                  "type": "string",
                  "maxLength": 64
                }
              },
              "Idempotent-Replayed": {
                "description": "`true` when the response is the stored response of an earlier request with the same `Idempotency-Key`; nothing new was recorded.",
                "schema": {
                  "type": "string",
                  "enum": [
                    "true"
                  ]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "payload_too_large",
                    "message": "The file is 14.2 MB; the limit is 10 MB.",
                    "param": null,
                    "details": [],
                    "request_id": "req_4e9a2c7f1b5d8e36",
                    "existing_id": null
                  }
                }
              }
            }
          },
          "415": {
            "description": "By its content, the file is not PDF, JPEG, PNG or WebP.",
            "headers": {
              "Request-Id": {
                "description": "SLF's id for the request: an opaque string of up to 64 characters. Quote it when you contact SLF. A replayed response carries the id of the first request.",
                "schema": {
                  "type": "string",
                  "maxLength": 64
                }
              },
              "Idempotent-Replayed": {
                "description": "`true` when the response is the stored response of an earlier request with the same `Idempotency-Key`; nothing new was recorded.",
                "schema": {
                  "type": "string",
                  "enum": [
                    "true"
                  ]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "unsupported_media_type",
                    "message": "Files of type application/zip cannot be attached.",
                    "param": "/file",
                    "details": [],
                    "request_id": "req_7b3d1f8a4c6e2b95",
                    "existing_id": null
                  }
                }
              }
            }
          },
          "422": {
            "description": "The record to attach to does not exist or is voided, or a field is invalid.",
            "headers": {
              "Request-Id": {
                "description": "SLF's id for the request: an opaque string of up to 64 characters. Quote it when you contact SLF. A replayed response carries the id of the first request.",
                "schema": {
                  "type": "string",
                  "maxLength": 64
                }
              },
              "Idempotent-Replayed": {
                "description": "`true` when the response is the stored response of an earlier request with the same `Idempotency-Key`; nothing new was recorded.",
                "schema": {
                  "type": "string",
                  "enum": [
                    "true"
                  ]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "reference_not_found",
                    "message": "No sales document doc_9Rt3Vb6Nz1Hx exists for your company.",
                    "param": "/object_id",
                    "details": [],
                    "request_id": "req_2a8c5e1d9f4b7a63",
                    "existing_id": null
                  }
                }
              }
            }
          },
          "429": {
            "description": "Your company's daily upload limit is reached.",
            "headers": {
              "Request-Id": {
                "description": "SLF's id for the request: an opaque string of up to 64 characters. Quote it when you contact SLF. A replayed response carries the id of the first request.",
                "schema": {
                  "type": "string",
                  "maxLength": 64
                }
              },
              "Idempotent-Replayed": {
                "description": "`true` when the response is the stored response of an earlier request with the same `Idempotency-Key`; nothing new was recorded.",
                "schema": {
                  "type": "string",
                  "enum": [
                    "true"
                  ]
                }
              },
              "Retry-After": {
                "description": "Seconds to wait before retrying.",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "rate_limited",
                    "message": "Your company has uploaded 1,000 files today, the daily limit. Retry after midnight Bangkok time.",
                    "param": null,
                    "details": [],
                    "request_id": "req_5d8b2f6a9c1e4d73",
                    "existing_id": null
                  }
                }
              }
            }
          },
          "default": {
            "description": "Error. See the error codes in the reference.",
            "headers": {
              "Request-Id": {
                "description": "SLF's id for the request: an opaque string of up to 64 characters. Quote it when you contact SLF. A replayed response carries the id of the first request.",
                "schema": {
                  "type": "string",
                  "maxLength": 64
                }
              },
              "Idempotent-Replayed": {
                "description": "`true` when the response is the stored response of an earlier request with the same `Idempotency-Key`; nothing new was recorded.",
                "schema": {
                  "type": "string",
                  "enum": [
                    "true"
                  ]
                }
              },
              "Retry-After": {
                "description": "Seconds to wait before retrying.",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "get": {
        "operationId": "listAttachments",
        "tags": [
          "Attachments"
        ],
        "summary": "List attachments of a record",
        "x-release": 1,
        "description": "Draft specification: not live yet. Returns the attachments of one record that were uploaded through the API, newest first. Files SLF attached itself are not listed.",
        "parameters": [
          {
            "name": "object_type",
            "in": "query",
            "required": true,
            "description": "The kind of record.",
            "schema": {
              "$ref": "#/components/schemas/attachment_object_type"
            },
            "example": "sales_document"
          },
          {
            "name": "object_id",
            "in": "query",
            "required": true,
            "description": "The record's id.",
            "schema": {
              "type": "string"
            },
            "example": "doc_9Rt3Vb6Nz1Hs"
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Number of records per page: a whole number from 1 to 100. Default 25. For the refusals, see Pagination in [Conventions](https://slf-accounting.co/developers/reference#guide-conventions).",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 25
            },
            "example": 25
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "description": "The `next_cursor` value from the previous page, unchanged. Omit it for the first page; an empty value is refused. For the refusals, see Pagination in [Conventions](https://slf-accounting.co/developers/reference#guide-conventions).",
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 512
            },
            "example": "cur_8Tn3XqL5Vd"
          }
        ],
        "responses": {
          "200": {
            "description": "A page of attachments.",
            "headers": {
              "Request-Id": {
                "description": "SLF's id for the request: an opaque string of up to 64 characters. Quote it when you contact SLF. A replayed response carries the id of the first request.",
                "schema": {
                  "type": "string",
                  "maxLength": 64
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Attachment"
                      }
                    },
                    "next_cursor": {
                      "type": [
                        "string",
                        "null"
                      ]
                    }
                  },
                  "required": [
                    "data",
                    "next_cursor"
                  ]
                },
                "example": {
                  "data": [
                    {
                      "id": "att_2Bh5Rx8Fk3Wq",
                      "object_type": "sales_document",
                      "object_id": "doc_9Rt3Vb6Nz1Hs",
                      "kind": "document_copy",
                      "file_name": "TIV-2026-0412.pdf",
                      "content_type": "application/pdf",
                      "size": 184233,
                      "sha256": "9f2b5c1e7a4d8f0c3b6e9a2d5c8f1b4e7a0d3c6f9b2e5a8d1c4f7b0e3a6d9c2f",
                      "created_at": "2026-10-08T11:05:37+07:00"
                    }
                  ],
                  "next_cursor": null
                }
              }
            }
          },
          "default": {
            "description": "Error. See the error codes in the reference.",
            "headers": {
              "Request-Id": {
                "description": "SLF's id for the request: an opaque string of up to 64 characters. Quote it when you contact SLF. A replayed response carries the id of the first request.",
                "schema": {
                  "type": "string",
                  "maxLength": 64
                }
              },
              "Retry-After": {
                "description": "Seconds to wait before retrying.",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/attachments/{id}": {
      "get": {
        "operationId": "getAttachment",
        "tags": [
          "Attachments"
        ],
        "summary": "Get attachment details",
        "x-release": 1,
        "description": "Draft specification: not live yet. Returns an attachment's details, without the file.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "The attachment's id (`att_`).",
            "schema": {
              "type": "string"
            },
            "example": "att_…"
          }
        ],
        "responses": {
          "200": {
            "description": "The attachment's details.",
            "headers": {
              "Request-Id": {
                "description": "SLF's id for the request: an opaque string of up to 64 characters. Quote it when you contact SLF. A replayed response carries the id of the first request.",
                "schema": {
                  "type": "string",
                  "maxLength": 64
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Attachment"
                },
                "example": {
                  "id": "att_2Bh5Rx8Fk3Wq",
                  "object_type": "sales_document",
                  "object_id": "doc_9Rt3Vb6Nz1Hs",
                  "kind": "document_copy",
                  "file_name": "TIV-2026-0412.pdf",
                  "content_type": "application/pdf",
                  "size": 184233,
                  "sha256": "9f2b5c1e7a4d8f0c3b6e9a2d5c8f1b4e7a0d3c6f9b2e5a8d1c4f7b0e3a6d9c2f",
                  "created_at": "2026-10-08T11:05:37+07:00"
                }
              }
            }
          },
          "default": {
            "description": "Error. See the error codes in the reference.",
            "headers": {
              "Request-Id": {
                "description": "SLF's id for the request: an opaque string of up to 64 characters. Quote it when you contact SLF. A replayed response carries the id of the first request.",
                "schema": {
                  "type": "string",
                  "maxLength": 64
                }
              },
              "Retry-After": {
                "description": "Seconds to wait before retrying.",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/attachments/{id}/content": {
      "get": {
        "operationId": "getAttachmentContent",
        "tags": [
          "Attachments"
        ],
        "summary": "Download an attachment",
        "x-release": 1,
        "description": "Draft specification: not live yet. Returns the file itself.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "The attachment's id (`att_`).",
            "schema": {
              "type": "string"
            },
            "example": "att_…"
          }
        ],
        "responses": {
          "200": {
            "description": "The file, with its `content_type` as the `Content-Type` header and its `file_name` in a `Content-Disposition` header.",
            "headers": {
              "Request-Id": {
                "description": "SLF's id for the request: an opaque string of up to 64 characters. Quote it when you contact SLF. A replayed response carries the id of the first request.",
                "schema": {
                  "type": "string",
                  "maxLength": 64
                }
              }
            },
            "content": {
              "application/octet-stream": {
                "schema": {
                  "type": "string",
                  "format": "binary",
                  "contentMediaType": "application/octet-stream"
                }
              }
            }
          },
          "default": {
            "description": "Error. See the error codes in the reference.",
            "headers": {
              "Request-Id": {
                "description": "SLF's id for the request: an opaque string of up to 64 characters. Quote it when you contact SLF. A replayed response carries the id of the first request.",
                "schema": {
                  "type": "string",
                  "maxLength": 64
                }
              },
              "Retry-After": {
                "description": "Seconds to wait before retrying.",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/periods/{month}": {
      "get": {
        "operationId": "getPeriod",
        "tags": [
          "Periods"
        ],
        "summary": "Get a month's totals",
        "x-release": 1,
        "description": "Draft specification: not live yet. Returns the month's figures as SLF has recorded them, so you can compare them with your own system's totals. If they differ, contact SLF. All amounts are in THB. `status` shows whether SLF has filed the month's VAT return or closed the period. Sales lines SLF has not classified yet are counted in `sales.unclassified_value`, and sales records held back by SLF's arithmetic check in `quarantined`; neither is included in the other figures. For a company that is not VAT-registered, every VAT figure is zero. A month with no records returns zero totals.",
        "parameters": [
          {
            "name": "month",
            "in": "path",
            "required": true,
            "description": "The month, as `YYYY-MM`.",
            "schema": {
              "type": "string"
            },
            "example": "2026-09"
          }
        ],
        "responses": {
          "200": {
            "description": "The month's figures.",
            "headers": {
              "Request-Id": {
                "description": "SLF's id for the request: an opaque string of up to 64 characters. Quote it when you contact SLF. A replayed response carries the id of the first request.",
                "schema": {
                  "type": "string",
                  "maxLength": 64
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Period"
                },
                "example": {
                  "month": "2026-09",
                  "status": "vat_filed",
                  "filings": [
                    {
                      "form": "pp30",
                      "filed": true
                    },
                    {
                      "form": "pnd3",
                      "filed": true
                    },
                    {
                      "form": "pnd53",
                      "filed": true
                    },
                    {
                      "form": "pnd1",
                      "filed": false
                    }
                  ],
                  "sales": {
                    "document_count": 64,
                    "taxable_value": "412350.00",
                    "zero_rated_value": "38900.00",
                    "exempt_value": "0.00",
                    "unclassified_value": "0.00",
                    "vat": "28864.50"
                  },
                  "purchases": {
                    "document_count": 41,
                    "taxable_value": "158200.00",
                    "vat": "11074.00"
                  },
                  "out_of_scope_value": "12750.00",
                  "quarantined": {
                    "count": 0,
                    "value": "0.00"
                  },
                  "withholding": {
                    "pnd3_amount": "1250.00",
                    "pnd53_amount": "4830.00"
                  }
                }
              }
            }
          },
          "default": {
            "description": "Error. See the error codes in the reference.",
            "headers": {
              "Request-Id": {
                "description": "SLF's id for the request: an opaque string of up to 64 characters. Quote it when you contact SLF. A replayed response carries the id of the first request.",
                "schema": {
                  "type": "string",
                  "maxLength": 64
                }
              },
              "Retry-After": {
                "description": "Seconds to wait before retrying.",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "description": "API key that SLF Accounting will issue when the API opens (planned: test keys would start with slf_test_, live keys with slf_live_). The API is not live and no keys are issued yet."
      }
    },
    "schemas": {
      "sales_document_type": {
        "type": "string",
        "enum": [
          "quotation",
          "invoice",
          "tax_invoice",
          "tax_invoice_receipt",
          "credit_note",
          "debit_note"
        ],
        "description": "The kind of sales document.\n\n- `quotation`: Quotation (ใบเสนอราคา). Creates nothing owed and cannot be receipted.\n- `invoice`: An invoice that is not a tax invoice (ใบแจ้งหนี้). Paid with receipts.\n- `tax_invoice`: Tax invoice (ใบกำกับภาษี). Paid with receipts.\n- `tax_invoice_receipt`: A tax invoice that is also the receipt, for a cash sale. Recorded as paid; it cannot be receipted.\n- `credit_note`: Credit note (ใบลดหนี้): a decrease in value after a tax invoice. Needs the note fields; see [Corrections](https://slf-accounting.co/developers/reference#guide-corrections).\n- `debit_note`: Debit note (ใบเพิ่มหนี้): an increase in value after a tax invoice. Needs the note fields; see [Corrections](https://slf-accounting.co/developers/reference#guide-corrections). Paid with receipts."
      },
      "sales_document_status": {
        "type": "string",
        "enum": [
          "open",
          "partially_paid",
          "paid",
          "expired",
          "rejected",
          "void"
        ],
        "description": "Status of a sales document. Quotations use `open`, `expired`, `rejected` and `void`.\n\n- `open`: Recorded, and no receipt recorded against it yet. For a quotation: still valid. For a credit note: recorded.\n- `partially_paid`: Receipts are recorded against it, and something is still outstanding.\n- `paid`: Nothing is outstanding: receipts, together with any credit notes, cover the total. A `tax_invoice_receipt`, and a `tax_invoice` with `related_invoice_id`, are `paid` from the start.\n- `expired`: Quotations only: `valid_until` has passed.\n- `rejected`: Quotations only: recorded at SLF as rejected by the customer. The API does not set it.\n- `void`: Voided. The document keeps its number."
      },
      "vat_category": {
        "type": "string",
        "enum": [
          "standard",
          "standard_incl",
          "zero",
          "exempt",
          "none"
        ],
        "description": "How VAT applies to a sales line. The VAT rate is never sent; it follows from the category. Not tax advice; see [Tax notes](https://slf-accounting.co/developers/reference#guide-tax-notes).\n\n- `standard`: Current standard rate: 7% including local tax (the Revenue Code s.80 rate is 10%, reduced by royal decree). The price excludes VAT.\n- `standard_incl`: Same rate as `standard`; the price includes VAT.\n- `zero`: 0%: only where s.80/1 applies, for example qualifying exports. SLF reviews every `zero` line (warning `zero_rated_review`).\n- `exempt`: Exempt under s.81.\n- `none`: Not subject to VAT on this document: disbursements recovered, or the company is not VAT-registered. On a VAT-registered company's document, a `none` line that is not a `disbursement` billed to the customer is counted as unclassified until SLF classifies it, and a document with no other kind of line is refused (`vat_category_unexplained`)."
      },
      "wht_rate": {
        "type": "string",
        "enum": [
          "0",
          "1",
          "2",
          "3",
          "5",
          "10",
          "15"
        ],
        "description": "Withholding tax rate as a percentage. On sales lines: the rate your customer is expected to withhold. On supplier payments: the rate you actually withheld. The API does not say which rate applies to which income; SLF reviews the rates.\n\n- `0`: No tax withheld.\n- `1`: 1%.\n- `2`: 2%.\n- `3`: 3%.\n- `5`: 5%.\n- `10`: 10%.\n- `15`: 15%."
      },
      "charge_role": {
        "type": "string",
        "enum": [
          "own_supply",
          "disbursement"
        ],
        "description": "Whether a sales line is your own supply or the recovery of an amount you paid for the customer. Optional, with no default: a line sent without it is recorded as not stated and returned with `charge_role: null`.\n\n- `own_supply`: Your own sale of goods or services.\n- `disbursement`: Recovering an amount you paid on your customer's behalf (เงินทดรองจ่าย). In ruling กค 0811/12237 the Revenue Department answered one company that recovering costs it had paid on another company's behalf was not a sale or service under s.77/2, so it could not issue a tax invoice for it; a ruling answers the facts put to it. Needs `supplier_invoice_billed_to`, `pass_through_cost` and `vat_category: none`. Recorded as printed, never split; a line priced above its `pass_through_cost` is refused (`disbursement_marked_up`), except for a company that is not VAT-registered, or on a document not in THB, where it is flagged with the warning of the same name. Whether a charge is a disbursement, and how such lines are shown on your documents: confirm with SLF. Not tax advice; see [Tax notes](https://slf-accounting.co/developers/reference#guide-tax-notes)."
      },
      "supplier_invoice_billed_to": {
        "type": "string",
        "enum": [
          "customer",
          "self"
        ],
        "description": "For a disbursement line: who the supplier's document for the cost is addressed to.\n\n- `customer`: Addressed to your customer.\n- `self`: Addressed to your company. The line is recorded and flagged `disbursement_billed_to_self` for SLF review."
      },
      "payment_terms": {
        "type": "string",
        "enum": [
          "tt",
          "lc",
          "sblc",
          "bg"
        ],
        "description": "Trade payment terms printed on a sales document.\n\n- `tt`: Telegraphic (bank) transfer.\n- `lc`: Letter of credit.\n- `sblc`: Standby letter of credit.\n- `bg`: Bank guarantee."
      },
      "credit_note_reason": {
        "type": "string",
        "enum": [
          "goods_nonconforming",
          "goods_returned",
          "goods_return_exchange",
          "service_deficient",
          "price_overcharged",
          "service_contract_cancelled_deficient",
          "service_contract_cancelled_not_provided",
          "deposit_refund",
          "compensation"
        ],
        "description": "Reason for a credit note (ใบลดหนี้), following s.82/10 of the Revenue Code, DG VAT Notice No. 82 and Order ป.80/2542 clause 2(3). There is no `other` value. Not tax advice; see [Tax notes](https://slf-accounting.co/developers/reference#guide-tax-notes).\n\n- `goods_nonconforming`: Price reduced because goods did not meet the agreed specification, were damaged or short.\n- `goods_returned`: Goods returned because defective, not matching sample or description.\n- `goods_return_exchange`: Goods returned or exchanged under a trade agreement: between VAT-registered businesses, or between you and a buyer if done within a reasonable time.\n- `service_deficient`: Service price reduced because the service was deficient, short or not as agreed.\n- `price_overcharged`: Price calculated higher than it should have been.\n- `service_contract_cancelled_deficient`: Service contract cancelled because the service was deficient or not as agreed.\n- `service_contract_cancelled_not_provided`: Service contract cancelled because the service was not provided.\n- `deposit_refund`: Refund of an advance payment, deposit, guarantee or booking money under a trade agreement.\n- `compensation`: Compensation or similar the seller must pay the buyer by law."
      },
      "debit_note_reason": {
        "type": "string",
        "enum": [
          "goods_quantity_exceeded",
          "goods_undercharged",
          "service_exceeded",
          "service_undercharged",
          "other_announced"
        ],
        "description": "Reason for a debit note (ใบเพิ่มหนี้), following s.82/9 of the Revenue Code. Not tax advice; see [Tax notes](https://slf-accounting.co/developers/reference#guide-tax-notes).\n\n- `goods_quantity_exceeded`: More goods delivered than agreed.\n- `goods_undercharged`: Goods price calculated lower than it should have been.\n- `service_exceeded`: Service provided beyond what was agreed.\n- `service_undercharged`: Service price calculated lower than it should have been.\n- `other_announced`: Another cause set by the Director-General. `reason_text` must name it; SLF reviews."
      },
      "bill_document_type": {
        "type": "string",
        "enum": [
          "tax_invoice",
          "receipt",
          "invoice",
          "import_entry",
          "foreign_invoice",
          "other"
        ],
        "description": "What the supplier gave you. SLF uses it when booking the bill, including input VAT, and reviews it.\n\n- `tax_invoice`: A tax invoice (ใบกำกับภาษี) issued to you.\n- `receipt`: A receipt that is not a tax invoice.\n- `invoice`: An invoice or bill that is not a tax invoice.\n- `import_entry`: An import entry (customs declaration) for goods you imported.\n- `foreign_invoice`: An invoice from a supplier outside Thailand.\n- `other`: Any other document. Describe it in `remark`."
      },
      "bill_status": {
        "type": "string",
        "enum": [
          "open",
          "partially_paid",
          "paid",
          "void"
        ],
        "description": "Payment status of a supplier bill.\n\n- `open`: Nothing paid yet.\n- `partially_paid`: Payments or supplier credit notes cover part of it, and something is still outstanding.\n- `paid`: Nothing is outstanding.\n- `void`: Voided."
      },
      "bill_note_type": {
        "type": "string",
        "enum": [
          "credit_note",
          "debit_note"
        ],
        "description": "The kind of supplier adjustment note.\n\n- `credit_note`: The supplier reduced the amount.\n- `debit_note`: The supplier increased the amount."
      },
      "payment_method": {
        "type": "string",
        "enum": [
          "transfer",
          "cheque",
          "cash"
        ],
        "description": "How a supplier payment was made.\n\n- `transfer`: Bank transfer. Needs `bank_account_id`.\n- `cheque`: Cheque. Needs `bank_account_id`.\n- `cash`: Cash."
      },
      "payment_state": {
        "type": "string",
        "enum": [
          "recorded",
          "reversed"
        ],
        "description": "Whether a supplier payment stands.\n\n- `recorded`: The payment is recorded.\n- `reversed`: The payment was reversed; its allocations and withholding no longer count."
      },
      "payee_type": {
        "type": "string",
        "enum": [
          "individual",
          "company"
        ],
        "description": "Who tax was withheld from. `return_form` is set from it. Not tax advice; see [Tax notes](https://slf-accounting.co/developers/reference#guide-tax-notes).\n\n- `individual`: An individual. `return_form` is set to `pnd3` (ภ.ง.ด.3); SLF confirms the return on review (see [Tax notes](https://slf-accounting.co/developers/reference#guide-tax-notes)).\n- `company`: A company or juristic partnership. `return_form` is set to `pnd53` (ภ.ง.ด.53); SLF confirms the return on review (see [Tax notes](https://slf-accounting.co/developers/reference#guide-tax-notes))."
      },
      "income_type": {
        "type": "string",
        "enum": [
          "service",
          "professional_fee",
          "rent",
          "transport",
          "advertising",
          "commission",
          "interest",
          "other"
        ],
        "description": "The kind of payment tax was withheld from, as on your 50 ทวิ certificate. The API does not link income types to rates.\n\n- `service`: Service fees.\n- `professional_fee`: Professional fees.\n- `rent`: Rent.\n- `transport`: Transport charges.\n- `advertising`: Advertising fees.\n- `commission`: Commissions.\n- `interest`: Interest.\n- `other`: Anything else. Describe it in `income_description`."
      },
      "return_form": {
        "type": "string",
        "enum": [
          "pnd3",
          "pnd53"
        ],
        "description": "The withholding tax return SLF expects the entry to go on, set from `payee_type`. Read-only. SLF confirms it on review; some withholding belongs on another return. Not tax advice; see [Tax notes](https://slf-accounting.co/developers/reference#guide-tax-notes).\n\n- `pnd3`: ภ.ง.ด.3.\n- `pnd53`: ภ.ง.ด.53."
      },
      "attachment_object_type": {
        "type": "string",
        "enum": [
          "sales_document",
          "receipt",
          "bill",
          "payment"
        ],
        "description": "The kind of record a file is attached to.\n\n- `sales_document`: A sales document (`doc_`).\n- `receipt`: A receipt (`rcp_`).\n- `bill`: A supplier bill (`bil_`). From the second release; until then refused with `reference_not_found`.\n- `payment`: A supplier payment (`pay_`). From the second release; until then refused with `reference_not_found`."
      },
      "attachment_kind": {
        "type": "string",
        "enum": [
          "document_copy",
          "supplier_document",
          "payment_proof",
          "wht_certificate_received",
          "wht_certificate_issued",
          "customs_document",
          "other"
        ],
        "description": "What an attached file is.\n\n- `document_copy`: A copy of a document you issued.\n- `supplier_document`: A document you received from a supplier.\n- `payment_proof`: Proof of payment, such as a transfer slip.\n- `wht_certificate_received`: A withholding tax certificate (50 ทวิ) your customer gave you.\n- `wht_certificate_issued`: A withholding tax certificate (50 ทวิ) you issued.\n- `customs_document`: A customs document, such as an import or export entry.\n- `other`: Anything else."
      },
      "bank_account_type": {
        "type": "string",
        "enum": [
          "personal"
        ],
        "description": "Whose name a bank account is held in, where SLF has recorded it. Any other account has `type` `null`.\n\n- `personal`: A person's name."
      },
      "period_status": {
        "type": "string",
        "enum": [
          "open",
          "vat_filed",
          "closed"
        ],
        "description": "Where a month stands at SLF.\n\n- `open`: SLF has not filed the month's VAT return or closed the period.\n- `vat_filed`: SLF has filed the month's VAT return. Records that would change it are refused with `period_filed`; see [Filed periods](https://slf-accounting.co/developers/reference#guide-filed-periods).\n- `closed`: SLF has closed the accounting period. Records dated in it are refused with `period_closed`; see [Filed periods](https://slf-accounting.co/developers/reference#guide-filed-periods)."
      },
      "filing_form": {
        "type": "string",
        "enum": [
          "pp30",
          "pnd3",
          "pnd53",
          "pnd1"
        ],
        "description": "A monthly return shown in `GET /periods/{month}`.\n\n- `pp30`: ภ.พ.30, the VAT return.\n- `pnd3`: ภ.ง.ด.3, a withholding tax return.\n- `pnd53`: ภ.ง.ด.53, a withholding tax return.\n- `pnd1`: ภ.ง.ด.1. Shown for completeness; the API does not record payroll."
      },
      "error_detail_code": {
        "type": "string",
        "enum": [
          "required",
          "invalid_format",
          "invalid_value",
          "out_of_range",
          "too_long",
          "invalid_tax_id",
          "mismatch"
        ],
        "description": "What is wrong with one field, in `error.details[]`.\n\n- `required`: A required field is missing or empty.\n- `invalid_format`: The value has the wrong format, such as a date that is not `YYYY-MM-DD` or money without two decimals.\n- `invalid_value`: The value is not allowed here, such as an unknown enum value or a voided original.\n- `out_of_range`: The value is too small or too large, such as a quantity of zero.\n- `too_long`: The text is longer than the limit.\n- `invalid_tax_id`: A Thai tax ID does not have 13 digits or its check digit is wrong.\n- `mismatch`: A figure differs from the one the API computed; see `expected` and `received`."
      },
      "Error": {
        "type": "object",
        "title": "Error",
        "description": "The body of every error response.",
        "properties": {
          "error": {
            "$ref": "#/components/schemas/ErrorObject",
            "description": "What went wrong.",
            "readOnly": true
          }
        }
      },
      "ErrorObject": {
        "type": "object",
        "title": "Error object",
        "description": "Details of an error. See [Errors and retries](https://slf-accounting.co/developers/reference#guide-errors).",
        "properties": {
          "code": {
            "type": "string",
            "description": "The error code, one of those listed under [Error codes](https://slf-accounting.co/developers/reference#errors). Stable; branch on this.",
            "readOnly": true,
            "examples": [
              "validation_failed"
            ]
          },
          "message": {
            "type": "string",
            "description": "A short explanation for people. It may change; do not parse it.",
            "readOnly": true
          },
          "param": {
            "type": [
              "string",
              "null"
            ],
            "description": "The field concerned, as a JSON Pointer into your request body, or `null`. A query parameter is written as `/` followed by its name, such as `/limit`. Format: JSON Pointer.",
            "readOnly": true,
            "examples": [
              "/lines/2/vat_category"
            ]
          },
          "details": {
            "type": [
              "array",
              "null"
            ],
            "items": {
              "$ref": "#/components/schemas/ErrorDetail"
            },
            "description": "For `validation_failed`, mismatch errors and `vat_category_unexplained`: one entry per problem. Empty otherwise.",
            "readOnly": true
          },
          "request_id": {
            "type": "string",
            "description": "The same value as the `Request-Id` header. Quote it when you contact SLF.",
            "maxLength": 64,
            "readOnly": true,
            "examples": [
              "req_3c9e1f7a2b5d8c04"
            ]
          },
          "existing_id": {
            "type": [
              "string",
              "null"
            ],
            "description": "For a 409 duplicate refusal (`duplicate_external_id`, `duplicate_number`, `customer_exists`, `duplicate_bill`), the id of the record already there, when it is one the API returns. `null` for a `duplicate_number` whose number belongs to a pro-forma document SLF recorded, for `recorded_by_slf` and `recorded_by_slf_posted`, and for every other error.",
            "readOnly": true,
            "examples": [
              "cus_7Hc4Nf2Pq9Xz"
            ]
          }
        }
      },
      "ErrorDetail": {
        "type": "object",
        "title": "Error detail",
        "description": "One problem found in a request.",
        "properties": {
          "param": {
            "type": "string",
            "description": "The field concerned, as a JSON Pointer into your request body. A query parameter is written as `/` followed by its name, such as `/limit` or `/cursor`. Format: JSON Pointer.",
            "readOnly": true,
            "examples": [
              "/tax_id"
            ]
          },
          "code": {
            "$ref": "#/components/schemas/error_detail_code",
            "description": "What is wrong with it.",
            "readOnly": true,
            "examples": [
              "invalid_tax_id"
            ]
          },
          "message": {
            "type": "string",
            "description": "A short explanation for people.",
            "readOnly": true
          },
          "expected": {
            "type": [
              "string",
              "null"
            ],
            "format": "decimal",
            "description": "Mismatch details only: the figure the API computed. `null` otherwise.",
            "readOnly": true,
            "examples": [
              "1326.66"
            ]
          },
          "received": {
            "type": [
              "string",
              "null"
            ],
            "format": "decimal",
            "description": "Mismatch details only: the figure you sent. `null` otherwise.",
            "readOnly": true,
            "examples": [
              "1431.66"
            ]
          }
        }
      },
      "Warning": {
        "type": "object",
        "title": "Warning",
        "description": "A note that a record was accepted but flagged for SLF to review. Warnings never block a record.",
        "properties": {
          "code": {
            "type": "string",
            "description": "The warning code, one of those listed under [Warning codes](https://slf-accounting.co/developers/reference#warnings).",
            "readOnly": true,
            "examples": [
              "zero_rated_review"
            ]
          },
          "message": {
            "type": "string",
            "description": "A short explanation for people.",
            "readOnly": true
          },
          "param": {
            "type": [
              "string",
              "null"
            ],
            "description": "The field concerned, or `null`. Format: JSON Pointer.",
            "readOnly": true,
            "examples": [
              "/lines/0/vat_category"
            ]
          }
        }
      },
      "Company": {
        "type": "object",
        "title": "Company",
        "description": "The company your key belongs to.",
        "properties": {
          "name": {
            "type": [
              "string",
              "null"
            ],
            "description": "The name SLF records for the company. It is not necessarily the registered name; SLF records the registered name in Thai as `name_local`.",
            "readOnly": true,
            "examples": [
              "Example Trading Co., Ltd."
            ]
          },
          "name_local": {
            "type": [
              "string",
              "null"
            ],
            "description": "The company's registered name in Thai, as SLF has it on record.",
            "readOnly": true,
            "examples": [
              "บริษัท ตัวอย่าง จำกัด"
            ]
          },
          "tax_id": {
            "type": [
              "string",
              "null"
            ],
            "description": "The company's tax ID. Format: 13 digits.",
            "readOnly": true,
            "examples": [
              "0999000000019"
            ]
          },
          "branch_no": {
            "type": [
              "string",
              "null"
            ],
            "description": "The branch number SLF has on record for the company the key belongs to. `00000` is the head office. Format: 5 digits.",
            "readOnly": true,
            "examples": [
              "00000"
            ]
          },
          "vat_registered": {
            "type": [
              "boolean",
              "null"
            ],
            "description": "The VAT setting of your company's profile at SLF: whether the company is VAT-registered, or `null` when the profile has no VAT setting. Someone at your company can also change it in the client portal. If `false`, every sales line's `vat_category` is recorded as `none`. Writes are refused with 403 `forbidden` unless this setting and SLF's own record of your VAT registration are both set and agree; send the refused records again once SLF tells you they agree.",
            "readOnly": true,
            "examples": [
              true
            ]
          }
        }
      },
      "BankAccount": {
        "type": "object",
        "title": "Bank account",
        "description": "A bank account of your company as SLF has recorded it.",
        "properties": {
          "id": {
            "type": [
              "string",
              "null"
            ],
            "description": "Use it as `bank_account_id`. Format: `bnk_` id.",
            "readOnly": true,
            "examples": [
              "bnk_5Qm2Rk8Lt3Vw"
            ]
          },
          "bank_name": {
            "type": [
              "string",
              "null"
            ],
            "description": "The bank, as SLF has recorded it for this account. It may also name the branch, such as `Example Bank, Main branch`.",
            "readOnly": true,
            "examples": [
              "Example Bank Public Company Limited"
            ]
          },
          "account_name": {
            "type": [
              "string",
              "null"
            ],
            "description": "The name the account is held in.",
            "readOnly": true,
            "examples": [
              "Example Trading Co., Ltd."
            ]
          },
          "account_number_last4": {
            "type": [
              "string",
              "null"
            ],
            "description": "The last four digits of the account number. The full number is never returned. Format: 4 digits.",
            "readOnly": true,
            "examples": [
              "4821"
            ]
          },
          "currency": {
            "type": [
              "string",
              "null"
            ],
            "description": "The account's currency. Format: ISO 4217.",
            "readOnly": true,
            "examples": [
              "THB"
            ]
          },
          "type": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/bank_account_type"
              },
              {
                "type": "null"
              }
            ],
            "description": "`personal` when SLF has recorded the account as held in a person's name; otherwise `null`, which does not say whose name the account is in (see `account_name`).",
            "readOnly": true,
            "examples": [
              "personal"
            ]
          }
        }
      },
      "Customer": {
        "type": "object",
        "title": "Customer",
        "description": "A customer your sales documents are issued to.",
        "properties": {
          "id": {
            "type": [
              "string",
              "null"
            ],
            "description": "SLF's id for the customer. Format: `cus_` id.",
            "readOnly": true,
            "examples": [
              "cus_7Hc4Nf2Pq9Xz"
            ]
          },
          "external_id": {
            "type": "string",
            "description": "Your system's id for the customer. Unique among your customers (`duplicate_external_id`). Required when you create the customer; `null` on customers SLF entered itself.",
            "maxLength": 100,
            "examples": [
              "CUST-00412"
            ]
          },
          "name": {
            "type": "string",
            "description": "The customer's name as printed on your documents.",
            "maxLength": 300,
            "examples": [
              "Sample Retail Co., Ltd."
            ]
          },
          "name_local": {
            "type": [
              "string",
              "null"
            ],
            "description": "The name in Thai, if different.",
            "maxLength": 300,
            "examples": [
              "บริษัท ตัวอย่างค้าปลีก จำกัด"
            ]
          },
          "country": {
            "type": [
              "string",
              "null"
            ],
            "description": "The customer's country. Thai tax-ID validation applies only when it is `TH`. Format: ISO 3166-1 alpha-2.",
            "default": "TH",
            "examples": [
              "TH"
            ]
          },
          "tax_id": {
            "type": [
              "string",
              "null"
            ],
            "description": "The customer's tax ID. For `TH`, 13 digits with a valid check digit (`invalid_tax_id`); for other countries, optional and not checked. Cannot change once set. Format: 13 digits when `country` is `TH`.",
            "examples": [
              "0999000000027"
            ]
          },
          "branch_no": {
            "type": [
              "string",
              "null"
            ],
            "description": "The customer's branch. `00000` is the head office. Defaults to `00000` when `country` is `TH` and `tax_id` is given; otherwise `null` unless you send it. Cannot change once set. Format: 5 digits.",
            "examples": [
              "00000"
            ]
          },
          "address": {
            "type": [
              "string",
              "null"
            ],
            "description": "The address printed on your documents.",
            "maxLength": 1000,
            "examples": [
              "88 Example Road, Pathum Wan, Bangkok 10330"
            ]
          },
          "email": {
            "type": [
              "string",
              "null"
            ],
            "description": "Billing email address.",
            "maxLength": 254,
            "examples": [
              "accounts@sample-retail.example"
            ]
          },
          "phone": {
            "type": [
              "string",
              "null"
            ],
            "description": "Phone number.",
            "maxLength": 50,
            "examples": [
              "+66 2 000 0000"
            ]
          },
          "notes": {
            "type": [
              "string",
              "null"
            ],
            "description": "Your notes about the customer.",
            "maxLength": 2000
          },
          "created_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "When the customer was created.",
            "readOnly": true,
            "examples": [
              "2026-10-15T09:12:44+07:00"
            ]
          }
        },
        "required": [
          "external_id",
          "name"
        ]
      },
      "CustomerUpdate": {
        "type": "object",
        "title": "Customer update",
        "description": "The fields `PATCH /customers/{id}` can change. Send only the fields you change.",
        "properties": {
          "name": {
            "type": [
              "string",
              "null"
            ],
            "description": "New name. Cannot be cleared.",
            "maxLength": 300
          },
          "name_local": {
            "type": [
              "string",
              "null"
            ],
            "description": "New name in Thai.",
            "maxLength": 300
          },
          "address": {
            "type": [
              "string",
              "null"
            ],
            "description": "New address.",
            "maxLength": 1000
          },
          "email": {
            "type": [
              "string",
              "null"
            ],
            "description": "New billing email address.",
            "maxLength": 254,
            "examples": [
              "ap@sample-retail.example"
            ]
          },
          "phone": {
            "type": [
              "string",
              "null"
            ],
            "description": "New phone number.",
            "maxLength": 50,
            "examples": [
              "+66 2 000 0001"
            ]
          },
          "notes": {
            "type": [
              "string",
              "null"
            ],
            "description": "New notes.",
            "maxLength": 2000
          },
          "tax_id": {
            "type": [
              "string",
              "null"
            ],
            "description": "Only while the customer has no tax ID yet. A different value once one is set is refused with `immutable_field`; a tax ID and branch already used by another customer with `customer_exists`. Format: 13 digits when `country` is `TH`."
          },
          "branch_no": {
            "type": [
              "string",
              "null"
            ],
            "description": "Only while the customer has no branch yet. A different value once one is set is refused with `immutable_field`. Defaults to `00000` when you add a Thai `tax_id` without it. Format: 5 digits."
          }
        }
      },
      "SalesDocument": {
        "type": "object",
        "title": "Sales document",
        "description": "A quotation, invoice, tax invoice, cash-sale tax invoice/receipt, credit note or debit note you issued, recorded as printed.",
        "properties": {
          "id": {
            "type": [
              "string",
              "null"
            ],
            "description": "SLF's id for the document. Format: `doc_` id.",
            "readOnly": true,
            "examples": [
              "doc_4Fp9Km2Qx7Ld"
            ]
          },
          "type": {
            "$ref": "#/components/schemas/sales_document_type",
            "description": "What kind of document it is.",
            "examples": [
              "invoice"
            ]
          },
          "external_id": {
            "type": "string",
            "description": "Your system's id for the document. Unique among your sales documents, voided ones included (`duplicate_external_id`). Required when you create the document; `null` on documents SLF entered itself.",
            "maxLength": 100,
            "examples": [
              "SO-2026-10-0187"
            ]
          },
          "number": {
            "type": "string",
            "description": "The number printed on the document, from your own system. It must be unique among your invoices, tax invoices, cash sales, credit notes and debit notes that are not voided, including pro-forma documents SLF recorded; quotations have their own numbers (`duplicate_number`). A tax invoice or cash sale that SLF already entered by hand under the same number and total is refused with `recorded_by_slf`. A voided document keeps its number on record. SLF does not number documents.",
            "maxLength": 40,
            "examples": [
              "INV-2026-0187"
            ]
          },
          "issue_date": {
            "type": "string",
            "format": "date",
            "description": "The date printed on the document. Not before your start date. For a `tax_invoice` or `tax_invoice_receipt`, also not after today in Thailand, and not before the VAT registration date SLF has on record for your company. Otherwise `validation_failed` (`out_of_range`).",
            "examples": [
              "2026-10-15"
            ]
          },
          "due_date": {
            "type": [
              "string",
              "null"
            ],
            "format": "date",
            "description": "For `invoice`, `tax_invoice` and `debit_note`: the payment due date. Not before `issue_date`.",
            "examples": [
              "2026-11-14"
            ]
          },
          "valid_until": {
            "type": [
              "string",
              "null"
            ],
            "format": "date",
            "description": "For `quotation`: the last day the quotation is valid. After it, `status` becomes `expired`, unless the quotation is `rejected` or `void`.",
            "examples": [
              "2026-11-30"
            ]
          },
          "customer_id": {
            "type": [
              "string",
              "null"
            ],
            "description": "The customer the document is issued to. Required unless `customer_external_id` is given.",
            "examples": [
              "cus_7Hc4Nf2Pq9Xz"
            ]
          },
          "customer_external_id": {
            "type": [
              "string",
              "null"
            ],
            "description": "Instead of `customer_id`: the `external_id` you gave the customer. Request only; responses always carry `customer_id`. Required unless `customer_id` is given.",
            "examples": [
              "CUST-00412"
            ]
          },
          "bill_to_address": {
            "type": [
              "string",
              "null"
            ],
            "description": "The buyer address printed on this document, if different from the customer's `address`.",
            "maxLength": 1000
          },
          "currency": {
            "type": [
              "string",
              "null"
            ],
            "description": "The document's currency. All amounts on the document are in it. A `tax_invoice`, `tax_invoice_receipt`, `credit_note` or `debit_note` in a currency other than THB is accepted only if SLF holds the Director-General's approval for your company (`foreign_currency_tax_invoice_not_allowed`; see [Tax notes](https://slf-accounting.co/developers/reference#guide-tax-notes)). For some companies SLF converts to THB for VAT at a rate of its own (`fx_basis_unavailable`; see [Conventions](https://slf-accounting.co/developers/reference#guide-conventions)). Format: ISO 4217.",
            "default": "THB",
            "examples": [
              "THB"
            ]
          },
          "fx_rate": {
            "type": [
              "string",
              "null"
            ],
            "format": "decimal",
            "description": "THB per one unit of `currency`, as used by your system (`fx_rate_required`). Required when `currency` is not `THB`. Format: up to 6 decimals.",
            "examples": [
              "32.4512"
            ]
          },
          "fx_date": {
            "type": [
              "string",
              "null"
            ],
            "format": "date",
            "description": "The date of `fx_rate`. Required when `currency` is not `THB`.",
            "examples": [
              "2026-10-27"
            ]
          },
          "payment_terms": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/payment_terms"
              },
              {
                "type": "null"
              }
            ],
            "description": "Trade payment terms printed on the document, if any.",
            "examples": [
              "tt"
            ]
          },
          "bank_account_id": {
            "type": [
              "string",
              "null"
            ],
            "description": "The bank account printed on the document for payment (a `bnk_` id from `GET /bank-accounts`).",
            "examples": [
              "bnk_5Qm2Rk8Lt3Vw"
            ]
          },
          "remark": {
            "type": [
              "string",
              "null"
            ],
            "description": "The remark printed on the document, as plain text.",
            "maxLength": 20000,
            "examples": [
              "Please pay by bank transfer within 30 days."
            ]
          },
          "reference": {
            "type": [
              "string",
              "null"
            ],
            "description": "Your own reference for grouping documents, such as a job, project or order number. It does not have to be printed on the document; several documents may share it, and lists can be filtered by it.",
            "maxLength": 60,
            "examples": [
              "PRJ-2026-031"
            ]
          },
          "related_invoice_id": {
            "type": [
              "string",
              "null"
            ],
            "description": "For a `tax_invoice` issued for an earlier `invoice` that has been paid in full (for example, where the tax invoice is issued when payment is received): that invoice's id. The invoice must be for the same customer and currency, fully paid by receipts already recorded, with no credit or debit note on it or on its receipts, and with no other tax invoice issued for it. This tax invoice's `total` and `vat_total` must equal what those receipts recorded (their `gross_amount` and `vat_amount`), and its `issue_date` may not be earlier than the invoice or its last payment. It books no VAT again (the receipts did), is returned with `status: paid`, and cannot be the original of a credit or debit note. Otherwise it is refused with `validation_failed` (`invalid_value` on `/related_invoice_id`)."
          },
          "replaces_id": {
            "type": [
              "string",
              "null"
            ],
            "description": "For a replacement tax invoice in a cancel-and-reissue: the id of the original it replaces. Its `issue_date` must equal the original's, and the original must be a `tax_invoice` or `tax_invoice_receipt` for the same customer that is not voided yet; otherwise `validation_failed` (`invalid_value`). See [Corrections](https://slf-accounting.co/developers/reference#guide-corrections).",
            "examples": [
              "doc_1Gh6Tc9Rw2Ne"
            ]
          },
          "original_document_ids": {
            "type": [
              "array",
              "null"
            ],
            "items": {
              "type": "string"
            },
            "description": "The originals the note adjusts, for the same customer and not voided (otherwise `validation_failed`, `invalid_value`). Each is a `tax_invoice` or `tax_invoice_receipt` (`doc_` id), or a receipt (`rcp_` id) recorded against an `invoice` whose lines carry VAT, which is the record that booked that sale's VAT; anything else is refused with `note_original_not_tax_invoice`. One note may cover more than one original (Order ป.80/2542, clause 4), but not tax invoices and receipts together; the note's value is then applied to the originals in the order listed, each up to the value still remaining on it. A note may not be dated before its originals. A note on a receipt changes no document's `outstanding`, and a credit note on a receipt is accepted only once that invoice is paid in full. Required for `credit_note` and `debit_note`.",
            "examples": [
              [
                "doc_9Rt3Vb6Nz1Hs"
              ]
            ]
          },
          "reason_code": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/credit_note_reason"
              },
              {
                "$ref": "#/components/schemas/debit_note_reason"
              },
              {
                "type": "null"
              }
            ],
            "description": "Why the value changed: a value of `credit_note_reason` for a credit note, of `debit_note_reason` for a debit note. Required for `credit_note` and `debit_note`.",
            "examples": [
              "goods_returned"
            ]
          },
          "reason_text": {
            "type": [
              "string",
              "null"
            ],
            "description": "The short explanation of the reason printed on the note. For `other_announced`, it must name the cause. Required for `credit_note` and `debit_note`.",
            "maxLength": 500,
            "examples": [
              "2 chairs returned: gas lift defective"
            ]
          },
          "original_value": {
            "type": [
              "string",
              "null"
            ],
            "format": "decimal",
            "description": "The total value before VAT shown on the original document or documents. Required for `credit_note` and `debit_note`.",
            "examples": [
              "29168.00"
            ]
          },
          "correct_value": {
            "type": [
              "string",
              "null"
            ],
            "format": "decimal",
            "description": "The correct value before VAT. The difference from `original_value` must equal the note's `subtotal` (`note_difference_mismatch`). Required for `credit_note` and `debit_note`.",
            "examples": [
              "24268.00"
            ]
          },
          "lines": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/SalesDocumentLine"
            },
            "description": "The lines as printed. For a credit or debit note: the change in value, as positive amounts. Format: 1 to 500 lines."
          },
          "totals": {
            "$ref": "#/components/schemas/DocumentTotals",
            "description": "The totals as printed. Checked against the lines (`totals_mismatch`)."
          },
          "attachments": {
            "type": [
              "array",
              "null"
            ],
            "items": {
              "$ref": "#/components/schemas/Attachment"
            },
            "description": "Files attached with `POST /attachments`.",
            "readOnly": true
          },
          "status": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/sales_document_status"
              },
              {
                "type": "null"
              }
            ],
            "description": "Payment or validity status.",
            "readOnly": true,
            "examples": [
              "open"
            ]
          },
          "paid_amount": {
            "type": [
              "string",
              "null"
            ],
            "format": "decimal",
            "description": "The sum of `gross_amount` of the receipts recorded against the document (cash received plus tax withheld). `0.00` for documents that cannot be receipted; equal to `total` for a `tax_invoice_receipt` and for a `tax_invoice` with `related_invoice_id`.",
            "readOnly": true,
            "examples": [
              "0.00"
            ]
          },
          "credited_amount": {
            "type": [
              "string",
              "null"
            ],
            "format": "decimal",
            "description": "What credit notes recorded against this document took off it, VAT included. `0.00` if none. Credit notes on a receipt are not counted here.",
            "readOnly": true,
            "examples": [
              "0.00"
            ]
          },
          "outstanding": {
            "type": [
              "string",
              "null"
            ],
            "format": "decimal",
            "description": "`total` minus `paid_amount` minus `credited_amount`, never below `0.00`. `0.00` for quotations, credit notes, voided documents and tax invoices with `related_invoice_id`. If credit notes take off more than is still owed, contact SLF about the refund; refunds are not recorded through the API in v1.",
            "readOnly": true,
            "examples": [
              "21778.91"
            ]
          },
          "voided_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "When the document was voided, or `null`.",
            "readOnly": true
          },
          "void_reason": {
            "type": [
              "string",
              "null"
            ],
            "description": "The `reason` given when voiding, or `null`.",
            "readOnly": true
          },
          "replaced_by_id": {
            "type": [
              "string",
              "null"
            ],
            "description": "For a voided tax invoice: the replacement's id, or `null`.",
            "readOnly": true,
            "examples": [
              "doc_8Jd2Sv6Wm4Pa"
            ]
          },
          "warnings": {
            "type": [
              "array",
              "null"
            ],
            "items": {
              "$ref": "#/components/schemas/Warning"
            },
            "description": "Points flagged for SLF review. See [Warnings and review](https://slf-accounting.co/developers/reference#guide-warnings).",
            "readOnly": true
          },
          "created_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "When the document was recorded.",
            "readOnly": true,
            "examples": [
              "2026-10-15T14:02:11+07:00"
            ]
          }
        },
        "required": [
          "type",
          "external_id",
          "number",
          "issue_date",
          "lines",
          "totals"
        ]
      },
      "SalesDocumentLine": {
        "type": "object",
        "title": "Sales document line",
        "description": "One line of a sales document, as printed.",
        "properties": {
          "name": {
            "type": "string",
            "description": "The item or service, as printed.",
            "maxLength": 300,
            "examples": [
              "Accounting system setup"
            ]
          },
          "description": {
            "type": [
              "string",
              "null"
            ],
            "description": "Further description printed under the name.",
            "maxLength": 1000
          },
          "quantity": {
            "type": "string",
            "format": "decimal",
            "description": "Quantity. Format: > 0, up to 4 decimals.",
            "examples": [
              "3"
            ]
          },
          "unit_price": {
            "type": "string",
            "format": "decimal",
            "description": "Price per unit: excluding VAT, or including VAT for `standard_incl`. Format: ≥ 0, 2 decimals.",
            "examples": [
              "2150.75"
            ]
          },
          "vat_category": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/vat_category"
              },
              {
                "type": "null"
              }
            ],
            "description": "How VAT applies to the line. If your company is not VAT-registered, it is recorded as `none` whatever you send (warning `vat_category_ignored`). A `disbursement` line must be `none` (`disbursement_vat_category`). If your company is VAT-registered, a `none` line that is not a `disbursement` billed to the customer is counted in `unclassified_value` until SLF classifies it, and a document in which no line carries VAT or is `zero`, `exempt` or such a disbursement is refused (`vat_category_unexplained`).",
            "default": "standard",
            "examples": [
              "standard"
            ]
          },
          "wht_rate": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/wht_rate"
              },
              {
                "type": "null"
              }
            ],
            "description": "The rate your customer is expected to withhold from this line. It also caps the tax a receipt can record as withheld (`wht_exceeds_expected`), and a recorded document cannot be edited, so set it whenever your customer may withhold.",
            "default": "0",
            "examples": [
              "3"
            ]
          },
          "item_code": {
            "type": [
              "string",
              "null"
            ],
            "description": "Your product or service code. SLF maps your codes to accounts in your books. A code SLF has not mapped yet is not refused; SLF maps it when it reviews the document.",
            "maxLength": 50,
            "examples": [
              "SVC-SUPPORT"
            ]
          },
          "account_code": {
            "type": [
              "string",
              "null"
            ],
            "description": "An active income account code from your company's chart of accounts at SLF. Any other code is refused (`account_code_unknown`). SLF gives you the codes you may use; there is no chart-of-accounts endpoint in v1. Usually left out, and SLF maps `item_code` instead.",
            "maxLength": 20
          },
          "charge_role": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/charge_role"
              },
              {
                "type": "null"
              }
            ],
            "description": "Whether the line is your own supply or a disbursement recovered from the customer. There is no default: if you leave it out, the line's role is recorded as not stated and returned as `null`. It matters for lines with `vat_category: none`: only a `disbursement` billed to the customer is counted in `out_of_scope_value`; for a VAT-registered company, any other `none` line is counted as unclassified until SLF classifies it.",
            "examples": [
              "own_supply"
            ]
          },
          "supplier_invoice_billed_to": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/supplier_invoice_billed_to"
              },
              {
                "type": "null"
              }
            ],
            "description": "Who the supplier's document for the cost is addressed to. Required when `charge_role` is `disbursement`.",
            "examples": [
              "customer"
            ]
          },
          "pass_through_cost": {
            "type": [
              "string",
              "null"
            ],
            "format": "decimal",
            "description": "The amount you paid on the customer's behalf. A line whose amount is above it is refused with `disbursement_marked_up`: show the cost as the `disbursement` line and the difference as a separate `own_supply` line. For a company that is not VAT-registered, or a document in a currency other than THB, such a line is recorded as sent and flagged with the warning `disbursement_marked_up` instead. Required when `charge_role` is `disbursement`.",
            "examples": [
              "1500.00"
            ]
          },
          "pre_vat_amount": {
            "type": [
              "string",
              "null"
            ],
            "format": "decimal",
            "description": "The line's value before VAT, as computed by the API. When a VAT difference is put on a `standard_incl` line, that line's pre-VAT amount moves by the opposite amount, so its gross stays the same (see [How the API checks totals](https://slf-accounting.co/developers/reference#guide-conventions)).",
            "readOnly": true,
            "examples": [
              "6452.25"
            ]
          },
          "vat_rate": {
            "type": [
              "string",
              "null"
            ],
            "description": "The VAT rate applied, following `vat_category`: `7` for `standard` and `standard_incl`, `0` otherwise. Format: percentage.",
            "readOnly": true,
            "examples": [
              "7"
            ]
          },
          "vat_amount": {
            "type": [
              "string",
              "null"
            ],
            "format": "decimal",
            "description": "The line's VAT, as computed by the API. The last line that carries VAT also takes any difference between that sum and your printed `vat_total` (see [How the API checks totals](https://slf-accounting.co/developers/reference#guide-conventions)).",
            "readOnly": true,
            "examples": [
              "451.66"
            ]
          },
          "wht_amount": {
            "type": [
              "string",
              "null"
            ],
            "format": "decimal",
            "description": "`round2(pre_vat_amount × wht_rate / 100)`.",
            "readOnly": true,
            "examples": [
              "193.57"
            ]
          }
        },
        "required": [
          "name",
          "quantity",
          "unit_price"
        ]
      },
      "DocumentTotals": {
        "type": "object",
        "title": "Document totals",
        "description": "The totals printed on a sales document. The API computes its own from the lines and checks yours against them; see [How the API checks totals](https://slf-accounting.co/developers/reference#guide-conventions).",
        "properties": {
          "subtotal": {
            "type": "string",
            "format": "decimal",
            "description": "Sum of the lines' pre-VAT amounts, all VAT categories.",
            "examples": [
              "20452.25"
            ]
          },
          "vat_total": {
            "type": "string",
            "format": "decimal",
            "description": "Sum of the lines' VAT, as printed. Within 0.01 per line that carries VAT of the API's own sum, this figure is recorded; the difference goes on the last line that carries VAT.",
            "examples": [
              "1326.66"
            ]
          },
          "total": {
            "type": "string",
            "format": "decimal",
            "description": "`subtotal` plus `vat_total`.",
            "examples": [
              "21778.91"
            ]
          },
          "wht_total": {
            "type": [
              "string",
              "null"
            ],
            "format": "decimal",
            "description": "Sum of the lines' withholding tax, if printed.",
            "examples": [
              "568.57"
            ]
          },
          "net_to_pay": {
            "type": [
              "string",
              "null"
            ],
            "format": "decimal",
            "description": "`total` minus `wht_total`, if printed.",
            "examples": [
              "21210.34"
            ]
          }
        },
        "required": [
          "subtotal",
          "vat_total",
          "total"
        ]
      },
      "SalesDocumentVoidRequest": {
        "type": "object",
        "title": "Void request (sales document)",
        "description": "The body of `POST /sales-documents/{id}/void`.",
        "properties": {
          "reason": {
            "type": "string",
            "description": "Why the document is voided.",
            "maxLength": 500,
            "examples": [
              "Buyer's address was wrong. Replaced by TIV-2026-0415."
            ]
          },
          "replacement_id": {
            "type": [
              "string",
              "null"
            ],
            "description": "When a tax invoice is cancelled and reissued: the id of the replacement, recorded first with `replaces_id` set to this document.",
            "examples": [
              "doc_8Jd2Sv6Wm4Pa"
            ]
          }
        },
        "required": [
          "reason"
        ]
      },
      "Receipt": {
        "type": "object",
        "title": "Receipt",
        "description": "A payment received from a customer against an invoice, tax invoice or debit note.",
        "properties": {
          "id": {
            "type": [
              "string",
              "null"
            ],
            "description": "SLF's id for the receipt. Format: `rcp_` id.",
            "readOnly": true,
            "examples": [
              "rcp_3Np8Gz5Kd1Vt"
            ]
          },
          "external_id": {
            "type": "string",
            "description": "Your system's id for the receipt. Unique among your receipts, voided ones included (`duplicate_external_id`). Required when you create the receipt; `null` on receipts SLF entered itself.",
            "maxLength": 100,
            "examples": [
              "RCV-2026-10-0233"
            ]
          },
          "number": {
            "type": "string",
            "description": "Your receipt number, as printed. Unique among your receipts that are not voided (`duplicate_number`).",
            "maxLength": 40,
            "examples": [
              "RE-2026-0233"
            ]
          },
          "document_id": {
            "type": "string",
            "description": "The `invoice`, `tax_invoice` or `debit_note` being paid.",
            "examples": [
              "doc_4Fp9Km2Qx7Ld"
            ]
          },
          "payment_date": {
            "type": "string",
            "format": "date",
            "description": "The date the money arrived. Not after today in Thailand, and not before your start date (`validation_failed`, `out_of_range`).",
            "examples": [
              "2026-10-30"
            ]
          },
          "amount_received": {
            "type": "string",
            "format": "decimal",
            "description": "The money that arrived, in the document's currency.",
            "examples": [
              "21210.34"
            ]
          },
          "wht_amount": {
            "type": [
              "string",
              "null"
            ],
            "format": "decimal",
            "description": "Tax the customer withheld from this payment. Not more than the withholding still expected from the document's lines (`wht_exceeds_expected`).",
            "default": "0.00",
            "examples": [
              "568.57"
            ]
          },
          "bank_account_id": {
            "type": [
              "string",
              "null"
            ],
            "description": "The account the money arrived in.",
            "examples": [
              "bnk_5Qm2Rk8Lt3Vw"
            ]
          },
          "remark": {
            "type": [
              "string",
              "null"
            ],
            "description": "Your remark, as plain text. Stored as you sent it: a short payment is flagged with the warning `short_payment`, not written into the remark.",
            "maxLength": 20000
          },
          "gross_amount": {
            "type": [
              "string",
              "null"
            ],
            "format": "decimal",
            "description": "`amount_received` plus `wht_amount`. This is what reduces the document's `outstanding`.",
            "readOnly": true,
            "examples": [
              "21778.91"
            ]
          },
          "vat_amount": {
            "type": [
              "string",
              "null"
            ],
            "format": "decimal",
            "description": "The VAT this payment booked: `round2(vat_total × gross_amount / total)` of the document, halves rounded up, where `vat_total` is the VAT recorded for the document (as printed; see [How the API checks totals](https://slf-accounting.co/developers/reference#guide-conventions)). The receipt that brings the document's `outstanding` to `0.00` takes the document's `vat_total` less the VAT of its earlier receipts, so the shares add up. `0.00` for a receipt against a `tax_invoice` or `debit_note`, whose VAT that document booked.",
            "readOnly": true,
            "examples": [
              "1326.66"
            ]
          },
          "currency": {
            "type": [
              "string",
              "null"
            ],
            "description": "Taken from the document. Format: ISO 4217.",
            "readOnly": true,
            "examples": [
              "THB"
            ]
          },
          "fx_rate": {
            "type": [
              "string",
              "null"
            ],
            "format": "decimal",
            "description": "Taken from the document; `null` for THB.",
            "readOnly": true
          },
          "attachments": {
            "type": [
              "array",
              "null"
            ],
            "items": {
              "$ref": "#/components/schemas/Attachment"
            },
            "description": "Files attached with `POST /attachments`.",
            "readOnly": true
          },
          "warnings": {
            "type": [
              "array",
              "null"
            ],
            "items": {
              "$ref": "#/components/schemas/Warning"
            },
            "description": "Points flagged for SLF review, such as `wht_rate_review` or `short_payment`.",
            "readOnly": true
          },
          "voided_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "When the receipt was voided, or `null`.",
            "readOnly": true
          },
          "void_reason": {
            "type": [
              "string",
              "null"
            ],
            "description": "The `reason` given when voiding, or `null`.",
            "readOnly": true
          },
          "created_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "When the receipt was recorded.",
            "readOnly": true,
            "examples": [
              "2026-10-30T17:08:26+07:00"
            ]
          }
        },
        "required": [
          "external_id",
          "number",
          "document_id",
          "payment_date",
          "amount_received"
        ]
      },
      "VoidRequest": {
        "type": "object",
        "title": "Void or reverse request",
        "description": "The body of `POST /receipts/{id}/void`, `POST /bills/{id}/void` and `POST /payments/{id}/reverse`.",
        "properties": {
          "reason": {
            "type": "string",
            "description": "Why the record is voided or reversed.",
            "maxLength": 500,
            "examples": [
              "Recorded against the wrong invoice."
            ]
          }
        },
        "required": [
          "reason"
        ]
      },
      "Bill": {
        "type": "object",
        "title": "Supplier bill",
        "description": "A document you received from a supplier, with amounts typed as printed.",
        "properties": {
          "id": {
            "type": [
              "string",
              "null"
            ],
            "description": "SLF's id for the bill. Format: `bil_` id.",
            "readOnly": true,
            "examples": [
              "bil_5Tg9Hw2Lr6Mx"
            ]
          },
          "external_id": {
            "type": "string",
            "description": "Your system's id for the bill. Unique among your bills, voided ones included (`duplicate_external_id`). Required when you create the bill; `null` on bills SLF entered itself.",
            "maxLength": 100,
            "examples": [
              "AP-2026-10-0058"
            ]
          },
          "document_type": {
            "$ref": "#/components/schemas/bill_document_type",
            "description": "What the supplier gave you.",
            "examples": [
              "tax_invoice"
            ]
          },
          "supplier": {
            "$ref": "#/components/schemas/Supplier",
            "description": "The supplier, as printed on the document."
          },
          "bill_number": {
            "type": "string",
            "description": "The supplier's document number.",
            "maxLength": 40,
            "examples": [
              "DS-2610-0058"
            ]
          },
          "bill_date": {
            "type": "string",
            "format": "date",
            "description": "The date printed on the supplier's document.",
            "examples": [
              "2026-10-25"
            ]
          },
          "due_date": {
            "type": [
              "string",
              "null"
            ],
            "format": "date",
            "description": "When the bill is due.",
            "examples": [
              "2026-11-24"
            ]
          },
          "currency": {
            "type": [
              "string",
              "null"
            ],
            "description": "The bill's currency. Format: ISO 4217.",
            "default": "THB",
            "examples": [
              "THB"
            ]
          },
          "fx_rate": {
            "type": [
              "string",
              "null"
            ],
            "format": "decimal",
            "description": "THB per one unit of `currency` (`fx_rate_required`). Required when `currency` is not `THB`. Format: up to 6 decimals."
          },
          "fx_date": {
            "type": [
              "string",
              "null"
            ],
            "format": "date",
            "description": "The date of `fx_rate`. Required when `currency` is not `THB`."
          },
          "subtotal": {
            "type": "string",
            "format": "decimal",
            "description": "Value before VAT, as printed.",
            "examples": [
              "15000.00"
            ]
          },
          "vat_amount": {
            "type": "string",
            "format": "decimal",
            "description": "VAT as printed; `0.00` if none.",
            "examples": [
              "1050.00"
            ]
          },
          "total": {
            "type": "string",
            "format": "decimal",
            "description": "Total as printed. Must equal `subtotal` plus `vat_amount` (`totals_mismatch`).",
            "examples": [
              "16050.00"
            ]
          },
          "lines": {
            "type": [
              "array",
              "null"
            ],
            "items": {
              "$ref": "#/components/schemas/BillLine"
            },
            "description": "The bill's lines, if you have them. They help SLF classify the cost. Format: 0 to 500 lines."
          },
          "on_behalf_of_customer_id": {
            "type": [
              "string",
              "null"
            ],
            "description": "When the bill is a cost you paid on a customer's behalf and is addressed to that customer (the cost side of a disbursement): that customer's id."
          },
          "remark": {
            "type": [
              "string",
              "null"
            ],
            "description": "Your remark, as plain text.",
            "maxLength": 20000
          },
          "reference": {
            "type": [
              "string",
              "null"
            ],
            "description": "Your own reference for grouping documents, such as a job, project or order number. It does not have to be printed on the document; several documents may share it, and lists can be filtered by it. Use the same value as on the sales documents it belongs with to see income and costs together.",
            "maxLength": 60,
            "examples": [
              "PRJ-2026-031"
            ]
          },
          "status": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/bill_status"
              },
              {
                "type": "null"
              }
            ],
            "description": "Payment status.",
            "readOnly": true,
            "examples": [
              "open"
            ]
          },
          "paid_amount": {
            "type": [
              "string",
              "null"
            ],
            "format": "decimal",
            "description": "Cash paid plus tax withheld, from payment allocations to this bill.",
            "readOnly": true,
            "examples": [
              "0.00"
            ]
          },
          "outstanding": {
            "type": [
              "string",
              "null"
            ],
            "format": "decimal",
            "description": "`total` minus `paid_amount`, less supplier credit notes and plus supplier debit notes recorded against the bill.",
            "readOnly": true,
            "examples": [
              "16050.00"
            ]
          },
          "notes": {
            "type": [
              "array",
              "null"
            ],
            "items": {
              "$ref": "#/components/schemas/BillNote"
            },
            "description": "Supplier credit and debit notes recorded against the bill.",
            "readOnly": true
          },
          "attachments": {
            "type": [
              "array",
              "null"
            ],
            "items": {
              "$ref": "#/components/schemas/Attachment"
            },
            "description": "Files attached with `POST /attachments`.",
            "readOnly": true
          },
          "voided_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "When the bill was voided, or `null`.",
            "readOnly": true
          },
          "void_reason": {
            "type": [
              "string",
              "null"
            ],
            "description": "The `reason` given when voiding, or `null`.",
            "readOnly": true
          },
          "created_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "When the bill was recorded.",
            "readOnly": true,
            "examples": [
              "2026-10-26T09:41:15+07:00"
            ]
          }
        },
        "required": [
          "external_id",
          "document_type",
          "supplier",
          "bill_number",
          "bill_date",
          "subtotal",
          "vat_amount",
          "total"
        ]
      },
      "Supplier": {
        "type": "object",
        "title": "Supplier",
        "description": "The supplier as printed on a bill. Suppliers are not a separate resource in v1.",
        "properties": {
          "name": {
            "type": "string",
            "description": "The supplier's name.",
            "maxLength": 300,
            "examples": [
              "Demo Services Co., Ltd."
            ]
          },
          "tax_id": {
            "type": [
              "string",
              "null"
            ],
            "description": "The supplier's tax ID. For `TH`, the check digit is validated (`invalid_tax_id`). Together with `bill_number` it identifies the bill (`duplicate_bill`); without a tax ID, the supplier's `name` and `bill_number` identify it. Format: 13 digits when `country` is `TH`.",
            "examples": [
              "0999000000035"
            ]
          },
          "branch_no": {
            "type": [
              "string",
              "null"
            ],
            "description": "The supplier's branch, as printed. `00000` is the head office. Format: 5 digits.",
            "examples": [
              "00000"
            ]
          },
          "country": {
            "type": [
              "string",
              "null"
            ],
            "description": "The supplier's country. Format: ISO 3166-1 alpha-2.",
            "default": "TH",
            "examples": [
              "TH"
            ]
          }
        },
        "required": [
          "name"
        ]
      },
      "BillLine": {
        "type": "object",
        "title": "Supplier bill line",
        "description": "One line of a supplier's document. Line amounts are not added up against the bill's header.",
        "properties": {
          "description": {
            "type": "string",
            "description": "The line as printed.",
            "maxLength": 1000,
            "examples": [
              "IT support, October 2026"
            ]
          },
          "quantity": {
            "type": [
              "string",
              "null"
            ],
            "format": "decimal",
            "description": "Quantity. Format: > 0, up to 4 decimals.",
            "examples": [
              "1"
            ]
          },
          "unit_price": {
            "type": [
              "string",
              "null"
            ],
            "format": "decimal",
            "description": "Price per unit. Format: ≥ 0.",
            "examples": [
              "15000.00"
            ]
          },
          "amount": {
            "type": "string",
            "format": "decimal",
            "description": "The line amount as printed.",
            "examples": [
              "15000.00"
            ]
          },
          "item_code": {
            "type": [
              "string",
              "null"
            ],
            "description": "The supplier's item code, if printed. SLF maps it to an account.",
            "maxLength": 50,
            "examples": [
              "DS-ITS-01"
            ]
          },
          "account_code": {
            "type": [
              "string",
              "null"
            ],
            "description": "An active account code from your company's chart of accounts at SLF (`account_code_unknown`). SLF gives you the codes you may use. Usually left out.",
            "maxLength": 20
          }
        },
        "required": [
          "description",
          "amount"
        ]
      },
      "BillNote": {
        "type": "object",
        "title": "Supplier adjustment note",
        "description": "A credit or debit note your supplier issued against a bill.",
        "properties": {
          "id": {
            "type": [
              "string",
              "null"
            ],
            "description": "SLF's id for the note. Format: `bnt_` id.",
            "readOnly": true,
            "examples": [
              "bnt_1Qz6Ck3Pv8Ys"
            ]
          },
          "bill_id": {
            "type": [
              "string",
              "null"
            ],
            "description": "The bill the note adjusts (from the path).",
            "readOnly": true,
            "examples": [
              "bil_2Cw8Np4Vs7Kf"
            ]
          },
          "external_id": {
            "type": "string",
            "description": "Your system's id for the note. Unique among your supplier notes (`duplicate_external_id`). Required when you create the note; `null` on notes SLF entered itself.",
            "maxLength": 100,
            "examples": [
              "AP-CN-2026-11-0007"
            ]
          },
          "type": {
            "$ref": "#/components/schemas/bill_note_type",
            "description": "Credit or debit note.",
            "examples": [
              "credit_note"
            ]
          },
          "number": {
            "type": "string",
            "description": "The supplier's note number.",
            "maxLength": 40,
            "examples": [
              "DS-CN-0007"
            ]
          },
          "date": {
            "type": "string",
            "format": "date",
            "description": "The date printed on the note.",
            "examples": [
              "2026-11-02"
            ]
          },
          "amount": {
            "type": "string",
            "format": "decimal",
            "description": "The change in value before VAT, as printed.",
            "examples": [
              "1000.00"
            ]
          },
          "vat_amount": {
            "type": "string",
            "format": "decimal",
            "description": "The VAT on that change, as printed; `0.00` if none.",
            "examples": [
              "70.00"
            ]
          },
          "reason": {
            "type": "string",
            "description": "The supplier's reason, as free text.",
            "maxLength": 500,
            "examples": [
              "Two support visits were not provided"
            ]
          },
          "created_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "When the note was recorded.",
            "readOnly": true,
            "examples": [
              "2026-11-02T14:22:40+07:00"
            ]
          }
        },
        "required": [
          "external_id",
          "type",
          "number",
          "date",
          "amount",
          "vat_amount",
          "reason"
        ]
      },
      "Payment": {
        "type": "object",
        "title": "Supplier payment",
        "description": "A payment you made to suppliers, allocated to bills, with any tax you withheld.",
        "properties": {
          "id": {
            "type": [
              "string",
              "null"
            ],
            "description": "SLF's id for the payment. Format: `pay_` id.",
            "readOnly": true,
            "examples": [
              "pay_7Mv4Ys1Jn9Bc"
            ]
          },
          "external_id": {
            "type": "string",
            "description": "Your system's id for the payment. Unique among your payments, reversed ones included (`duplicate_external_id`). Required when you create the payment; `null` on payments SLF entered itself.",
            "maxLength": 100,
            "examples": [
              "AP-PAY-2026-10-0031"
            ]
          },
          "pay_date": {
            "type": "string",
            "format": "date",
            "description": "The date you paid.",
            "examples": [
              "2026-10-31"
            ]
          },
          "method": {
            "$ref": "#/components/schemas/payment_method",
            "description": "How you paid.",
            "examples": [
              "transfer"
            ]
          },
          "bank_account_id": {
            "type": [
              "string",
              "null"
            ],
            "description": "The account you paid from. Required unless `method` is `cash`.",
            "examples": [
              "bnk_5Qm2Rk8Lt3Vw"
            ]
          },
          "reference": {
            "type": [
              "string",
              "null"
            ],
            "description": "The bank transfer or cheque reference.",
            "maxLength": 100,
            "examples": [
              "TRF-20261031-0007"
            ]
          },
          "allocations": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PaymentAllocation"
            },
            "description": "The bills this payment settles. Format: 1 to 100."
          },
          "withholding": {
            "type": [
              "array",
              "null"
            ],
            "items": {
              "$ref": "#/components/schemas/WithholdingEntry"
            },
            "description": "The tax you withheld, one entry per payee and income type, as on your 50 ทวิ certificate. The sum of `wht_amount` must equal the sum over `allocations` (`withholding_mismatch`). Required when any `allocations[].wht_amount` is above zero. Format: up to 50."
          },
          "attachments": {
            "type": [
              "array",
              "null"
            ],
            "items": {
              "$ref": "#/components/schemas/Attachment"
            },
            "description": "Files attached with `POST /attachments`.",
            "readOnly": true
          },
          "state": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/payment_state"
              },
              {
                "type": "null"
              }
            ],
            "description": "Whether the payment stands or was reversed.",
            "readOnly": true,
            "examples": [
              "recorded"
            ]
          },
          "reversed_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "When the payment was reversed, or `null`.",
            "readOnly": true
          },
          "reverse_reason": {
            "type": [
              "string",
              "null"
            ],
            "description": "The `reason` given when reversing, or `null`.",
            "readOnly": true
          },
          "created_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "When the payment was recorded.",
            "readOnly": true,
            "examples": [
              "2026-10-31T16:55:02+07:00"
            ]
          }
        },
        "required": [
          "external_id",
          "pay_date",
          "method",
          "allocations"
        ]
      },
      "PaymentAllocation": {
        "type": "object",
        "title": "Payment allocation",
        "description": "The part of a payment that settles one bill.",
        "properties": {
          "bill_id": {
            "type": "string",
            "description": "The bill.",
            "examples": [
              "bil_5Tg9Hw2Lr6Mx"
            ]
          },
          "amount": {
            "type": "string",
            "format": "decimal",
            "description": "The cash paid towards this bill, in the bill's currency.",
            "examples": [
              "15600.00"
            ]
          },
          "wht_amount": {
            "type": [
              "string",
              "null"
            ],
            "format": "decimal",
            "description": "The tax you withheld from this bill's payment. `amount` plus `wht_amount` may not exceed the bill's `outstanding`. Above zero only for a bill in THB.",
            "default": "0.00",
            "examples": [
              "450.00"
            ]
          }
        },
        "required": [
          "bill_id",
          "amount"
        ]
      },
      "WithholdingEntry": {
        "type": "object",
        "title": "Withholding entry",
        "description": "Tax you withheld from one payee for one income type, as on the withholding tax certificate (50 ทวิ). The API does not say which rate applies to which income; SLF reviews the rates.",
        "properties": {
          "payee_name": {
            "type": "string",
            "description": "The payee's name.",
            "maxLength": 300,
            "examples": [
              "Demo Services Co., Ltd."
            ]
          },
          "payee_tax_id": {
            "type": "string",
            "description": "The payee's tax ID, with a valid check digit (`invalid_tax_id`). Format: 13 digits.",
            "examples": [
              "0999000000035"
            ]
          },
          "payee_branch_no": {
            "type": [
              "string",
              "null"
            ],
            "description": "The payee's branch. `00000` is the head office. Format: 5 digits.",
            "default": "00000",
            "examples": [
              "00000"
            ]
          },
          "payee_address": {
            "type": [
              "string",
              "null"
            ],
            "description": "The payee's address, as on the certificate.",
            "maxLength": 1000,
            "examples": [
              "1 Example Road, Khlong Toei, Bangkok 10110"
            ]
          },
          "payee_type": {
            "$ref": "#/components/schemas/payee_type",
            "description": "Individual or company. `return_form` is set from it, and SLF confirms the return on review.",
            "examples": [
              "company"
            ]
          },
          "income_type": {
            "$ref": "#/components/schemas/income_type",
            "description": "The kind of payment the tax was withheld from.",
            "examples": [
              "service"
            ]
          },
          "income_description": {
            "type": [
              "string",
              "null"
            ],
            "description": "What the payment was for. Required when `income_type` is `other`.",
            "maxLength": 300
          },
          "gross_amount": {
            "type": "string",
            "format": "decimal",
            "description": "The amount the tax was computed on, in THB.",
            "examples": [
              "15000.00"
            ]
          },
          "rate": {
            "$ref": "#/components/schemas/wht_rate",
            "description": "The rate you actually withheld.",
            "examples": [
              "3"
            ]
          },
          "wht_amount": {
            "type": "string",
            "format": "decimal",
            "description": "The tax withheld, in THB. Must equal `round2(gross_amount × rate / 100)` (`totals_mismatch`).",
            "examples": [
              "450.00"
            ]
          },
          "certificate_number": {
            "type": [
              "string",
              "null"
            ],
            "description": "The number of the 50 ทวิ certificate, if you issued it yourself.",
            "maxLength": 40,
            "examples": [
              "WHT-2026-0101"
            ]
          },
          "return_form": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/return_form"
              },
              {
                "type": "null"
              }
            ],
            "description": "The return SLF expects the tax to be reported on, set from `payee_type`; SLF confirms it on review (see [Tax notes](https://slf-accounting.co/developers/reference#guide-tax-notes)).",
            "readOnly": true,
            "examples": [
              "pnd53"
            ]
          }
        },
        "required": [
          "payee_name",
          "payee_tax_id",
          "payee_type",
          "income_type",
          "gross_amount",
          "rate",
          "wht_amount"
        ]
      },
      "Attachment": {
        "type": "object",
        "title": "Attachment",
        "description": "A file attached through the API to a sales document or receipt, or, from the second release, to a bill or payment.",
        "properties": {
          "id": {
            "type": [
              "string",
              "null"
            ],
            "description": "SLF's id for the attachment. Format: `att_` id.",
            "readOnly": true,
            "examples": [
              "att_2Bh5Rx8Fk3Wq"
            ]
          },
          "object_type": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/attachment_object_type"
              },
              {
                "type": "null"
              }
            ],
            "description": "The kind of record it is attached to.",
            "readOnly": true,
            "examples": [
              "sales_document"
            ]
          },
          "object_id": {
            "type": [
              "string",
              "null"
            ],
            "description": "The record's id.",
            "readOnly": true,
            "examples": [
              "doc_9Rt3Vb6Nz1Hs"
            ]
          },
          "kind": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/attachment_kind"
              },
              {
                "type": "null"
              }
            ],
            "description": "What the file is.",
            "readOnly": true,
            "examples": [
              "document_copy"
            ]
          },
          "file_name": {
            "type": [
              "string",
              "null"
            ],
            "description": "The file name you uploaded.",
            "readOnly": true,
            "examples": [
              "TIV-2026-0412.pdf"
            ]
          },
          "content_type": {
            "type": [
              "string",
              "null"
            ],
            "description": "The file's media type, as recognised from its content.",
            "readOnly": true,
            "examples": [
              "application/pdf"
            ]
          },
          "size": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Size in bytes.",
            "readOnly": true,
            "examples": [
              184233
            ]
          },
          "sha256": {
            "type": [
              "string",
              "null"
            ],
            "description": "SHA-256 of the file. The same file on the same record is stored once. Format: 64 hex characters.",
            "readOnly": true
          },
          "created_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "When the file was uploaded.",
            "readOnly": true,
            "examples": [
              "2026-10-08T11:05:37+07:00"
            ]
          }
        }
      },
      "AttachmentUpload": {
        "type": "object",
        "title": "Attachment upload",
        "description": "The `multipart/form-data` fields of `POST /attachments`. Other form fields are ignored.",
        "properties": {
          "file": {
            "type": "string",
            "format": "binary",
            "contentMediaType": "application/octet-stream",
            "description": "The file, with its file name. One file per request. Its type is read from its content; HEIC is not accepted. Format: binary; PDF, JPEG, PNG or WebP; ≤ 10 MB."
          },
          "object_type": {
            "$ref": "#/components/schemas/attachment_object_type",
            "description": "The kind of record to attach it to.",
            "examples": [
              "sales_document"
            ]
          },
          "object_id": {
            "type": "string",
            "description": "The record's id (`reference_not_found` if it does not exist). A voided record takes no new attachments (`validation_failed`, `invalid_value`).",
            "examples": [
              "doc_9Rt3Vb6Nz1Hs"
            ]
          },
          "kind": {
            "$ref": "#/components/schemas/attachment_kind",
            "description": "What the file is.",
            "examples": [
              "document_copy"
            ]
          }
        },
        "required": [
          "file",
          "object_type",
          "object_id",
          "kind"
        ]
      },
      "Period": {
        "type": "object",
        "title": "Period",
        "description": "A month's figures as SLF has recorded them. All amounts are in THB. For a company that is not VAT-registered, every VAT figure (`sales`, `purchases`, `out_of_scope_value`, `quarantined`) is zero.",
        "properties": {
          "month": {
            "type": [
              "string",
              "null"
            ],
            "description": "The month. Format: YYYY-MM.",
            "readOnly": true,
            "examples": [
              "2026-09"
            ]
          },
          "status": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/period_status"
              },
              {
                "type": "null"
              }
            ],
            "description": "Whether the month is open, VAT-filed or closed.",
            "readOnly": true,
            "examples": [
              "vat_filed"
            ]
          },
          "filings": {
            "type": [
              "array",
              "null"
            ],
            "items": {
              "$ref": "#/components/schemas/PeriodFiling"
            },
            "description": "Which of the month's returns SLF has filed.",
            "readOnly": true
          },
          "sales": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/PeriodSales"
              },
              {
                "type": "null"
              }
            ],
            "description": "Sales recorded for VAT in the month.",
            "readOnly": true
          },
          "purchases": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/PeriodPurchases"
              },
              {
                "type": "null"
              }
            ],
            "description": "Purchases recorded for VAT in the month.",
            "readOnly": true
          },
          "out_of_scope_value": {
            "type": [
              "string",
              "null"
            ],
            "format": "decimal",
            "description": "Disbursements recovered from customers in the month: `disbursement` lines billed to the customer. Not included in `sales`.",
            "readOnly": true,
            "examples": [
              "12750.00"
            ]
          },
          "quarantined": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/PeriodQuarantined"
              },
              {
                "type": "null"
              }
            ],
            "description": "Sales records of the month held back by SLF's arithmetic check until SLF resolves them. Not included in `sales`.",
            "readOnly": true
          },
          "withholding": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/PeriodWithholding"
              },
              {
                "type": "null"
              }
            ],
            "description": "Tax you withheld from supplier payments in the month.",
            "readOnly": true
          }
        }
      },
      "PeriodFiling": {
        "type": "object",
        "title": "Period filing",
        "description": "One return for the month and whether SLF has filed it.",
        "properties": {
          "form": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/filing_form"
              },
              {
                "type": "null"
              }
            ],
            "description": "The return.",
            "readOnly": true,
            "examples": [
              "pp30"
            ]
          },
          "filed": {
            "type": [
              "boolean",
              "null"
            ],
            "description": "Whether SLF has filed it.",
            "readOnly": true,
            "examples": [
              true
            ]
          }
        }
      },
      "PeriodSales": {
        "type": "object",
        "title": "Period sales",
        "description": "The month's sales as recorded for VAT: tax invoices, cash sales and debit notes by `issue_date`; receipts against `invoice` documents whose lines carry VAT, by `payment_date` (the service rule; see [Tax notes](https://slf-accounting.co/developers/reference#guide-tax-notes)); less credit notes by their `issue_date`. Voided records are left out, and so are records held back by SLF's arithmetic check (see `quarantined`). Records SLF entered itself are included.",
        "properties": {
          "document_count": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Number of documents and receipts counted.",
            "readOnly": true,
            "examples": [
              64
            ]
          },
          "taxable_value": {
            "type": [
              "string",
              "null"
            ],
            "format": "decimal",
            "description": "Value before VAT of `standard` and `standard_incl` lines.",
            "readOnly": true,
            "examples": [
              "412350.00"
            ]
          },
          "zero_rated_value": {
            "type": [
              "string",
              "null"
            ],
            "format": "decimal",
            "description": "Value of `zero` lines.",
            "readOnly": true,
            "examples": [
              "38900.00"
            ]
          },
          "exempt_value": {
            "type": [
              "string",
              "null"
            ],
            "format": "decimal",
            "description": "Value of `exempt` lines.",
            "readOnly": true,
            "examples": [
              "0.00"
            ]
          },
          "unclassified_value": {
            "type": [
              "string",
              "null"
            ],
            "format": "decimal",
            "description": "Value of lines SLF has not classified yet: `none` lines that are not a `disbursement` billed to the customer. Not included in the other figures until SLF classifies them.",
            "readOnly": true,
            "examples": [
              "0.00"
            ]
          },
          "vat": {
            "type": [
              "string",
              "null"
            ],
            "format": "decimal",
            "description": "Output VAT.",
            "readOnly": true,
            "examples": [
              "28864.50"
            ]
          }
        }
      },
      "PeriodPurchases": {
        "type": "object",
        "title": "Period purchases",
        "description": "The month's purchases as recorded for VAT: the bills whose input VAT SLF claims in this month's return. SLF decides the month, and bills SLF entered itself are included, so it can differ from your bill dates.",
        "properties": {
          "document_count": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Number of documents counted.",
            "readOnly": true,
            "examples": [
              41
            ]
          },
          "taxable_value": {
            "type": [
              "string",
              "null"
            ],
            "format": "decimal",
            "description": "Value before VAT.",
            "readOnly": true,
            "examples": [
              "158200.00"
            ]
          },
          "vat": {
            "type": [
              "string",
              "null"
            ],
            "format": "decimal",
            "description": "Input VAT.",
            "readOnly": true,
            "examples": [
              "11074.00"
            ]
          }
        }
      },
      "PeriodQuarantined": {
        "type": "object",
        "title": "Period quarantined",
        "description": "Sales records of the month, documents and receipts alike and including those SLF entered itself, whose VAT did not pass SLF's arithmetic check (on sales documents you send, the warning `vat_arithmetic_review`; a receipt carries no warning for it). They are held back from `sales` until SLF resolves them; see [How the API checks totals](https://slf-accounting.co/developers/reference#guide-conventions).",
        "properties": {
          "count": {
            "type": [
              "integer",
              "null"
            ],
            "description": "How many are held back.",
            "readOnly": true,
            "examples": [
              0
            ]
          },
          "value": {
            "type": [
              "string",
              "null"
            ],
            "format": "decimal",
            "description": "Their value before VAT.",
            "readOnly": true,
            "examples": [
              "0.00"
            ]
          }
        }
      },
      "PeriodWithholding": {
        "type": "object",
        "title": "Period withholding",
        "description": "Tax you withheld in the month, by return, as SLF has recorded it: withholding SLF entered, and from the second release the withholding entries of payments recorded through the API, by `pay_date`. Reversed payments are left out.",
        "properties": {
          "pnd3_amount": {
            "type": [
              "string",
              "null"
            ],
            "format": "decimal",
            "description": "Entries with `return_form` `pnd3`, for the ภ.ง.ด.3 withholding return.",
            "readOnly": true,
            "examples": [
              "1250.00"
            ]
          },
          "pnd53_amount": {
            "type": [
              "string",
              "null"
            ],
            "format": "decimal",
            "description": "Entries with `return_form` `pnd53`, for the ภ.ง.ด.53 withholding return.",
            "readOnly": true,
            "examples": [
              "4830.00"
            ]
          }
        }
      }
    }
  },
  "externalDocs": {
    "description": "SLF Data API reference",
    "url": "https://slf-accounting.co/developers/reference"
  }
}