# Light API documentation (full text) > REST API for accounting documents, invoices, payments, cards and the ledger. Base URL `https://api.light.inc`. Every guide and every endpoint page in one file. Index: https://light.inc/docs/llms.txt · OpenAPI spec: https://light.inc/docs/openapi-public.json # Introduction > Welcome to the Light API documentation. The Light API is organised around [REST](https://en.wikipedia.org/wiki/REST) and uses standard HTTP response codes, authentication and verbs. Most endpoints accept and return JSON-encoded data in [camel case](https://en.wikipedia.org/wiki/Camel_case). All requests go to: ``` https://api.light.inc ``` ## Where to start - For the accounting concepts behind the API, [Concepts](/docs/concepts/how-light-records-money) is five short pages on what the API's objects are and why its rules exist. The reference assumes them. - To start calling the API, [Authentication](/docs/getting-started/authentication) gets you a key, [Pagination, filtering and errors](/docs/getting-started/pagination-filtering-errors) covers the mechanics every endpoint shares, and [Choosing an endpoint](/docs/concepts/choosing-an-endpoint) maps common jobs to the calls that do them. - To connect an AI assistant rather than write code, see [Using Light from an AI client](/docs/getting-started/ai-clients). ## Enum values and forward compatibility Some fields in this API use enumerated (enum) values to represent specific states or types. While these enums are fully documented, they are not guaranteed to be exhaustive. New enum values may be introduced over time as the system evolves. To maintain forward compatibility: - Always handle unexpected or unknown enum values gracefully. - Avoid assuming the list of values is complete or immutable. - Where possible, use string-based comparisons or a safe fallback rather than exhaustive matching. This policy allows Light to extend functionality without introducing breaking changes for consumers who implement robust handling. ## Amounts Amounts are integers in minor units: `1250` USD is 12.50 USD and `150` JPY is 150 JPY. Each amount is paired with its currency in the same object. Direction (debit or credit) travels separately from size; [Reading amounts](/docs/concepts/reading-amounts) explains the conventions and the one place their polarity flips. Full page: https://light.inc/docs --- # Authentication > Authenticate with an API key or the OAuth 2.0 authorization code flow. You can authenticate to the Light API using [API keys](#api-keys) or the [OAuth 2.0](#oauth-20) user flow. All API requests must be made over HTTPS. Calls made over plain HTTP will fail, and so will requests without authentication. Make sure your HTTP client follows redirects and forwards the `Authorization` header, as some endpoints may redirect to other URLs. ## API keys To create an API key, log in to Light, navigate to **Settings > API Keys** and click **Create key**. Copy and securely store the generated key — it is not shown again. Light API keys are linked to roles the same way user accounts are. The roles assigned to the API key determine what actions the key can perform. To use an API key, include the `Authorization` header on your requests with the `Basic` scheme: ``` Authorization: Basic YOUR_API_KEY ``` Send the key exactly as Light issued it. Unlike standard HTTP Basic authentication there is no `username:password` pair to base64-encode — the value after `Basic` is the key itself. Here is a complete request, listing customers. The key below is made up — yours comes from **Settings > API Keys**: ```http GET /v1/customers HTTP/1.1 Host: api.light.inc Authorization: Basic live_4f8Kq2mXpR7vN3wZ6yB1tD5s Accept: application/json ``` The same call, ready to run — swap in your own key: ```bash cURL curl "https://api.light.inc/v1/customers" \ -H "Authorization: Basic live_4f8Kq2mXpR7vN3wZ6yB1tD5s" ``` ```javascript JavaScript const res = await fetch("https://api.light.inc/v1/customers", { headers: { Authorization: `Basic ${process.env.LIGHT_API_KEY}` }, }); const data = await res.json(); ``` ```python Python import os, requests res = requests.get( "https://api.light.inc/v1/customers", headers={"Authorization": f"Basic {os.environ['LIGHT_API_KEY']}"}, ) data = res.json() ``` > **Never expose an API key in client-side code, a public repository or a shared document.** Use environment variables or a secrets manager. ## OAuth 2.0 > **Note.** Contact Light support at [help@light.inc](mailto:help@light.inc) to set your account up for the OAuth 2.0 flow. Once your account is set up you receive a `client_id` and `client_secret`. You also give Light a redirect URI, where users are sent after they authorise your application. To start the OAuth 2.0 authorization code flow, open: ``` https://api.light.inc/oauth/authorize?client_id=YOUR_CLIENT_ID&redirect_uri=YOUR_REDIRECT_URI ``` You can also pass an optional `state` parameter. See the [OAuth 2.0 spec](https://datatracker.ietf.org/doc/html/rfc6749#section-4.1.1) for what it is for. ### Exchanging the authorization code for an access token After the user authorises your application they are redirected back to your redirect URI with an authorization code. Exchange it for an access token by POSTing to the token endpoint: ```shell curl -X POST https://api.light.inc/oauth/token \ -H "Content-Type: application/x-www-form-urlencoded" \ -d "grant_type=authorization_code&code=AUTHORIZATION_CODE&redirect_uri=YOUR_REDIRECT_URI&client_id=YOUR_CLIENT_ID&client_secret=YOUR_CLIENT_SECRET" ``` The response includes an `access_token`, which authenticates your API requests. Send it in the `Authorization` header with the `Bearer` scheme: ``` Authorization: Bearer YOUR_ACCESS_TOKEN ``` The response also includes `refresh_token` and `expires_in`. Store all three securely so you can refresh the access token when it expires. ### Refreshing access tokens When your access token expires, use the refresh token to get a new one: ```shell curl -X POST https://api.light.inc/oauth/token \ -H "Content-Type: application/x-www-form-urlencoded" \ -d "grant_type=refresh_token&refresh_token=YOUR_REFRESH_TOKEN&client_id=YOUR_CLIENT_ID&client_secret=YOUR_CLIENT_SECRET" ``` The response contains a **new** `access_token`, `refresh_token` and `expires_in`. Use the new access token for subsequent requests. > **Warning.** Replace your stored refresh token with the new one from the response — the old one is invalidated after use. Full page: https://light.inc/docs/getting-started/authentication --- # Rate limits > 300 requests a minute per user, 100,000 a day per organisation, and how to handle a 429. The Light API enforces rate limits to ensure fair usage and maintain performance for everyone. Exceed one and you get a `429 Too Many Requests` response. ## Rate limit structure Two limits apply by default. Light can agree different limits with your company. ### Requests per minute - **300 requests per minute** per user. - Every API key and OAuth token belonging to one user draws on that same allowance, so adding keys does not add capacity. ### Daily limit - **100,000 requests per day** per organisation. - Shared across all users in your organisation. - Resets at midnight UTC. ## Handling rate limit errors A `429 Too Many Requests` response carries these headers: | Header | Meaning | | --- | --- | | `X-RateLimit-Limit` | Maximum capacity (e.g. 300 for the per-minute limit) | | `X-RateLimit-Remaining` | Remaining capacity | | `X-RateLimit-Reset` | Unix timestamp when the limit returns to full capacity | | `Retry-After` | Recommended seconds to wait before retrying | ### Best practices 1. **Monitor the headers.** Check `X-RateLimit-Remaining` before a large batch of requests. 2. **Implement exponential backoff.** Wait progressively longer between retries — 1s, 2s, 4s, 8s. 3. **Respect `Retry-After`.** Always wait at least that long before retrying. 4. **Spread out scheduled jobs.** Avoid running every batch operation at the same time. ## Need higher limits? If your use case requires higher rate limits, contact Light support at [help@light.inc](mailto:help@light.inc) to discuss custom limits for your organisation. Full page: https://light.inc/docs/getting-started/rate-limits --- # Pagination, filtering and errors > How list endpoints page and sort, the filter grammar and its limits, what an error looks like, how to retry safely, and the conventions partial updates, custom properties and file endpoints follow. Every list endpoint pages the same way, every `filter` and `sort` parameter uses the same grammar, and every error has the same shape. This page covers those shared mechanics once. The endpoint pages only note where an endpoint departs from them. ## Pagination List endpoints return one page at a time: ```json { "records": [], "hasMore": true, "total": 1234, "nextCursor": null, "prevCursor": null } ``` `limit` sets the page size. The default is 50 and the maximum is 200; a larger value is rejected with `400`. There are two ways to move through pages. **Offset pagination** is what you get by default. Send `offset` (the number of records to skip) and read `total`. It is deprecated: `total` costs a count query on every page, and `offset` cannot exceed 50,000 — a larger value fails with `INVALID_OFFSET_SIZE`. **Cursor pagination** is opt-in. Send `cursor=0` on the first request. Each response then carries `nextCursor` and `prevCursor` (`null` when there is no such page), and `total` is `null`. Pass a cursor back exactly as received; one the endpoint cannot decode fails with `INVALID_CURSOR`. On most endpoints a cursor is a numeric offset under the hood, so the 50,000-record depth limit applies to cursors too — narrow the query with a filter rather than paging deeper. `GET /v1/general-ledger-summary` is the exception: it uses a keyset cursor, has no `offset` parameter, rejects `cursor=0`, and never returns `prevCursor`. Omit `cursor` on its first request and follow `nextCursor`. Pages are stable: the API appends the record id as a final tiebreaker to whatever sort you request. ## Sorting `sort=field:asc,otherField:desc`. The fields an endpoint accepts are listed on its `sort` parameter. A field that isn't listed fails with `INVALID_QUERY_FIELD`; a value that doesn't match the grammar fails with `ILLEGAL_SORT_SYNTAX`. ## Filtering `filter=field:operator:value`, comma-separated for several filters, which are ANDed. Operators: `eq`, `ne`, `in`, `not_in`, `gt`, `gte`, `lt`, `lte`. `in` and `not_in` take values separated by `|`: ``` filter=status:in:IN_DRAFT|SCHEDULED,createdAt:gte:2026-01-01T00:00:00Z ``` Rules the grammar doesn't make obvious: - Each endpoint's `filter` parameter lists the fields it accepts. Any other field fails with `INVALID_QUERY_FIELD`; an operator the field doesn't support fails with `UNSUPPORTED_FILTER_OPERATOR`. - There is no `is_null` operator. Write `field:eq:null` or `field:ne:null`. `null` with any other operator fails with `ILLEGAL_NULL_FILTER_OPERATOR`. - There is no quoting or escaping. A value may contain letters, digits, spaces and `_ - : . / @ +`, nothing else. `,` and `|` are always separators, and characters such as `%`, `&`, quotes and parentheses fail the whole request with `ILLEGAL_FILTER_SYNTAX`. - Timestamp fields (`createdAt`, `updatedAt`, `performedAt`, ...) take a full ISO-8601 instant such as `2026-01-31T00:00:00Z`. A bare date fails with `INVALID_FILTER_VALUE`, as does an enum value in the wrong case or a malformed UUID. - Boolean fields treat `true` (any case) as true and anything else as false. Some list endpoints apply a default filter, for example `GET /v1/users` hides deactivated users and `GET /v1/entities` hides inactive entities. The endpoint page says whether sending your own filter replaces that default. ## Errors Client errors (`400`, `403`, `404`, `409`) share one envelope: ```json { "name": "InvalidCursorException", "type": "BAD_REQUEST", "errors": [ { "type": "INVALID_CURSOR", "message": "Invalid cursor: 'abc'", "path": null, "context": null } ] } ``` `errors[].type` is the stable key to branch on; `message` is for humans and may change. Validation failures can carry several entries, each with a `path` into the request body and a `context` with the identifiers involved. - `401`: the credential is missing, invalid or deactivated. - `403`: the credential is valid but its roles don't allow the operation. - `404`: the record doesn't exist or belongs to another company. - `429` and `504` use a flat `{ "type", "message" }` body instead of the envelope: `TOO_MANY_REQUESTS` (see [Rate limits](/docs/getting-started/rate-limits)) and `GATEWAY_TIMEOUT`, when a query exceeds the database's statement timeout. ## Partial updates Most `PATCH` bodies follow one convention for fields marked nullable in the reference: omit the field to leave it unchanged, send `null` to clear it. A few fields can't be cleared because the record requires them; the endpoint page names those. ## Custom properties on writes Many create and update bodies take `customProperties`, a list of `{ "groupId", "valueIds", "inlineValues" }`. The same rules apply everywhere: - `SINGLE_SELECT` and `MULTI_SELECT` groups accept `valueIds` only. `TEXT`, `NUMERIC`, `BOOLEAN` and `DATE` groups accept either `valueIds` (a catalogue value) or `inlineValues` (a literal). Sending a literal to a select group fails with `CUSTOM_PROPERTY_VALUE_TYPE_MISMATCH`. - Inline values are strings: `DATE` as `yyyy-MM-dd`, `NUMERIC` as a decimal. A value that doesn't parse fails with `CUSTOM_PROPERTY_VALUE_INVALID_TYPE`. - Each item replaces that group's values. An empty `valueIds` and `inlineValues` clears the group; leaving the group out of the list leaves it unchanged. Omitting `customProperties` altogether leaves everything unchanged. - A `valueId` from another group fails with `CUSTOM_PROPERTY_VALUE_NOT_RECOGNIZED`, the same `groupId` twice with `CUSTOM_PROPERTY_DUPLICATE_GROUPS_REQUESTED`, and a group not enabled for that record type with `CUSTOM_PROPERTY_GROUP_NOT_ALLOWED_FOR_OBJECT_TYPE`. - A group marked required must be present with a value: `REQUIRED_CUSTOM_PROPERTY_HEADER_GROUP_MISSING` on the record, `REQUIRED_CUSTOM_PROPERTY_LINE_GROUP_MISSING` on a line. Some documents enforce this only when they are posted. Only groups your company defined are visible on `GET /v1/custom-properties/groups` and usable here. ## Files Endpoints that return a stored file (`.../document`, `.../receipt`) do not stream the bytes. They answer `307 Temporary Redirect` to a pre-signed URL that is valid for two hours. Follow the redirect **without** your Light `Authorization` header, which the storage service rejects. Uploads are the mirror image and take three steps: 1. Call the resource's `upload-url` endpoint. The response carries `uploadUrl`, `key` and `metadata`. 2. `PUT` the bytes to `uploadUrl` within five minutes, with the same `Content-Type` you declared and **every entry of `metadata` as a request header**. They are part of the signature, so the upload is rejected without them. 3. Tell Light about the file, or wait for it: attachments need a `POST /v1/attachments` with the `key`; card receipts are picked up automatically; expense receipts depend on the mode you chose (see [Upload a receipt](/docs/examples/upload-receipt)). ## Retries and idempotency A request that times out may still have succeeded. On the endpoints that accept it, send an `X-Idempotency-Key` header, any string unique to the operation you intend (an order id, a hash of the payload), and retry with the same key: - The first request runs and its response is stored. A retry with the same key within **24 hours** returns that stored response instead of running again. - A retry that arrives while the first is still in flight (within 60 seconds) fails with `409` rather than running twice. - The same key with a **different body** fails with `409 IDEMPOTENCY_VIOLATION`. Keys are scoped to your company and the operation, so the same key on two different endpoints is two different keys. Without the header nothing is deduplicated: each retry creates another record. The endpoints that accept the header list it under **Headers** on their page. Today that is creating, updating and archiving journal entries; creating and updating customers, products and customer credits; creating credit notes, sales invoices and expenses; the contract lifecycle; and issuing, freezing and unfreezing cards. Bill creation is not among them, so guard it with a read before you write. ## Acting as a user An API key authenticates as a service account that belongs to your company. It carries the roles you gave it, so any role-gated endpoint works as long as the key has the role, and its id appears as `createdBy` on records it creates. It is not a person, though: endpoints that act on "the current user" (creating and submitting expenses, uploading an expense or card receipt) look for a real user and fail with `USER_NOT_RECOGNIZED` under an API key. Call those with an OAuth token obtained by the user in question. Full page: https://light.inc/docs/getting-started/pagination-filtering-errors --- # Using Light from an AI client > Light's MCP server for Claude and other AI clients: how it differs from the REST API, and what an agent reading this reference should know. Light exposes the same data and actions two ways: the REST API documented on this site, and an MCP server ([Model Context Protocol](https://modelcontextprotocol.io)) that AI assistants such as Claude call directly. If you are reading this as an agent, or setting one up, this page says which to use. ## Which one | | REST API | MCP server | | --- | --- | --- | | Caller | Your code, on a schedule or in a workflow | An AI assistant acting for a signed-in person | | Credential | API key (`Authorization: Basic …`) or OAuth token | Personal `lmcp_…` token, or OAuth 2.1 through the Claude connector | | Acts as | A service account with the roles you gave the key | The person who connected, with their roles | | Amounts | Integers in minor units (`1250` is 12.50) | Decimals in major units (`12.5`); field names end in `InMajors` | | Surface | Every endpoint on this site | Roughly a hundred tools: search and read across master data, documents and reports; create and submit; approve; and flagged write operations | | Discover | This site, and `/docs/llms.txt` | `tools/list` at runtime. The list is filtered to what the caller may do. | API keys cannot call the MCP server, and MCP tokens work only on the MCP endpoint. They are separate credentials with separate audiences. ## Connecting Setup is in the product under **Settings → Profile → MCP Tokens**: create a token (shown once, `lmcp_` prefix, up to 20 active per user, optional expiry) and point your client at ``` https://api.light.inc/rest/ext/mcp ``` with `Authorization: Bearer lmcp_…`. Claude.ai and Claude Desktop users connect through the Light connector instead and sign in with their Light account; no token needed. Step-by-step instructions for Claude Code, OpenCode, n8n and other clients are in the help centre: [Connect your AI assistant to Light](https://light.inc/help/ai-features/how-to-use-light-mcp). The server speaks JSON-RPC 2.0 over HTTP POST (`initialize`, `tools/list`, `tools/call`, `ping`). Rate limiting is reported as a JSON-RPC error inside a `200` response rather than an HTTP `429`, so the session survives and the client can back off. ## If you are an agent reading the REST reference - The five [Concepts](/docs/concepts/how-light-records-money) pages are short and explain the rules the endpoint notes assume: why entries balance, how amounts are signed, why a status change is its own endpoint. - Every page here has a markdown twin: append `.md` to its URL. `/docs/llms.txt` indexes them, and `/docs/llms-full.txt` is the whole reference in one file. - Each endpoint's **Note** records behaviour the OpenAPI spec gets wrong or omits, verified against Light's source. Read it before the field list. - Example payloads are generated from the schema unless the page says otherwise: shapes are real, values are placeholders, and fields that exclude each other are all shown. Do not send a generated example unchanged. - The MCP server also exposes Light's help articles as tools, for "how do I" questions about the product rather than the API. Full page: https://light.inc/docs/getting-started/ai-clients --- # How Light records money > Documents, posting and the ledger: what the API's objects are, and why every transaction has two sides. Every number Light reports is a sum over the ledger. Everything else in the API (bills, sales invoices, journal entries, card transactions) is a way of getting a balanced entry into it. This page covers the three objects involved and the rule they all follow. ## Documents A bill, a sales invoice, a journal entry or a card transaction is an **accounting document**: the editable record of a business event. It records who the event involves, what it is for, how much, in which currency and on which date. Documents have lines, and each line points at a ledger account and carries an amount. Every document has a `documentType`, a two-letter code that is also the first segment of its document number: | Code | What it is | Where it comes from | | --- | --- | --- | | `AP` | Bill (invoice payable), including reimbursements | Vendors and employees | | `AR` | Sales invoice (invoice receivable) | Customers | | `BP` | Bank payment | Bank reconciliation and payment runs | | `CN` | Credit note from a vendor (credit entry), applied to a bill | Vendors | | `CC` | Customer credit, applied to a sales invoice | Customers | | `CT` | Card transaction | Corporate cards | | `JE` | Journal entry | You, the product, or the API | | `DE` | Accounting release: one instalment of a deferral, accrual or depreciation schedule | Release templates | | `FX` | FX revaluation | Period close | | `YC` | Year closing | Year-end close | [List accounting documents](/docs/api-reference/v1--accounting-documents/list-accounting-documents) returns all of them in one shape. Each type also has its own endpoints for creating it and moving it through its life. A document in `DRAFT` has no effect on any report. ## Posting **Posting** is what turns a document into accounting. Light validates the document, assigns its document number (`documentSequenceId`, for example `AP/001/000000042`), converts every amount into the entity's local currency and the company's group currency, adds the lines the document implies but does not show (tax, the balancing line, rounding), and writes the result as a **ledger transaction**: a set of **ledger transaction lines** that share one transaction number (`TX/…`). Ledger lines are never edited or deleted. If a posted document is wrong, Light posts a **reversal**: a new transaction with the same lines and the directions flipped. The document goes back to draft or is archived, keeps its number, and both the original and the reversing lines stay in the ledger. The ledger therefore carries the correction next to what it corrected, which is what makes it auditable. [List ledger transaction lines](/docs/api-reference/v1--ledger-transactions/list-ledger-transaction-lines) returns the ledger itself. Every report Light produces is a sum over these lines, so start there to rebuild a figure. ## Why every transaction has two sides Every business event changes two things at once. When a company buys software for 100, it owes 100 more to a vendor *and* has 100 more expense. When a customer pays, the bank balance goes up *and* the amount the customer owes goes down. A ledger transaction records both halves, so the books show what changed and what it was balanced against. The two halves are called **debit** and **credit**, and each ledger line carries one of them in `dcSign` (`D` or `C`). Within every ledger transaction, debits equal credits, in every currency the line carries. Light enforces this when it posts: a journal entry whose lines do not net to zero fails with `ACCOUNTING_DOCUMENT_LINES_DEBITS_AND_CREDITS_NOT_ZERO_SUM`, and one with only debits or only credits fails with `ACCOUNTING_DOCUMENT_LINES_NO_CREDIT_AND_DEBIT`. The API therefore never lets you write a single ledger line. You describe an event as a document, and Light produces the balanced transaction, adding the other side where the document type implies it: - On a **bill**, you enter expense lines; Light adds the balancing line on the entity's accounts payable account. - On a **sales invoice**, you enter revenue lines; Light adds the balancing line on accounts receivable. - On a **journal entry**, you state both sides yourself, line by line, with an explicit `dcSign` on each amount. Whether a debit makes a balance go up or down depends on the kind of account: debits increase assets and expenses, credits increase liabilities, equity and revenue. You can use the API without memorising that, but it explains what a ledger line looks like. The expense line of a bill is a debit and its accounts payable line is a credit; a customer payment debits the bank and credits accounts receivable. ## Settlement: clearing A posted bill is money owed. When the payment posts, the two documents settle each other on the accounts payable account. Light records that as a **clearing event**, and the bill's status moves to `PARTIALLY_CLEARED` or `CLEARED`. Clearing does not rewrite ledger lines: the payable line and the payment line already net to zero. It records only that they belong together, which is what open-item and ageing reports read. If the exchange rate moved between invoice and payment, the difference is posted as a separate realised FX transaction. ## What this means for your calls - Read the ledger from ledger transaction lines, and documents from their own endpoints or the accounting documents list. A ledger line points back at its document through `accountingDocumentId`. - A draft is invisible to reports: nothing you send reaches the ledger until it is posted. - Reversals leave two sets of lines that net to zero. Summing ledger lines for a period includes both, which is correct rather than a double count. - You cannot post an unbalanced entry, and you cannot post a line without a counterpart. A request rejected on balance is missing one side of the event. Next: [Reading amounts](/docs/concepts/reading-amounts), which covers how the amounts on those lines are expressed. Full page: https://light.inc/docs/concepts/how-light-records-money --- # Reading amounts > Minor units, debit and credit, signed and unsigned figures, and the three currencies on every ledger line. Amounts in the Light API follow four rules. This page states each one and where it applies. ## 1. Amounts are integers in minor units `1250` with `currency: "USD"` is 12.50 USD. `150` with `currency: "JPY"` is 150 yen, because the yen has no minor unit. There are no decimals on the wire, so nothing is lost to floating-point rounding. Fields whose name ends in `InMajors` are the exception: they carry the same figure as a decimal (`12.5`) and appear beside the minor-unit field on responses. Where a request field is named `InMajors`, it takes majors; everything else takes minor units. MCP tools are different again: there, every amount is in major units. See [Using Light from an AI client](/docs/getting-started/ai-clients). ## 2. Direction is separate from size Ledger amounts are never negative. Each carries a size and a direction, and the direction is in `dcSign`: `D` for debit, `C` for credit. A journal entry line is sent as: ```json { "netTransactionAmount": { "amount": 125000, "dcSign": "D" } } ``` A negative `amount` is rejected (`ACCOUNTING_DOCUMENT_LINE_NEGATIVE_AMOUNT`). One `dcSign` covers all three currency amounts on a ledger line: a line is a debit or a credit as a whole. Document endpoints hide this for the common case. On a bill, a positive line amount is an expense debit; on a sales invoice, a positive line amount is a revenue credit. You only state `dcSign` yourself on journal entries and bank transactions. ## 3. Signed figures have a polarity, and it depends on the endpoint For convenience, [List ledger transaction lines](/docs/api-reference/v1--ledger-transactions/list-ledger-transaction-lines) also returns each amount as a signed number: `signedTransactionAmount`, `signedLocalAmount`, `signedGroupAmount`. On those, **a credit is positive and a debit is negative**. Summing `signedLocalAmount` over an account therefore gives a credit-positive balance: a revenue account sums positive, an expense account sums negative. [General ledger summary](/docs/api-reference/v1--general-ledger-summary) and the bank account balance endpoint return balances with the **opposite** polarity: debit-positive, the way a trial balance is usually read, so a bank account in overdraft is negative there. Reconciling one against the other means flipping the sign on one side. `dcSign` with the unsigned amount is unambiguous on every endpoint, so prefer it, and check which endpoint you are on before reading the sign of a signed field. ## 4. Every ledger line carries three currencies Light keeps every ledger line in up to three currencies at once, and the API returns all three: | Amount | Currency | Set by | | --- | --- | --- | | `transactionAmount` | The document's `currency` | The document | | `localAmount` | The entity's local currency | The entity, when it was created | | `groupAmount` | The company's group currency | The company, when it was created | Local and group amounts are computed at posting, from the exchange rate on the document's `valuationDate` (which defaults to the posting date), and then stored. A report in group currency reads stored figures; it does not re-convert at report time. If a document supplies its own rate (`localCurrencyFxRateOverride`, `groupCurrencyFxRateOverride`), or a journal entry states local and group amounts directly, those are used instead. Which one to read: - **Transaction**: what the document says, in the currency it was issued in. Use it to match against an invoice or a bank statement line. - **Local**: the entity's statutory books. Use it for anything filed in that entity's country. - **Group**: consolidation. Use it to add up across entities. Because each line converts separately, the local or group totals of a transaction can end up a few minor units off zero after rounding. Light adds a rounding line on its rounding account so that debits equal credits in every currency. That line has no transaction amount, and it is not an error. ## Common mistakes - A bill for 1,000.00 is `amount: 100000`. Sending `1000` creates a bill for 10.00. - Totals on the accounting documents list are absolute values; ignore the `dcSign` on `totalTransactionAmount` there. - Zero-amount lines count as debits internally. Do not read direction off a zero. - A journal entry that states local and group amounts directly must balance in those currencies too, and cannot combine them with tax on the same lines. Next: [Document lifecycle](/docs/concepts/document-lifecycle). Full page: https://light.inc/docs/concepts/reading-amounts --- # Document lifecycle > The statuses every document moves through, which endpoints move them, and what can still change after posting. All ten document types share one status machine. Where a type has extra states of its own (a sales invoice's payment-side `state`, a bill's processing state), they sit on top of this one and are described on the resource's pages. ## The statuses | Status | Meaning | Ledger effect | | --- | --- | --- | | `DRAFT` | Editable. No document number yet. | None | | `APPROVAL_PENDING` | Submitted to an approval workflow and waiting. Light dry-runs the posting first, so a document that could not post is never sent for approval. | None | | `APPROVED` | Approved, not yet posted. | None | | `POSTED` | Ledger lines exist. Accounting data is frozen. | Yes | | `PARTIALLY_CLEARED` | Posted, and part of the open balance has been settled by a payment or credit. | Yes | | `CLEARED` | Posted and fully settled. | Yes | | `ARCHIVED` | Finished. A draft that was archived, or a posted document that was reversed and not reopened. | Reversed | There is no `REVERSED` status. Reversing a posted document either returns it to `DRAFT` (to edit and post again) or archives it, and it keeps its document number either way. Sales invoices additionally expose a `Reversed` state in their own state machine for the reverse-and-reissue flow. ## Changing status You cannot set `status` on any document. Each transition is an action endpoint that runs the checks for that transition. The pattern across resources: | Transition | Endpoint pattern | | --- | --- | | Draft into approval, or straight to posted | `…/submit-for-approval`, `…/post`. Journal entries post at creation with `shouldPost: true`. | | Approval pending to approved or declined | `…/approve`, `…/decline` | | Sales invoice issued to the customer | `…/open`, then `…/send-email` | | Posted to settled | Payments and credits: `…/mark-as-paid`, `…/payments`, or linking a credit note or customer credit | | Anything to archived | `…/archive`. A posted journal entry is reversed and archived in one step. | | Back to draft | `…/reset`, where the resource offers it | The reference lists the exact set for each resource. If an endpoint is missing for a transition you need (there is no call to post an existing draft journal entry, for example), the transition is not available through the API, and the page says so. ## What you can change, and when - **Draft**: everything. Header, lines, currency, dates, tax settings, rate overrides. - **Posted**: nothing that touches the ledger. Amounts, accounts, dates and tax are frozen. Metadata can still change: custom properties, and type-specific fields such as a purchase-order reference on a sales invoice. These edits are allowed even in a closed period, because they change no ledger line. - **To change a posted amount**: reverse (which returns the document to draft), edit, post again. In the product this is one operation; through the API it is the sequence of endpoints the resource exposes. The document number is kept, and the ledger shows the original lines, the reversing lines and the new lines. ## Two kinds of number - `documentSequenceId` (`AP/001/000000042`): assigned at first posting, per entity and document type, never reused, never reset. Drafts have none. Gaps are possible. - `documentNumber` on a sales invoice (for example `INV-2026-00042`, the entity's template decides): assigned when the invoice is opened, gap-free, and the number the customer sees. A bill's `invoiceNumber` is the vendor's number, copied from their invoice. ## Reading a document back A document's own endpoint returns its header and lines as entered. Its ledger lines, including the tax, balancing and rounding lines Light added, are on [List ledger transaction lines](/docs/api-reference/v1--ledger-transactions/list-ledger-transaction-lines) filtered by `accDocId`. Journal entries are the special case: the API has no read endpoint for them, so read the header from [List accounting documents](/docs/api-reference/v1--accounting-documents/list-accounting-documents) and the lines from the ledger once posted. Next: [Periods and locks](/docs/concepts/periods-and-locks). Full page: https://light.inc/docs/concepts/document-lifecycle --- # Periods and locks > Why a posting is rejected with ACCOUNTING_PERIOD_CLOSED or ACCOUNTING_PERIOD_LOCKED, and what to do about it. Once a month has been reported, its numbers must stop moving. Accounting periods are how Light enforces that, and they are why a request that worked yesterday can fail today with `ACCOUNTING_PERIOD_CLOSED`. ## Periods An accounting period is a company-wide slice of time, usually a month, with two statuses: `OPEN` and `CLOSED`. Every operation that changes the ledger (post, reverse, clear, unclear) is checked against the period that contains its **posting date**: the `postingDate` on the document, which is neither the document date nor today (on a journal entry it defaults to today). Periods are generated on demand by the company, not automatically. A date that no generated period covers is unprotected: postings into it are allowed. Companies normally generate periods ahead, so an unexpected success on a far-future or far-past date is worth raising rather than relying on. ## Locks Closing is the final step. Before it, each period carries four close tasks, and three of them are **soft locks** that a controller can complete per entity while the month is still being finished: | Task | Blocks | | --- | --- | | Lock AP | Posting, reversing and clearing bills (`AP`) for the entities marked complete | | Lock AR | The same for sales invoices (`AR`) | | Lock JE | The same for journal entries (`JE`) | | FX revaluation | Runs the period's revaluation; it does not block postings | Only bills, sales invoices and journal entries can be soft-locked. Bank payments, card transactions, credits and system entries are stopped only by a fully closed period. ## What the errors mean | Error type | Meaning | What to do | | --- | --- | --- | | `ACCOUNTING_PERIOD_CLOSED` | The period covering the posting date is closed for everything. | Post into an open period, or ask the company's controller to reopen. Reopening a period reopens every later period as well. | | `ACCOUNTING_PERIOD_LOCKED` | The period is open, but the lock task for this document type (and, if the message names one, this entity) is complete. | Post into a later period, or ask for the lock to be lifted for that entity. | Both checks run **before** anything else in the posting pipeline, so a rejected posting consumes no document number and writes nothing. ## Reversals are postings too Reversing a posted document writes new ledger lines dated with the original posting date, not today's. So archiving a journal entry that was posted in March fails in June if March is closed, and unclearing a March payment does the same. If the period cannot be reopened, the correction is a new, opposite journal entry in the current period. ## Year end Closing an accounting year posts a year-closing entry (`YC`) that moves the year's profit or loss into retained earnings. Its lines appear on [List ledger transaction lines](/docs/api-reference/v1--ledger-transactions/list-ledger-transaction-lines) like any other, with `documentType: "YC"`. If you compute a balance sheet from ledger lines across a year end, include them. If you compute a profit and loss statement, exclude them, or the year sums to zero. Next: [Choosing an endpoint](/docs/concepts/choosing-an-endpoint). Full page: https://light.inc/docs/concepts/periods-and-locks --- # Choosing an endpoint > Common jobs mapped to the calls that do them, in order, with the rule that trips people up on each. The reference is organised by resource; this page is organised by job. Each row names the calls that do the job, in order, and the rule most likely to trip you up. Read [How Light records money](/docs/concepts/how-light-records-money) first if the words document, posting or ledger line are new. ## Read the books | Job | Calls | Watch for | | --- | --- | --- | | Pull the general ledger for a period | [List ledger transaction lines](/docs/api-reference/v1--ledger-transactions/list-ledger-transaction-lines), filtered on `postingDate`, with `cursor=0` and `limit=200`, following `nextCursor` | Signed amounts are credit-positive. Reversal lines are included and net to zero. | | Trial balance, or account balances at a date | [Get general ledger summary](/docs/api-reference/v1--general-ledger-summary/get-general-ledger-summary) with `from` and `to` | Balances are debit-positive, the opposite of the ledger lines. Keyset cursor: omit `cursor` on the first call. | | Chart of accounts | [List ledger accounts](/docs/api-reference/v1--ledger-accounts/list-ledger-accounts) | Only posting accounts are returned, never header or sum accounts. | | Every document, whatever its type | [List accounting documents](/docs/api-reference/v1--accounting-documents/list-accounting-documents) | Totals are absolute values. `postingDate` can be filtered on but is not returned; read it from the ledger line. | | Open bills, open sales invoices | [List invoice payables](/docs/api-reference/v1--invoice-payables/list-invoice-payables), [List invoices](/docs/api-reference/v1--invoice-receivables/list-invoices), filtered on status | Neither list carries an open amount. The status says whether a document is settled; the amount still open is the sum of ledger lines on the payable or receivable account for that document, or what [List invoice payments](/docs/api-reference/v1--invoice-receivables/list-invoice-payments) leaves unpaid. | | Entities, and the currencies the books are kept in | [Entities](/docs/api-reference/v1--entities), [Companies](/docs/api-reference/v1--companies) | Local currency sits on the entity, group currency on the company. Both are fixed at creation. | | The exchange rate Light applied | [Get exchange rate](/docs/api-reference/v1--exchange/get-exchange-rate), [Get currency exchange rates](/docs/api-reference/v1--exchange/get-currency-exchange-rates) | Daily reference rates. A document's `valuationDate` says which day's rate it took. | | Bank statement lines | [List bank transactions](/docs/api-reference/v1--bank-accounts/list-bank-transactions) | Bank transactions are feed data, not documents. Matching them to bills and invoices happens in bank reconciliation, which the API does not expose. | | Card spend, expenses | [List card transactions](/docs/api-reference/v1--card-transactions/list-card-transactions), [List expenses](/docs/api-reference/v1--expenses/list-expenses) | Card transactions carry their own status on top of the document status. | ## Write to the books | Job | Calls, in order | Watch for | | --- | --- | --- | | Push bills from a procurement or AP system | [Create vendor](/docs/api-reference/v1--vendors/create-vendor) if new → [Create invoice payable](/docs/api-reference/v1--invoice-payables/create-invoice-payable) → [Create invoice payable line item](/docs/api-reference/v1--invoice-payables/create-invoice-payable-line-item) per line → [Submit for approval](/docs/api-reference/v1--invoice-payables/submit-for-approval). If the bill was paid outside Light, [Mark invoice payable as paid](/docs/api-reference/v1--invoice-payables/mark-invoice-payable-as-paid). | Amounts in minor units. Bill creation takes no idempotency key, so look the bill up before you retry. Worked example: [Create an invoice payable](/docs/examples/create-invoice-payable). | | Invoice a customer from a CRM or billing system | [Create customer](/docs/api-reference/v1--customers/create-customer) if new → [Create invoice](/docs/api-reference/v1--invoice-receivables/create-invoice) → [Create line](/docs/api-reference/v1--invoice-receivables/create-line) → [Open invoice](/docs/api-reference/v1--invoice-receivables/open-invoice) → [Send invoice email](/docs/api-reference/v1--invoice-receivables/send-invoice-email) | Opening assigns the gap-free invoice number and posts the invoice. Nothing is checked for duplicate customers; de-duplicate on your side. | | Post an accrual, a reclassification or a correction | [Create journal entry](/docs/api-reference/v1--journal-entries/create-journal-entry) with `shouldPost: true` and an `X-Idempotency-Key` | Lines net to zero, at least one `D` and one `C`, period open. There is no read endpoint: read it back from the ledger lines. | | Reverse a journal entry | [Archive journal entry](/docs/api-reference/v1--journal-entries/archive-journal-entry) | The reversal takes the original posting date, so that period must still be open. | | Spread a cost or revenue over time | [Create accounting release template](/docs/api-reference/v1--accounting-release-templates/create-accounting-release-template), then reference it from a journal entry line as `amortizationTemplateId` with a start and end date | The instalments post as `DE` documents on their own dates, and each date's period is checked when the entry posts. | | Keep master data in sync | [Create customer](/docs/api-reference/v1--customers/create-customer), [Create vendor](/docs/api-reference/v1--vendors/create-vendor), [Update vendor](/docs/api-reference/v1--vendors/update-vendor), [Create product](/docs/api-reference/v1--products/create-product) | Vendors update with `PUT`, a full replacement. A change to a vendor's bank details may come back as a pending change request rather than being applied. | | Record commitments and subscriptions | [Create purchase order](/docs/api-reference/v1--purchase-orders/create-purchase-order) and its lines; [Create contract](/docs/api-reference/v1--contracts/create-contract) and its lines | Neither posts to the ledger by itself. A purchase order is matched to bills; a contract generates sales invoices and revenue releases when published. | | Attach receipts to expenses and card transactions | [Upload a receipt](/docs/examples/upload-receipt) | These act as "the current user" and need an OAuth token for that user. An API key gets `USER_NOT_RECOGNIZED`. | ## What the API does not do - **No webhooks.** Nothing calls you when a document changes. Poll the list endpoints with an `updatedAt` filter and cursor pagination. - **Tax codes are not listable.** Lines reference a tax code by id (`taxCodeId`, or `ledgerTaxId` on journal entries), but there is no endpoint to fetch the ids. Copy them from the product, or ask through the MCP server, which has a tax code search tool. - **No report endpoints beyond the general ledger summary.** Aged payables and receivables, the profit and loss statement and the balance sheet as Light shows them are not exposed. Rebuilding them from ledger lines is possible for balances, but ageing and open items also depend on clearing events and FX revaluation, which the ledger lines alone do not carry. - **Bank reconciliation and period close are not exposed.** Matching, locking and closing happen in the product. - **Journal entries are write-only.** No endpoint reads a journal entry or posts an existing draft. Create it posted, and read it back from the ledger. Full page: https://light.inc/docs/concepts/choosing-an-endpoint --- # OAuth callback > Handle the OAuth 2.0 redirect and exchange the authorization code for an access token. This example shows how to handle the OAuth 2.0 callback when using the [OAuth 2.0 user flow](/docs/getting-started/authentication#oauth-20). When a user authorises your application they are redirected back to your redirect URI with an authorization code. Your application handles that callback and exchanges the code for an access token. ```javascript Node.js const express = require('express'); const axios = require('axios'); const app = express(); const CLIENT_ID = process.env.CLIENT_ID; const CLIENT_SECRET = process.env.CLIENT_SECRET; // store this securely const REDIRECT_URI = process.env.REDIRECT_URI; // same redirect URI used in the authorize endpoint app.get('/auth/callback', async (req, res) => { console.log('Received callback with query:', req.query); try { const { code, error, error_description } = req.query; // Handle errors if (error) { return res.status(400).json({ error: error, error_description: error_description }); } if (!code) { return res.status(400).json({ error: 'Authorization code not provided' }); } // Optionally validate the state parameter here if you provided one in the authorize request const params = new URLSearchParams(); params.append('grant_type', 'authorization_code'); params.append('code', code); params.append('client_id', CLIENT_ID); params.append('client_secret', CLIENT_SECRET); params.append('redirect_uri', REDIRECT_URI); // Exchange authorization code for tokens const tokenResponse = await axios.post('https://api.light.inc/oauth/token', params, { headers: { 'Accept': 'application/json', 'Content-Type': 'application/x-www-form-urlencoded' }, }); // Store tokens in your database, preferably encrypted // saveTokens(tokenResponse.data); res.json({ success: true }); } catch (error) { res.status(500).json(error.response?.data || { error: error.message }); } }); const PORT = process.env.PORT || 3000; app.listen(PORT, () => { console.log(`Server is running on port ${PORT}`); }); ``` Full page: https://light.inc/docs/examples/oauth-callback --- # Create an invoice payable > End-to-end: create a vendor invoice with line items and a document, then submit it for approval. This example walks through creating a vendor invoice programmatically — creating the invoice, adding line items, uploading the document and submitting it for approval. ```javascript Node.js const API_KEY = process.env.LIGHT_API_KEY; const BASE_URL = 'https://api.light.inc'; const headers = { 'Authorization': `Basic ${API_KEY}`, 'Content-Type': 'application/json', }; async function createInvoicePayable() { // 1. Create the invoice const invoiceRes = await fetch(`${BASE_URL}/v1/invoice-payables`, { method: 'POST', headers, body: JSON.stringify({ vendorId: '3c90c3cc-0d44-4b50-8888-8dd25736052a', invoiceNumber: 'INV-2026-042', issueDate: '2026-01-15', dueDate: '2026-02-15', currency: 'GBP', }), }); const invoice = await invoiceRes.json(); console.log('Created invoice:', invoice.id); // 2. Add line items const lines = [ { description: 'Software license', quantity: 1, unitPrice: 120000 }, { description: 'Support contract', quantity: 1, unitPrice: 30000 }, ]; for (const line of lines) { await fetch(`${BASE_URL}/v1/invoice-payables/${invoice.id}/line-items`, { method: 'POST', headers, body: JSON.stringify(line), }); } console.log('Added', lines.length, 'line items'); // 3. Upload the invoice document const uploadUrlRes = await fetch( `${BASE_URL}/v1/invoice-payables/${invoice.id}/document/upload-url`, { method: 'POST', headers, body: JSON.stringify({ fileName: 'invoice-042.pdf', contentType: 'application/pdf', }), } ); const { uploadUrl } = await uploadUrlRes.json(); // Upload the file to the presigned URL const fs = require('fs'); const fileBuffer = fs.readFileSync('./invoice-042.pdf'); await fetch(uploadUrl, { method: 'PUT', headers: { 'Content-Type': 'application/pdf' }, body: fileBuffer, }); console.log('Uploaded document'); // 4. Submit for approval await fetch(`${BASE_URL}/v1/invoice-payables/${invoice.id}/submit-for-approval`, { method: 'POST', headers, }); console.log('Submitted for approval'); return invoice; } createInvoicePayable().catch(console.error); ``` ```python Python import requests import os API_KEY = os.environ['LIGHT_API_KEY'] BASE_URL = 'https://api.light.inc' headers = { 'Authorization': f'Basic {API_KEY}', 'Content-Type': 'application/json', } # 1. Create the invoice invoice = requests.post(f'{BASE_URL}/v1/invoice-payables', headers=headers, json={ 'vendorId': '3c90c3cc-0d44-4b50-8888-8dd25736052a', 'invoiceNumber': 'INV-2026-042', 'issueDate': '2026-01-15', 'dueDate': '2026-02-15', 'currency': 'GBP', }).json() invoice_id = invoice['id'] print(f'Created invoice: {invoice_id}') # 2. Add line items lines = [ {'description': 'Software license', 'quantity': 1, 'unitPrice': 120000}, {'description': 'Support contract', 'quantity': 1, 'unitPrice': 30000}, ] for line in lines: requests.post( f'{BASE_URL}/v1/invoice-payables/{invoice_id}/line-items', headers=headers, json=line, ) print(f'Added {len(lines)} line items') # 3. Upload the invoice document upload_url_data = requests.post( f'{BASE_URL}/v1/invoice-payables/{invoice_id}/document/upload-url', headers=headers, json={'fileName': 'invoice-042.pdf', 'contentType': 'application/pdf'}, ).json() with open('./invoice-042.pdf', 'rb') as f: requests.put( upload_url_data['uploadUrl'], headers={'Content-Type': 'application/pdf'}, data=f.read(), ) print('Uploaded document') # 4. Submit for approval requests.post(f'{BASE_URL}/v1/invoice-payables/{invoice_id}/submit-for-approval', headers=headers) print('Submitted for approval') ``` Full page: https://light.inc/docs/examples/create-invoice-payable --- # Upload a receipt > Upload receipts for expenses and card transactions using presigned URLs. Light uses presigned URLs for file uploads. The two-step process keeps your API key out of the upload itself and supports files of any size. ## How it works 1. Your app asks Light for an upload URL — `POST` to the relevant `upload-url` endpoint. 2. Light returns `{ "uploadUrl": "https://…" }`, a short-lived presigned URL on its storage provider. 3. Your app `PUT`s the file straight to that URL. The file never passes through the Light API. ## Upload a receipt for a card transaction ```javascript Node.js const fs = require('fs'); async function uploadReceipt(cardTransactionId, filePath) { const API_KEY = process.env.LIGHT_API_KEY; const fileName = filePath.split('/').pop(); const contentType = fileName.endsWith('.pdf') ? 'application/pdf' : 'image/jpeg'; // Step 1: Get a presigned upload URL const urlRes = await fetch( `https://api.light.inc/v1/card-transactions/${cardTransactionId}/receipt-upload-url`, { method: 'POST', headers: { 'Authorization': `Basic ${API_KEY}`, 'Content-Type': 'application/json', }, body: JSON.stringify({ fileName, contentType }), } ); const { uploadUrl } = await urlRes.json(); // Step 2: Upload the file directly const fileBuffer = fs.readFileSync(filePath); const uploadRes = await fetch(uploadUrl, { method: 'PUT', headers: { 'Content-Type': contentType }, body: fileBuffer, }); if (!uploadRes.ok) { throw new Error(`Upload failed: ${uploadRes.status}`); } console.log('Receipt uploaded successfully'); } uploadReceipt('3c90c3cc-0d44-4b50-8888-8dd25736052a', './receipts/coffee.jpg'); ``` ```python Python import requests import os import mimetypes def upload_receipt(card_transaction_id: str, file_path: str): api_key = os.environ['LIGHT_API_KEY'] file_name = os.path.basename(file_path) content_type = mimetypes.guess_type(file_path)[0] or 'application/octet-stream' # Step 1: Get a presigned upload URL url_res = requests.post( f'https://api.light.inc/v1/card-transactions/{card_transaction_id}/receipt-upload-url', headers={ 'Authorization': f'Basic {api_key}', 'Content-Type': 'application/json', }, json={'fileName': file_name, 'contentType': content_type}, ) upload_url = url_res.json()['uploadUrl'] # Step 2: Upload the file directly with open(file_path, 'rb') as f: upload_res = requests.put( upload_url, headers={'Content-Type': content_type}, data=f.read(), ) upload_res.raise_for_status() print('Receipt uploaded successfully') upload_receipt('3c90c3cc-0d44-4b50-8888-8dd25736052a', './receipts/coffee.jpg') ``` ## Upload a receipt for an expense Expense receipts use the same two-step flow, with two differences from card transactions: - `POST /v1/expenses/upload-url` returns a `metadata` object. **Send every entry as a request header on the `PUT`** — the headers are part of the presigned signature, and storage rejects the upload without them. - By default (`shouldAutoCreateExpense: true`, as in the examples below) Light converts the receipt to PDF, creates the expense automatically and extracts its fields with OCR. Set `shouldAutoCreateExpense: false` to only store the receipt — no expense is created and nothing is parsed — when your integration creates the expense itself through the API. ```javascript Node.js const fs = require('fs'); async function uploadExpenseReceipt(filePath) { const API_KEY = process.env.LIGHT_API_KEY; const filename = filePath.split('/').pop(); const contentType = filename.endsWith('.pdf') ? 'application/pdf' : 'image/jpeg'; // Step 1: Get a presigned upload URL const urlRes = await fetch('https://api.light.inc/v1/expenses/upload-url', { method: 'POST', headers: { 'Authorization': `Basic ${API_KEY}`, 'Content-Type': 'application/json', }, body: JSON.stringify({ filename, contentType }), }); const { uploadUrl, key, metadata } = await urlRes.json(); // Step 2: Upload the file directly, echoing the metadata as headers const uploadRes = await fetch(uploadUrl, { method: 'PUT', headers: { 'Content-Type': contentType, ...metadata }, body: fs.readFileSync(filePath), }); if (!uploadRes.ok) { throw new Error(`Upload failed: ${uploadRes.status}`); } return key; // the receipt's storage key } uploadExpenseReceipt('./receipts/taxi.jpg'); ``` ```python Python import requests import os import mimetypes def upload_expense_receipt(file_path: str) -> str: api_key = os.environ['LIGHT_API_KEY'] filename = os.path.basename(file_path) content_type = mimetypes.guess_type(file_path)[0] or 'application/octet-stream' # Step 1: Get a presigned upload URL url_res = requests.post( 'https://api.light.inc/v1/expenses/upload-url', headers={ 'Authorization': f'Basic {api_key}', 'Content-Type': 'application/json', }, json={'filename': filename, 'contentType': content_type}, ) url_res.raise_for_status() body = url_res.json() # Step 2: Upload the file directly, echoing the metadata as headers with open(file_path, 'rb') as f: upload_res = requests.put( body['uploadUrl'], headers={'Content-Type': content_type, **(body.get('metadata') or {})}, data=f.read(), ) upload_res.raise_for_status() return body['key'] # the receipt's storage key upload_expense_receipt('./receipts/taxi.jpg') ``` ## Create an expense without OCR When your integration already knows the expense data (per diems, mileage and so on) you don't need Light to read the receipt. Upload it with `shouldAutoCreateExpense: false`, then create the expense yourself with `POST /v1/expenses`. The call returns the finished expense with its ID — no polling, no OCR — and the expense is a draft for the authenticated user until `POST /v1/expenses/submit`, which submits **all** of that user's drafts. - A PDF receipt is attached as-is (~1s). JPEG, PNG, HEIC and TIFF receipts are converted to PDF during the call (a few seconds). Receipts are limited to 10 MB. - Amounts are integers in minor units (`1250` = 12.50). `originalAmount` is in `originalCurrency`; `billingAmount` is in the user's reimbursement currency and may be omitted — it is copied when the currencies match and derived from the exchange rate of `performedDate` otherwise. - Every line needs a `reimbursementCategoryId`: the category decides the GL account and tax code on the reimbursement. List the available categories with `GET /v1/reimbursement-categories`. - Send an `X-Idempotency-Key` header to retry safely. A receipt can be used by one expense only (`409` otherwise). ```javascript Node.js const fs = require('fs'); async function createExpense(filePath, expense) { const API_KEY = process.env.LIGHT_API_KEY; const headers = { 'Authorization': `Basic ${API_KEY}`, 'Content-Type': 'application/json' }; const filename = filePath.split('/').pop(); const contentType = filename.endsWith('.pdf') ? 'application/pdf' : 'image/jpeg'; // 1. Presign — store only, do not auto-create const urlRes = await fetch('https://api.light.inc/v1/expenses/upload-url', { method: 'POST', headers, body: JSON.stringify({ filename, contentType, shouldAutoCreateExpense: false }), }); const { uploadUrl, key, metadata } = await urlRes.json(); // 2. Upload, echoing the metadata headers const uploadRes = await fetch(uploadUrl, { method: 'PUT', headers: { 'Content-Type': contentType, ...metadata }, body: fs.readFileSync(filePath), }); if (!uploadRes.ok) throw new Error(`Upload failed: ${uploadRes.status}`); // 3. Create the expense with your own data const createRes = await fetch('https://api.light.inc/v1/expenses', { method: 'POST', headers: { ...headers, 'X-Idempotency-Key': expense.idempotencyKey }, body: JSON.stringify({ receiptDocumentKey: key, originalCurrency: 'USD', performedDate: '2026-08-20', detailedDescription: 'Per diem – Austin trip', lineItems: [ { originalAmount: 7400, description: 'Per diem day 1', reimbursementCategoryId: expense.categoryId }, ], }), }); return createRes.json(); // { id, status: "IN_DRAFT", receiptDocumentKey, lineItems, ... } } ``` ## Supported file types | Type | Content type | Max size | | --- | --- | --- | | PDF | `application/pdf` | 10 MB | | JPEG | `image/jpeg` | 10 MB | | PNG | `image/png` | 10 MB | | HEIC / HEIF | `image/heic`, `image/heif` | 10 MB | | TIFF | `image/tiff` | 10 MB | > **Tip.** Presigned URLs expire after a short period. Upload the file immediately after obtaining the URL; if it expires, request a new one. Full page: https://light.inc/docs/examples/upload-receipt --- # Authorization (resource) The OAuth 2.0 authorization flow: start it, and exchange the code for an access token. Resource page: https://light.inc/docs/api-reference/authorization # Create access token > Exchanges an authorization code or refresh token for an access token `POST https://api.light.inc/oauth/token` ## Note Send the body as application/x-www-form-urlencoded , not JSON. Light forwards the six fields to its identity provider unchanged and returns its answer, so a rejected grant comes back with the provider's own status and body ( {"error": "invalid_grant", "error_description": "..."} ), not the {name, type, errors[]} envelope used elsewhere. Response keys are snake_case ( access_token , expires_in in seconds, token_type , refresh_token ), and refresh_token is null when the grant didn't produce one. ## Authorization - API key - Bearer token See https://light.inc/docs/getting-started/authentication. ## Request body `application/x-www-form-urlencoded` ```json { "client_id": "string", "client_secret": "string", "grant_type": "string", "code": "string", "redirect_uri": "string", "refresh_token": "string" } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders, and fields that exclude each other are all shown. Do not send it unchanged. ## Response ```json { "access_token": "string", "expires_in": 100000, "token_type": "string", "refresh_token": "string" } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders. ## Code ```bash curl -X POST "https://api.light.inc/oauth/token" \ -H "Authorization: Basic YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "client_id": "string", "client_secret": "string", "grant_type": "string", "code": "string", "redirect_uri": "string", "refresh_token": "string" }' ``` Full page: https://light.inc/docs/api-reference/authorization/create-access-token --- # Start authorization flow > Redirects the user to the authorization page to start the OAuth V2 authorization flow `GET https://api.light.inc/oauth/authorize` ## Note This endpoint does not return JSON. It answers 303 See Other with an empty body and a Location header pointing at Light's identity provider, so send the user's browser here rather than calling it from a server. client_id and redirect_uri are required; state is optional and echoed back unchanged on the callback. The scope is fixed by Light ( openid profile email offline_access ) and the user is always shown the login and consent screens; PKCE ( code_challenge ) is not supported and any scope you pass is ignored. ## Authorization - API key - Bearer token See https://light.inc/docs/getting-started/authentication. ## Query parameters - `redirect_uri` (string) - `state` (string) - `client_id` (string) ## Response This endpoint returns no content. ## Code ```bash curl -X GET "https://api.light.inc/oauth/authorize" \ -H "Authorization: Basic YOUR_API_KEY" ``` Full page: https://light.inc/docs/api-reference/authorization/start-authorization-flow --- # Accounting Documents (resource) List and query every accounting document, across all document types. Resource page: https://light.inc/docs/api-reference/v1--accounting-documents # List accounting documents > Returns a paginated list of accounting documents `GET https://api.light.inc/v1/accounting-documents/accounting-documents` ## Note Every posting-capable record in one list. documentType : AP vendor bill, AR customer invoice, BP bank payment, CC customer credit, CN vendor credit note, CT card transaction, DE accounting-release (amortisation or depreciation) entry, FX revaluation entry, JE journal entry, YC year-closing entry. status : DRAFT , APPROVAL_PENDING , APPROVED , POSTED , PARTIALLY_CLEARED and CLEARED (matched against payments or credits), ARCHIVED (a draft archived, or a posted document reversed). Drafts and archived documents are included unless filtered; default order is newest first. Read totalTransactionAmount as the document's absolute total and ignore its dcSign : the sign is derived from a type-specific sum, so a journal entry's total shows C and a customer invoice's shows D . postingDate , valuationDate and ledgerName can be filtered and sorted on but are not in the response; for those and for lines, use GET /v1/ledger-transaction-lines filtered by accDocId . The document types and statuses are explained in How Light records money (/docs/concepts/how-light-records-money) and Document lifecycle (/docs/concepts/document-lifecycle). ## Authorization - API key - Bearer token See https://light.inc/docs/getting-started/authentication. ## Query parameters - `sort` (string) — Sort string in the format field:direction . To provide multiple sort fields, separate them with commas. Available directions: asc , desc . Available fields: companyEntityId , documentSequenceId , postingDate , valuationDate , documentDate , businessPartnerName , status , createdBy , createdAt , description , documentNumber , arDueDate , arOpenedAt , ctPerformedAt , ctStatus , ctAmount , ccAmount . - `filter` (string) — Filter string in the format field:operator:value . To provide multiple filters, separate them with commas. Available operators: eq , ne , in , not_in , gt , gte , lt , lte . - For in and not_in operators, provide multiple values separated by the pipe character ( ). Available fields: id , documentSequenceId , documentNumber , documentType , companyEntityId , ledgerName , businessPartnerName , businessPartnerId , status , currency , postingDate , documentDate , valuationDate , createdAt , updatedAt , createdBy , intercompanyDocumentId , apDueDate , apState , apVendorId , arContractId , arDueDate , arCustomerId , arInvoiceTemplateId , arPayeeBankAccountId , arOpenedAt , arState , ctCardId , ctCardBalanceAccountId , ctStatus , ctPerformedAt , cnToBeAdjustedAccDocType , intercompanyJournalEntryId , ycAccountingYearId , accountCode , accountLabel , taxCode . - `limit` (integer, int32) — Maximum number of items to return. Default is 50, maximum is 200. - `offset` (integer, int64) — Number of items to skip before starting to collect the result set. Deprecated, use 'cursor' instead. - `cursor` (string) — The cursor position to start returning results from. To opt-in into cursor-based pagination, provide 0 for the initial request. For subsequent requests, use nextCursor and prevCursor from the previous response to navigate. Cursor values are opaque and should not be constructed manually. ## Response - `records.id` — The document id, the same id its type-specific endpoints use. - `records.companyId` — Your company id. - `records.companyEntityId` — The entity the document belongs to; `null` on a draft bill that has no entity yet. - `records.documentSequenceId` — Light's document number, `//<9 digits>`; `null` until the document is first posted. - `records.documentNumber` — The external number: the vendor's invoice number on a bill, the invoice number on a sales invoice, the free-text reference on a journal entry. - `records.description` — The document header description. - `records.documentDate` — The document's own date. This model carries no `postingDate` — for the date the document hit the ledger, read the ledger line via `GET /v1/ledger-transaction-lines`. - `records.areLinesWithTax` — Whether line amounts were entered gross of tax (`true`) or net (`false`). - `records.businessPartnerName` — The vendor or customer on the document, when it has one. - `records.businessPartnerId` — Id of that vendor or customer. - `records.createdAt` — When the document was created, as a draft. - `records.updatedAt` — The last change to the document, including metadata edits after posting. - `records.totalTransactionAmount` — Treat `amount` as the absolute document total. `dcSign` is derived from a type-specific sum, not the document's nature: a journal entry shows `C`, a customer invoice `D`. - `records.totalTransactionAmount.amount` — Unsigned integer in minor units. The direction is in `dcSign`; a negative value is rejected. - `records.totalTransactionAmountInMajors` — `totalTransactionAmount` as a decimal, unsigned. - `records.currency` — The document's currency; `null` on a draft that has none yet. ```json { "records": [ { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyEntityId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "documentSequenceId": "string", "documentNumber": "string", "documentType": "AP", "status": "DRAFT", "description": "string", "documentDate": "2026-01-15", "areLinesWithTax": true, "businessPartnerName": "string", "businessPartnerId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z", "totalTransactionAmount": { "amount": 100000, "dcSign": "D" }, "totalTransactionAmountInMajors": 0, "currency": "USD" } ], "hasMore": true, "total": 100000, "nextCursor": "string", "prevCursor": "string" } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders. ## Code ```bash curl -X GET "https://api.light.inc/v1/accounting-documents/accounting-documents" \ -H "Authorization: Basic YOUR_API_KEY" ``` Full page: https://light.inc/docs/api-reference/v1--accounting-documents/list-accounting-documents --- # Accounting Release Templates (resource) Create and manage the templates that generate accounting releases, and archive the ones no longer in use. Resource page: https://light.inc/docs/api-reference/v1--accounting-release-templates # Archive accounting release template > Archives the given accounting release template so it can no longer be assigned to new documents. Releases already generated from it are unaffected `POST https://api.light.inc/v1/accounting-release-templates/{templateId}/archive` ## Note Idempotent and unconditional: archiving an archived template succeeds again. The only failure is 404 ACCOUNTING_RELEASE_TEMPLATE_NOT_FOUND . ## Authorization - API key - Bearer token See https://light.inc/docs/getting-started/authentication. ## Path parameters - `templateId` (string, uuid, required) ## Response ```json { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "createdBy": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "name": "string", "method": "STRAIGHT_LINE_WITH_PARTIAL_ADJUSTMENT", "type": "AR", "deferralAccountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "contractAccountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "additionsAccountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "disposalAccountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "profitAccountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "lossAccountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "initialAmountPercentage": 0, "residualAmountPercentage": 0, "residualAmount": 100000, "reducingRate": 0, "accumulatePastReleasesEnabled": true, "defaultDuration": 0, "context": "string", "status": "ACTIVE", "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z" } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders. ## Code ```bash curl -X POST "https://api.light.inc/v1/accounting-release-templates/3c90c3cc-0d44-4b50-8888-8dd25736052a/archive" \ -H "Authorization: Basic YOUR_API_KEY" ``` Full page: https://light.inc/docs/api-reference/v1--accounting-release-templates/archive-accounting-release-template --- # List accounting release templates > Returns a list of accounting release templates `GET https://api.light.inc/v1/accounting-release-templates` ## Note Archived templates are included; add filter=status:eq:ACTIVE to exclude them. Default order is newest first. ## Authorization - API key - Bearer token See https://light.inc/docs/getting-started/authentication. ## Query parameters - `sort` (string) — Sort string in the format field:direction . To provide multiple sort fields, separate them with commas. Available directions: asc , desc . Available fields: name , method , type , deferralAccountId , createdAt . - `filter` (string) — Filter string in the format field:operator:value . To provide multiple filters, separate them with commas. Available operators: eq , ne , in , not_in , gt , gte , lt , lte . - For in and not_in operators, provide multiple values separated by the pipe character ( ). Available fields: id , companyId , name , method , type , deferralAccountId , initialAmountPercentage , residualAmountPercentage , status . - `limit` (integer, int32) — Maximum number of items to return. Default is 50, maximum is 200. - `offset` (integer, int64) — Number of items to skip before starting to collect the result set. Deprecated, use 'cursor' instead. - `cursor` (string) — The cursor position to start returning results from. To opt-in into cursor-based pagination, provide 0 for the initial request. For subsequent requests, use nextCursor and prevCursor from the previous response to navigate. Cursor values are opaque and should not be constructed manually. ## Response ```json { "records": [ { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "createdBy": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "name": "string", "method": "STRAIGHT_LINE_WITH_PARTIAL_ADJUSTMENT", "type": "AR", "deferralAccountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "contractAccountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "additionsAccountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "disposalAccountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "profitAccountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "lossAccountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "initialAmountPercentage": 0, "residualAmountPercentage": 0, "residualAmount": 100000, "reducingRate": 0, "accumulatePastReleasesEnabled": true, "defaultDuration": 0, "context": "string", "status": "ACTIVE", "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z" } ], "hasMore": true, "total": 100000, "nextCursor": "string", "prevCursor": "string" } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders. ## Code ```bash curl -X GET "https://api.light.inc/v1/accounting-release-templates" \ -H "Authorization: Basic YOUR_API_KEY" ``` Full page: https://light.inc/docs/api-reference/v1--accounting-release-templates/list-accounting-release-templates --- # Create accounting release template > Creates a new accounting release template. The ledger accounts and type chosen here are fixed for the lifetime of the template `POST https://api.light.inc/v1/accounting-release-templates` ## Note residualAmount and reducingRate are not mutually exclusive as the description says: at least one is required for REDUCING_BALANCE ( ACCOUNTING_RELEASE_TEMPLATE_REDUCING_BALANCE_MISSING_RATE_OR_RESIDUAL ), and both may be sent and stored. REDUCING_BALANCE is allowed only for type FIXED_ASSET , AP or JE ; type: CONTRACT requires contractAccountId . reducingRate must be in [0, 1) , residualAmount above zero, initialAmountPercentage + residualAmountPercentage at most 1. None of the account ids may point at a payables or receivables control account ( ACCOUNTING_RELEASE_TEMPLATE_RECONCILABLE_ACCOUNT_NOT_ALLOWED ). ## Authorization - API key - Bearer token See https://light.inc/docs/getting-started/authentication. ## Request body `application/json;charset=UTF-8` ```json { "name": "string", "method": "STRAIGHT_LINE_WITH_PARTIAL_ADJUSTMENT", "type": "AR", "deferralAccountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "contractAccountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "additionsAccountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "disposalAccountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "profitAccountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "lossAccountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "initialAmountPercentage": 0, "residualAmountPercentage": 0, "residualAmount": 100000, "reducingRate": 0, "accumulatePastReleasesEnabled": true, "defaultDuration": 0, "context": "string" } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders, and fields that exclude each other are all shown. Do not send it unchanged. ## Response ```json { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "createdBy": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "name": "string", "method": "STRAIGHT_LINE_WITH_PARTIAL_ADJUSTMENT", "type": "AR", "deferralAccountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "contractAccountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "additionsAccountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "disposalAccountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "profitAccountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "lossAccountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "initialAmountPercentage": 0, "residualAmountPercentage": 0, "residualAmount": 100000, "reducingRate": 0, "accumulatePastReleasesEnabled": true, "defaultDuration": 0, "context": "string", "status": "ACTIVE", "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z" } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders. ## Code ```bash curl -X POST "https://api.light.inc/v1/accounting-release-templates" \ -H "Authorization: Basic YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "name": "string", "method": "STRAIGHT_LINE_WITH_PARTIAL_ADJUSTMENT", "type": "AR", "deferralAccountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "contractAccountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "additionsAccountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "disposalAccountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "profitAccountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "lossAccountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "initialAmountPercentage": 0, "residualAmountPercentage": 0, "residualAmount": 100000, "reducingRate": 0, "accumulatePastReleasesEnabled": true, "defaultDuration": 0, "context": "string" }' ``` Full page: https://light.inc/docs/api-reference/v1--accounting-release-templates/create-accounting-release-template --- # Get accounting release template > Returns an accounting release template by ID `GET https://api.light.inc/v1/accounting-release-templates/{templateId}` ## Note An unknown id, or one from another company, is 404 . Same permission as listing templates. ## Authorization - API key - Bearer token See https://light.inc/docs/getting-started/authentication. ## Path parameters - `templateId` (string, uuid, required) ## Response ```json { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "createdBy": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "name": "string", "method": "STRAIGHT_LINE_WITH_PARTIAL_ADJUSTMENT", "type": "AR", "deferralAccountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "contractAccountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "additionsAccountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "disposalAccountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "profitAccountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "lossAccountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "initialAmountPercentage": 0, "residualAmountPercentage": 0, "residualAmount": 100000, "reducingRate": 0, "accumulatePastReleasesEnabled": true, "defaultDuration": 0, "context": "string", "status": "ACTIVE", "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z" } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders. ## Code ```bash curl -X GET "https://api.light.inc/v1/accounting-release-templates/3c90c3cc-0d44-4b50-8888-8dd25736052a" \ -H "Authorization: Basic YOUR_API_KEY" ``` Full page: https://light.inc/docs/api-reference/v1--accounting-release-templates/get-accounting-release-template --- # Update accounting release template > Updates an existing accounting release template. Only the fields present in the request body are changed. The ledger accounts and type are fixed at creation and cannot be updated. To use different ones, create a new template and archive this one. `PATCH https://api.light.inc/v1/accounting-release-templates/{templateId}` ## Note No status check: an ARCHIVED template can still be updated and stays archived. name , method and accumulatePastReleasesEnabled cannot be cleared; defaultDuration , the percentages, residualAmount , reducingRate and context follow the null -clears rule. The merged result is re-validated with the create rules. ## Authorization - API key - Bearer token See https://light.inc/docs/getting-started/authentication. ## Path parameters - `templateId` (string, uuid, required) ## Request body `application/json;charset=UTF-8` ```json { "name": "string", "method": "STRAIGHT_LINE_WITH_PARTIAL_ADJUSTMENT", "accumulatePastReleasesEnabled": true, "defaultDuration": 0, "initialAmountPercentage": 0, "residualAmountPercentage": 0, "residualAmount": 100000, "reducingRate": 0, "context": "string" } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders, and fields that exclude each other are all shown. Do not send it unchanged. ## Response ```json { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "createdBy": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "name": "string", "method": "STRAIGHT_LINE_WITH_PARTIAL_ADJUSTMENT", "type": "AR", "deferralAccountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "contractAccountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "additionsAccountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "disposalAccountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "profitAccountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "lossAccountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "initialAmountPercentage": 0, "residualAmountPercentage": 0, "residualAmount": 100000, "reducingRate": 0, "accumulatePastReleasesEnabled": true, "defaultDuration": 0, "context": "string", "status": "ACTIVE", "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z" } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders. ## Code ```bash curl -X PATCH "https://api.light.inc/v1/accounting-release-templates/3c90c3cc-0d44-4b50-8888-8dd25736052a" \ -H "Authorization: Basic YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "name": "string", "method": "STRAIGHT_LINE_WITH_PARTIAL_ADJUSTMENT", "accumulatePastReleasesEnabled": true, "defaultDuration": 0, "initialAmountPercentage": 0, "residualAmountPercentage": 0, "residualAmount": 100000, "reducingRate": 0, "context": "string" }' ``` Full page: https://light.inc/docs/api-reference/v1--accounting-release-templates/update-accounting-release-template --- # Attachments (resource) Upload, list and manage the documents attached to a record. Resource page: https://light.inc/docs/api-reference/v1--attachments # List attachments > Returns a list of attachments associated with a specific resource `GET https://api.light.inc/v1/attachments` ## Note Returns a bare JSON array, not the paginated {records, hasMore} envelope, and takes no filter , sort or limit . resourceId is required; an unknown id yields [] rather than 404 . ## Authorization - API key - Bearer token See https://light.inc/docs/getting-started/authentication. ## Query parameters - `resourceId` (string, uuid) ## Response ```json [ { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "resourceId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "documentKey": "string", "fileName": "string", "contentType": "string", "createdBy": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "metadata": { "type": "AR" }, "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z" } ] ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders. ## Code ```bash curl -X GET "https://api.light.inc/v1/attachments" \ -H "Authorization: Basic YOUR_API_KEY" ``` Full page: https://light.inc/docs/api-reference/v1--attachments/list-attachments --- # Create attachment > Creates a new attachment record `POST https://api.light.inc/v1/attachments` ## Note Step three of the upload flow: documentKey is the key returned by POST /v1/attachments/upload-url , and the bytes must already be there — otherwise ATTACHMENT_FILE_NOT_FOUND . A resource can carry at most 10 attachments ( ATTACHMENT_NUMBER_FOR_RESOURCE_EXCEEDED ); the same documentKey or fileName twice on one resource fails with ATTACHMENT_DOCUMENT_KEY_ALREADY_EXISTS / ATTACHMENT_FILE_NAME_FOR_RESOURCE_ALREADY_EXISTS . resourceId is not validated. metadata is only read when Light emails a sales invoice or customer credit ( type: "AR" , shouldAttachToEmail ); on other resources it has no effect. ## Authorization - API key - Bearer token See https://light.inc/docs/getting-started/authentication. ## Request body `application/json;charset=UTF-8` ```json { "resourceId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "documentKey": "string", "fileName": "string", "contentType": "string", "metadata": { "type": "AR" } } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders, and fields that exclude each other are all shown. Do not send it unchanged. ## Response ```json { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "resourceId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "documentKey": "string", "fileName": "string", "contentType": "string", "createdBy": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "metadata": { "type": "AR" }, "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z" } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders. ## Code ```bash curl -X POST "https://api.light.inc/v1/attachments" \ -H "Authorization: Basic YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "resourceId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "documentKey": "string", "fileName": "string", "contentType": "string", "metadata": { "type": "AR" } }' ``` Full page: https://light.inc/docs/api-reference/v1--attachments/create-attachment --- # Generate attachment upload URL > Generates a secure upload URL for attachment files `POST https://api.light.inc/v1/attachments/upload-url` ## Note Step one of three; see Files (/docs/getting-started/pagination-filtering-errors files). The URL is valid for five minutes . When you PUT the bytes to it, set Content-Type to the contentType you asked for and send every entry of the returned metadata as a request header — they are signed into the URL and the upload is rejected without them. Then register the file with POST /v1/attachments , passing the returned key as documentKey . fileName must be unique per resourceId ; reusing one fails with ATTACHMENT_FILE_NAME_FOR_RESOURCE_ALREADY_EXISTS . contentType must be one of the PDF, image ( image/ ), text or Office document types; anything else fails with UNSUPPORTED_FILE_MIME_TYPE . The key is generated by Light; you cannot choose it. There is no resourceType in this API: resourceId is the id of the record (an invoice, a purchase order, ...) and it is not checked against anything, so a typo produces an attachment nothing will ever show. ## Authorization - API key - Bearer token See https://light.inc/docs/getting-started/authentication. ## Request body `application/json;charset=UTF-8` ```json { "resourceId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "fileName": "string", "contentType": "string" } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders, and fields that exclude each other are all shown. Do not send it unchanged. ## Response - `key` — Pass this as `documentKey` to `POST /v1/attachments` once the upload is done. - `metadata` — Send every entry as a request header on the `PUT` to `uploadUrl`, exactly as returned. They are signed into the URL; the upload is rejected without them. ```json { "uploadUrl": "https://example.com", "key": "string", "metadata": null } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders. ## Code ```bash curl -X POST "https://api.light.inc/v1/attachments/upload-url" \ -H "Authorization: Basic YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "resourceId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "fileName": "string", "contentType": "string" }' ``` Full page: https://light.inc/docs/api-reference/v1--attachments/generate-attachment-upload-url --- # Delete attachment > Deletes a specific attachment and its associated file `DELETE https://api.light.inc/v1/attachments/{attachmentId}` ## Note The stored file is not deleted. Despite the description, this removes only the attachment record; the uploaded object stays in storage. Deleting is refused with ATTACHMENT_CANNOT_BE_DELETED_FOR_POSTED_DOCUMENT when the resource is an accounting document that has been posted. Any principal in the company may delete, not only the uploader. Success is 204 with no body. ## Authorization - API key - Bearer token See https://light.inc/docs/getting-started/authentication. ## Path parameters - `attachmentId` (string, uuid, required) ## Response This endpoint returns no content. ## Code ```bash curl -X DELETE "https://api.light.inc/v1/attachments/3c90c3cc-0d44-4b50-8888-8dd25736052a" \ -H "Authorization: Basic YOUR_API_KEY" ``` Full page: https://light.inc/docs/api-reference/v1--attachments/delete-attachment --- # Get attachment document > Returns the document file for a specific attachment `GET https://api.light.inc/v1/attachments/{attachmentId}/document` ## Note Returns a 307 Temporary Redirect with an empty body, not the file. The Location is a pre-signed download URL valid for two hours that serves the file with its stored content type and a Content-Disposition: attachment header. Follow it without your Light Authorization header. Unknown id: 404 ATTACHMENT_NOT_FOUND . ## Authorization - API key - Bearer token See https://light.inc/docs/getting-started/authentication. ## Path parameters - `attachmentId` (string, uuid, required) ## Response This endpoint returns no content. ## Code ```bash curl -X GET "https://api.light.inc/v1/attachments/3c90c3cc-0d44-4b50-8888-8dd25736052a/document" \ -H "Authorization: Basic YOUR_API_KEY" ``` Full page: https://light.inc/docs/api-reference/v1--attachments/get-attachment-document --- # Get attachment options > Handles CORS preflight requests for attachment document access `OPTIONS https://api.light.inc/v1/attachments/{attachmentId}/document` ## Note CORS preflight for browsers that download the file directly. Answers 200 with the allowed-origin headers and no body, without authentication. API clients never need to call it. ## Authorization - API key - Bearer token See https://light.inc/docs/getting-started/authentication. ## Path parameters - `attachmentId` (string, uuid, required) ## Request body `application/json;charset=UTF-8` ```json { "roles": [ "string" ], "name": "string" } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders, and fields that exclude each other are all shown. Do not send it unchanged. ## Response This endpoint returns no content. ## Code ```bash curl -X OPTIONS "https://api.light.inc/v1/attachments/3c90c3cc-0d44-4b50-8888-8dd25736052a/document" \ -H "Authorization: Basic YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "roles": [ "string" ], "name": "string" }' ``` Full page: https://light.inc/docs/api-reference/v1--attachments/get-attachment-options --- # Bank Accounts (resource) Create and access bank accounts. Creating one also creates its linked ledger account atomically. Resource page: https://light.inc/docs/api-reference/v1--bank-accounts # Get bank accounts of the company > Returns all bank accounts of the company `GET https://api.light.inc/v1/bank-accounts` ## Note Not paginated and not filterable: every bank account of the company, with no status to tell active from retired ones. ## Authorization - API key - Bearer token See https://light.inc/docs/getting-started/authentication. ## Response - `paymentSchedulingEligibility` — Derived from the provider: `INTERNAL` for banks Light can pay through, otherwise `INELIGIBLE`. Accounts created here never come back as `BANK_PROVIDER`. ```json [ { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyEntityId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "name": "string", "type": "PHYSICAL", "bankProvider": "ABANCA", "paymentSchedulingEligibility": "INTERNAL", "iban": "string", "bic": "string", "domesticBankAccountNumber": "string", "domesticBankCode": "string", "currency": "USD", "bankCountry": "UNDEFINED", "bankCity": "string", "bankAddress": "string", "bankZipcode": "string", "bankName": "string", "bankState": "string", "ledgerAccountCode": 0, "createdAt": "2026-01-15T09:30:00Z" } ] ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders. ## Code ```bash curl -X GET "https://api.light.inc/v1/bank-accounts" \ -H "Authorization: Basic YOUR_API_KEY" ``` Full page: https://light.inc/docs/api-reference/v1--bank-accounts/get-bank-accounts-of-the-company --- # Create bank account > Creates a bank account along with its linked ledger (chart-of-accounts) entry in a single transaction. The ledger account code must be a unique 6-digit integer within the company's chart of accounts. `POST https://api.light.inc/v1/bank-accounts` ## Note The ledger account is created with fixed attributes you cannot choose: type BANK , active, revalued for FX at end-of-month rates, in the bank account's currency, scoped to the one companyEntityId . Its label defaults to the bank account's name , not the bank name as the description says. code must be exactly six digits ( LEDGER_ACCOUNT_CODE_LENGTH ) and unused ( BANK_ACCOUNT_LEDGER_ACCOUNT_CODE_ALREADY_EXISTS ; nothing is created). bankProvider: OTHER requires bankName ; other providers fill it in. The response's type and paymentSchedulingEligibility are derived from the provider (only Airwallex accounts are VIRTUAL ; only providers Light can pay through are INTERNAL , everything else INELIGIBLE ). Company-admin role only. ## Authorization - API key - Bearer token See https://light.inc/docs/getting-started/authentication. ## Request body `application/json;charset=UTF-8` ```json { "companyEntityId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "name": "string", "bankProvider": "ABANCA", "currency": "USD", "bankCountry": "UNDEFINED", "ledgerAccount": { "code": 0, "label": "string" }, "iban": "string", "bic": "string", "domesticBankAccountNumber": "string", "domesticBankCode": "string", "bankName": "string", "bankCity": "string", "bankAddress": "string", "bankZipcode": "string", "bankState": "string", "defaultChargeBearerCode": "OUR" } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders, and fields that exclude each other are all shown. Do not send it unchanged. ## Response - `paymentSchedulingEligibility` — Derived from the provider: `INTERNAL` for banks Light can pay through, otherwise `INELIGIBLE`. Accounts created here never come back as `BANK_PROVIDER`. ```json { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyEntityId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "name": "string", "type": "PHYSICAL", "bankProvider": "ABANCA", "paymentSchedulingEligibility": "INTERNAL", "iban": "string", "bic": "string", "domesticBankAccountNumber": "string", "domesticBankCode": "string", "currency": "USD", "bankCountry": "UNDEFINED", "bankCity": "string", "bankAddress": "string", "bankZipcode": "string", "bankName": "string", "bankState": "string", "ledgerAccountCode": 0, "createdAt": "2026-01-15T09:30:00Z" } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders. ## Code ```bash curl -X POST "https://api.light.inc/v1/bank-accounts" \ -H "Authorization: Basic YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "companyEntityId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "name": "string", "bankProvider": "ABANCA", "currency": "USD", "bankCountry": "UNDEFINED", "ledgerAccount": { "code": 0, "label": "string" }, "iban": "string", "bic": "string", "domesticBankAccountNumber": "string", "domesticBankCode": "string", "bankName": "string", "bankCity": "string", "bankAddress": "string", "bankZipcode": "string", "bankState": "string", "defaultChargeBearerCode": "OUR" }' ``` Full page: https://light.inc/docs/api-reference/v1--bank-accounts/create-bank-account --- # List bank transactions > Returns a paginated list of bank transactions for the specified bank account, including the balance `GET https://api.light.inc/v1/bank-accounts/{bankAccountId}/bank-transactions` ## Note balance is not the page's balance: it is D minus C over every transaction matching the filter, and, unlike GET .../balance , it includes EXCLUDED transactions unless you filter them out. Cursor pagination doesn't apply here: cursor is treated as an offset and the response has no nextCursor or hasMore , so page with offset , limit and total . Default order is newest-created first, not by date . ## Authorization - API key - Bearer token See https://light.inc/docs/getting-started/authentication. ## Path parameters - `bankAccountId` (string, uuid, required) ## Query parameters - `sort` (string) — Sort string in the format field:direction . To provide multiple sort fields, separate them with commas. Available directions: asc , desc . Available fields: reconciliationStatus , dcSign , date , amount , name , memo . - `filter` (string) — Filter string in the format field:operator:value . To provide multiple filters, separate them with commas. Available operators: eq , ne , in , not_in , gt , gte , lt , lte . - For in and not_in operators, provide multiple values separated by the pipe character ( ). Available fields: reconciliationStatus , dcSign , date . - `limit` (integer, int32) — Maximum number of items to return. Default is 50, maximum is 200. - `offset` (integer, int64) — Number of items to skip before starting to collect the result set. Deprecated, use 'cursor' instead. - `cursor` (string) — The cursor position to start returning results from. To opt-in into cursor-based pagination, provide 0 for the initial request. For subsequent requests, use nextCursor and prevCursor from the previous response to navigate. Cursor values are opaque and should not be constructed manually. ## Response ```json { "total": 100000, "records": [ { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "bankAccountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "date": "2026-01-15", "amount": 100000, "dcSign": "D", "reconciliationStatus": "EXCLUDED", "name": "string", "memo": "string", "reference": "string", "transactionId": "string", "createdAt": "2026-01-15T09:30:00Z" } ], "balance": 100000 } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders. ## Code ```bash curl -X GET "https://api.light.inc/v1/bank-accounts/3c90c3cc-0d44-4b50-8888-8dd25736052a/bank-transactions" \ -H "Authorization: Basic YOUR_API_KEY" ``` Full page: https://light.inc/docs/api-reference/v1--bank-accounts/list-bank-transactions --- # Create bank transactions > Creates bank transactions in batch. Maximum 500 transactions per request. Duplicate transactions (same transactionId for the same bank account) are silently skipped. `POST https://api.light.inc/v1/bank-accounts/{bankAccountId}/bank-transactions` ## Note dcSign is the reverse of the description. A bank account is an asset, so D is money in (increases the balance) and C is money out ; this is what the bank feeds, the CSV import and both balance endpoints use. Sending D for outflows inverts every balance. Duplicate handling is silent: a row whose transactionId already exists for this API on the account is skipped and simply missing from the response (a full retry returns [] ). Rows with transactionId: null are never de-duplicated, and a transaction already present from a bank feed or CSV import under the same id is not treated as a duplicate either. Over 500 rows is BANK_TRANSACTION_BATCH_SIZE_EXCEEDED , an empty list BANK_TRANSACTION_BATCH_EMPTY . Nothing is posted to the ledger: transactions land as UNMATCHED for bank reconciliation only. A negative amount is accepted and flips the arithmetic, so keep amounts positive and use dcSign . ## Authorization - API key - Bearer token See https://light.inc/docs/getting-started/authentication. ## Path parameters - `bankAccountId` (string, uuid, required) ## Request body `application/json;charset=UTF-8` - `transactions.dcSign` — `D` is money **in** (the balance goes up), `C` is money **out** — the reverse of the description. A bank account is an asset, and every other way transactions reach Light uses this convention. - `transactions.transactionId` — The de-duplication key, among transactions created through this API only. `null` disables it for the row, so retries insert it again. ```json { "transactions": [ { "date": "2026-01-15", "amount": 100000, "dcSign": "D", "name": "string", "memo": "string", "reference": "string", "transactionId": "string" } ] } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders, and fields that exclude each other are all shown. Do not send it unchanged. ## Response ```json [ { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "bankAccountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "date": "2026-01-15", "amount": 100000, "dcSign": "D", "reconciliationStatus": "EXCLUDED", "name": "string", "memo": "string", "reference": "string", "transactionId": "string", "createdAt": "2026-01-15T09:30:00Z" } ] ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders. ## Code ```bash curl -X POST "https://api.light.inc/v1/bank-accounts/3c90c3cc-0d44-4b50-8888-8dd25736052a/bank-transactions" \ -H "Authorization: Basic YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "transactions": [ { "date": "2026-01-15", "amount": 100000, "dcSign": "D", "name": "string", "memo": "string", "reference": "string", "transactionId": "string" } ] }' ``` Full page: https://light.inc/docs/api-reference/v1--bank-accounts/create-bank-transactions --- # Get bank account balance > Returns the bank statement balance and ledger balance for a bank account as of the given date. If asOf is omitted, today's balance is returned. The bank balance is derived from the opening balance plus all bank transactions on or before asOf ; the ledger balance is the sum of ledger transaction lines posted on or before asOf for the linked ledger account. `GET https://api.light.inc/v1/bank-accounts/{bankAccountId}/balance` ## Note bankBalance is the stored closing balance plus the signed non-EXCLUDED transactions dated after its day up to asOf ; it is null when no balance has been set or when asOf is before the day the balance was set for . ledgerBalance is the debit-positive sum, in the transaction currency, of lines on the linked ledger account posted up to asOf , excluding FX revaluations, archived documents and reversed lines; it is 0 rather than null when there are none. ## Authorization - API key - Bearer token See https://light.inc/docs/getting-started/authentication. ## Path parameters - `bankAccountId` (string, uuid, required) ## Query parameters - `asOf` (string) — Date the balance is computed for (ISO-8601, e.g. 2026-05-07 ). Defaults to today. ## Response ```json { "bankAccountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "currency": "string", "bankBalance": 100000, "ledgerBalance": 100000, "asOf": "2026-01-15" } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders. ## Code ```bash curl -X GET "https://api.light.inc/v1/bank-accounts/3c90c3cc-0d44-4b50-8888-8dd25736052a/balance" \ -H "Authorization: Basic YOUR_API_KEY" ``` Full page: https://light.inc/docs/api-reference/v1--bank-accounts/get-bank-account-balance --- # Upsert bank account balance > Creates or updates the opening balance for a bank account. Only one balance per bank account is allowed — subsequent calls update the existing balance. `PUT https://api.light.inc/v1/bank-accounts/{bankAccountId}/balance` ## Note This stores a closing (end-of-day) balance, not an opening one. balanceAt is normalised to 23:59:59 UTC of its day, and transactions dated on or before that day are treated as already included in the balance; only later transactions are added on top. So give the statement balance at the end of that day, and load transactions dated after it. A second call replaces both balance and balanceAt for the account. ## Authorization - API key - Bearer token See https://light.inc/docs/getting-started/authentication. ## Path parameters - `bankAccountId` (string, uuid, required) ## Request body `application/json;charset=UTF-8` - `balanceAt` — A closing (end-of-day) point: the time of day is discarded and transactions dated that day or earlier count as already included in `balance`. ```json { "balanceAt": "2026-01-15T09:30:00Z", "balance": 100000 } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders, and fields that exclude each other are all shown. Do not send it unchanged. ## Response ```json { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "bankAccountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "balanceAt": "2026-01-15T09:30:00Z", "balance": 100000 } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders. ## Code ```bash curl -X PUT "https://api.light.inc/v1/bank-accounts/3c90c3cc-0d44-4b50-8888-8dd25736052a/balance" \ -H "Authorization: Basic YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "balanceAt": "2026-01-15T09:30:00Z", "balance": 100000 }' ``` Full page: https://light.inc/docs/api-reference/v1--bank-accounts/upsert-bank-account-balance --- # Get bank transaction > Returns a specific bank transaction by ID `GET https://api.light.inc/v1/bank-accounts/{bankAccountId}/bank-transactions/{bankTransactionId}` ## Note 404 unless the transaction belongs to that bank account. ## Authorization - API key - Bearer token See https://light.inc/docs/getting-started/authentication. ## Path parameters - `bankAccountId` (string, uuid, required) - `bankTransactionId` (string, uuid, required) ## Response ```json { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "bankAccountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "date": "2026-01-15", "amount": 100000, "dcSign": "D", "reconciliationStatus": "EXCLUDED", "name": "string", "memo": "string", "reference": "string", "transactionId": "string", "createdAt": "2026-01-15T09:30:00Z" } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders. ## Code ```bash curl -X GET "https://api.light.inc/v1/bank-accounts/3c90c3cc-0d44-4b50-8888-8dd25736052a/bank-transactions/3c90c3cc-0d44-4b50-8888-8dd25736052a" \ -H "Authorization: Basic YOUR_API_KEY" ``` Full page: https://light.inc/docs/api-reference/v1--bank-accounts/get-bank-transaction --- # Invoice Payables (resource) Create, approve, decline and mark as paid — bills and their line items, end to end. Resource page: https://light.inc/docs/api-reference/v1--invoice-payables # List invoice payables > Returns a paginated list of invoice payables `GET https://api.light.inc/v1/bff/invoice-payables` ## Note This is the only list operation for invoice payables — /v1/invoice-payables has no GET . The single-record read is GET /v1/invoice-payables/{invoicePayableId} , and it returns a different shape : list rows have no lineItems , customProperties , outstandingBalance , purchaseOrderId , FX rates or payment references, and instead carry vendor , user , nextApprover , companyEntityName and documentKey . nextApprover is null when the next approver is a user group. include accepts only REIMBURSEMENT . The documentNumber filter matches the invoice number. A credential without the company-admin, AP-preparation or auditor role must filter on its own user id ( approverUserId:eq: Approves an invoice payable for payment processing `POST https://api.light.inc/v1/invoice-payables/{invoicePayableId}/approve` ## Note Records the decision of the credential's user , who must be one of the bill's assigned approvers ( USER_NOT_PART_OF_APPROVAL ) with the invoice-approver role; an API key approves as its service account, so it must have been assigned by the workflow. With several approvers the state stays APPROVAL_PENDING until the last one approves, then moves to APPROVED_ACCOUNTING_ENTRY_PENDING and is posted in the background, ending in READY_FOR_PAYMENT_RELEASE , SCHEDULED or UNPAID . If the bill's approval is no longer in progress the call is a silent no-op returning the bill; a bill with no approval at all is 404 INVOICE_APPROVAL_NOT_FOUND . ## Authorization - API key - Bearer token See https://light.inc/docs/getting-started/authentication. ## Path parameters - `invoicePayableId` (string, uuid, required) ## Request body `application/json;charset=UTF-8` ```json { "note": "string" } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders, and fields that exclude each other are all shown. Do not send it unchanged. ## Response - `invoicePayableId` — Always identical to `id`. - `state` — Every `*_PENDING` state resolves in the background: poll. Actions called in the wrong state fail with `INVOICE_PAYABLE_EVENT_NOT_SUPPORTED`. `PAID` means marked as paid but not yet settled; `COMPLETED` is settled, and only then can the clearing be reversed. - `failureContext` — On a bill this carries approval-submission, posting or duplicate errors (`APPROVAL_SUBMISSION_FAILED`, `ERP_ENTRY_FAILED`, `DUPLICATE_INVOICE`); the description about vendor onboarding is a copy-paste from another model. - `vendorDetailsOcr.phoneNumber` — May be `null` when the scan did not find one. - `vendorDetailsOcr.phoneNumber.localNumber` — The number without the country code. - `outstandingBalance` — `null` on every write response and on `GET` without `includeOutstandingBalance=true`; also `null` when the computed balance would be negative. - `issuedDate` — The date the vendor issued the invoice. This model carries no `postingDate` — for the date the document hit the ledger, read the ledger line via `GET /v1/ledger-transaction-lines`. - `purchaseOrderId` — The order matched to this bill in Light. Read-only in practice: the `PATCH` field of the same name is ignored. ```json { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "type": "REIMBURSEMENT", "metadata": { "type": "SELF_BILLED_METADATA" }, "invoicePayableId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "state": "INIT", "failureReason": "EMAIL_NOT_ALLOWED", "failureContext": { "name": "string", "type": "BAD_REQUEST", "errors": [ { "type": "string", "message": "string", "path": [ "string" ], "context": null } ] }, "warningContext": { "name": "string", "type": "BAD_REQUEST", "errors": [ { "type": "string", "message": "string", "path": [ "string" ], "context": null } ] }, "approvalNote": "string", "cancellationReason": "string", "payeeName": "string", "payeeIban": "string", "payeeBban": "string", "payeeBic": "string", "payeeBankCode": "string", "payeeSwedishBankgiroNumber": "string", "payeeSwedishPlusgiroNumber": "string", "payeeCountry": "UNDEFINED", "payeeAddress": "string", "payeeZipcode": "string", "payeeBankName": "string", "payeeBankCountry": "UNDEFINED", "payeeBankAddress": "string", "payeeBankZipcode": "string", "payeeCity": "string", "payeeBankCity": "string", "vendorId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "vendorDetailsOcr": { "avatarUrl": "string", "name": "string", "email": "string", "phoneNumber": { "countryCode": "UNDEFINED", "localNumber": "string" }, "website": "string", "country": "UNDEFINED", "city": "string", "address": "string", "zipcode": "string", "bankAccountNumber": "string", "bankAccountBic": "string", "domesticBankAccountNumber": "string", "domesticBankAccountCode": "string", "vatId": "string" }, "companyEntityId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "invoiceNumber": "string", "amount": 100000, "outstandingBalance": 100000, "currency": "USD", "description": "string", "senderBankAccountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "fiNumber": "string", "finnishPaymentReference": "string", "norKidReference": "string", "swissPaymentReference": "string", "swedishOcrReference": "string", "paymentAt": "2026-01-15T09:30:00Z", "ocrCompletedAt": "2026-01-15T09:30:00Z", "canceledAt": "2026-01-15T09:30:00Z", "issuedDate": "2026-01-15", "dueDate": "2026-01-15", "invoiceCreatedAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z", "purchaseOrderId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "lineItemsIncludeTax": true, "localCurrencyFxRate": 0, "groupCurrencyFxRate": 0, "lineItems": [ { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "invoicePayableId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "type": "REIMBURSEMENT", "metadata": { "type": "REIMBURSEMENT" }, "amount": 100000, "netAmount": 100000, "description": "string", "taxCodeId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "taxAmount": 100000, "accountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "costCenterId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "amortizationStartDate": "2026-01-15", "amortizationEndDate": "2026-01-15", "amortizationTemplateId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "customPropertiesOld": { "items": null }, "aiValueSuggestions": [ { "field": "string", "fieldValues": [ "string" ], "reasoning": "string" } ], "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupInternalName": "string", "values": [ {} ] } ], "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z" } ], "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupInternalName": "string", "values": [ { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupInternalName": "string", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "internalName": "string", "label": "string", "context": "string", "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z" } ] } ], "paymentPausedBy": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "paymentPausedAt": "2026-01-15T09:30:00Z", "senderEmail": "string", "documentName": "string" } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders. ## Code ```bash curl -X POST "https://api.light.inc/v1/invoice-payables/3c90c3cc-0d44-4b50-8888-8dd25736052a/approve" \ -H "Authorization: Basic YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "note": "string" }' ``` Full page: https://light.inc/docs/api-reference/v1--invoice-payables/approve-invoice-payable --- # Cancel invoice payable > Cancels an invoice payable `POST https://api.light.inc/v1/invoice-payables/{invoicePayableId}/cancel` ## Note From IN_DRAFT , DUPLICATED , DECLINED or APPROVAL_PENDING the bill is cancelled immediately. From a posted, unpaid state ( UNPAID , READY_FOR_PAYMENT_RELEASE , SCHEDULED , PAYMENT_PAUSED , PENDING_PAYMENT_APPROVAL , PAYMENT_PENDING ) it moves to CANCELLATION_PENDING and becomes CANCELLED once the ledger entry is reversed in the background; this needs an open accounting period. PAID , PARTIALLY_PAID and COMPLETED cannot be cancelled: reverse the clearings first. Cancelling a cancelled bill is a no-op. The body is optional; reason is stored as cancellationReason . ## Authorization - API key - Bearer token See https://light.inc/docs/getting-started/authentication. ## Path parameters - `invoicePayableId` (string, uuid, required) ## Request body `application/json;charset=UTF-8` ```json { "reason": "string" } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders, and fields that exclude each other are all shown. Do not send it unchanged. ## Response - `invoicePayableId` — Always identical to `id`. - `state` — Every `*_PENDING` state resolves in the background: poll. Actions called in the wrong state fail with `INVOICE_PAYABLE_EVENT_NOT_SUPPORTED`. `PAID` means marked as paid but not yet settled; `COMPLETED` is settled, and only then can the clearing be reversed. - `failureContext` — On a bill this carries approval-submission, posting or duplicate errors (`APPROVAL_SUBMISSION_FAILED`, `ERP_ENTRY_FAILED`, `DUPLICATE_INVOICE`); the description about vendor onboarding is a copy-paste from another model. - `vendorDetailsOcr.phoneNumber` — May be `null` when the scan did not find one. - `vendorDetailsOcr.phoneNumber.localNumber` — The number without the country code. - `outstandingBalance` — `null` on every write response and on `GET` without `includeOutstandingBalance=true`; also `null` when the computed balance would be negative. - `issuedDate` — The date the vendor issued the invoice. This model carries no `postingDate` — for the date the document hit the ledger, read the ledger line via `GET /v1/ledger-transaction-lines`. - `purchaseOrderId` — The order matched to this bill in Light. Read-only in practice: the `PATCH` field of the same name is ignored. ```json { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "type": "REIMBURSEMENT", "metadata": { "type": "SELF_BILLED_METADATA" }, "invoicePayableId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "state": "INIT", "failureReason": "EMAIL_NOT_ALLOWED", "failureContext": { "name": "string", "type": "BAD_REQUEST", "errors": [ { "type": "string", "message": "string", "path": [ "string" ], "context": null } ] }, "warningContext": { "name": "string", "type": "BAD_REQUEST", "errors": [ { "type": "string", "message": "string", "path": [ "string" ], "context": null } ] }, "approvalNote": "string", "cancellationReason": "string", "payeeName": "string", "payeeIban": "string", "payeeBban": "string", "payeeBic": "string", "payeeBankCode": "string", "payeeSwedishBankgiroNumber": "string", "payeeSwedishPlusgiroNumber": "string", "payeeCountry": "UNDEFINED", "payeeAddress": "string", "payeeZipcode": "string", "payeeBankName": "string", "payeeBankCountry": "UNDEFINED", "payeeBankAddress": "string", "payeeBankZipcode": "string", "payeeCity": "string", "payeeBankCity": "string", "vendorId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "vendorDetailsOcr": { "avatarUrl": "string", "name": "string", "email": "string", "phoneNumber": { "countryCode": "UNDEFINED", "localNumber": "string" }, "website": "string", "country": "UNDEFINED", "city": "string", "address": "string", "zipcode": "string", "bankAccountNumber": "string", "bankAccountBic": "string", "domesticBankAccountNumber": "string", "domesticBankAccountCode": "string", "vatId": "string" }, "companyEntityId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "invoiceNumber": "string", "amount": 100000, "outstandingBalance": 100000, "currency": "USD", "description": "string", "senderBankAccountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "fiNumber": "string", "finnishPaymentReference": "string", "norKidReference": "string", "swissPaymentReference": "string", "swedishOcrReference": "string", "paymentAt": "2026-01-15T09:30:00Z", "ocrCompletedAt": "2026-01-15T09:30:00Z", "canceledAt": "2026-01-15T09:30:00Z", "issuedDate": "2026-01-15", "dueDate": "2026-01-15", "invoiceCreatedAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z", "purchaseOrderId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "lineItemsIncludeTax": true, "localCurrencyFxRate": 0, "groupCurrencyFxRate": 0, "lineItems": [ { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "invoicePayableId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "type": "REIMBURSEMENT", "metadata": { "type": "REIMBURSEMENT" }, "amount": 100000, "netAmount": 100000, "description": "string", "taxCodeId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "taxAmount": 100000, "accountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "costCenterId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "amortizationStartDate": "2026-01-15", "amortizationEndDate": "2026-01-15", "amortizationTemplateId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "customPropertiesOld": { "items": null }, "aiValueSuggestions": [ { "field": "string", "fieldValues": [ "string" ], "reasoning": "string" } ], "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupInternalName": "string", "values": [ {} ] } ], "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z" } ], "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupInternalName": "string", "values": [ { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupInternalName": "string", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "internalName": "string", "label": "string", "context": "string", "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z" } ] } ], "paymentPausedBy": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "paymentPausedAt": "2026-01-15T09:30:00Z", "senderEmail": "string", "documentName": "string" } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders. ## Code ```bash curl -X POST "https://api.light.inc/v1/invoice-payables/3c90c3cc-0d44-4b50-8888-8dd25736052a/cancel" \ -H "Authorization: Basic YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "reason": "string" }' ``` Full page: https://light.inc/docs/api-reference/v1--invoice-payables/cancel-invoice-payable --- # Create invoice payable > Creates a new invoice payable document. Supports inline line items via the lineItems field for single-request creation. `POST https://api.light.inc/v1/invoice-payables` ## Note processingMode decides which fields are read. With AI_PARSE_AND_MERGE only vendorId , amount and currency are used; companyEntityId , invoiceNumber , dates, senderBankAccountId , lineItems , customProperties and FX overrides are silently dropped , and the invoice is created in CREATED , where it waits for a document: upload one via POST .../document/upload-url , after which AI parsing fills the fields and moves it to IN_DRAFT in the background. With DATA_ONLY every field is stored, the invoice starts in IN_DRAFT , and a later document upload only attaches the file. There is no GET on this path; list with GET /v1/bff/invoice-payables . Line items: with lineItemsIncludeTax: true send amount (gross) and omit netAmount ; with false send netAmount and omit amount — the wrong field or both fails with INVALID_LINE_ITEM_AMOUNT_TYPE . Lines don't have to add up to amount yet; that is checked at submit or post ( INVALID_LINE_ITEM_SUM ). When companyEntityId is set, line tax amounts are recomputed from taxCodeId . Payee fields are copied from the vendor and cannot be set. senderBankAccountId omitted with an entity given defaults to the entity's bank account for the currency. type is always VENDOR_INVOICE . outstandingBalance is null on every response except a GET with includeOutstandingBalance=true . ## Authorization - API key - Bearer token See https://light.inc/docs/getting-started/authentication. ## Request body `application/json;charset=UTF-8` - `currency` — ISO 4217 code of the invoice currency. - `processingMode` — With `AI_PARSE_AND_MERGE` only `vendorId`, `amount` and `currency` are read; every other field in this body is dropped, and the bill waits in `CREATED` for a document upload. Use `DATA_ONLY` to store what you send. - `lineItems.customProperties.valueIds` — Catalogue value ids for this group. Required; send `[]` (with an empty `inlineValues`) to clear the group. `SINGLE_SELECT` and `MULTI_SELECT` groups accept nothing else. See [Custom properties on writes](/docs/getting-started/pagination-filtering-errors#custom-properties-on-writes). - `lineItems.customProperties.inlineValues` — Literal values for `TEXT`, `NUMERIC`, `BOOLEAN` and `DATE` groups, as strings (`yyyy-MM-dd` for dates). Rejected on select groups with `CUSTOM_PROPERTY_VALUE_TYPE_MISMATCH`. See [Custom properties on writes](/docs/getting-started/pagination-filtering-errors#custom-properties-on-writes). - `customProperties.valueIds` — Catalogue value ids for this group. Required; send `[]` (with an empty `inlineValues`) to clear the group. `SINGLE_SELECT` and `MULTI_SELECT` groups accept nothing else. See [Custom properties on writes](/docs/getting-started/pagination-filtering-errors#custom-properties-on-writes). - `customProperties.inlineValues` — Literal values for `TEXT`, `NUMERIC`, `BOOLEAN` and `DATE` groups, as strings (`yyyy-MM-dd` for dates). Rejected on select groups with `CUSTOM_PROPERTY_VALUE_TYPE_MISMATCH`. See [Custom properties on writes](/docs/getting-started/pagination-filtering-errors#custom-properties-on-writes). ```json { "vendorId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "amount": 100000, "currency": "USD", "processingMode": "DATA_ONLY", "companyEntityId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "invoiceNumber": "string", "description": "string", "issuedDate": "2026-01-15", "dueDate": "2026-01-15", "paymentAt": "2026-01-15T09:30:00Z", "senderBankAccountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "lineItemsIncludeTax": true, "lineItems": [ { "amount": 100000, "netAmount": 100000, "taxAmount": 100000, "description": "string", "taxCodeId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "accountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "amortizationStartDate": "2026-01-15", "amortizationEndDate": "2026-01-15", "amortizationTemplateId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "valueIds": [ "3c90c3cc-0d44-4b50-8888-8dd25736052a" ], "inlineValues": [ "string" ] } ] } ], "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "valueIds": [ "3c90c3cc-0d44-4b50-8888-8dd25736052a" ], "inlineValues": [ "string" ] } ], "localCurrencyFxRateOverride": 0, "groupCurrencyFxRateOverride": 0 } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders, and fields that exclude each other are all shown. Do not send it unchanged. ## Response - `invoicePayableId` — Always identical to `id`. - `state` — Every `*_PENDING` state resolves in the background: poll. Actions called in the wrong state fail with `INVOICE_PAYABLE_EVENT_NOT_SUPPORTED`. `PAID` means marked as paid but not yet settled; `COMPLETED` is settled, and only then can the clearing be reversed. - `failureContext` — On a bill this carries approval-submission, posting or duplicate errors (`APPROVAL_SUBMISSION_FAILED`, `ERP_ENTRY_FAILED`, `DUPLICATE_INVOICE`); the description about vendor onboarding is a copy-paste from another model. - `vendorDetailsOcr.phoneNumber` — May be `null` when the scan did not find one. - `vendorDetailsOcr.phoneNumber.localNumber` — The number without the country code. - `outstandingBalance` — `null` on every write response and on `GET` without `includeOutstandingBalance=true`; also `null` when the computed balance would be negative. - `issuedDate` — The date the vendor issued the invoice. This model carries no `postingDate` — for the date the document hit the ledger, read the ledger line via `GET /v1/ledger-transaction-lines`. - `purchaseOrderId` — The order matched to this bill in Light. Read-only in practice: the `PATCH` field of the same name is ignored. ```json { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "type": "REIMBURSEMENT", "metadata": { "type": "SELF_BILLED_METADATA" }, "invoicePayableId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "state": "INIT", "failureReason": "EMAIL_NOT_ALLOWED", "failureContext": { "name": "string", "type": "BAD_REQUEST", "errors": [ { "type": "string", "message": "string", "path": [ "string" ], "context": null } ] }, "warningContext": { "name": "string", "type": "BAD_REQUEST", "errors": [ { "type": "string", "message": "string", "path": [ "string" ], "context": null } ] }, "approvalNote": "string", "cancellationReason": "string", "payeeName": "string", "payeeIban": "string", "payeeBban": "string", "payeeBic": "string", "payeeBankCode": "string", "payeeSwedishBankgiroNumber": "string", "payeeSwedishPlusgiroNumber": "string", "payeeCountry": "UNDEFINED", "payeeAddress": "string", "payeeZipcode": "string", "payeeBankName": "string", "payeeBankCountry": "UNDEFINED", "payeeBankAddress": "string", "payeeBankZipcode": "string", "payeeCity": "string", "payeeBankCity": "string", "vendorId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "vendorDetailsOcr": { "avatarUrl": "string", "name": "string", "email": "string", "phoneNumber": { "countryCode": "UNDEFINED", "localNumber": "string" }, "website": "string", "country": "UNDEFINED", "city": "string", "address": "string", "zipcode": "string", "bankAccountNumber": "string", "bankAccountBic": "string", "domesticBankAccountNumber": "string", "domesticBankAccountCode": "string", "vatId": "string" }, "companyEntityId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "invoiceNumber": "string", "amount": 100000, "outstandingBalance": 100000, "currency": "USD", "description": "string", "senderBankAccountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "fiNumber": "string", "finnishPaymentReference": "string", "norKidReference": "string", "swissPaymentReference": "string", "swedishOcrReference": "string", "paymentAt": "2026-01-15T09:30:00Z", "ocrCompletedAt": "2026-01-15T09:30:00Z", "canceledAt": "2026-01-15T09:30:00Z", "issuedDate": "2026-01-15", "dueDate": "2026-01-15", "invoiceCreatedAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z", "purchaseOrderId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "lineItemsIncludeTax": true, "localCurrencyFxRate": 0, "groupCurrencyFxRate": 0, "lineItems": [ { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "invoicePayableId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "type": "REIMBURSEMENT", "metadata": { "type": "REIMBURSEMENT" }, "amount": 100000, "netAmount": 100000, "description": "string", "taxCodeId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "taxAmount": 100000, "accountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "costCenterId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "amortizationStartDate": "2026-01-15", "amortizationEndDate": "2026-01-15", "amortizationTemplateId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "customPropertiesOld": { "items": null }, "aiValueSuggestions": [ { "field": "string", "fieldValues": [ "string" ], "reasoning": "string" } ], "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupInternalName": "string", "values": [ {} ] } ], "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z" } ], "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupInternalName": "string", "values": [ { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupInternalName": "string", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "internalName": "string", "label": "string", "context": "string", "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z" } ] } ], "paymentPausedBy": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "paymentPausedAt": "2026-01-15T09:30:00Z", "senderEmail": "string", "documentName": "string" } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders. ## Code ```bash curl -X POST "https://api.light.inc/v1/invoice-payables" \ -H "Authorization: Basic YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "vendorId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "amount": 100000, "currency": "USD", "processingMode": "DATA_ONLY", "companyEntityId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "invoiceNumber": "string", "description": "string", "issuedDate": "2026-01-15", "dueDate": "2026-01-15", "paymentAt": "2026-01-15T09:30:00Z", "senderBankAccountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "lineItemsIncludeTax": true, "lineItems": [ { "amount": 100000, "netAmount": 100000, "taxAmount": 100000, "description": "string", "taxCodeId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "accountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "amortizationStartDate": "2026-01-15", "amortizationEndDate": "2026-01-15", "amortizationTemplateId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "valueIds": [ "3c90c3cc-0d44-4b50-8888-8dd25736052a" ], "inlineValues": [ "string" ] } ] } ], "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "valueIds": [ "3c90c3cc-0d44-4b50-8888-8dd25736052a" ], "inlineValues": [ "string" ] } ], "localCurrencyFxRateOverride": 0, "groupCurrencyFxRateOverride": 0 }' ``` Full page: https://light.inc/docs/api-reference/v1--invoice-payables/create-invoice-payable --- # Generate document upload URL > Generates a secure upload URL for invoice payable documents `POST https://api.light.inc/v1/invoice-payables/{invoicePayableId}/document/upload-url` ## Note The URL is valid for five minutes. PUT the bytes to it with every returned header set on the request — they carry the signed metadata that ties the file to the bill (see Files (/docs/getting-started/pagination-filtering-errors files)). Nothing else to call: Light attaches the file in the background, so poll GET /v1/invoice-payables/{invoicePayableId} until documentName is set. What happens next depends on state: a bill in CREATED (created with AI_PARSE_AND_MERGE ) is parsed and moves to IN_DRAFT ; a bill already in IN_DRAFT just gets the file, with nothing parsed or overwritten. A document is required before submit-for-approval and before converting to a credit note. ## Authorization - API key - Bearer token See https://light.inc/docs/getting-started/authentication. ## Path parameters - `invoicePayableId` (string, uuid, required) ## Request body `application/json;charset=UTF-8` ```json { "documentName": "string", "contentType": "string" } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders, and fields that exclude each other are all shown. Do not send it unchanged. ## Response ```json { "uploadUrl": "https://example.com", "headers": null } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders. ## Code ```bash curl -X POST "https://api.light.inc/v1/invoice-payables/3c90c3cc-0d44-4b50-8888-8dd25736052a/document/upload-url" \ -H "Authorization: Basic YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "documentName": "string", "contentType": "string" }' ``` Full page: https://light.inc/docs/api-reference/v1--invoice-payables/generate-document-upload-url --- # Create invoice payable line item > Creates an invoice payable line item `POST https://api.light.inc/v1/invoice-payables/{invoicePayableId}/line-items` ## Note Only while the bill is IN_DRAFT ( INVALID_LINE_ITEM_INVOICE_PAYABLE_STATE ). Send amount or netAmount according to the bill's lineItemsIncludeTax , never both ( INVALID_LINE_ITEM_AMOUNT_TYPE ). accountId may not be a payables or receivables control account ( DISALLOWED_LINE_ITEM_ACCOUNT_TYPE ). When the bill has an entity, taxAmount is recomputed from the tax code. costCenterId cannot be set through the API. ## Authorization - API key - Bearer token See https://light.inc/docs/getting-started/authentication. ## Path parameters - `invoicePayableId` (string, uuid, required) ## Request body `application/json;charset=UTF-8` - `customProperties.valueIds` — Catalogue value ids for this group. Required; send `[]` (with an empty `inlineValues`) to clear the group. `SINGLE_SELECT` and `MULTI_SELECT` groups accept nothing else. See [Custom properties on writes](/docs/getting-started/pagination-filtering-errors#custom-properties-on-writes). - `customProperties.inlineValues` — Literal values for `TEXT`, `NUMERIC`, `BOOLEAN` and `DATE` groups, as strings (`yyyy-MM-dd` for dates). Rejected on select groups with `CUSTOM_PROPERTY_VALUE_TYPE_MISMATCH`. See [Custom properties on writes](/docs/getting-started/pagination-filtering-errors#custom-properties-on-writes). ```json { "amount": 100000, "netAmount": 100000, "taxAmount": 100000, "description": "string", "taxCodeId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "accountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "amortizationStartDate": "2026-01-15", "amortizationEndDate": "2026-01-15", "amortizationTemplateId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "valueIds": [ "3c90c3cc-0d44-4b50-8888-8dd25736052a" ], "inlineValues": [ "string" ] } ] } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders, and fields that exclude each other are all shown. Do not send it unchanged. ## Response ```json { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "invoicePayableId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "type": "REIMBURSEMENT", "metadata": { "type": "REIMBURSEMENT" }, "amount": 100000, "netAmount": 100000, "description": "string", "taxCodeId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "taxAmount": 100000, "accountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "costCenterId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "amortizationStartDate": "2026-01-15", "amortizationEndDate": "2026-01-15", "amortizationTemplateId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "customPropertiesOld": { "items": null }, "aiValueSuggestions": [ { "field": "string", "fieldValues": [ "string" ], "reasoning": "string" } ], "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupInternalName": "string", "values": [ { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupInternalName": "string", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "internalName": "string", "label": "string", "context": "string", "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z" } ] } ], "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z" } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders. ## Code ```bash curl -X POST "https://api.light.inc/v1/invoice-payables/3c90c3cc-0d44-4b50-8888-8dd25736052a/line-items" \ -H "Authorization: Basic YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "amount": 100000, "netAmount": 100000, "taxAmount": 100000, "description": "string", "taxCodeId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "accountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "amortizationStartDate": "2026-01-15", "amortizationEndDate": "2026-01-15", "amortizationTemplateId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "valueIds": [ "3c90c3cc-0d44-4b50-8888-8dd25736052a" ], "inlineValues": [ "string" ] } ] }' ``` Full page: https://light.inc/docs/api-reference/v1--invoice-payables/create-invoice-payable-line-item --- # Decline invoice payable > Declines an invoice payable `POST https://api.light.inc/v1/invoice-payables/{invoicePayableId}/decline` ## Note Records the decision of the credential's user, who must be an assigned approver ( USER_NOT_PART_OF_APPROVAL ). The bill moves to DECLINED , from which the only public action is cancel ; there is no reset. If the approval is no longer in progress the call is a silent no-op. ## Authorization - API key - Bearer token See https://light.inc/docs/getting-started/authentication. ## Path parameters - `invoicePayableId` (string, uuid, required) ## Request body `application/json;charset=UTF-8` ```json { "note": "string" } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders, and fields that exclude each other are all shown. Do not send it unchanged. ## Response - `invoicePayableId` — Always identical to `id`. - `state` — Every `*_PENDING` state resolves in the background: poll. Actions called in the wrong state fail with `INVOICE_PAYABLE_EVENT_NOT_SUPPORTED`. `PAID` means marked as paid but not yet settled; `COMPLETED` is settled, and only then can the clearing be reversed. - `failureContext` — On a bill this carries approval-submission, posting or duplicate errors (`APPROVAL_SUBMISSION_FAILED`, `ERP_ENTRY_FAILED`, `DUPLICATE_INVOICE`); the description about vendor onboarding is a copy-paste from another model. - `vendorDetailsOcr.phoneNumber` — May be `null` when the scan did not find one. - `vendorDetailsOcr.phoneNumber.localNumber` — The number without the country code. - `outstandingBalance` — `null` on every write response and on `GET` without `includeOutstandingBalance=true`; also `null` when the computed balance would be negative. - `issuedDate` — The date the vendor issued the invoice. This model carries no `postingDate` — for the date the document hit the ledger, read the ledger line via `GET /v1/ledger-transaction-lines`. - `purchaseOrderId` — The order matched to this bill in Light. Read-only in practice: the `PATCH` field of the same name is ignored. ```json { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "type": "REIMBURSEMENT", "metadata": { "type": "SELF_BILLED_METADATA" }, "invoicePayableId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "state": "INIT", "failureReason": "EMAIL_NOT_ALLOWED", "failureContext": { "name": "string", "type": "BAD_REQUEST", "errors": [ { "type": "string", "message": "string", "path": [ "string" ], "context": null } ] }, "warningContext": { "name": "string", "type": "BAD_REQUEST", "errors": [ { "type": "string", "message": "string", "path": [ "string" ], "context": null } ] }, "approvalNote": "string", "cancellationReason": "string", "payeeName": "string", "payeeIban": "string", "payeeBban": "string", "payeeBic": "string", "payeeBankCode": "string", "payeeSwedishBankgiroNumber": "string", "payeeSwedishPlusgiroNumber": "string", "payeeCountry": "UNDEFINED", "payeeAddress": "string", "payeeZipcode": "string", "payeeBankName": "string", "payeeBankCountry": "UNDEFINED", "payeeBankAddress": "string", "payeeBankZipcode": "string", "payeeCity": "string", "payeeBankCity": "string", "vendorId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "vendorDetailsOcr": { "avatarUrl": "string", "name": "string", "email": "string", "phoneNumber": { "countryCode": "UNDEFINED", "localNumber": "string" }, "website": "string", "country": "UNDEFINED", "city": "string", "address": "string", "zipcode": "string", "bankAccountNumber": "string", "bankAccountBic": "string", "domesticBankAccountNumber": "string", "domesticBankAccountCode": "string", "vatId": "string" }, "companyEntityId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "invoiceNumber": "string", "amount": 100000, "outstandingBalance": 100000, "currency": "USD", "description": "string", "senderBankAccountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "fiNumber": "string", "finnishPaymentReference": "string", "norKidReference": "string", "swissPaymentReference": "string", "swedishOcrReference": "string", "paymentAt": "2026-01-15T09:30:00Z", "ocrCompletedAt": "2026-01-15T09:30:00Z", "canceledAt": "2026-01-15T09:30:00Z", "issuedDate": "2026-01-15", "dueDate": "2026-01-15", "invoiceCreatedAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z", "purchaseOrderId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "lineItemsIncludeTax": true, "localCurrencyFxRate": 0, "groupCurrencyFxRate": 0, "lineItems": [ { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "invoicePayableId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "type": "REIMBURSEMENT", "metadata": { "type": "REIMBURSEMENT" }, "amount": 100000, "netAmount": 100000, "description": "string", "taxCodeId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "taxAmount": 100000, "accountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "costCenterId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "amortizationStartDate": "2026-01-15", "amortizationEndDate": "2026-01-15", "amortizationTemplateId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "customPropertiesOld": { "items": null }, "aiValueSuggestions": [ { "field": "string", "fieldValues": [ "string" ], "reasoning": "string" } ], "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupInternalName": "string", "values": [ {} ] } ], "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z" } ], "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupInternalName": "string", "values": [ { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupInternalName": "string", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "internalName": "string", "label": "string", "context": "string", "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z" } ] } ], "paymentPausedBy": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "paymentPausedAt": "2026-01-15T09:30:00Z", "senderEmail": "string", "documentName": "string" } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders. ## Code ```bash curl -X POST "https://api.light.inc/v1/invoice-payables/3c90c3cc-0d44-4b50-8888-8dd25736052a/decline" \ -H "Authorization: Basic YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "note": "string" }' ``` Full page: https://light.inc/docs/api-reference/v1--invoice-payables/decline-invoice-payable --- # Get invoice payable line item > Gets an invoice payable line item `GET https://api.light.inc/v1/invoice-payables/{invoicePayableId}/line-items/{lineItemId}` ## Note Requires the permission to update bills, not only to view them; a read-only key gets 403 . ## Authorization - API key - Bearer token See https://light.inc/docs/getting-started/authentication. ## Path parameters - `invoicePayableId` (string, uuid, required) - `lineItemId` (string, uuid, required) ## Response ```json { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "invoicePayableId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "type": "REIMBURSEMENT", "metadata": { "type": "REIMBURSEMENT" }, "amount": 100000, "netAmount": 100000, "description": "string", "taxCodeId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "taxAmount": 100000, "accountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "costCenterId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "amortizationStartDate": "2026-01-15", "amortizationEndDate": "2026-01-15", "amortizationTemplateId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "customPropertiesOld": { "items": null }, "aiValueSuggestions": [ { "field": "string", "fieldValues": [ "string" ], "reasoning": "string" } ], "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupInternalName": "string", "values": [ { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupInternalName": "string", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "internalName": "string", "label": "string", "context": "string", "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z" } ] } ], "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z" } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders. ## Code ```bash curl -X GET "https://api.light.inc/v1/invoice-payables/3c90c3cc-0d44-4b50-8888-8dd25736052a/line-items/3c90c3cc-0d44-4b50-8888-8dd25736052a" \ -H "Authorization: Basic YOUR_API_KEY" ``` Full page: https://light.inc/docs/api-reference/v1--invoice-payables/get-invoice-payable-line-item --- # Update invoice payable line item > Updates an invoice payable line item `PUT https://api.light.inc/v1/invoice-payables/{invoicePayableId}/line-items/{lineItemId}` ## Note Only while the bill is IN_DRAFT ( INVALID_LINE_ITEM_INVOICE_PAYABLE_STATE ). Not a strict replace: an omitted taxCodeId or accountId keeps the current value, and taxAmount is recomputed whenever the amount changes. amount versus netAmount follows the bill's lineItemsIncludeTax ( INVALID_LINE_ITEM_AMOUNT_TYPE ). metadata.type defaults to VENDOR_INVOICE and must match the bill's type . ## Authorization - API key - Bearer token See https://light.inc/docs/getting-started/authentication. ## Path parameters - `invoicePayableId` (string, uuid, required) - `lineItemId` (string, uuid, required) ## Request body `application/json;charset=UTF-8` - `customProperties.valueIds` — Catalogue value ids for this group. Required; send `[]` (with an empty `inlineValues`) to clear the group. `SINGLE_SELECT` and `MULTI_SELECT` groups accept nothing else. See [Custom properties on writes](/docs/getting-started/pagination-filtering-errors#custom-properties-on-writes). - `customProperties.inlineValues` — Literal values for `TEXT`, `NUMERIC`, `BOOLEAN` and `DATE` groups, as strings (`yyyy-MM-dd` for dates). Rejected on select groups with `CUSTOM_PROPERTY_VALUE_TYPE_MISMATCH`. See [Custom properties on writes](/docs/getting-started/pagination-filtering-errors#custom-properties-on-writes). ```json { "amount": 100000, "netAmount": 100000, "taxAmount": 100000, "description": "string", "taxCodeId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "accountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "metadata": { "type": "REIMBURSEMENT" }, "amortizationStartDate": "2026-01-15", "amortizationEndDate": "2026-01-15", "amortizationTemplateId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "valueIds": [ "3c90c3cc-0d44-4b50-8888-8dd25736052a" ], "inlineValues": [ "string" ] } ] } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders, and fields that exclude each other are all shown. Do not send it unchanged. ## Response ```json { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "invoicePayableId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "type": "REIMBURSEMENT", "metadata": { "type": "REIMBURSEMENT" }, "amount": 100000, "netAmount": 100000, "description": "string", "taxCodeId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "taxAmount": 100000, "accountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "costCenterId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "amortizationStartDate": "2026-01-15", "amortizationEndDate": "2026-01-15", "amortizationTemplateId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "customPropertiesOld": { "items": null }, "aiValueSuggestions": [ { "field": "string", "fieldValues": [ "string" ], "reasoning": "string" } ], "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupInternalName": "string", "values": [ { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupInternalName": "string", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "internalName": "string", "label": "string", "context": "string", "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z" } ] } ], "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z" } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders. ## Code ```bash curl -X PUT "https://api.light.inc/v1/invoice-payables/3c90c3cc-0d44-4b50-8888-8dd25736052a/line-items/3c90c3cc-0d44-4b50-8888-8dd25736052a" \ -H "Authorization: Basic YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "amount": 100000, "netAmount": 100000, "taxAmount": 100000, "description": "string", "taxCodeId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "accountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "metadata": { "type": "REIMBURSEMENT" }, "amortizationStartDate": "2026-01-15", "amortizationEndDate": "2026-01-15", "amortizationTemplateId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "valueIds": [ "3c90c3cc-0d44-4b50-8888-8dd25736052a" ], "inlineValues": [ "string" ] } ] }' ``` Full page: https://light.inc/docs/api-reference/v1--invoice-payables/update-invoice-payable-line-item --- # Delete invoice payable line item > Deletes an invoice payable line item `DELETE https://api.light.inc/v1/invoice-payables/{invoicePayableId}/line-items/{lineItemId}` ## Note Only while the bill is IN_DRAFT ( INVALID_LINE_ITEM_INVOICE_PAYABLE_STATE ). Answers 204 with no body. ## Authorization - API key - Bearer token See https://light.inc/docs/getting-started/authentication. ## Path parameters - `invoicePayableId` (string, uuid, required) - `lineItemId` (string, uuid, required) ## Response This endpoint returns no content. ## Code ```bash curl -X DELETE "https://api.light.inc/v1/invoice-payables/3c90c3cc-0d44-4b50-8888-8dd25736052a/line-items/3c90c3cc-0d44-4b50-8888-8dd25736052a" \ -H "Authorization: Basic YOUR_API_KEY" ``` Full page: https://light.inc/docs/api-reference/v1--invoice-payables/delete-invoice-payable-line-item --- # Get invoice payable > Returns a specific invoice payable by ID `GET https://api.light.inc/v1/invoice-payables/{invoicePayableId}` ## Note To list payables, use GET /v1/bff/invoice-payables — this path has no list operation, and the list returns a slimmer shape. outstandingBalance is populated only with includeOutstandingBalance=true and a positive amount ; it is null if the computed balance would be negative. purchaseOrderId reflects the purchase order matched to the bill in Light, which no public endpoint sets. States and the endpoint that moves them: CREATED (waiting for a document) → IN_DRAFT (parsing done, or created with DATA_ONLY ) → APPROVAL_REQUESTED → APPROVAL_PENDING (via submit-for-approval ) → APPROVED_ACCOUNTING_ENTRY_PENDING (last approve ) → READY_FOR_PAYMENT_RELEASE , SCHEDULED or UNPAID depending on how the bill will be paid; or IN_DRAFT → UNPAID via post . mark-as-paid gives PAID (then COMPLETED once settled) or PARTIALLY_PAID . Also DUPLICATED , DECLINED , CANCELLATION_PENDING , CANCELLED , PAYMENT_PAUSED , PENDING_PAYMENT_APPROVAL , PAYMENT_PENDING . Every _PENDING state resolves in the background, so poll this endpoint. Any action called in the wrong state fails with INVOICE_PAYABLE_EVENT_NOT_SUPPORTED . ## Authorization - API key - Bearer token See https://light.inc/docs/getting-started/authentication. ## Path parameters - `invoicePayableId` (string, uuid, required) ## Query parameters - `includeOutstandingBalance` (boolean) ## Response - `invoicePayableId` — Always identical to `id`. - `state` — Every `*_PENDING` state resolves in the background: poll. Actions called in the wrong state fail with `INVOICE_PAYABLE_EVENT_NOT_SUPPORTED`. `PAID` means marked as paid but not yet settled; `COMPLETED` is settled, and only then can the clearing be reversed. - `failureContext` — On a bill this carries approval-submission, posting or duplicate errors (`APPROVAL_SUBMISSION_FAILED`, `ERP_ENTRY_FAILED`, `DUPLICATE_INVOICE`); the description about vendor onboarding is a copy-paste from another model. - `vendorDetailsOcr.phoneNumber` — May be `null` when the scan did not find one. - `vendorDetailsOcr.phoneNumber.localNumber` — The number without the country code. - `outstandingBalance` — `null` on every write response and on `GET` without `includeOutstandingBalance=true`; also `null` when the computed balance would be negative. - `issuedDate` — The date the vendor issued the invoice. This model carries no `postingDate` — for the date the document hit the ledger, read the ledger line via `GET /v1/ledger-transaction-lines`. - `purchaseOrderId` — The order matched to this bill in Light. Read-only in practice: the `PATCH` field of the same name is ignored. ```json { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "type": "REIMBURSEMENT", "metadata": { "type": "SELF_BILLED_METADATA" }, "invoicePayableId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "state": "INIT", "failureReason": "EMAIL_NOT_ALLOWED", "failureContext": { "name": "string", "type": "BAD_REQUEST", "errors": [ { "type": "string", "message": "string", "path": [ "string" ], "context": null } ] }, "warningContext": { "name": "string", "type": "BAD_REQUEST", "errors": [ { "type": "string", "message": "string", "path": [ "string" ], "context": null } ] }, "approvalNote": "string", "cancellationReason": "string", "payeeName": "string", "payeeIban": "string", "payeeBban": "string", "payeeBic": "string", "payeeBankCode": "string", "payeeSwedishBankgiroNumber": "string", "payeeSwedishPlusgiroNumber": "string", "payeeCountry": "UNDEFINED", "payeeAddress": "string", "payeeZipcode": "string", "payeeBankName": "string", "payeeBankCountry": "UNDEFINED", "payeeBankAddress": "string", "payeeBankZipcode": "string", "payeeCity": "string", "payeeBankCity": "string", "vendorId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "vendorDetailsOcr": { "avatarUrl": "string", "name": "string", "email": "string", "phoneNumber": { "countryCode": "UNDEFINED", "localNumber": "string" }, "website": "string", "country": "UNDEFINED", "city": "string", "address": "string", "zipcode": "string", "bankAccountNumber": "string", "bankAccountBic": "string", "domesticBankAccountNumber": "string", "domesticBankAccountCode": "string", "vatId": "string" }, "companyEntityId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "invoiceNumber": "string", "amount": 100000, "outstandingBalance": 100000, "currency": "USD", "description": "string", "senderBankAccountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "fiNumber": "string", "finnishPaymentReference": "string", "norKidReference": "string", "swissPaymentReference": "string", "swedishOcrReference": "string", "paymentAt": "2026-01-15T09:30:00Z", "ocrCompletedAt": "2026-01-15T09:30:00Z", "canceledAt": "2026-01-15T09:30:00Z", "issuedDate": "2026-01-15", "dueDate": "2026-01-15", "invoiceCreatedAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z", "purchaseOrderId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "lineItemsIncludeTax": true, "localCurrencyFxRate": 0, "groupCurrencyFxRate": 0, "lineItems": [ { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "invoicePayableId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "type": "REIMBURSEMENT", "metadata": { "type": "REIMBURSEMENT" }, "amount": 100000, "netAmount": 100000, "description": "string", "taxCodeId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "taxAmount": 100000, "accountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "costCenterId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "amortizationStartDate": "2026-01-15", "amortizationEndDate": "2026-01-15", "amortizationTemplateId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "customPropertiesOld": { "items": null }, "aiValueSuggestions": [ { "field": "string", "fieldValues": [ "string" ], "reasoning": "string" } ], "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupInternalName": "string", "values": [ {} ] } ], "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z" } ], "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupInternalName": "string", "values": [ { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupInternalName": "string", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "internalName": "string", "label": "string", "context": "string", "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z" } ] } ], "paymentPausedBy": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "paymentPausedAt": "2026-01-15T09:30:00Z", "senderEmail": "string", "documentName": "string" } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders. ## Code ```bash curl -X GET "https://api.light.inc/v1/invoice-payables/3c90c3cc-0d44-4b50-8888-8dd25736052a" \ -H "Authorization: Basic YOUR_API_KEY" ``` Full page: https://light.inc/docs/api-reference/v1--invoice-payables/get-invoice-payable --- # Update invoice payable > Updates an existing invoice payable document header `PATCH https://api.light.inc/v1/invoice-payables/{invoicePayableId}` ## Note Only in IN_DRAFT or DUPLICATED ( INVOICE_PAYABLE_EVENT_NOT_SUPPORTED otherwise); for a posted bill only PATCH .../custom-properties works. purchaseOrderId is accepted and ignored : the field in responses comes from Light's bill-to-order matching, which has no public endpoint. Most fields follow the omit-to-keep, null -to-clear rule; lineItemsIncludeTax and customProperties cannot be cleared. Every update runs duplicate detection: if another live bill has the same invoiceNumber and vendorId , the call still returns 200 but with state: DUPLICATED , failureReason: DUPLICATE_INVOICE and the other bill's id in failureContext — patch again or cancel. Changing vendorId re-copies the payee fields, defaults companyEntityId to the vendor's entity, and rewrites line account, tax and cost centre from the vendor's defaults; changing companyEntityId clears account and tax code on every line, and the entity must be one the vendor is enabled for ( INVOICE_PAYABLE_COMPANY_ENTITY_NOT_ALLOWED_FOR_VENDOR ). invoiceNumber and the payment references have all whitespace removed. ## Authorization - API key - Bearer token See https://light.inc/docs/getting-started/authentication. ## Path parameters - `invoicePayableId` (string, uuid, required) ## Request body `application/json;charset=UTF-8` - `purchaseOrderId` — Accepted but ignored. The order matched to a bill is set in Light, not through this API, and is what the response's `purchaseOrderId` reflects. - `customProperties.valueIds` — Catalogue value ids for this group. Required; send `[]` (with an empty `inlineValues`) to clear the group. `SINGLE_SELECT` and `MULTI_SELECT` groups accept nothing else. See [Custom properties on writes](/docs/getting-started/pagination-filtering-errors#custom-properties-on-writes). - `customProperties.inlineValues` — Literal values for `TEXT`, `NUMERIC`, `BOOLEAN` and `DATE` groups, as strings (`yyyy-MM-dd` for dates). Rejected on select groups with `CUSTOM_PROPERTY_VALUE_TYPE_MISMATCH`. See [Custom properties on writes](/docs/getting-started/pagination-filtering-errors#custom-properties-on-writes). ```json { "vendorId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyEntityId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "invoiceNumber": "string", "amount": 100000, "currency": "USD", "description": "string", "senderBankAccountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "fiNumber": "string", "finnishPaymentReference": "string", "norKidReference": "string", "swissPaymentReference": "string", "swedishOcrReference": "string", "paymentAt": "2026-01-15T09:30:00Z", "issuedDate": "2026-01-15", "dueDate": "2026-01-15", "approvalNote": "string", "purchaseOrderId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "lineItemsIncludeTax": true, "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "valueIds": [ "3c90c3cc-0d44-4b50-8888-8dd25736052a" ], "inlineValues": [ "string" ] } ], "localCurrencyFxRateOverride": 0, "groupCurrencyFxRateOverride": 0 } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders, and fields that exclude each other are all shown. Do not send it unchanged. ## Response - `invoicePayableId` — Always identical to `id`. - `state` — Every `*_PENDING` state resolves in the background: poll. Actions called in the wrong state fail with `INVOICE_PAYABLE_EVENT_NOT_SUPPORTED`. `PAID` means marked as paid but not yet settled; `COMPLETED` is settled, and only then can the clearing be reversed. - `failureContext` — On a bill this carries approval-submission, posting or duplicate errors (`APPROVAL_SUBMISSION_FAILED`, `ERP_ENTRY_FAILED`, `DUPLICATE_INVOICE`); the description about vendor onboarding is a copy-paste from another model. - `vendorDetailsOcr.phoneNumber` — May be `null` when the scan did not find one. - `vendorDetailsOcr.phoneNumber.localNumber` — The number without the country code. - `outstandingBalance` — `null` on every write response and on `GET` without `includeOutstandingBalance=true`; also `null` when the computed balance would be negative. - `issuedDate` — The date the vendor issued the invoice. This model carries no `postingDate` — for the date the document hit the ledger, read the ledger line via `GET /v1/ledger-transaction-lines`. - `purchaseOrderId` — The order matched to this bill in Light. Read-only in practice: the `PATCH` field of the same name is ignored. ```json { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "type": "REIMBURSEMENT", "metadata": { "type": "SELF_BILLED_METADATA" }, "invoicePayableId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "state": "INIT", "failureReason": "EMAIL_NOT_ALLOWED", "failureContext": { "name": "string", "type": "BAD_REQUEST", "errors": [ { "type": "string", "message": "string", "path": [ "string" ], "context": null } ] }, "warningContext": { "name": "string", "type": "BAD_REQUEST", "errors": [ { "type": "string", "message": "string", "path": [ "string" ], "context": null } ] }, "approvalNote": "string", "cancellationReason": "string", "payeeName": "string", "payeeIban": "string", "payeeBban": "string", "payeeBic": "string", "payeeBankCode": "string", "payeeSwedishBankgiroNumber": "string", "payeeSwedishPlusgiroNumber": "string", "payeeCountry": "UNDEFINED", "payeeAddress": "string", "payeeZipcode": "string", "payeeBankName": "string", "payeeBankCountry": "UNDEFINED", "payeeBankAddress": "string", "payeeBankZipcode": "string", "payeeCity": "string", "payeeBankCity": "string", "vendorId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "vendorDetailsOcr": { "avatarUrl": "string", "name": "string", "email": "string", "phoneNumber": { "countryCode": "UNDEFINED", "localNumber": "string" }, "website": "string", "country": "UNDEFINED", "city": "string", "address": "string", "zipcode": "string", "bankAccountNumber": "string", "bankAccountBic": "string", "domesticBankAccountNumber": "string", "domesticBankAccountCode": "string", "vatId": "string" }, "companyEntityId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "invoiceNumber": "string", "amount": 100000, "outstandingBalance": 100000, "currency": "USD", "description": "string", "senderBankAccountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "fiNumber": "string", "finnishPaymentReference": "string", "norKidReference": "string", "swissPaymentReference": "string", "swedishOcrReference": "string", "paymentAt": "2026-01-15T09:30:00Z", "ocrCompletedAt": "2026-01-15T09:30:00Z", "canceledAt": "2026-01-15T09:30:00Z", "issuedDate": "2026-01-15", "dueDate": "2026-01-15", "invoiceCreatedAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z", "purchaseOrderId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "lineItemsIncludeTax": true, "localCurrencyFxRate": 0, "groupCurrencyFxRate": 0, "lineItems": [ { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "invoicePayableId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "type": "REIMBURSEMENT", "metadata": { "type": "REIMBURSEMENT" }, "amount": 100000, "netAmount": 100000, "description": "string", "taxCodeId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "taxAmount": 100000, "accountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "costCenterId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "amortizationStartDate": "2026-01-15", "amortizationEndDate": "2026-01-15", "amortizationTemplateId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "customPropertiesOld": { "items": null }, "aiValueSuggestions": [ { "field": "string", "fieldValues": [ "string" ], "reasoning": "string" } ], "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupInternalName": "string", "values": [ {} ] } ], "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z" } ], "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupInternalName": "string", "values": [ { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupInternalName": "string", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "internalName": "string", "label": "string", "context": "string", "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z" } ] } ], "paymentPausedBy": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "paymentPausedAt": "2026-01-15T09:30:00Z", "senderEmail": "string", "documentName": "string" } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders. ## Code ```bash curl -X PATCH "https://api.light.inc/v1/invoice-payables/3c90c3cc-0d44-4b50-8888-8dd25736052a" \ -H "Authorization: Basic YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "vendorId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyEntityId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "invoiceNumber": "string", "amount": 100000, "currency": "USD", "description": "string", "senderBankAccountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "fiNumber": "string", "finnishPaymentReference": "string", "norKidReference": "string", "swissPaymentReference": "string", "swedishOcrReference": "string", "paymentAt": "2026-01-15T09:30:00Z", "issuedDate": "2026-01-15", "dueDate": "2026-01-15", "approvalNote": "string", "purchaseOrderId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "lineItemsIncludeTax": true, "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "valueIds": [ "3c90c3cc-0d44-4b50-8888-8dd25736052a" ], "inlineValues": [ "string" ] } ], "localCurrencyFxRateOverride": 0, "groupCurrencyFxRateOverride": 0 }' ``` Full page: https://light.inc/docs/api-reference/v1--invoice-payables/update-invoice-payable --- # Get invoice document > Returns the attached document for an invoice payable `GET https://api.light.inc/v1/invoice-payables/{invoicePayableId}/document` ## Note Answers 307 Temporary Redirect to a pre-signed download URL valid for 30 minutes, not the file; follow it without your Light Authorization header. documentType=GENERATED returns the PDF Light renders at submission, which exists only after submit-for-approval ( 404 INVOICE_PAYABLE_DOCUMENT_TYPE_NOT_FOUND before that); the default ORIGINAL is the uploaded file. ## Authorization - API key - Bearer token See https://light.inc/docs/getting-started/authentication. ## Path parameters - `invoicePayableId` (string, uuid, required) ## Query parameters - `documentType` (string) — ⚠️ This enum is not exhaustive; new values may be added in the future. ## Response Returns a file (application/pdf) rather than JSON. ## Code ```bash curl -X GET "https://api.light.inc/v1/invoice-payables/3c90c3cc-0d44-4b50-8888-8dd25736052a/document" \ -H "Authorization: Basic YOUR_API_KEY" ``` Full page: https://light.inc/docs/api-reference/v1--invoice-payables/get-invoice-document --- # Get linked credit notes > Returns all credit notes linked to the invoice payable `GET https://api.light.inc/v1/invoice-payables/{invoicePayableId}/credit-notes` ## Note Not paginated: every linked credit note comes back in one list. ## Authorization - API key - Bearer token See https://light.inc/docs/getting-started/authentication. ## Path parameters - `invoicePayableId` (string, uuid, required) ## Response ```json [ { "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "creditNote": { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "documentNumber": "string", "documentDate": "2026-01-15", "status": "DRAFT", "amount": 100000, "currency": "USD" }, "invoicePayable": { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "documentNumber": "string", "documentDate": "2026-01-15", "status": "DRAFT", "amount": 100000, "currency": "USD" }, "amount": 100000, "currency": "USD", "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z" } ] ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders. ## Code ```bash curl -X GET "https://api.light.inc/v1/invoice-payables/3c90c3cc-0d44-4b50-8888-8dd25736052a/credit-notes" \ -H "Authorization: Basic YOUR_API_KEY" ``` Full page: https://light.inc/docs/api-reference/v1--invoice-payables/get-linked-credit-notes --- # List invoice payable payments > Returns all clearings (bank payments and credit notes) linked to the invoice payable. Each entry carries a type discriminator ( BP for bank payments, CN for credit notes) so consumers can filter client-side if only one kind is needed. Reversed clearings are excluded. `GET https://api.light.inc/v1/invoice-payables/{invoicePayableId}/payments` ## Note A plain array. The top-level id is the clearing event, not the document: to reverse a payment, pass payment.accountingDocumentId and the matching type ( BP or CN ) to reverse-clearing . amount is the cleared amount in the invoice currency. payment is null for clearing types the API doesn't model. ## Authorization - API key - Bearer token See https://light.inc/docs/getting-started/authentication. ## Path parameters - `invoicePayableId` (string, uuid, required) ## Response ```json [ { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "invoicePayableId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "amount": 100000, "currency": "USD", "paymentDate": "2026-01-15", "payment": {}, "createdAt": "2026-01-15T09:30:00Z" } ] ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders. ## Code ```bash curl -X GET "https://api.light.inc/v1/invoice-payables/3c90c3cc-0d44-4b50-8888-8dd25736052a/payments" \ -H "Authorization: Basic YOUR_API_KEY" ``` Full page: https://light.inc/docs/api-reference/v1--invoice-payables/list-invoice-payable-payments --- # Mark invoice payable as paid > Marks an invoice payable as paid by recording a bank payment that clears it. Use paymentOption=FULL to clear the remaining outstanding balance, or paymentOption=PARTIAL to record an installment. The invoice transitions to PAID (full) or PARTIALLY_PAID (partial). `POST https://api.light.inc/v1/invoice-payables/{invoicePayableId}/mark-as-paid` ## Note paymentAt is required , contrary to the description; omitting it fails with INVOICE_PAYABLE_MARK_AS_PAID_INVALID_FIELD ("Payment date is required"). One of bankAccountId or ledgerAccountId is also required. amount is in the bank account's currency when you pay from a bank account (the invoice amount is converted at the company rate), and in the invoice currency for a non-bank ledger account. Allowed from UNPAID , READY_FOR_PAYMENT_RELEASE , SCHEDULED , PAYMENT_PENDING and PARTIALLY_PAID . paymentOption: FULL needs amount at least the remaining balance ( INVOICE_PAYABLE_FULL_PAYMENT_AMOUNT_TOO_SMALL ); any excess is booked as bank fees and the bill becomes PAID , then COMPLETED once settled. PARTIAL needs amount below the balance ( INVOICE_PAYABLE_PARTIAL_PAYMENT_AMOUNT_TOO_LARGE ) and gives PARTIALLY_PAID without storing paymentAt . Either way a bank-payment document is posted that clears the bill; it appears on GET .../payments as type BP , and its payment.accountingDocumentId is what reverse-clearing takes. Requires a user credential. ## Authorization - API key - Bearer token See https://light.inc/docs/getting-started/authentication. ## Path parameters - `invoicePayableId` (string, uuid, required) ## Request body `application/json;charset=UTF-8` - `amount` — In the **bank account's** currency when paying from `bankAccountId`; in the invoice currency only for a non-bank `ledgerAccountId`. - `paymentAt` — Required, despite the description: omitting it fails with `INVOICE_PAYABLE_MARK_AS_PAID_INVALID_FIELD`. ```json { "amount": 100000, "bankAccountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "ledgerAccountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "paymentAt": "2026-01-15T09:30:00Z", "comment": "string", "paymentOption": "FULL" } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders, and fields that exclude each other are all shown. Do not send it unchanged. ## Response - `invoicePayableId` — Always identical to `id`. - `state` — Every `*_PENDING` state resolves in the background: poll. Actions called in the wrong state fail with `INVOICE_PAYABLE_EVENT_NOT_SUPPORTED`. `PAID` means marked as paid but not yet settled; `COMPLETED` is settled, and only then can the clearing be reversed. - `failureContext` — On a bill this carries approval-submission, posting or duplicate errors (`APPROVAL_SUBMISSION_FAILED`, `ERP_ENTRY_FAILED`, `DUPLICATE_INVOICE`); the description about vendor onboarding is a copy-paste from another model. - `vendorDetailsOcr.phoneNumber` — May be `null` when the scan did not find one. - `vendorDetailsOcr.phoneNumber.localNumber` — The number without the country code. - `outstandingBalance` — `null` on every write response and on `GET` without `includeOutstandingBalance=true`; also `null` when the computed balance would be negative. - `issuedDate` — The date the vendor issued the invoice. This model carries no `postingDate` — for the date the document hit the ledger, read the ledger line via `GET /v1/ledger-transaction-lines`. - `purchaseOrderId` — The order matched to this bill in Light. Read-only in practice: the `PATCH` field of the same name is ignored. ```json { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "type": "REIMBURSEMENT", "metadata": { "type": "SELF_BILLED_METADATA" }, "invoicePayableId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "state": "INIT", "failureReason": "EMAIL_NOT_ALLOWED", "failureContext": { "name": "string", "type": "BAD_REQUEST", "errors": [ { "type": "string", "message": "string", "path": [ "string" ], "context": null } ] }, "warningContext": { "name": "string", "type": "BAD_REQUEST", "errors": [ { "type": "string", "message": "string", "path": [ "string" ], "context": null } ] }, "approvalNote": "string", "cancellationReason": "string", "payeeName": "string", "payeeIban": "string", "payeeBban": "string", "payeeBic": "string", "payeeBankCode": "string", "payeeSwedishBankgiroNumber": "string", "payeeSwedishPlusgiroNumber": "string", "payeeCountry": "UNDEFINED", "payeeAddress": "string", "payeeZipcode": "string", "payeeBankName": "string", "payeeBankCountry": "UNDEFINED", "payeeBankAddress": "string", "payeeBankZipcode": "string", "payeeCity": "string", "payeeBankCity": "string", "vendorId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "vendorDetailsOcr": { "avatarUrl": "string", "name": "string", "email": "string", "phoneNumber": { "countryCode": "UNDEFINED", "localNumber": "string" }, "website": "string", "country": "UNDEFINED", "city": "string", "address": "string", "zipcode": "string", "bankAccountNumber": "string", "bankAccountBic": "string", "domesticBankAccountNumber": "string", "domesticBankAccountCode": "string", "vatId": "string" }, "companyEntityId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "invoiceNumber": "string", "amount": 100000, "outstandingBalance": 100000, "currency": "USD", "description": "string", "senderBankAccountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "fiNumber": "string", "finnishPaymentReference": "string", "norKidReference": "string", "swissPaymentReference": "string", "swedishOcrReference": "string", "paymentAt": "2026-01-15T09:30:00Z", "ocrCompletedAt": "2026-01-15T09:30:00Z", "canceledAt": "2026-01-15T09:30:00Z", "issuedDate": "2026-01-15", "dueDate": "2026-01-15", "invoiceCreatedAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z", "purchaseOrderId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "lineItemsIncludeTax": true, "localCurrencyFxRate": 0, "groupCurrencyFxRate": 0, "lineItems": [ { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "invoicePayableId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "type": "REIMBURSEMENT", "metadata": { "type": "REIMBURSEMENT" }, "amount": 100000, "netAmount": 100000, "description": "string", "taxCodeId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "taxAmount": 100000, "accountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "costCenterId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "amortizationStartDate": "2026-01-15", "amortizationEndDate": "2026-01-15", "amortizationTemplateId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "customPropertiesOld": { "items": null }, "aiValueSuggestions": [ { "field": "string", "fieldValues": [ "string" ], "reasoning": "string" } ], "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupInternalName": "string", "values": [ {} ] } ], "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z" } ], "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupInternalName": "string", "values": [ { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupInternalName": "string", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "internalName": "string", "label": "string", "context": "string", "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z" } ] } ], "paymentPausedBy": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "paymentPausedAt": "2026-01-15T09:30:00Z", "senderEmail": "string", "documentName": "string" } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders. ## Code ```bash curl -X POST "https://api.light.inc/v1/invoice-payables/3c90c3cc-0d44-4b50-8888-8dd25736052a/mark-as-paid" \ -H "Authorization: Basic YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "amount": 100000, "bankAccountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "ledgerAccountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "paymentAt": "2026-01-15T09:30:00Z", "comment": "string", "paymentOption": "FULL" }' ``` Full page: https://light.inc/docs/api-reference/v1--invoice-payables/mark-invoice-payable-as-paid --- # Post invoice payable without approval > Posts an invoice payable directly to the ledger without going through the approval workflow. The invoice must be in IN_DRAFT state. After posting, linked credit notes are applied and unlinked credit notes may be auto-allocated. If the invoice is fully cleared by credit notes, it transitions to COMPLETED ; otherwise it transitions to UNPAID . `POST https://api.light.inc/v1/invoice-payables/{invoicePayableId}/post` ## Note The shortcut past approval: from IN_DRAFT straight to the ledger, synchronously, landing in UNPAID (or COMPLETED if nothing is owed). Any other state fails with INVOICE_PAYABLE_EVENT_NOT_SUPPORTED . Requires the company-admin role and a company using Light's ledger ( LEDGER_NOT_ENABLED_FOR_COMPANY otherwise). Compare approve , which records one approver's decision on a bill in APPROVAL_PENDING and posts in the background once the last approver has approved. ## Authorization - API key - Bearer token See https://light.inc/docs/getting-started/authentication. ## Path parameters - `invoicePayableId` (string, uuid, required) ## Response - `invoicePayableId` — Always identical to `id`. - `state` — Every `*_PENDING` state resolves in the background: poll. Actions called in the wrong state fail with `INVOICE_PAYABLE_EVENT_NOT_SUPPORTED`. `PAID` means marked as paid but not yet settled; `COMPLETED` is settled, and only then can the clearing be reversed. - `failureContext` — On a bill this carries approval-submission, posting or duplicate errors (`APPROVAL_SUBMISSION_FAILED`, `ERP_ENTRY_FAILED`, `DUPLICATE_INVOICE`); the description about vendor onboarding is a copy-paste from another model. - `vendorDetailsOcr.phoneNumber` — May be `null` when the scan did not find one. - `vendorDetailsOcr.phoneNumber.localNumber` — The number without the country code. - `outstandingBalance` — `null` on every write response and on `GET` without `includeOutstandingBalance=true`; also `null` when the computed balance would be negative. - `issuedDate` — The date the vendor issued the invoice. This model carries no `postingDate` — for the date the document hit the ledger, read the ledger line via `GET /v1/ledger-transaction-lines`. - `purchaseOrderId` — The order matched to this bill in Light. Read-only in practice: the `PATCH` field of the same name is ignored. ```json { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "type": "REIMBURSEMENT", "metadata": { "type": "SELF_BILLED_METADATA" }, "invoicePayableId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "state": "INIT", "failureReason": "EMAIL_NOT_ALLOWED", "failureContext": { "name": "string", "type": "BAD_REQUEST", "errors": [ { "type": "string", "message": "string", "path": [ "string" ], "context": null } ] }, "warningContext": { "name": "string", "type": "BAD_REQUEST", "errors": [ { "type": "string", "message": "string", "path": [ "string" ], "context": null } ] }, "approvalNote": "string", "cancellationReason": "string", "payeeName": "string", "payeeIban": "string", "payeeBban": "string", "payeeBic": "string", "payeeBankCode": "string", "payeeSwedishBankgiroNumber": "string", "payeeSwedishPlusgiroNumber": "string", "payeeCountry": "UNDEFINED", "payeeAddress": "string", "payeeZipcode": "string", "payeeBankName": "string", "payeeBankCountry": "UNDEFINED", "payeeBankAddress": "string", "payeeBankZipcode": "string", "payeeCity": "string", "payeeBankCity": "string", "vendorId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "vendorDetailsOcr": { "avatarUrl": "string", "name": "string", "email": "string", "phoneNumber": { "countryCode": "UNDEFINED", "localNumber": "string" }, "website": "string", "country": "UNDEFINED", "city": "string", "address": "string", "zipcode": "string", "bankAccountNumber": "string", "bankAccountBic": "string", "domesticBankAccountNumber": "string", "domesticBankAccountCode": "string", "vatId": "string" }, "companyEntityId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "invoiceNumber": "string", "amount": 100000, "outstandingBalance": 100000, "currency": "USD", "description": "string", "senderBankAccountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "fiNumber": "string", "finnishPaymentReference": "string", "norKidReference": "string", "swissPaymentReference": "string", "swedishOcrReference": "string", "paymentAt": "2026-01-15T09:30:00Z", "ocrCompletedAt": "2026-01-15T09:30:00Z", "canceledAt": "2026-01-15T09:30:00Z", "issuedDate": "2026-01-15", "dueDate": "2026-01-15", "invoiceCreatedAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z", "purchaseOrderId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "lineItemsIncludeTax": true, "localCurrencyFxRate": 0, "groupCurrencyFxRate": 0, "lineItems": [ { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "invoicePayableId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "type": "REIMBURSEMENT", "metadata": { "type": "REIMBURSEMENT" }, "amount": 100000, "netAmount": 100000, "description": "string", "taxCodeId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "taxAmount": 100000, "accountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "costCenterId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "amortizationStartDate": "2026-01-15", "amortizationEndDate": "2026-01-15", "amortizationTemplateId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "customPropertiesOld": { "items": null }, "aiValueSuggestions": [ { "field": "string", "fieldValues": [ "string" ], "reasoning": "string" } ], "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupInternalName": "string", "values": [ {} ] } ], "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z" } ], "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupInternalName": "string", "values": [ { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupInternalName": "string", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "internalName": "string", "label": "string", "context": "string", "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z" } ] } ], "paymentPausedBy": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "paymentPausedAt": "2026-01-15T09:30:00Z", "senderEmail": "string", "documentName": "string" } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders. ## Code ```bash curl -X POST "https://api.light.inc/v1/invoice-payables/3c90c3cc-0d44-4b50-8888-8dd25736052a/post" \ -H "Authorization: Basic YOUR_API_KEY" ``` Full page: https://light.inc/docs/api-reference/v1--invoice-payables/post-invoice-payable-without-approval --- # Reverse invoice payable payment > Reverses a clearing applied to an invoice payable — either a bank payment ( BP ) or a credit note ( CN ) — identified by its accounting document ID. Use the List invoice payable payments endpoint to obtain the accountingDocumentId and type of the clearing to reverse. Reversing removes the clearing's effect from the ledger and transitions the invoice back to UNPAID or PARTIALLY_PAID depending on the remaining outstanding balance. Optionally set shouldArchiveClearingDocument to also archive the underlying bank payment or credit note. `POST https://api.light.inc/v1/invoice-payables/{invoicePayableId}/reverse-clearing` ## Note Only from PARTIALLY_PAID or COMPLETED . A bill in PAID (marked as paid but not yet settled) is not accepted until it reaches COMPLETED ; anything else fails with INVOICE_PAYABLE_EVENT_NOT_SUPPORTED . clearingAccountingDocumentId is the payment.accountingDocumentId from GET .../payments . The result mirrors the ledger: PARTIALLY_PAID if anything is still cleared, otherwise UNPAID . Reversing a credit-note clearing also removes the link; shouldArchiveClearingDocument archives the payment or credit note as well. ## Authorization - API key - Bearer token See https://light.inc/docs/getting-started/authentication. ## Path parameters - `invoicePayableId` (string, uuid, required) ## Request body `application/json;charset=UTF-8` - `clearingAccountingDocumentId` — The `payment.accountingDocumentId` from `GET .../payments`, not that list's top-level `id`. ```json { "clearingAccountingDocumentId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "clearingType": "BP", "shouldArchiveClearingDocument": true } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders, and fields that exclude each other are all shown. Do not send it unchanged. ## Response - `invoicePayableId` — Always identical to `id`. - `state` — Every `*_PENDING` state resolves in the background: poll. Actions called in the wrong state fail with `INVOICE_PAYABLE_EVENT_NOT_SUPPORTED`. `PAID` means marked as paid but not yet settled; `COMPLETED` is settled, and only then can the clearing be reversed. - `failureContext` — On a bill this carries approval-submission, posting or duplicate errors (`APPROVAL_SUBMISSION_FAILED`, `ERP_ENTRY_FAILED`, `DUPLICATE_INVOICE`); the description about vendor onboarding is a copy-paste from another model. - `vendorDetailsOcr.phoneNumber` — May be `null` when the scan did not find one. - `vendorDetailsOcr.phoneNumber.localNumber` — The number without the country code. - `outstandingBalance` — `null` on every write response and on `GET` without `includeOutstandingBalance=true`; also `null` when the computed balance would be negative. - `issuedDate` — The date the vendor issued the invoice. This model carries no `postingDate` — for the date the document hit the ledger, read the ledger line via `GET /v1/ledger-transaction-lines`. - `purchaseOrderId` — The order matched to this bill in Light. Read-only in practice: the `PATCH` field of the same name is ignored. ```json { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "type": "REIMBURSEMENT", "metadata": { "type": "SELF_BILLED_METADATA" }, "invoicePayableId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "state": "INIT", "failureReason": "EMAIL_NOT_ALLOWED", "failureContext": { "name": "string", "type": "BAD_REQUEST", "errors": [ { "type": "string", "message": "string", "path": [ "string" ], "context": null } ] }, "warningContext": { "name": "string", "type": "BAD_REQUEST", "errors": [ { "type": "string", "message": "string", "path": [ "string" ], "context": null } ] }, "approvalNote": "string", "cancellationReason": "string", "payeeName": "string", "payeeIban": "string", "payeeBban": "string", "payeeBic": "string", "payeeBankCode": "string", "payeeSwedishBankgiroNumber": "string", "payeeSwedishPlusgiroNumber": "string", "payeeCountry": "UNDEFINED", "payeeAddress": "string", "payeeZipcode": "string", "payeeBankName": "string", "payeeBankCountry": "UNDEFINED", "payeeBankAddress": "string", "payeeBankZipcode": "string", "payeeCity": "string", "payeeBankCity": "string", "vendorId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "vendorDetailsOcr": { "avatarUrl": "string", "name": "string", "email": "string", "phoneNumber": { "countryCode": "UNDEFINED", "localNumber": "string" }, "website": "string", "country": "UNDEFINED", "city": "string", "address": "string", "zipcode": "string", "bankAccountNumber": "string", "bankAccountBic": "string", "domesticBankAccountNumber": "string", "domesticBankAccountCode": "string", "vatId": "string" }, "companyEntityId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "invoiceNumber": "string", "amount": 100000, "outstandingBalance": 100000, "currency": "USD", "description": "string", "senderBankAccountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "fiNumber": "string", "finnishPaymentReference": "string", "norKidReference": "string", "swissPaymentReference": "string", "swedishOcrReference": "string", "paymentAt": "2026-01-15T09:30:00Z", "ocrCompletedAt": "2026-01-15T09:30:00Z", "canceledAt": "2026-01-15T09:30:00Z", "issuedDate": "2026-01-15", "dueDate": "2026-01-15", "invoiceCreatedAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z", "purchaseOrderId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "lineItemsIncludeTax": true, "localCurrencyFxRate": 0, "groupCurrencyFxRate": 0, "lineItems": [ { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "invoicePayableId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "type": "REIMBURSEMENT", "metadata": { "type": "REIMBURSEMENT" }, "amount": 100000, "netAmount": 100000, "description": "string", "taxCodeId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "taxAmount": 100000, "accountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "costCenterId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "amortizationStartDate": "2026-01-15", "amortizationEndDate": "2026-01-15", "amortizationTemplateId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "customPropertiesOld": { "items": null }, "aiValueSuggestions": [ { "field": "string", "fieldValues": [ "string" ], "reasoning": "string" } ], "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupInternalName": "string", "values": [ {} ] } ], "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z" } ], "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupInternalName": "string", "values": [ { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupInternalName": "string", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "internalName": "string", "label": "string", "context": "string", "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z" } ] } ], "paymentPausedBy": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "paymentPausedAt": "2026-01-15T09:30:00Z", "senderEmail": "string", "documentName": "string" } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders. ## Code ```bash curl -X POST "https://api.light.inc/v1/invoice-payables/3c90c3cc-0d44-4b50-8888-8dd25736052a/reverse-clearing" \ -H "Authorization: Basic YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "clearingAccountingDocumentId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "clearingType": "BP", "shouldArchiveClearingDocument": true }' ``` Full page: https://light.inc/docs/api-reference/v1--invoice-payables/reverse-invoice-payable-payment --- # Submit for approval > Submits an invoice for approval `POST https://api.light.inc/v1/invoice-payables/{invoicePayableId}/submit-for-approval` ## Note Only from IN_DRAFT , and validated synchronously: a document ( documentKey ), amount above zero, currency , paymentAt , issuedDate , dueDate , companyEntityId , senderBankAccountId , invoiceNumber , vendorId ( INVOICE_PAYABLE_MISSING_FIELD names the field); at least one line, each with amount , accountId , taxCodeId and taxAmount ( INVOICE_PAYABLE_LINE_MISSING_FIELD ); lines summing to amount ( INVALID_LINE_ITEM_SUM ); payee name and countries copied from the vendor ( INVOICE_PAYABLE_MISSING_PAYEE_FIELD ); required custom properties; and a ledger posting preview, so a closed accounting period fails here. The body is optional. Approvers cannot be set through the API: they come from the company's bill-approval workflow. The response is APPROVAL_REQUESTED ; the approval records are created in the background, after which the state is APPROVAL_PENDING — or back to IN_DRAFT with failureReason: APPROVAL_SUBMISSION_FAILED when, for example, no approver could be assigned. closePurchaseOrder closes the order matched to the bill in Light, not any purchaseOrderId you sent. Requires the AP-clerk role. ## Authorization - API key - Bearer token See https://light.inc/docs/getting-started/authentication. ## Path parameters - `invoicePayableId` (string, uuid, required) ## Request body `application/json;charset=UTF-8` ```json { "closePurchaseOrder": true } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders, and fields that exclude each other are all shown. Do not send it unchanged. ## Response - `invoicePayableId` — Always identical to `id`. - `state` — Every `*_PENDING` state resolves in the background: poll. Actions called in the wrong state fail with `INVOICE_PAYABLE_EVENT_NOT_SUPPORTED`. `PAID` means marked as paid but not yet settled; `COMPLETED` is settled, and only then can the clearing be reversed. - `failureContext` — On a bill this carries approval-submission, posting or duplicate errors (`APPROVAL_SUBMISSION_FAILED`, `ERP_ENTRY_FAILED`, `DUPLICATE_INVOICE`); the description about vendor onboarding is a copy-paste from another model. - `vendorDetailsOcr.phoneNumber` — May be `null` when the scan did not find one. - `vendorDetailsOcr.phoneNumber.localNumber` — The number without the country code. - `outstandingBalance` — `null` on every write response and on `GET` without `includeOutstandingBalance=true`; also `null` when the computed balance would be negative. - `issuedDate` — The date the vendor issued the invoice. This model carries no `postingDate` — for the date the document hit the ledger, read the ledger line via `GET /v1/ledger-transaction-lines`. - `purchaseOrderId` — The order matched to this bill in Light. Read-only in practice: the `PATCH` field of the same name is ignored. ```json { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "type": "REIMBURSEMENT", "metadata": { "type": "SELF_BILLED_METADATA" }, "invoicePayableId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "state": "INIT", "failureReason": "EMAIL_NOT_ALLOWED", "failureContext": { "name": "string", "type": "BAD_REQUEST", "errors": [ { "type": "string", "message": "string", "path": [ "string" ], "context": null } ] }, "warningContext": { "name": "string", "type": "BAD_REQUEST", "errors": [ { "type": "string", "message": "string", "path": [ "string" ], "context": null } ] }, "approvalNote": "string", "cancellationReason": "string", "payeeName": "string", "payeeIban": "string", "payeeBban": "string", "payeeBic": "string", "payeeBankCode": "string", "payeeSwedishBankgiroNumber": "string", "payeeSwedishPlusgiroNumber": "string", "payeeCountry": "UNDEFINED", "payeeAddress": "string", "payeeZipcode": "string", "payeeBankName": "string", "payeeBankCountry": "UNDEFINED", "payeeBankAddress": "string", "payeeBankZipcode": "string", "payeeCity": "string", "payeeBankCity": "string", "vendorId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "vendorDetailsOcr": { "avatarUrl": "string", "name": "string", "email": "string", "phoneNumber": { "countryCode": "UNDEFINED", "localNumber": "string" }, "website": "string", "country": "UNDEFINED", "city": "string", "address": "string", "zipcode": "string", "bankAccountNumber": "string", "bankAccountBic": "string", "domesticBankAccountNumber": "string", "domesticBankAccountCode": "string", "vatId": "string" }, "companyEntityId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "invoiceNumber": "string", "amount": 100000, "outstandingBalance": 100000, "currency": "USD", "description": "string", "senderBankAccountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "fiNumber": "string", "finnishPaymentReference": "string", "norKidReference": "string", "swissPaymentReference": "string", "swedishOcrReference": "string", "paymentAt": "2026-01-15T09:30:00Z", "ocrCompletedAt": "2026-01-15T09:30:00Z", "canceledAt": "2026-01-15T09:30:00Z", "issuedDate": "2026-01-15", "dueDate": "2026-01-15", "invoiceCreatedAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z", "purchaseOrderId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "lineItemsIncludeTax": true, "localCurrencyFxRate": 0, "groupCurrencyFxRate": 0, "lineItems": [ { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "invoicePayableId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "type": "REIMBURSEMENT", "metadata": { "type": "REIMBURSEMENT" }, "amount": 100000, "netAmount": 100000, "description": "string", "taxCodeId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "taxAmount": 100000, "accountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "costCenterId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "amortizationStartDate": "2026-01-15", "amortizationEndDate": "2026-01-15", "amortizationTemplateId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "customPropertiesOld": { "items": null }, "aiValueSuggestions": [ { "field": "string", "fieldValues": [ "string" ], "reasoning": "string" } ], "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupInternalName": "string", "values": [ {} ] } ], "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z" } ], "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupInternalName": "string", "values": [ { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupInternalName": "string", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "internalName": "string", "label": "string", "context": "string", "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z" } ] } ], "paymentPausedBy": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "paymentPausedAt": "2026-01-15T09:30:00Z", "senderEmail": "string", "documentName": "string" } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders. ## Code ```bash curl -X POST "https://api.light.inc/v1/invoice-payables/3c90c3cc-0d44-4b50-8888-8dd25736052a/submit-for-approval" \ -H "Authorization: Basic YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "closePurchaseOrder": true }' ``` Full page: https://light.inc/docs/api-reference/v1--invoice-payables/submit-for-approval --- # Update the custom properties of a posted invoice payable > Replaces all custom fields on an invoice payable after it has been posted/approved (e.g. ready for payment release, scheduled, unpaid, partially paid, completed). Any custom property group not included in the request is removed. Use this to set fields such as a reconciliation link once the invoice has left the inbox. Editing is locked while approval is actively pending. `PATCH https://api.light.inc/v1/invoice-payables/{invoicePayableId}/custom-properties` ## Note For posted bills only: READY_FOR_PAYMENT_RELEASE , SCHEDULED , PAYMENT_PAUSED , PENDING_PAYMENT_APPROVAL , UNPAID , PARTIALLY_PAID and COMPLETED . In IN_DRAFT use the header PATCH ; in APPROVAL_PENDING , PAID , DECLINED and CANCELLED it fails with INVOICE_PAYABLE_EVENT_NOT_SUPPORTED . One more trap: an UNPAID bill whose sender bank account is eligible for payment scheduling rejects every call with INVOICE_PAYABLE_MODIFY_POSTED_FIELD_NOT_ALLOWED . The list replaces all custom properties. ## Authorization - API key - Bearer token See https://light.inc/docs/getting-started/authentication. ## Path parameters - `invoicePayableId` (string, uuid, required) ## Request body `application/json;charset=UTF-8` - `customProperties.valueIds` — Catalogue value ids for this group. Required; send `[]` (with an empty `inlineValues`) to clear the group. `SINGLE_SELECT` and `MULTI_SELECT` groups accept nothing else. See [Custom properties on writes](/docs/getting-started/pagination-filtering-errors#custom-properties-on-writes). - `customProperties.inlineValues` — Literal values for `TEXT`, `NUMERIC`, `BOOLEAN` and `DATE` groups, as strings (`yyyy-MM-dd` for dates). Rejected on select groups with `CUSTOM_PROPERTY_VALUE_TYPE_MISMATCH`. See [Custom properties on writes](/docs/getting-started/pagination-filtering-errors#custom-properties-on-writes). ```json { "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "valueIds": [ "3c90c3cc-0d44-4b50-8888-8dd25736052a" ], "inlineValues": [ "string" ] } ] } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders, and fields that exclude each other are all shown. Do not send it unchanged. ## Response - `invoicePayableId` — Always identical to `id`. - `state` — Every `*_PENDING` state resolves in the background: poll. Actions called in the wrong state fail with `INVOICE_PAYABLE_EVENT_NOT_SUPPORTED`. `PAID` means marked as paid but not yet settled; `COMPLETED` is settled, and only then can the clearing be reversed. - `failureContext` — On a bill this carries approval-submission, posting or duplicate errors (`APPROVAL_SUBMISSION_FAILED`, `ERP_ENTRY_FAILED`, `DUPLICATE_INVOICE`); the description about vendor onboarding is a copy-paste from another model. - `vendorDetailsOcr.phoneNumber` — May be `null` when the scan did not find one. - `vendorDetailsOcr.phoneNumber.localNumber` — The number without the country code. - `outstandingBalance` — `null` on every write response and on `GET` without `includeOutstandingBalance=true`; also `null` when the computed balance would be negative. - `issuedDate` — The date the vendor issued the invoice. This model carries no `postingDate` — for the date the document hit the ledger, read the ledger line via `GET /v1/ledger-transaction-lines`. - `purchaseOrderId` — The order matched to this bill in Light. Read-only in practice: the `PATCH` field of the same name is ignored. ```json { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "type": "REIMBURSEMENT", "metadata": { "type": "SELF_BILLED_METADATA" }, "invoicePayableId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "state": "INIT", "failureReason": "EMAIL_NOT_ALLOWED", "failureContext": { "name": "string", "type": "BAD_REQUEST", "errors": [ { "type": "string", "message": "string", "path": [ "string" ], "context": null } ] }, "warningContext": { "name": "string", "type": "BAD_REQUEST", "errors": [ { "type": "string", "message": "string", "path": [ "string" ], "context": null } ] }, "approvalNote": "string", "cancellationReason": "string", "payeeName": "string", "payeeIban": "string", "payeeBban": "string", "payeeBic": "string", "payeeBankCode": "string", "payeeSwedishBankgiroNumber": "string", "payeeSwedishPlusgiroNumber": "string", "payeeCountry": "UNDEFINED", "payeeAddress": "string", "payeeZipcode": "string", "payeeBankName": "string", "payeeBankCountry": "UNDEFINED", "payeeBankAddress": "string", "payeeBankZipcode": "string", "payeeCity": "string", "payeeBankCity": "string", "vendorId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "vendorDetailsOcr": { "avatarUrl": "string", "name": "string", "email": "string", "phoneNumber": { "countryCode": "UNDEFINED", "localNumber": "string" }, "website": "string", "country": "UNDEFINED", "city": "string", "address": "string", "zipcode": "string", "bankAccountNumber": "string", "bankAccountBic": "string", "domesticBankAccountNumber": "string", "domesticBankAccountCode": "string", "vatId": "string" }, "companyEntityId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "invoiceNumber": "string", "amount": 100000, "outstandingBalance": 100000, "currency": "USD", "description": "string", "senderBankAccountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "fiNumber": "string", "finnishPaymentReference": "string", "norKidReference": "string", "swissPaymentReference": "string", "swedishOcrReference": "string", "paymentAt": "2026-01-15T09:30:00Z", "ocrCompletedAt": "2026-01-15T09:30:00Z", "canceledAt": "2026-01-15T09:30:00Z", "issuedDate": "2026-01-15", "dueDate": "2026-01-15", "invoiceCreatedAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z", "purchaseOrderId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "lineItemsIncludeTax": true, "localCurrencyFxRate": 0, "groupCurrencyFxRate": 0, "lineItems": [ { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "invoicePayableId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "type": "REIMBURSEMENT", "metadata": { "type": "REIMBURSEMENT" }, "amount": 100000, "netAmount": 100000, "description": "string", "taxCodeId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "taxAmount": 100000, "accountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "costCenterId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "amortizationStartDate": "2026-01-15", "amortizationEndDate": "2026-01-15", "amortizationTemplateId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "customPropertiesOld": { "items": null }, "aiValueSuggestions": [ { "field": "string", "fieldValues": [ "string" ], "reasoning": "string" } ], "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupInternalName": "string", "values": [ {} ] } ], "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z" } ], "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupInternalName": "string", "values": [ { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupInternalName": "string", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "internalName": "string", "label": "string", "context": "string", "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z" } ] } ], "paymentPausedBy": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "paymentPausedAt": "2026-01-15T09:30:00Z", "senderEmail": "string", "documentName": "string" } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders. ## Code ```bash curl -X PATCH "https://api.light.inc/v1/invoice-payables/3c90c3cc-0d44-4b50-8888-8dd25736052a/custom-properties" \ -H "Authorization: Basic YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "valueIds": [ "3c90c3cc-0d44-4b50-8888-8dd25736052a" ], "inlineValues": [ "string" ] } ] }' ``` Full page: https://light.inc/docs/api-reference/v1--invoice-payables/update-the-custom-properties-of-a-posted-invoice-payable --- # Card Balance Accounts (resource) Access card balance accounts, their statements and total spend. Resource page: https://light.inc/docs/api-reference/v1--card-balance-accounts # Generate a card balance account statement > Generates a statement for a card balance account over a period. Dates are interpreted as UTC day boundaries and all timestamps in the response are in UTC. Runs a fresh provider sync inline so the statement reflects the latest activity. `GET https://api.light.inc/v1/card-balance-accounts/{accountId}/statement` ## Note A JSON statement, not a PDF, built from the issuer's own ledger for the balance account rather than from Light card transactions (Light syncs with the issuer before answering). to is exclusive (start of that UTC day) and must be after from ( CARD_BALANCE_ACCOUNT_STATEMENT_INVALID_PERIOD ). openingBalance is the booked balance before from ; runningBalance adds credits and subtracts debits from there. Line amounts are unsigned with the sign in direction . Company-admin and auditor roles only, and at most two concurrent calls per credential ( 429 beyond that). ## Authorization - API key - Bearer token See https://light.inc/docs/getting-started/authentication. ## Path parameters - `accountId` (string, uuid, required) ## Query parameters - `from` (string, date) — Start of the statement period, inclusive. A UTC calendar date in YYYY-MM-DD format. - `to` (string, date) — End of the statement period. A UTC calendar date in YYYY-MM-DD format; must be after from . ## Response ```json { "balanceAccountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "currency": "USD", "periodStart": "2026-01-15T09:30:00Z", "periodEnd": "2026-01-15T09:30:00Z", "openingBalance": 100000, "closingBalance": 100000, "transactions": [ { "providerId": "string", "direction": "DEBIT", "amount": 100000, "runningBalance": 100000, "bookedAt": "2026-01-15T09:30:00Z", "valuedAt": "2026-01-15T09:30:00Z", "description": "string", "reference": "string" } ], "generatedAt": "2026-01-15T09:30:00Z" } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders. ## Code ```bash curl -X GET "https://api.light.inc/v1/card-balance-accounts/3c90c3cc-0d44-4b50-8888-8dd25736052a/statement" \ -H "Authorization: Basic YOUR_API_KEY" ``` Full page: https://light.inc/docs/api-reference/v1--card-balance-accounts/generate-a-card-balance-account-statement --- # Get card balance account > Returns a card balance account by ID, including balance details `GET https://api.light.inc/v1/card-balance-accounts/{accountId}` ## Note balance is read live from the card issuer; if the issuer cannot answer, it comes back as zeros rather than an error. ## Authorization - API key - Bearer token See https://light.inc/docs/getting-started/authentication. ## Path parameters - `accountId` (string, uuid, required) ## Response ```json { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "isPrimary": true, "companyEntityId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "currency": "USD", "label": "string", "status": "ACTIVE", "balance": { "available": 100000, "settled": 100000, "reserved": 100000, "currency": "USD" }, "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z" } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders. ## Code ```bash curl -X GET "https://api.light.inc/v1/card-balance-accounts/3c90c3cc-0d44-4b50-8888-8dd25736052a" \ -H "Authorization: Basic YOUR_API_KEY" ``` Full page: https://light.inc/docs/api-reference/v1--card-balance-accounts/get-card-balance-account --- # List card balance accounts > Returns a list of card balance accounts `GET https://api.light.inc/v1/card-balance-accounts` ## Note balance is read live from the card issuer for every account on each call; if the issuer cannot answer for an account, its balance comes back as zeros rather than an error. ## Authorization - API key - Bearer token See https://light.inc/docs/getting-started/authentication. ## Query parameters - `sort` (string) — Sort string in the format field:direction . To provide multiple sort fields, separate them with commas. Available directions: asc , desc . Available fields: companyEntityId , status , createdAt . - `filter` (string) — Filter string in the format field:operator:value . To provide multiple filters, separate them with commas. Available operators: eq , ne , in , not_in , gt , gte , lt , lte . - For in and not_in operators, provide multiple values separated by the pipe character ( ). Available fields: id , companyId , companyEntityId , currency , status , createdAt . - `limit` (integer, int32) — Maximum number of items to return. Default is 50, maximum is 200. - `offset` (integer, int64) — Number of items to skip before starting to collect the result set. Deprecated, use 'cursor' instead. - `cursor` (string) — The cursor position to start returning results from. To opt-in into cursor-based pagination, provide 0 for the initial request. For subsequent requests, use nextCursor and prevCursor from the previous response to navigate. Cursor values are opaque and should not be constructed manually. ## Response ```json { "records": [ { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "isPrimary": true, "companyEntityId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "currency": "USD", "label": "string", "status": "ACTIVE", "balance": { "available": 100000, "settled": 100000, "reserved": 100000, "currency": "USD" }, "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z" } ], "hasMore": true, "total": 100000, "nextCursor": "string", "prevCursor": "string" } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders. ## Code ```bash curl -X GET "https://api.light.inc/v1/card-balance-accounts" \ -H "Authorization: Basic YOUR_API_KEY" ``` Full page: https://light.inc/docs/api-reference/v1--card-balance-accounts/list-card-balance-accounts --- # Get total spend for a card balance account > Returns the total spend for a card balance account within a date range `GET https://api.light.inc/v1/card-balance-accounts/{accountId}/total-spend` ## Note to is exclusive , contrary to the description: it is taken as the start of that UTC day, so to=2026-01-31 excludes 31 January. Omit to to count up to now. from is inclusive from 00:00 UTC. The total counts transactions in AUTHORIZED , CAPTURED , POSTED and REFUNDED , adding DEBIT amounts and subtracting CREDIT ones, so refunds reduce it and it can be negative. DECLINED and VOIDED are ignored. The response echoes from and to as the resolved instants. ## Authorization - API key - Bearer token See https://light.inc/docs/getting-started/authentication. ## Path parameters - `accountId` (string, uuid, required) ## Query parameters - `from` (string, date) — Start of the spend window, inclusive. A UTC calendar date in YYYY-MM-DD format. - `to` (string, date) — End of the spend window, inclusive. A UTC calendar date in YYYY-MM-DD format. Defaults to now if omitted. ## Response ```json { "currency": "USD", "total": 100000, "from": "2026-01-15T09:30:00Z", "to": "2026-01-15T09:30:00Z" } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders. ## Code ```bash curl -X GET "https://api.light.inc/v1/card-balance-accounts/3c90c3cc-0d44-4b50-8888-8dd25736052a/total-spend" \ -H "Authorization: Basic YOUR_API_KEY" ``` Full page: https://light.inc/docs/api-reference/v1--card-balance-accounts/get-total-spend-for-a-card-balance-account --- # Card Customers (resource) Retrieve the card integration public key. Resource page: https://light.inc/docs/api-reference/v1--card-customers # Get card integration public key > Returns the public key for the cards integration service `GET https://api.light.inc/v1/card-customers/public-key` ## Note The issuer's RSA public key for card-detail reveal: a client encrypts its session key with it when displaying a card's number and CVC. The reveal call itself is not part of this API, so most integrations never need this endpoint. companyEntityId must be an entity set up for cards ( CARD_CUSTOMER_NOT_RECOGNIZED ). ## Authorization - API key - Bearer token See https://light.inc/docs/getting-started/authentication. ## Query parameters - `companyEntityId` (string, uuid) ## Response ```json { "publicKey": "string", "expiryDate": "2026-01-15" } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders. ## Code ```bash curl -X GET "https://api.light.inc/v1/card-customers/public-key" \ -H "Authorization: Basic YOUR_API_KEY" ``` Full page: https://light.inc/docs/api-reference/v1--card-customers/get-card-integration-public-key --- # Card Transactions (resource) List, post and update card transactions and their receipts. Resource page: https://light.inc/docs/api-reference/v1--card-transactions # Batch update card transactions > Updates multiple card transactions in a single operation `PATCH https://api.light.inc/v1/card-transactions/batch-update` ## Note Asynchronous. The call authorises every id up front (one id you may not update makes the whole request 403 ), queues the work and returns an empty body immediately; nothing in the response tells you whether any update succeeded. Items are processed independently: one failing item does not stop the others, and a failure that is a validation error is written to that transaction's failureContext , where a later GET shows it. Poll updatedAt or failureContext on the transactions to confirm. There is no cap on the list length. This is the only endpoint that accepts postingDate , and it is write-only from the card side: no card-transaction response returns it. Read it back on the ledger line ( GET /v1/ledger-transaction-lines , postingDate ) once the transaction is posted. Line updates here take description , accountId , taxCodeId and customProperties only; edits to a posted transaction fail into failureContext rather than being rejected up front. ## Authorization - API key - Bearer token See https://light.inc/docs/getting-started/authentication. ## Request body `application/json;charset=UTF-8` - `customProperties.valueIds` — Catalogue value ids for this group. Required; send `[]` (with an empty `inlineValues`) to clear the group. `SINGLE_SELECT` and `MULTI_SELECT` groups accept nothing else. See [Custom properties on writes](/docs/getting-started/pagination-filtering-errors#custom-properties-on-writes). - `customProperties.inlineValues` — Literal values for `TEXT`, `NUMERIC`, `BOOLEAN` and `DATE` groups, as strings (`yyyy-MM-dd` for dates). Rejected on select groups with `CUSTOM_PROPERTY_VALUE_TYPE_MISMATCH`. See [Custom properties on writes](/docs/getting-started/pagination-filtering-errors#custom-properties-on-writes). - `lines.customProperties.valueIds` — Catalogue value ids for this group. Required; send `[]` (with an empty `inlineValues`) to clear the group. `SINGLE_SELECT` and `MULTI_SELECT` groups accept nothing else. See [Custom properties on writes](/docs/getting-started/pagination-filtering-errors#custom-properties-on-writes). - `lines.customProperties.inlineValues` — Literal values for `TEXT`, `NUMERIC`, `BOOLEAN` and `DATE` groups, as strings (`yyyy-MM-dd` for dates). Rejected on select groups with `CUSTOM_PROPERTY_VALUE_TYPE_MISMATCH`. See [Custom properties on writes](/docs/getting-started/pagination-filtering-errors#custom-properties-on-writes). - `postingDate` — Writable here and nowhere else on the card side, and returned by no card-transaction response. Read it back on the ledger line (`GET /v1/ledger-transaction-lines`, `postingDate`) once the transaction is posted. ```json [ { "cardTransactionId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "valueIds": [ "3c90c3cc-0d44-4b50-8888-8dd25736052a" ], "inlineValues": [ "string" ] } ], "lines": [ { "lineId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "valueIds": [], "inlineValues": [] } ], "description": "string", "accountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "taxCodeId": "3c90c3cc-0d44-4b50-8888-8dd25736052a" } ], "postingDate": "2026-01-15", "description": "string" } ] ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders, and fields that exclude each other are all shown. Do not send it unchanged. ## Response This endpoint returns no content. ## Code ```bash curl -X PATCH "https://api.light.inc/v1/card-transactions/batch-update" \ -H "Authorization: Basic YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '[ { "cardTransactionId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "valueIds": [ "3c90c3cc-0d44-4b50-8888-8dd25736052a" ], "inlineValues": [ "string" ] } ], "lines": [ { "lineId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "valueIds": [], "inlineValues": [] } ], "description": "string", "accountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "taxCodeId": "3c90c3cc-0d44-4b50-8888-8dd25736052a" } ], "postingDate": "2026-01-15", "description": "string" } ]' ``` Full page: https://light.inc/docs/api-reference/v1--card-transactions/batch-update-card-transactions --- # Generate receipt upload URL > Generates a secure upload URL for receipt documents `POST https://api.light.inc/v1/card-transactions/{cardTransactionId}/receipt-upload-url` ## Note The URL is valid for five minutes ; PUT the bytes with the declared Content-Type and every entry of metadata as a request header , or the upload is rejected (see Files (/docs/getting-started/pagination-filtering-errors files)). There is no follow-up call: Light picks the file up, converts it to PDF and sets receiptDocumentKey asynchronously — to the key of the converted PDF , not the key returned here — so poll GET /v1/card-transactions/{id} until it is non-null. If conversion fails, failureContext is set with CARD_TRANSACTION_PDF_RECEIPT_FAILED . While the transaction is unposted the receipt is also read by Light's document AI, which writes the account, tax code and custom properties it extracts onto every line — coding you set before the upload can be overwritten. The cardTransactionId is not checked at this step; a wrong id only fails later, inside the background job. Requires a user credential, not an API key. ## Authorization - API key - Bearer token See https://light.inc/docs/getting-started/authentication. ## Path parameters - `cardTransactionId` (string, uuid, required) ## Request body `application/json;charset=UTF-8` ```json { "filename": "string", "contentType": "string" } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders, and fields that exclude each other are all shown. Do not send it unchanged. ## Response ```json { "uploadUrl": "https://example.com", "key": "string", "metadata": null } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders. ## Code ```bash curl -X POST "https://api.light.inc/v1/card-transactions/3c90c3cc-0d44-4b50-8888-8dd25736052a/receipt-upload-url" \ -H "Authorization: Basic YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "filename": "string", "contentType": "string" }' ``` Full page: https://light.inc/docs/api-reference/v1--card-transactions/generate-receipt-upload-url --- # Get card transaction > Returns a card transaction by ID `GET https://api.light.inc/v1/card-transactions/{cardTransactionId}` ## Note Returns the same enriched shape as the list, without editStatus . To learn whether a transaction is still editable, read status ( POSTED , DECLINED and VOIDED are locked; AUTHORIZED allows everything but line amounts) or look at the editStatus on a PATCH response. ## Authorization - API key - Bearer token See https://light.inc/docs/getting-started/authentication. ## Path parameters - `cardTransactionId` (string, uuid, required) ## Response - `id` — The transaction id, also its accounting document id. - `companyId` — Your company id. - `companyEntityId` — The entity the card belongs to. - `companyEntityName` — That entity's name. - `cardBalanceAccountId` — The balance account the card draws on. - `cardBalanceAccountLabel` — Its name. - `cardId` — The card that was charged. - `cardVendorId` — The vendor Light matched to the merchant, if any. - `cardVendorAvatarUrl` — That vendor's logo URL. - `cardVendorName` — That vendor's name. - `cardOwnerName` — The cardholder's name. - `cardOwnerId` — The cardholder's user id. - `cardLastFour` — Last four digits of the card number. - `originalAmount` — The amount charged by the merchant, in the merchant's currency, minor units. - `originalCurrency` — The merchant's currency. - `amount` — Unsigned, in minor units. The sign is `direction`: `DEBIT` is money out, `CREDIT` is a refund or incoming credit. - `currency` — The balance account's currency, which `amount` is in. - `status` — Set by the card issuer, never by this API, apart from `POSTED`. `AUTHORIZED` moves to `CAPTURED`, `DECLINED` or `VOIDED`; `CAPTURED` and `REFUNDED` can be posted. A `REFUNDED` transaction is its **own record** with `direction: CREDIT` — the original capture keeps its status and nothing on the model links the two. - `merchant` — The merchant, as reported by the card network. - `merchant.name` — Merchant name as reported by the card network. - `merchant.cleanName` — The name cleaned up by Light, used for display and vendor matching. - `merchant.zipcode` — The merchant's postal code. - `merchant.id` — The card network's merchant id. - `merchant.mcc` — Merchant category code. - `merchant.acquirerId` — Id of the merchant's acquiring bank. - `merchant.logoUrl` — Logo URL, when Light has one. - `receiptDocumentKey` — Filled asynchronously after a receipt upload with the key of the converted PDF, which is not the `key` the upload endpoint returned. - `lines` — The accounting split of the transaction: account, tax code and cost center per line. - `lines.id` — The line id. - `lines.transactionId` — The card transaction the line belongs to. - `lines.companyId` — Your company id. - `lines.accountId` — The expense account for the line. - `lines.accountLabel` — Its name. - `lines.taxCodeId` — The tax code on the line. - `lines.taxCodeLabel` — Its name. - `lines.costCenterId` — Cost center on the line. - `lines.costCenterName` — Its name. - `lines.amount` — Gross line amount in the balance account currency, minor units. - `lines.netAmount` — Line amount excluding tax, minor units. - `lines.description` — The line description. - `lines.createdAt` — When the line was created. - `lines.updatedAt` — When it was last changed. - `lines.customProperties` — Custom property values on the line. - `lines.amortizationTemplateId` — Release template id when the line is spread over a schedule; `null` otherwise. - `lines.amortizationStartDate` — First date of that schedule. - `lines.amortizationEndDate` — Last date of that schedule. - `failureContext` — Set when a batch update or a post fails validation, or when receipt conversion fails; cleared by the next successful post. The description about vendor onboarding is a copy-paste from another model. - `description` — The transaction description. - `performedAt` — When the card was charged. - `exportedAt` — When the transaction's export to accounting completed; `null` until then. Legacy field from before card transactions posted to the ledger as documents. - `createdAt` — When Light received the transaction. - `updatedAt` — When it was last changed. - `customProperties` — Custom property values on the transaction. ```json { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyEntityId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyEntityName": "string", "cardBalanceAccountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "cardBalanceAccountLabel": "string", "cardId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "cardVendorId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "cardVendorAvatarUrl": "string", "cardVendorName": "string", "cardOwnerName": "string", "cardOwnerId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "cardLastFour": "string", "originalAmount": 100000, "originalCurrency": "USD", "amount": 100000, "currency": "USD", "direction": "DEBIT", "transactionReason": "ACCOUNT_NOT_ACTIVE", "purchaseType": "ATM", "status": "AUTHORIZED", "type": "PAYMENT", "merchant": { "name": "string", "cleanName": "string", "country": "UNDEFINED", "zipcode": "string", "id": "string", "mcc": "string", "acquirerId": "string", "logoUrl": "string" }, "receiptDocumentKey": "string", "lines": [ { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "transactionId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "accountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "accountLabel": "string", "taxCodeId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "taxCodeLabel": "string", "costCenterId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "costCenterName": "string", "amount": 100000, "netAmount": 100000, "description": "string", "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z", "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupInternalName": "string", "values": [ {} ] } ], "amortizationTemplateId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "amortizationStartDate": "2026-01-15", "amortizationEndDate": "2026-01-15" } ], "failureContext": { "name": "string", "type": "BAD_REQUEST", "errors": [ { "type": "string", "message": "string", "path": [ "string" ], "context": null } ] }, "description": "string", "performedAt": "2026-01-15T09:30:00Z", "exportedAt": "2026-01-15T09:30:00Z", "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z", "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupInternalName": "string", "values": [ { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupInternalName": "string", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "internalName": "string", "label": "string", "context": "string", "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z" } ] } ] } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders. ## Code ```bash curl -X GET "https://api.light.inc/v1/card-transactions/3c90c3cc-0d44-4b50-8888-8dd25736052a" \ -H "Authorization: Basic YOUR_API_KEY" ``` Full page: https://light.inc/docs/api-reference/v1--card-transactions/get-card-transaction --- # Get transaction receipt > Returns the attached receipt document for a card transaction `GET https://api.light.inc/v1/card-transactions/{transactionId}/receipt` ## Note Answers 307 Temporary Redirect to a pre-signed download URL valid for two hours, not the PDF bytes; follow it without your Light Authorization header. A transaction without a receipt fails with CARD_TRANSACTION_MISSING_RECEIPT . ## Authorization - API key - Bearer token See https://light.inc/docs/getting-started/authentication. ## Path parameters - `transactionId` (string, uuid, required) ## Response Returns a file (application/pdf) rather than JSON. ## Code ```bash curl -X GET "https://api.light.inc/v1/card-transactions/3c90c3cc-0d44-4b50-8888-8dd25736052a/receipt" \ -H "Authorization: Basic YOUR_API_KEY" ``` Full page: https://light.inc/docs/api-reference/v1--card-transactions/get-transaction-receipt --- # Remove transaction receipt > Removes the attached receipt document from a card transaction `DELETE https://api.light.inc/v1/card-transactions/{transactionId}/receipt` ## Note Clears receiptDocumentKey on the transaction; the stored file itself is kept. Works in any status and answers with an empty body. ## Authorization - API key - Bearer token See https://light.inc/docs/getting-started/authentication. ## Path parameters - `transactionId` (string, uuid, required) ## Response This endpoint returns no content. ## Code ```bash curl -X DELETE "https://api.light.inc/v1/card-transactions/3c90c3cc-0d44-4b50-8888-8dd25736052a/receipt" \ -H "Authorization: Basic YOUR_API_KEY" ``` Full page: https://light.inc/docs/api-reference/v1--card-transactions/remove-transaction-receipt --- # OPTIONS /v1/card-transactions/{transactionId}/receipt > `OPTIONS https://api.light.inc/v1/card-transactions/{transactionId}/receipt` ## Note CORS preflight for browsers that download the receipt directly. Answers 200 with the allowed-origin headers and no body, without authentication. API clients never need to call it. ## Authorization - API key - Bearer token See https://light.inc/docs/getting-started/authentication. ## Path parameters - `transactionId` (string, uuid, required) ## Request body `application/json;charset=UTF-8` ```json { "roles": [ "string" ], "name": "string" } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders, and fields that exclude each other are all shown. Do not send it unchanged. ## Response This endpoint returns no content. ## Code ```bash curl -X OPTIONS "https://api.light.inc/v1/card-transactions/3c90c3cc-0d44-4b50-8888-8dd25736052a/receipt" \ -H "Authorization: Basic YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "roles": [ "string" ], "name": "string" }' ``` Full page: https://light.inc/docs/api-reference/v1--card-transactions/get-card-transaction-receipt-options --- # List card transactions > Returns a paginated list of card transactions `GET https://api.light.inc/v1/card-transactions` ## Note The filter and sort field lists below are incomplete. The server also accepts ownerId , amount , originalAmount , originalCurrency , receiptDocumentKey , taxId and accountId as filters and originalAmount as a sort; an unknown field fails with INVALID_QUERY_FIELD listing the real set. The two undocumented flags: onlyPostable=true returns transactions a post would currently succeed for (a flag recomputed in the background after each edit, so it can lag a moment behind a PATCH ); missingData=true returns transactions with no receipt, or not yet posted and not postable. Sending both fails with CARD_TRANSACTION_INVALID_FILTER_COMBINATION . This list (and the single GET ) returns the enriched shape with labels and exportedAt , but without editStatus — that field only appears on the PATCH , post and reset responses. amount is an unsigned magnitude; direction ( DEBIT for spend, CREDIT for a refund or incoming credit) carries the sign. A refund is a separate transaction with status: REFUNDED , not a change to the original capture, and nothing on the model links the two. If the company's card setup has auto-posting on, a transaction can already be POSTED the first time you see it. A cardholder-only credential must filter on its own ownerId or cardId or it receives 403 . ## Authorization - API key - Bearer token See https://light.inc/docs/getting-started/authentication. ## Query parameters - `sort` (string) — Sort string in the format field:direction . To provide multiple sort fields, separate them with commas. Available directions: asc , desc . Available fields: companyEntityId , status , performedAt . - `filter` (string) — Filter string in the format field:operator:value . To provide multiple filters, separate them with commas. Available operators: eq , ne , in , not_in , gt , gte , lt , lte . - For in and not_in operators, provide multiple values separated by the pipe character ( ). Available fields: transactionId , cardBalanceAccountId , companyEntityId , cardId , status , performedAt , updatedAt . - `limit` (integer, int32) — Maximum number of items to return. Default is 50, maximum is 200. - `offset` (integer, int64) — Number of items to skip before starting to collect the result set. Deprecated, use 'cursor' instead. - `cursor` (string) — The cursor position to start returning results from. To opt-in into cursor-based pagination, provide 0 for the initial request. For subsequent requests, use nextCursor and prevCursor from the previous response to navigate. Cursor values are opaque and should not be constructed manually. - `onlyPostable` (boolean) - `missingData` (boolean) ## Response - `records.id` — The transaction id, also its accounting document id. - `records.companyId` — Your company id. - `records.companyEntityId` — The entity the card belongs to. - `records.companyEntityName` — That entity's name. - `records.cardBalanceAccountId` — The balance account the card draws on. - `records.cardBalanceAccountLabel` — Its name. - `records.cardId` — The card that was charged. - `records.cardVendorId` — The vendor Light matched to the merchant, if any. - `records.cardVendorAvatarUrl` — That vendor's logo URL. - `records.cardVendorName` — That vendor's name. - `records.cardOwnerName` — The cardholder's name. - `records.cardOwnerId` — The cardholder's user id. - `records.cardLastFour` — Last four digits of the card number. - `records.originalAmount` — The amount charged by the merchant, in the merchant's currency, minor units. - `records.originalCurrency` — The merchant's currency. - `records.amount` — Unsigned, in minor units. The sign is `direction`: `DEBIT` is money out, `CREDIT` is a refund or incoming credit. - `records.currency` — The balance account's currency, which `amount` is in. - `records.status` — Set by the card issuer, never by this API, apart from `POSTED`. `AUTHORIZED` moves to `CAPTURED`, `DECLINED` or `VOIDED`; `CAPTURED` and `REFUNDED` can be posted. A `REFUNDED` transaction is its **own record** with `direction: CREDIT` — the original capture keeps its status and nothing on the model links the two. - `records.merchant` — The merchant, as reported by the card network. - `records.merchant.name` — Merchant name as reported by the card network. - `records.merchant.cleanName` — The name cleaned up by Light, used for display and vendor matching. - `records.merchant.zipcode` — The merchant's postal code. - `records.merchant.id` — The card network's merchant id. - `records.merchant.mcc` — Merchant category code. - `records.merchant.acquirerId` — Id of the merchant's acquiring bank. - `records.merchant.logoUrl` — Logo URL, when Light has one. - `records.receiptDocumentKey` — Filled asynchronously after a receipt upload with the key of the converted PDF, which is not the `key` the upload endpoint returned. - `records.lines` — The accounting split of the transaction: account, tax code and cost center per line. - `records.lines.id` — The line id. - `records.lines.transactionId` — The card transaction the line belongs to. - `records.lines.companyId` — Your company id. - `records.lines.accountId` — The expense account for the line. - `records.lines.accountLabel` — Its name. - `records.lines.taxCodeId` — The tax code on the line. - `records.lines.taxCodeLabel` — Its name. - `records.lines.costCenterId` — Cost center on the line. - `records.lines.costCenterName` — Its name. - `records.lines.amount` — Gross line amount in the balance account currency, minor units. - `records.lines.netAmount` — Line amount excluding tax, minor units. - `records.lines.description` — The line description. - `records.lines.createdAt` — When the line was created. - `records.lines.updatedAt` — When it was last changed. - `records.lines.customProperties` — Custom property values on the line. - `records.lines.amortizationTemplateId` — Release template id when the line is spread over a schedule; `null` otherwise. - `records.lines.amortizationStartDate` — First date of that schedule. - `records.lines.amortizationEndDate` — Last date of that schedule. - `records.failureContext` — Set when a batch update or a post fails validation, or when receipt conversion fails; cleared by the next successful post. The description about vendor onboarding is a copy-paste from another model. - `records.description` — The transaction description. - `records.performedAt` — When the card was charged. - `records.exportedAt` — When the transaction's export to accounting completed; `null` until then. Legacy field from before card transactions posted to the ledger as documents. - `records.createdAt` — When Light received the transaction. - `records.updatedAt` — When it was last changed. - `records.customProperties` — Custom property values on the transaction. ```json { "records": [ { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyEntityId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyEntityName": "string", "cardBalanceAccountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "cardBalanceAccountLabel": "string", "cardId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "cardVendorId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "cardVendorAvatarUrl": "string", "cardVendorName": "string", "cardOwnerName": "string", "cardOwnerId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "cardLastFour": "string", "originalAmount": 100000, "originalCurrency": "USD", "amount": 100000, "currency": "USD", "direction": "DEBIT", "transactionReason": "ACCOUNT_NOT_ACTIVE", "purchaseType": "ATM", "status": "AUTHORIZED", "type": "PAYMENT", "merchant": { "name": "string", "cleanName": "string", "country": "UNDEFINED", "zipcode": "string", "id": "string", "mcc": "string", "acquirerId": "string", "logoUrl": "string" }, "receiptDocumentKey": "string", "lines": [ { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "transactionId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "accountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "accountLabel": "string", "taxCodeId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "taxCodeLabel": "string", "costCenterId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "costCenterName": "string", "amount": 100000, "netAmount": 100000, "description": "string", "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z", "customProperties": [ {} ], "amortizationTemplateId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "amortizationStartDate": "2026-01-15", "amortizationEndDate": "2026-01-15" } ], "failureContext": { "name": "string", "type": "BAD_REQUEST", "errors": [ { "type": "string", "message": "string", "path": [], "context": null } ] }, "description": "string", "performedAt": "2026-01-15T09:30:00Z", "exportedAt": "2026-01-15T09:30:00Z", "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z", "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupInternalName": "string", "values": [ {} ] } ] } ], "hasMore": true, "total": 100000, "nextCursor": "string", "prevCursor": "string" } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders. ## Code ```bash curl -X GET "https://api.light.inc/v1/card-transactions" \ -H "Authorization: Basic YOUR_API_KEY" ``` Full page: https://light.inc/docs/api-reference/v1--card-transactions/list-card-transactions --- # Post card transaction > Posts a card transaction to the ledger `POST https://api.light.inc/v1/card-transactions/{transactionId}/post` ## Note Requires status CAPTURED or REFUNDED ( CARD_TRANSACTION_CANNOT_BE_POSTED otherwise), a ledger account and a tax code on every line, and every required custom property. Posting writes the lines to the ledger plus an offsetting entry on the ledger account that represents the card balance account; when the transaction currency differs from the entity's, an exchange rate for the posting date must exist. Afterwards status is POSTED and editStatus ALL_EDITS_LOCKED ; use reset to edit again. Company-admin or AP-clerk roles only; cardholders cannot post. ## Authorization - API key - Bearer token See https://light.inc/docs/getting-started/authentication. ## Path parameters - `transactionId` (string, uuid, required) ## Response - `amount` — Unsigned, in minor units. The sign is `direction`: `DEBIT` is money out, `CREDIT` is a refund or incoming credit. - `status` — Set by the card issuer, never by this API, apart from `POSTED`. `AUTHORIZED` moves to `CAPTURED`, `DECLINED` or `VOIDED`; `CAPTURED` and `REFUNDED` can be posted. A `REFUNDED` transaction is its **own record** with `direction: CREDIT` — the original capture keeps its status and nothing on the model links the two. - `merchant.name` — Merchant name as reported by the card network. - `merchant.cleanName` — The name cleaned up by Light, used for display and vendor matching. - `merchant.zipcode` — The merchant's postal code. - `merchant.id` — The card network's merchant id. - `merchant.mcc` — Merchant category code. - `merchant.acquirerId` — Id of the merchant's acquiring bank. - `merchant.logoUrl` — Logo URL, when Light has one. - `receiptDocumentKey` — Filled asynchronously after a receipt upload with the key of the converted PDF, which is not the `key` the upload endpoint returned. - `failureContext` — Set when a batch update or a post fails validation, or when receipt conversion fails; cleared by the next successful post. The description about vendor onboarding is a copy-paste from another model. - `editStatus` — Derived from `status` and whether the transaction is posted: `AUTHORIZED` gives `LINE_AMOUNT_EDITS_LOCKED`, an unposted `CAPTURED` or `REFUNDED` gives `ALL_EDITS_ALLOWED`, everything else `ALL_EDITS_LOCKED`. Not returned by the list or single `GET`. ```json { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyEntityId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "cardBalanceAccountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "cardId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "originalAmount": 100000, "originalCurrency": "USD", "amount": 100000, "currency": "USD", "direction": "DEBIT", "transactionReason": "ACCOUNT_NOT_ACTIVE", "purchaseType": "ATM", "status": "AUTHORIZED", "type": "PAYMENT", "merchant": { "name": "string", "cleanName": "string", "country": "UNDEFINED", "zipcode": "string", "id": "string", "mcc": "string", "acquirerId": "string", "logoUrl": "string" }, "receiptDocumentKey": "string", "lines": [ { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "transactionId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "accountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "taxCodeId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "costCenterId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "amount": 100000, "netAmount": 100000, "taxAmount": 100000, "description": "string", "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z", "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupInternalName": "string", "values": [ {} ] } ], "amortizationTemplateId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "amortizationStartDate": "2026-01-15", "amortizationEndDate": "2026-01-15" } ], "failureContext": { "name": "string", "type": "BAD_REQUEST", "errors": [ { "type": "string", "message": "string", "path": [ "string" ], "context": null } ] }, "editStatus": "ALL_EDITS_ALLOWED", "description": "string", "performedAt": "2026-01-15T09:30:00Z", "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z", "updatedBy": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupInternalName": "string", "values": [ { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupInternalName": "string", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "internalName": "string", "label": "string", "context": "string", "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z" } ] } ] } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders. ## Code ```bash curl -X POST "https://api.light.inc/v1/card-transactions/3c90c3cc-0d44-4b50-8888-8dd25736052a/post" \ -H "Authorization: Basic YOUR_API_KEY" ``` Full page: https://light.inc/docs/api-reference/v1--card-transactions/post-card-transaction --- # Reset card transaction > Reverses a posted card transaction's ledger entries and returns it to an editable state `POST https://api.light.inc/v1/card-transactions/{transactionId}/reset` ## Note Only a POSTED transaction can be reset; anything else fails with CARD_TRANSACTION_CANNOT_BE_RESET . The ledger entries are reversed and status returns to CAPTURED (for a DEBIT ) or REFUNDED (for a CREDIT ), with editStatus back to ALL_EDITS_ALLOWED . ## Authorization - API key - Bearer token See https://light.inc/docs/getting-started/authentication. ## Path parameters - `transactionId` (string, uuid, required) ## Response - `amount` — Unsigned, in minor units. The sign is `direction`: `DEBIT` is money out, `CREDIT` is a refund or incoming credit. - `status` — Set by the card issuer, never by this API, apart from `POSTED`. `AUTHORIZED` moves to `CAPTURED`, `DECLINED` or `VOIDED`; `CAPTURED` and `REFUNDED` can be posted. A `REFUNDED` transaction is its **own record** with `direction: CREDIT` — the original capture keeps its status and nothing on the model links the two. - `merchant.name` — Merchant name as reported by the card network. - `merchant.cleanName` — The name cleaned up by Light, used for display and vendor matching. - `merchant.zipcode` — The merchant's postal code. - `merchant.id` — The card network's merchant id. - `merchant.mcc` — Merchant category code. - `merchant.acquirerId` — Id of the merchant's acquiring bank. - `merchant.logoUrl` — Logo URL, when Light has one. - `receiptDocumentKey` — Filled asynchronously after a receipt upload with the key of the converted PDF, which is not the `key` the upload endpoint returned. - `failureContext` — Set when a batch update or a post fails validation, or when receipt conversion fails; cleared by the next successful post. The description about vendor onboarding is a copy-paste from another model. - `editStatus` — Derived from `status` and whether the transaction is posted: `AUTHORIZED` gives `LINE_AMOUNT_EDITS_LOCKED`, an unposted `CAPTURED` or `REFUNDED` gives `ALL_EDITS_ALLOWED`, everything else `ALL_EDITS_LOCKED`. Not returned by the list or single `GET`. ```json { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyEntityId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "cardBalanceAccountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "cardId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "originalAmount": 100000, "originalCurrency": "USD", "amount": 100000, "currency": "USD", "direction": "DEBIT", "transactionReason": "ACCOUNT_NOT_ACTIVE", "purchaseType": "ATM", "status": "AUTHORIZED", "type": "PAYMENT", "merchant": { "name": "string", "cleanName": "string", "country": "UNDEFINED", "zipcode": "string", "id": "string", "mcc": "string", "acquirerId": "string", "logoUrl": "string" }, "receiptDocumentKey": "string", "lines": [ { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "transactionId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "accountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "taxCodeId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "costCenterId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "amount": 100000, "netAmount": 100000, "taxAmount": 100000, "description": "string", "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z", "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupInternalName": "string", "values": [ {} ] } ], "amortizationTemplateId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "amortizationStartDate": "2026-01-15", "amortizationEndDate": "2026-01-15" } ], "failureContext": { "name": "string", "type": "BAD_REQUEST", "errors": [ { "type": "string", "message": "string", "path": [ "string" ], "context": null } ] }, "editStatus": "ALL_EDITS_ALLOWED", "description": "string", "performedAt": "2026-01-15T09:30:00Z", "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z", "updatedBy": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupInternalName": "string", "values": [ { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupInternalName": "string", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "internalName": "string", "label": "string", "context": "string", "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z" } ] } ] } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders. ## Code ```bash curl -X POST "https://api.light.inc/v1/card-transactions/3c90c3cc-0d44-4b50-8888-8dd25736052a/reset" \ -H "Authorization: Basic YOUR_API_KEY" ``` Full page: https://light.inc/docs/api-reference/v1--card-transactions/reset-card-transaction --- # Update card transaction > Updates an existing card transaction `PATCH https://api.light.inc/v1/card-transactions/{transactionId}` ## Note Only description and customProperties are applied. postingDate is not accepted here — the batch endpoint is the only place it can be set. description follows the usual rule (omit to keep, null to clear). Required custom properties are enforced when the transaction is posted, not here. The response is the base shape, which includes editStatus . ## Authorization - API key - Bearer token See https://light.inc/docs/getting-started/authentication. ## Path parameters - `transactionId` (string, uuid, required) ## Request body `application/json;charset=UTF-8` - `customProperties.valueIds` — Catalogue value ids for this group. Required; send `[]` (with an empty `inlineValues`) to clear the group. `SINGLE_SELECT` and `MULTI_SELECT` groups accept nothing else. See [Custom properties on writes](/docs/getting-started/pagination-filtering-errors#custom-properties-on-writes). - `customProperties.inlineValues` — Literal values for `TEXT`, `NUMERIC`, `BOOLEAN` and `DATE` groups, as strings (`yyyy-MM-dd` for dates). Rejected on select groups with `CUSTOM_PROPERTY_VALUE_TYPE_MISMATCH`. See [Custom properties on writes](/docs/getting-started/pagination-filtering-errors#custom-properties-on-writes). ```json { "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "valueIds": [ "3c90c3cc-0d44-4b50-8888-8dd25736052a" ], "inlineValues": [ "string" ] } ], "description": "string" } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders, and fields that exclude each other are all shown. Do not send it unchanged. ## Response - `amount` — Unsigned, in minor units. The sign is `direction`: `DEBIT` is money out, `CREDIT` is a refund or incoming credit. - `status` — Set by the card issuer, never by this API, apart from `POSTED`. `AUTHORIZED` moves to `CAPTURED`, `DECLINED` or `VOIDED`; `CAPTURED` and `REFUNDED` can be posted. A `REFUNDED` transaction is its **own record** with `direction: CREDIT` — the original capture keeps its status and nothing on the model links the two. - `merchant.name` — Merchant name as reported by the card network. - `merchant.cleanName` — The name cleaned up by Light, used for display and vendor matching. - `merchant.zipcode` — The merchant's postal code. - `merchant.id` — The card network's merchant id. - `merchant.mcc` — Merchant category code. - `merchant.acquirerId` — Id of the merchant's acquiring bank. - `merchant.logoUrl` — Logo URL, when Light has one. - `receiptDocumentKey` — Filled asynchronously after a receipt upload with the key of the converted PDF, which is not the `key` the upload endpoint returned. - `failureContext` — Set when a batch update or a post fails validation, or when receipt conversion fails; cleared by the next successful post. The description about vendor onboarding is a copy-paste from another model. - `editStatus` — Derived from `status` and whether the transaction is posted: `AUTHORIZED` gives `LINE_AMOUNT_EDITS_LOCKED`, an unposted `CAPTURED` or `REFUNDED` gives `ALL_EDITS_ALLOWED`, everything else `ALL_EDITS_LOCKED`. Not returned by the list or single `GET`. ```json { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyEntityId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "cardBalanceAccountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "cardId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "originalAmount": 100000, "originalCurrency": "USD", "amount": 100000, "currency": "USD", "direction": "DEBIT", "transactionReason": "ACCOUNT_NOT_ACTIVE", "purchaseType": "ATM", "status": "AUTHORIZED", "type": "PAYMENT", "merchant": { "name": "string", "cleanName": "string", "country": "UNDEFINED", "zipcode": "string", "id": "string", "mcc": "string", "acquirerId": "string", "logoUrl": "string" }, "receiptDocumentKey": "string", "lines": [ { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "transactionId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "accountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "taxCodeId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "costCenterId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "amount": 100000, "netAmount": 100000, "taxAmount": 100000, "description": "string", "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z", "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupInternalName": "string", "values": [ {} ] } ], "amortizationTemplateId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "amortizationStartDate": "2026-01-15", "amortizationEndDate": "2026-01-15" } ], "failureContext": { "name": "string", "type": "BAD_REQUEST", "errors": [ { "type": "string", "message": "string", "path": [ "string" ], "context": null } ] }, "editStatus": "ALL_EDITS_ALLOWED", "description": "string", "performedAt": "2026-01-15T09:30:00Z", "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z", "updatedBy": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupInternalName": "string", "values": [ { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupInternalName": "string", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "internalName": "string", "label": "string", "context": "string", "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z" } ] } ] } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders. ## Code ```bash curl -X PATCH "https://api.light.inc/v1/card-transactions/3c90c3cc-0d44-4b50-8888-8dd25736052a" \ -H "Authorization: Basic YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "valueIds": [ "3c90c3cc-0d44-4b50-8888-8dd25736052a" ], "inlineValues": [ "string" ] } ], "description": "string" }' ``` Full page: https://light.inc/docs/api-reference/v1--card-transactions/update-card-transaction --- # Update card transaction line > Updates a specific card transaction line item `PATCH https://api.light.inc/v1/card-transactions/{transactionId}/lines/{transactionLineId}` ## Note Rejected with CARD_TRANSACTION_NOT_EDITABLE once the transaction is POSTED , DECLINED or VOIDED . While it is still AUTHORIZED , every field except amount may change; sending a different amount fails with CARD_TRANSACTION_AMOUNT_NOT_EDITABLE until the capture arrives. amount is the gross line amount in minor units of the balance account's currency, unsigned. All fields follow the omit-to-keep, null -to-clear rule. There is no endpoint to add or remove lines. ## Authorization - API key - Bearer token See https://light.inc/docs/getting-started/authentication. ## Path parameters - `transactionId` (string, uuid, required) - `transactionLineId` (string, uuid, required) ## Request body `application/json;charset=UTF-8` - `customProperties.valueIds` — Catalogue value ids for this group. Required; send `[]` (with an empty `inlineValues`) to clear the group. `SINGLE_SELECT` and `MULTI_SELECT` groups accept nothing else. See [Custom properties on writes](/docs/getting-started/pagination-filtering-errors#custom-properties-on-writes). - `customProperties.inlineValues` — Literal values for `TEXT`, `NUMERIC`, `BOOLEAN` and `DATE` groups, as strings (`yyyy-MM-dd` for dates). Rejected on select groups with `CUSTOM_PROPERTY_VALUE_TYPE_MISMATCH`. See [Custom properties on writes](/docs/getting-started/pagination-filtering-errors#custom-properties-on-writes). ```json { "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "valueIds": [ "3c90c3cc-0d44-4b50-8888-8dd25736052a" ], "inlineValues": [ "string" ] } ], "accountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "taxCodeId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "costCenterId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "amount": 100000, "description": "string", "amortizationTemplateId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "amortizationStartDate": "2026-01-15", "amortizationEndDate": "2026-01-15" } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders, and fields that exclude each other are all shown. Do not send it unchanged. ## Response ```json { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "transactionId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "accountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "taxCodeId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "costCenterId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "amount": 100000, "netAmount": 100000, "taxAmount": 100000, "description": "string", "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z", "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupInternalName": "string", "values": [ { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupInternalName": "string", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "internalName": "string", "label": "string", "context": "string", "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z" } ] } ], "amortizationTemplateId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "amortizationStartDate": "2026-01-15", "amortizationEndDate": "2026-01-15" } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders. ## Code ```bash curl -X PATCH "https://api.light.inc/v1/card-transactions/3c90c3cc-0d44-4b50-8888-8dd25736052a/lines/3c90c3cc-0d44-4b50-8888-8dd25736052a" \ -H "Authorization: Basic YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "valueIds": [ "3c90c3cc-0d44-4b50-8888-8dd25736052a" ], "inlineValues": [ "string" ] } ], "accountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "taxCodeId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "costCenterId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "amount": 100000, "description": "string", "amortizationTemplateId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "amortizationStartDate": "2026-01-15", "amortizationEndDate": "2026-01-15" }' ``` Full page: https://light.inc/docs/api-reference/v1--card-transactions/update-card-transaction-line --- # Cards (resource) Create, freeze, unfreeze and manage corporate cards. Resource page: https://light.inc/docs/api-reference/v1--cards # List cards > Returns a paginated list of cards `GET https://api.light.inc/v1/cards` ## Note The filter and sort field lists below are incomplete. The server also accepts ownerId , companyEntityId , formFactor and lastFour as filters and companyEntityId , cardBalanceAccountId , formFactor , type and lastFour as sorts. A cardholder-only credential must filter ownerId:eq: Creates a new card. Use metadata type 'VENDOR' for vendor cards or 'EMPLOYEE' for employee cards. `POST https://api.light.inc/v1/cards` ## Note Creation is synchronous with the card issuer: the response is the finished card, and a virtual card comes back ACTIVE and ready to use. A physical card is activated by POST /v1/cards/{cardId}/unfreeze once the cardholder has it. Preconditions, all 400 : the balance account is active ( CARD_BALANCE_ACCOUNT_NOT_ACTIVE ), its entity is set up for cards ( COMPANY_ENTITY_NOT_ACTIVE_ON_CARDS ), and ownerId is an active user ( CARD_CREATION_OWNER_NOT_RECOGNIZED ). With metadata.type = VENDOR the vendor must exist and be linked to that entity ( CARD_CREATION_VENDOR_NOT_RECOGNIZED ); with EMPLOYEE nothing further is validated. Two limits with the same interval fail with CARD_CREATION_CONFLICTING_LIMITS . formFactor defaults to VIRTUAL . Send an X-Idempotency-Key header: a retry with the same key returns the existing card, while a retry without one issues a second card. threeDs.password is generated by Light and always returned masked as . Not available in the sandbox. ## Authorization - API key - Bearer token See https://light.inc/docs/getting-started/authentication. ## Header parameters - `X-Idempotency-Key` (string) ## Request body `application/json;charset=UTF-8` - `authentication.phoneNumber.localNumber` — The number without the country code. - `deliveryContact.phoneNumber.localNumber` — The number without the country code. ```json { "balanceAccountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "ownerId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "metadata": { "type": "VENDOR" }, "description": "string", "authentication": { "phoneNumber": { "countryCode": "UNDEFINED", "localNumber": "string" }, "email": "string" }, "limits": [ { "amount": 100000, "currency": "USD", "interval": "PER_TRANSACTION" } ], "formFactor": "PHYSICAL", "deliveryContact": { "address": { "street": "string", "houseNumberOrName": "string", "city": "string", "postalCode": "string", "country": "UNDEFINED", "stateOrProvince": "string" }, "name": { "firstName": "string", "lastName": "string" }, "company": "string", "email": "string", "phoneNumber": { "countryCode": "UNDEFINED", "localNumber": "string" } } } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders, and fields that exclude each other are all shown. Do not send it unchanged. ## Response - `status` — `ACTIVE`, `FROZEN`, `CLOSED`, or the transient `UPDATE_IN_PROGRESS` while a freeze or unfreeze is being applied at the issuer. - `threeDs.phoneNumber` — May be `null`. - `threeDs.phoneNumber.localNumber` — The number without the country code. ```json { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyEntityId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "ownerId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "cardBalanceAccountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "form": "PHYSICAL", "status": "ACTIVE", "metadata": { "type": "VENDOR" }, "threeDs": { "phoneNumber": { "countryCode": "UNDEFINED", "localNumber": "string" }, "password": "string", "email": "string" }, "description": "string", "bin": "string", "lastFour": "string", "cardholderName": "string", "limits": [ { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "cardId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "amount": 100000, "currency": "USD", "interval": "PER_TRANSACTION", "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z" } ], "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z", "type": "VENDOR" } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders. ## Code ```bash curl -X POST "https://api.light.inc/v1/cards" \ -H "Authorization: Basic YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "balanceAccountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "ownerId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "metadata": { "type": "VENDOR" }, "description": "string", "authentication": { "phoneNumber": { "countryCode": "UNDEFINED", "localNumber": "string" }, "email": "string" }, "limits": [ { "amount": 100000, "currency": "USD", "interval": "PER_TRANSACTION" } ], "formFactor": "PHYSICAL", "deliveryContact": { "address": { "street": "string", "houseNumberOrName": "string", "city": "string", "postalCode": "string", "country": "UNDEFINED", "stateOrProvince": "string" }, "name": { "firstName": "string", "lastName": "string" }, "company": "string", "email": "string", "phoneNumber": { "countryCode": "UNDEFINED", "localNumber": "string" } } }' ``` Full page: https://light.inc/docs/api-reference/v1--cards/create-card --- # Freeze card > Freezes a card to block transactions `POST https://api.light.inc/v1/cards/{cardId}/freeze` ## Note While the issuer is updated the card reads UPDATE_IN_PROGRESS ; a second call during that window fails with CARD_UPDATE_IN_PROGRESS , and a CLOSED card with CARD_CLOSED . Freezing a card that is already frozen succeeds without change. Deactivating a user with PUT /v1/users/{userId}/status freezes every card they own. ## Authorization - API key - Bearer token See https://light.inc/docs/getting-started/authentication. ## Path parameters - `cardId` (string, uuid, required) ## Header parameters - `X-Idempotency-Key` (string) ## Response - `status` — `ACTIVE`, `FROZEN`, `CLOSED`, or the transient `UPDATE_IN_PROGRESS` while a freeze or unfreeze is being applied at the issuer. - `threeDs.phoneNumber` — May be `null`. - `threeDs.phoneNumber.localNumber` — The number without the country code. ```json { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyEntityId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "ownerId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "cardBalanceAccountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "form": "PHYSICAL", "status": "ACTIVE", "metadata": { "type": "VENDOR" }, "threeDs": { "phoneNumber": { "countryCode": "UNDEFINED", "localNumber": "string" }, "password": "string", "email": "string" }, "description": "string", "bin": "string", "lastFour": "string", "cardholderName": "string", "limits": [ { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "cardId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "amount": 100000, "currency": "USD", "interval": "PER_TRANSACTION", "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z" } ], "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z", "type": "VENDOR" } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders. ## Code ```bash curl -X POST "https://api.light.inc/v1/cards/3c90c3cc-0d44-4b50-8888-8dd25736052a/freeze" \ -H "Authorization: Basic YOUR_API_KEY" ``` Full page: https://light.inc/docs/api-reference/v1--cards/freeze-card --- # Get card > Returns a card by ID `GET https://api.light.inc/v1/cards/{cardId}` ## Note Company admins, AP clerks and auditors can read any card; a cardholder only their own ( 403 otherwise). ## Authorization - API key - Bearer token See https://light.inc/docs/getting-started/authentication. ## Path parameters - `cardId` (string, uuid, required) ## Response - `threeDs.phoneNumber` — May be `null`. - `threeDs.phoneNumber.localNumber` — The number without the country code. ```json { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyEntityId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyEntityName": "string", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "ownerId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "ownerName": "string", "cardBalanceAccountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "cardBalanceAccountLabel": "string", "currency": "USD", "form": "PHYSICAL", "status": "ACTIVE", "metadata": { "type": "VENDOR" }, "threeDs": { "phoneNumber": { "countryCode": "UNDEFINED", "localNumber": "string" }, "password": "string", "email": "string" }, "vendorId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "vendorName": "string", "vendorAvatarUrl": "string", "description": "string", "bin": "string", "lastFour": "string", "cardholderName": "string", "limitIntervalSpend": 100000, "limits": [ { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "cardId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "amount": 100000, "currency": "USD", "interval": "PER_TRANSACTION", "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z" } ], "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z", "type": "VENDOR" } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders. ## Code ```bash curl -X GET "https://api.light.inc/v1/cards/3c90c3cc-0d44-4b50-8888-8dd25736052a" \ -H "Authorization: Basic YOUR_API_KEY" ``` Full page: https://light.inc/docs/api-reference/v1--cards/get-card --- # Unfreeze card > Unfreezes a card to allow transactions. For physical cards, this confirms the cardholder is in possession of the card. `POST https://api.light.inc/v1/cards/{cardId}/unfreeze` ## Note Same transient UPDATE_IN_PROGRESS state and errors as freeze ( CARD_UPDATE_IN_PROGRESS , CARD_CLOSED ); unfreezing an active card succeeds without change. For a physical card this also marks the card order as delivered. ## Authorization - API key - Bearer token See https://light.inc/docs/getting-started/authentication. ## Path parameters - `cardId` (string, uuid, required) ## Header parameters - `X-Idempotency-Key` (string) ## Response - `status` — `ACTIVE`, `FROZEN`, `CLOSED`, or the transient `UPDATE_IN_PROGRESS` while a freeze or unfreeze is being applied at the issuer. - `threeDs.phoneNumber` — May be `null`. - `threeDs.phoneNumber.localNumber` — The number without the country code. ```json { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyEntityId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "ownerId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "cardBalanceAccountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "form": "PHYSICAL", "status": "ACTIVE", "metadata": { "type": "VENDOR" }, "threeDs": { "phoneNumber": { "countryCode": "UNDEFINED", "localNumber": "string" }, "password": "string", "email": "string" }, "description": "string", "bin": "string", "lastFour": "string", "cardholderName": "string", "limits": [ { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "cardId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "amount": 100000, "currency": "USD", "interval": "PER_TRANSACTION", "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z" } ], "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z", "type": "VENDOR" } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders. ## Code ```bash curl -X POST "https://api.light.inc/v1/cards/3c90c3cc-0d44-4b50-8888-8dd25736052a/unfreeze" \ -H "Authorization: Basic YOUR_API_KEY" ``` Full page: https://light.inc/docs/api-reference/v1--cards/unfreeze-card --- # Entities (resource) List the company's legal entities. Resource page: https://light.inc/docs/api-reference/v1--entities # List company entities > Returns a paginated list of company entities `GET https://api.light.inc/v1/entities` ## Note Without a filter , inactive entities are hidden (the default is status:in:ACTIVE HIDDEN ). Any filter you send replaces that default entirely , so filter=code:eq:001 will also return an INACTIVE entity — add status:ne:INACTIVE yourself when combining filters. HIDDEN entities are hidden in the app but usable. Default order is the app's own ordering ( sortPosition:asc ), not name or code . includeCardCustomer has no effect on the response body. ## Authorization - API key - Bearer token See https://light.inc/docs/getting-started/authentication. ## Query parameters - `sort` (string) — Sort string in the format field:direction . To provide multiple sort fields, separate them with commas. Available directions: asc , desc . Available fields: code , createdAt , displayName , localCurrency , name , sortPosition , status , vatNumber . - `filter` (string) — Filter string in the format field:operator:value . To provide multiple filters, separate them with commas. Available operators: eq , ne , in , not_in , gt , gte , lt , lte . - For in and not_in operators, provide multiple values separated by the pipe character ( ). Available fields: id , code , name , displayName , country , status , createdAt , updatedAt . - `limit` (integer, int32) — Maximum number of items to return. Default is 50, maximum is 200. - `offset` (integer, int64) — Number of items to skip before starting to collect the result set. Deprecated, use 'cursor' instead. - `cursor` (string) — The cursor position to start returning results from. To opt-in into cursor-based pagination, provide 0 for the initial request. For subsequent requests, use nextCursor and prevCursor from the previous response to navigate. Cursor values are opaque and should not be constructed manually. - `includeCardCustomer` (boolean) ## Response - `records.address.city` — City. - `records.address.state` — State or region, where the country uses one. - `records.address.zipcode` — Postal code. - `records.address.street` — First address line. - `records.address.street2` — Second address line. ```json { "records": [ { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "code": "string", "parentCompanyEntityId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "localCurrency": "USD", "displayName": "string", "vatNumber": "string", "name": "string", "address": { "country": "UNDEFINED", "city": "string", "state": "string", "zipcode": "string", "street": "string", "street2": "string" }, "status": "ACTIVE", "seedInvoiceNumber": 100000, "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z" } ], "hasMore": true, "total": 100000, "nextCursor": "string", "prevCursor": "string" } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders. ## Code ```bash curl -X GET "https://api.light.inc/v1/entities" \ -H "Authorization: Basic YOUR_API_KEY" ``` Full page: https://light.inc/docs/api-reference/v1--entities/list-company-entities --- # Companies (resource) Access company configuration, such as currency settings. Resource page: https://light.inc/docs/api-reference/v1--companies # Get current company > Returns the current company information `GET https://api.light.inc/v1/companies/current` ## Note Returns the company the credential belongs to. baseCurrency is the group (reporting) currency; each entity has its own localCurrency on GET /v1/entities . The four email fields are the company's inbound mailboxes: documents emailed to them are ingested by Light. There is no fiscal-year information on this endpoint. ## Authorization - API key - Bearer token See https://light.inc/docs/getting-started/authentication. ## Response - `baseCurrency` — The group (reporting) currency. Entities post in their own `localCurrency`; ledger amounts are carried in both. ```json { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "name": "string", "invoiceEmail": "string", "receiptEmail": "string", "contractEmail": "string", "salesInvoiceEmail": "string", "logoUrl": "string", "baseCurrency": "USD", "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z" } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders. ## Code ```bash curl -X GET "https://api.light.inc/v1/companies/current" \ -H "Authorization: Basic YOUR_API_KEY" ``` Full page: https://light.inc/docs/api-reference/v1--companies/get-current-company --- # Contracts (resource) Create, publish, renew, terminate and manage contracts. Resource page: https://light.inc/docs/api-reference/v1--contracts # Cancel scheduled termination > Cancels a scheduled termination, returning the contract to active `POST https://api.light.inc/v1/contracts/{contractId}/cancel-termination` ## Note Only from PENDING_TERMINATION ; no scheduled termination is 404 CONTRACT_TERMINATION_REQUEST_NOT_FOUND . ## Authorization - API key - Bearer token See https://light.inc/docs/getting-started/authentication. ## Path parameters - `contractId` (string, uuid, required) ## Header parameters - `X-Idempotency-Key` (string) ## Response - `terminatedAt` — The termination **date** at 00:00 UTC, not the moment the termination was entered. - `state` — API-created contracts start in `DRAFT` and `reset` returns them there; `CREATED` only occurs for PDFs uploaded for parsing in the app. `PENDING_TERMINATION` is a scheduled termination; `TERMINATED` is terminal. - `lines` — `[]` on the list endpoint; populated only by `GET /v1/contracts/{contractId}`. - `lines.priceOverwrite` — The **line total** before discount, in the smallest denomination — not a unit price. It stands in for `quantity` × the product's price, and the unit price Light displays is this figure divided by `quantity`. `null` means the line is priced from the product. The model carries no computed amounts (no net, discount or tax figure), so a line's arithmetic is this field, `quantity` and `discount`. ```json { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "startDate": "2026-01-15", "endDate": "2026-01-15", "activatedAt": "2026-01-15T09:30:00Z", "terminatedAt": "2026-01-15T09:30:00Z", "terminationReason": "string", "terminationReasonType": "FINISHED", "renewalDate": "2026-01-15", "companyEntityId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "invoiceTemplateId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "currency": "USD", "estimatedAmount": 100000, "paymentType": "AIRWALLEX", "payeeBankAccountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "billingStart": "2026-01-15", "netTerms": 0, "invoiceLeadDays": 0, "description": "string", "customerId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "state": "CREATED", "areLinesWithTax": true, "lines": [ { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "contractId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "productId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "billingStart": "2026-01-15", "billingEnd": "2026-01-15", "billingRecurrence": "ONE_TIME", "accountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "taxCodeId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "avataxCode": "string", "discount": { "startDate": "2026-01-15", "endDate": "2026-01-15", "type": "PERCENTAGE" }, "quantity": 0, "priceOverwrite": 100000, "productNameOverwrite": "string", "amortizationTemplateId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "amortizationStartDate": "2026-01-15", "amortizationEndDate": "2026-01-15", "aiValueSuggestions": [ { "field": "string", "fieldValues": [ "string" ], "reasoning": "string" } ], "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupInternalName": "string", "values": [ {} ] } ], "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z" } ], "taxEngineName": "AVATAX", "externalId": "string", "externalSource": "HUBSPOT", "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupInternalName": "string", "values": [ { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupInternalName": "string", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "internalName": "string", "label": "string", "context": "string", "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z" } ] } ], "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z" } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders. ## Code ```bash curl -X POST "https://api.light.inc/v1/contracts/3c90c3cc-0d44-4b50-8888-8dd25736052a/cancel-termination" \ -H "Authorization: Basic YOUR_API_KEY" ``` Full page: https://light.inc/docs/api-reference/v1--contracts/cancel-scheduled-termination --- # List contracts > Returns a paginated list of contracts `GET https://api.light.inc/v1/contracts` ## Note The filter parameter does accept fields , despite the empty list below: companyEntityId , customerId , id , state and updatedAt . There is no default filter (contracts of every state are returned), no searchTerm and no default order. lines is [] in list rows; only GET /v1/contracts/{contractId} returns them. ## Authorization - API key - Bearer token See https://light.inc/docs/getting-started/authentication. ## Query parameters - `sort` (string) — Sort string in the format field:direction . To provide multiple sort fields, separate them with commas. Available directions: asc , desc . Available fields: activatedAt , companyEntityId , companyEntityName , createdAt , customerId , customerName , description , endDate , estimatedAmount , renewalDate , startDate , state , terminatedAt . - `filter` (string) — Filter string in the format field:operator:value . To provide multiple filters, separate them with commas. Available operators: eq , ne , in , not_in , gt , gte , lt , lte . - For in and not_in operators, provide multiple values separated by the pipe character ( ). - `limit` (integer, int32) — Maximum number of items to return. Default is 50, maximum is 200. - `offset` (integer, int64) — Number of items to skip before starting to collect the result set. Deprecated, use 'cursor' instead. - `cursor` (string) — The cursor position to start returning results from. To opt-in into cursor-based pagination, provide 0 for the initial request. For subsequent requests, use nextCursor and prevCursor from the previous response to navigate. Cursor values are opaque and should not be constructed manually. ## Response - `records.terminatedAt` — The termination **date** at 00:00 UTC, not the moment the termination was entered. - `records.state` — API-created contracts start in `DRAFT` and `reset` returns them there; `CREATED` only occurs for PDFs uploaded for parsing in the app. `PENDING_TERMINATION` is a scheduled termination; `TERMINATED` is terminal. - `records.lines` — `[]` on the list endpoint; populated only by `GET /v1/contracts/{contractId}`. - `records.lines.priceOverwrite` — The **line total** before discount, in the smallest denomination — not a unit price. It stands in for `quantity` × the product's price, and the unit price Light displays is this figure divided by `quantity`. `null` means the line is priced from the product. The model carries no computed amounts (no net, discount or tax figure), so a line's arithmetic is this field, `quantity` and `discount`. ```json { "records": [ { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "startDate": "2026-01-15", "endDate": "2026-01-15", "activatedAt": "2026-01-15T09:30:00Z", "terminatedAt": "2026-01-15T09:30:00Z", "terminationReason": "string", "terminationReasonType": "FINISHED", "renewalDate": "2026-01-15", "companyEntityId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "invoiceTemplateId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "currency": "USD", "estimatedAmount": 100000, "paymentType": "AIRWALLEX", "payeeBankAccountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "billingStart": "2026-01-15", "netTerms": 0, "invoiceLeadDays": 0, "description": "string", "customerId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "state": "CREATED", "areLinesWithTax": true, "lines": [ { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "contractId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "productId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "billingStart": "2026-01-15", "billingEnd": "2026-01-15", "billingRecurrence": "ONE_TIME", "accountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "taxCodeId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "avataxCode": "string", "discount": { "startDate": "2026-01-15", "endDate": "2026-01-15", "type": "PERCENTAGE" }, "quantity": 0, "priceOverwrite": 100000, "productNameOverwrite": "string", "amortizationTemplateId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "amortizationStartDate": "2026-01-15", "amortizationEndDate": "2026-01-15", "aiValueSuggestions": [ {} ], "customProperties": [ {} ], "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z" } ], "taxEngineName": "AVATAX", "externalId": "string", "externalSource": "HUBSPOT", "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupInternalName": "string", "values": [ {} ] } ], "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z" } ], "hasMore": true, "total": 100000, "nextCursor": "string", "prevCursor": "string" } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders. ## Code ```bash curl -X GET "https://api.light.inc/v1/contracts" \ -H "Authorization: Basic YOUR_API_KEY" ``` Full page: https://light.inc/docs/api-reference/v1--contracts/list-contracts --- # Create contract > Creates a new contract `POST https://api.light.inc/v1/contracts` ## Note A new contract is in DRAFT , not CREATED ; CREATED is the transient state of a PDF uploaded for parsing in the app. Defaults: netTerms 30, invoiceLeadDays 0 (must be 0 to 365), areLinesWithTax true . Line billingStart falls back to the contract's, and line account and tax fields to the product's defaults for the tax engine in force. Bank account, accounts, tax codes and template must belong to companyEntityId . With an X-Idempotency-Key a replay returns the same contract and a different body is 409 IDEMPOTENCY_VIOLATION ; without one nothing is de-duplicated. ## Authorization - API key - Bearer token See https://light.inc/docs/getting-started/authentication. ## Header parameters - `X-Idempotency-Key` (string) ## Request body `application/json;charset=UTF-8` - `customProperties.valueIds` — Catalogue value ids for this group. Required; send `[]` (with an empty `inlineValues`) to clear the group. `SINGLE_SELECT` and `MULTI_SELECT` groups accept nothing else. See [Custom properties on writes](/docs/getting-started/pagination-filtering-errors#custom-properties-on-writes). - `customProperties.inlineValues` — Literal values for `TEXT`, `NUMERIC`, `BOOLEAN` and `DATE` groups, as strings (`yyyy-MM-dd` for dates). Rejected on select groups with `CUSTOM_PROPERTY_VALUE_TYPE_MISMATCH`. See [Custom properties on writes](/docs/getting-started/pagination-filtering-errors#custom-properties-on-writes). - `lines.priceOverwrite` — The **line total** before discount, in the smallest denomination — not a unit price. It replaces `quantity` × the product's price, and the unit price Light displays is this figure divided by `quantity`: 10 units at $0.20 each is `200` with `quantity: 10`, while `20` prices the whole line at $0.20. Any line `discount` then applies on top, so `20` with a 50% discount leaves the line at $0.10. Required when the product has no price in the contract's currency. - `lines.customProperties.valueIds` — Catalogue value ids for this group. Required; send `[]` (with an empty `inlineValues`) to clear the group. `SINGLE_SELECT` and `MULTI_SELECT` groups accept nothing else. See [Custom properties on writes](/docs/getting-started/pagination-filtering-errors#custom-properties-on-writes). - `lines.customProperties.inlineValues` — Literal values for `TEXT`, `NUMERIC`, `BOOLEAN` and `DATE` groups, as strings (`yyyy-MM-dd` for dates). Rejected on select groups with `CUSTOM_PROPERTY_VALUE_TYPE_MISMATCH`. See [Custom properties on writes](/docs/getting-started/pagination-filtering-errors#custom-properties-on-writes). ```json { "companyEntityId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "startDate": "2026-01-15", "endDate": "2026-01-15", "invoiceTemplateId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "currency": "USD", "estimatedAmount": 100000, "renewalDate": "2026-01-15", "paymentType": "AIRWALLEX", "payeeBankAccountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "netTerms": 0, "invoiceLeadDays": 0, "billingStart": "2026-01-15", "description": "string", "customerId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "areLinesWithTax": true, "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "valueIds": [ "3c90c3cc-0d44-4b50-8888-8dd25736052a" ], "inlineValues": [ "string" ] } ], "lines": [ { "productId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "billingStart": "2026-01-15", "billingEnd": "2026-01-15", "billingRecurrence": "ONE_TIME", "accountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "taxCodeId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "avataxCode": "string", "discount": { "startDate": "2026-01-15", "endDate": "2026-01-15", "type": "PERCENTAGE" }, "quantity": 0, "priceOverwrite": 100000, "productNameOverwrite": "string", "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "valueIds": [ "3c90c3cc-0d44-4b50-8888-8dd25736052a" ], "inlineValues": [ "string" ] } ], "amortizationTemplateId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "amortizationStartDate": "2026-01-15", "amortizationEndDate": "2026-01-15" } ] } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders, and fields that exclude each other are all shown. Do not send it unchanged. ## Response - `terminatedAt` — The termination **date** at 00:00 UTC, not the moment the termination was entered. - `state` — API-created contracts start in `DRAFT` and `reset` returns them there; `CREATED` only occurs for PDFs uploaded for parsing in the app. `PENDING_TERMINATION` is a scheduled termination; `TERMINATED` is terminal. - `lines` — `[]` on the list endpoint; populated only by `GET /v1/contracts/{contractId}`. - `lines.priceOverwrite` — The **line total** before discount, in the smallest denomination — not a unit price. It stands in for `quantity` × the product's price, and the unit price Light displays is this figure divided by `quantity`. `null` means the line is priced from the product. The model carries no computed amounts (no net, discount or tax figure), so a line's arithmetic is this field, `quantity` and `discount`. ```json { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "startDate": "2026-01-15", "endDate": "2026-01-15", "activatedAt": "2026-01-15T09:30:00Z", "terminatedAt": "2026-01-15T09:30:00Z", "terminationReason": "string", "terminationReasonType": "FINISHED", "renewalDate": "2026-01-15", "companyEntityId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "invoiceTemplateId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "currency": "USD", "estimatedAmount": 100000, "paymentType": "AIRWALLEX", "payeeBankAccountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "billingStart": "2026-01-15", "netTerms": 0, "invoiceLeadDays": 0, "description": "string", "customerId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "state": "CREATED", "areLinesWithTax": true, "lines": [ { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "contractId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "productId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "billingStart": "2026-01-15", "billingEnd": "2026-01-15", "billingRecurrence": "ONE_TIME", "accountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "taxCodeId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "avataxCode": "string", "discount": { "startDate": "2026-01-15", "endDate": "2026-01-15", "type": "PERCENTAGE" }, "quantity": 0, "priceOverwrite": 100000, "productNameOverwrite": "string", "amortizationTemplateId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "amortizationStartDate": "2026-01-15", "amortizationEndDate": "2026-01-15", "aiValueSuggestions": [ { "field": "string", "fieldValues": [ "string" ], "reasoning": "string" } ], "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupInternalName": "string", "values": [ {} ] } ], "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z" } ], "taxEngineName": "AVATAX", "externalId": "string", "externalSource": "HUBSPOT", "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupInternalName": "string", "values": [ { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupInternalName": "string", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "internalName": "string", "label": "string", "context": "string", "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z" } ] } ], "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z" } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders. ## Code ```bash curl -X POST "https://api.light.inc/v1/contracts" \ -H "Authorization: Basic YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "companyEntityId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "startDate": "2026-01-15", "endDate": "2026-01-15", "invoiceTemplateId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "currency": "USD", "estimatedAmount": 100000, "renewalDate": "2026-01-15", "paymentType": "AIRWALLEX", "payeeBankAccountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "netTerms": 0, "invoiceLeadDays": 0, "billingStart": "2026-01-15", "description": "string", "customerId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "areLinesWithTax": true, "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "valueIds": [ "3c90c3cc-0d44-4b50-8888-8dd25736052a" ], "inlineValues": [ "string" ] } ], "lines": [ { "productId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "billingStart": "2026-01-15", "billingEnd": "2026-01-15", "billingRecurrence": "ONE_TIME", "accountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "taxCodeId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "avataxCode": "string", "discount": { "startDate": "2026-01-15", "endDate": "2026-01-15", "type": "PERCENTAGE" }, "quantity": 0, "priceOverwrite": 100000, "productNameOverwrite": "string", "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "valueIds": [ "3c90c3cc-0d44-4b50-8888-8dd25736052a" ], "inlineValues": [ "string" ] } ], "amortizationTemplateId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "amortizationStartDate": "2026-01-15", "amortizationEndDate": "2026-01-15" } ] }' ``` Full page: https://light.inc/docs/api-reference/v1--contracts/create-contract --- # Create contract line > Creates a new contract line item `POST https://api.light.inc/v1/contracts/{contractId}/lines` ## Note Only while the contract is DRAFT ( CONTRACT_CANNOT_BE_MODIFIED ). A line discount carries its own startDate and endDate window in addition to type and value . ## Authorization - API key - Bearer token See https://light.inc/docs/getting-started/authentication. ## Path parameters - `contractId` (string, uuid, required) ## Header parameters - `X-Idempotency-Key` (string) ## Request body `application/json;charset=UTF-8` - `priceOverwrite` — The **line total** before discount, in the smallest denomination — not a unit price. It replaces `quantity` × the product's price, and the unit price Light displays is this figure divided by `quantity`: 10 units at $0.20 each is `200` with `quantity: 10`, while `20` prices the whole line at $0.20. Any line `discount` then applies on top, so `20` with a 50% discount leaves the line at $0.10. Required when the product has no price in the contract's currency. - `customProperties.valueIds` — Catalogue value ids for this group. Required; send `[]` (with an empty `inlineValues`) to clear the group. `SINGLE_SELECT` and `MULTI_SELECT` groups accept nothing else. See [Custom properties on writes](/docs/getting-started/pagination-filtering-errors#custom-properties-on-writes). - `customProperties.inlineValues` — Literal values for `TEXT`, `NUMERIC`, `BOOLEAN` and `DATE` groups, as strings (`yyyy-MM-dd` for dates). Rejected on select groups with `CUSTOM_PROPERTY_VALUE_TYPE_MISMATCH`. See [Custom properties on writes](/docs/getting-started/pagination-filtering-errors#custom-properties-on-writes). ```json { "productId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "billingStart": "2026-01-15", "billingEnd": "2026-01-15", "billingRecurrence": "ONE_TIME", "accountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "taxCodeId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "avataxCode": "string", "discount": { "startDate": "2026-01-15", "endDate": "2026-01-15", "type": "PERCENTAGE" }, "quantity": 0, "priceOverwrite": 100000, "productNameOverwrite": "string", "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "valueIds": [ "3c90c3cc-0d44-4b50-8888-8dd25736052a" ], "inlineValues": [ "string" ] } ], "amortizationTemplateId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "amortizationStartDate": "2026-01-15", "amortizationEndDate": "2026-01-15" } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders, and fields that exclude each other are all shown. Do not send it unchanged. ## Response - `priceOverwrite` — The **line total** before discount, in the smallest denomination — not a unit price. It stands in for `quantity` × the product's price, and the unit price Light displays is this figure divided by `quantity`. `null` means the line is priced from the product. The model carries no computed amounts (no net, discount or tax figure), so a line's arithmetic is this field, `quantity` and `discount`. ```json { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "contractId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "productId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "billingStart": "2026-01-15", "billingEnd": "2026-01-15", "billingRecurrence": "ONE_TIME", "accountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "taxCodeId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "avataxCode": "string", "discount": { "startDate": "2026-01-15", "endDate": "2026-01-15", "type": "PERCENTAGE" }, "quantity": 0, "priceOverwrite": 100000, "productNameOverwrite": "string", "amortizationTemplateId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "amortizationStartDate": "2026-01-15", "amortizationEndDate": "2026-01-15", "aiValueSuggestions": [ { "field": "string", "fieldValues": [ "string" ], "reasoning": "string" } ], "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupInternalName": "string", "values": [ { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupInternalName": "string", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "internalName": "string", "label": "string", "context": "string", "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z" } ] } ], "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z" } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders. ## Code ```bash curl -X POST "https://api.light.inc/v1/contracts/3c90c3cc-0d44-4b50-8888-8dd25736052a/lines" \ -H "Authorization: Basic YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "productId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "billingStart": "2026-01-15", "billingEnd": "2026-01-15", "billingRecurrence": "ONE_TIME", "accountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "taxCodeId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "avataxCode": "string", "discount": { "startDate": "2026-01-15", "endDate": "2026-01-15", "type": "PERCENTAGE" }, "quantity": 0, "priceOverwrite": 100000, "productNameOverwrite": "string", "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "valueIds": [ "3c90c3cc-0d44-4b50-8888-8dd25736052a" ], "inlineValues": [ "string" ] } ], "amortizationTemplateId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "amortizationStartDate": "2026-01-15", "amortizationEndDate": "2026-01-15" }' ``` Full page: https://light.inc/docs/api-reference/v1--contracts/create-contract-line --- # Get contract > Returns a specific contract by ID `GET https://api.light.inc/v1/contracts/{contractId}` ## Note Any status. An unknown id, or one from another company, is 404 . ## Authorization - API key - Bearer token See https://light.inc/docs/getting-started/authentication. ## Path parameters - `contractId` (string, uuid, required) ## Response - `terminatedAt` — The termination **date** at 00:00 UTC, not the moment the termination was entered. - `state` — API-created contracts start in `DRAFT` and `reset` returns them there; `CREATED` only occurs for PDFs uploaded for parsing in the app. `PENDING_TERMINATION` is a scheduled termination; `TERMINATED` is terminal. - `lines` — `[]` on the list endpoint; populated only by `GET /v1/contracts/{contractId}`. - `lines.priceOverwrite` — The **line total** before discount, in the smallest denomination — not a unit price. It stands in for `quantity` × the product's price, and the unit price Light displays is this figure divided by `quantity`. `null` means the line is priced from the product. The model carries no computed amounts (no net, discount or tax figure), so a line's arithmetic is this field, `quantity` and `discount`. ```json { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "startDate": "2026-01-15", "endDate": "2026-01-15", "activatedAt": "2026-01-15T09:30:00Z", "terminatedAt": "2026-01-15T09:30:00Z", "terminationReason": "string", "terminationReasonType": "FINISHED", "renewalDate": "2026-01-15", "companyEntityId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "invoiceTemplateId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "currency": "USD", "estimatedAmount": 100000, "paymentType": "AIRWALLEX", "payeeBankAccountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "billingStart": "2026-01-15", "netTerms": 0, "invoiceLeadDays": 0, "description": "string", "customerId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "state": "CREATED", "areLinesWithTax": true, "lines": [ { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "contractId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "productId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "billingStart": "2026-01-15", "billingEnd": "2026-01-15", "billingRecurrence": "ONE_TIME", "accountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "taxCodeId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "avataxCode": "string", "discount": { "startDate": "2026-01-15", "endDate": "2026-01-15", "type": "PERCENTAGE" }, "quantity": 0, "priceOverwrite": 100000, "productNameOverwrite": "string", "amortizationTemplateId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "amortizationStartDate": "2026-01-15", "amortizationEndDate": "2026-01-15", "aiValueSuggestions": [ { "field": "string", "fieldValues": [ "string" ], "reasoning": "string" } ], "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupInternalName": "string", "values": [ {} ] } ], "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z" } ], "taxEngineName": "AVATAX", "externalId": "string", "externalSource": "HUBSPOT", "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupInternalName": "string", "values": [ { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupInternalName": "string", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "internalName": "string", "label": "string", "context": "string", "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z" } ] } ], "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z" } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders. ## Code ```bash curl -X GET "https://api.light.inc/v1/contracts/3c90c3cc-0d44-4b50-8888-8dd25736052a" \ -H "Authorization: Basic YOUR_API_KEY" ``` Full page: https://light.inc/docs/api-reference/v1--contracts/get-contract --- # Delete contract > Deletes a contract by ID `DELETE https://api.light.inc/v1/contracts/{contractId}` ## Note Only a never-published DRAFT can be deleted ( CONTRACT_CANNOT_BE_DELETED otherwise). Use terminate for an active contract. ## Authorization - API key - Bearer token See https://light.inc/docs/getting-started/authentication. ## Path parameters - `contractId` (string, uuid, required) ## Header parameters - `X-Idempotency-Key` (string) ## Response This endpoint returns no content. ## Code ```bash curl -X DELETE "https://api.light.inc/v1/contracts/3c90c3cc-0d44-4b50-8888-8dd25736052a" \ -H "Authorization: Basic YOUR_API_KEY" ``` Full page: https://light.inc/docs/api-reference/v1--contracts/delete-contract --- # Update contract > Updates a contract `PATCH https://api.light.inc/v1/contracts/{contractId}` ## Note Only while DRAFT . An ACTIVE contract cannot be edited through this API (there is no endpoint to open a working version): every change fails with CONTRACT_CANNOT_BE_MODIFIED , and the only routes are reset (back to DRAFT , with its side effects) or renew . Unlike most PATCH bodies, null clears nearly every field here, including startDate , endDate , customerId and netTerms . Changing billingStart moves every line whose billingStart matched the old value; changing companyEntityId drops a bank account or template that doesn't belong to the new entity and re-resolves line accounts and taxes. ## Authorization - API key - Bearer token See https://light.inc/docs/getting-started/authentication. ## Path parameters - `contractId` (string, uuid, required) ## Header parameters - `X-Idempotency-Key` (string) ## Request body `application/json;charset=UTF-8` - `customProperties.valueIds` — Catalogue value ids for this group. Required; send `[]` (with an empty `inlineValues`) to clear the group. `SINGLE_SELECT` and `MULTI_SELECT` groups accept nothing else. See [Custom properties on writes](/docs/getting-started/pagination-filtering-errors#custom-properties-on-writes). - `customProperties.inlineValues` — Literal values for `TEXT`, `NUMERIC`, `BOOLEAN` and `DATE` groups, as strings (`yyyy-MM-dd` for dates). Rejected on select groups with `CUSTOM_PROPERTY_VALUE_TYPE_MISMATCH`. See [Custom properties on writes](/docs/getting-started/pagination-filtering-errors#custom-properties-on-writes). ```json { "areLinesWithTax": true, "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "valueIds": [ "3c90c3cc-0d44-4b50-8888-8dd25736052a" ], "inlineValues": [ "string" ] } ], "startDate": "2026-01-15", "endDate": "2026-01-15", "companyEntityId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "invoiceTemplateId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "currency": "USD", "estimatedAmount": 100000, "paymentType": "AIRWALLEX", "payeeBankAccountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "netTerms": 0, "invoiceLeadDays": 0, "billingStart": "2026-01-15", "description": "string", "customerId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "renewalDate": "2026-01-15" } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders, and fields that exclude each other are all shown. Do not send it unchanged. ## Response - `terminatedAt` — The termination **date** at 00:00 UTC, not the moment the termination was entered. - `state` — API-created contracts start in `DRAFT` and `reset` returns them there; `CREATED` only occurs for PDFs uploaded for parsing in the app. `PENDING_TERMINATION` is a scheduled termination; `TERMINATED` is terminal. - `lines` — `[]` on the list endpoint; populated only by `GET /v1/contracts/{contractId}`. - `lines.priceOverwrite` — The **line total** before discount, in the smallest denomination — not a unit price. It stands in for `quantity` × the product's price, and the unit price Light displays is this figure divided by `quantity`. `null` means the line is priced from the product. The model carries no computed amounts (no net, discount or tax figure), so a line's arithmetic is this field, `quantity` and `discount`. ```json { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "startDate": "2026-01-15", "endDate": "2026-01-15", "activatedAt": "2026-01-15T09:30:00Z", "terminatedAt": "2026-01-15T09:30:00Z", "terminationReason": "string", "terminationReasonType": "FINISHED", "renewalDate": "2026-01-15", "companyEntityId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "invoiceTemplateId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "currency": "USD", "estimatedAmount": 100000, "paymentType": "AIRWALLEX", "payeeBankAccountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "billingStart": "2026-01-15", "netTerms": 0, "invoiceLeadDays": 0, "description": "string", "customerId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "state": "CREATED", "areLinesWithTax": true, "lines": [ { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "contractId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "productId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "billingStart": "2026-01-15", "billingEnd": "2026-01-15", "billingRecurrence": "ONE_TIME", "accountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "taxCodeId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "avataxCode": "string", "discount": { "startDate": "2026-01-15", "endDate": "2026-01-15", "type": "PERCENTAGE" }, "quantity": 0, "priceOverwrite": 100000, "productNameOverwrite": "string", "amortizationTemplateId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "amortizationStartDate": "2026-01-15", "amortizationEndDate": "2026-01-15", "aiValueSuggestions": [ { "field": "string", "fieldValues": [ "string" ], "reasoning": "string" } ], "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupInternalName": "string", "values": [ {} ] } ], "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z" } ], "taxEngineName": "AVATAX", "externalId": "string", "externalSource": "HUBSPOT", "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupInternalName": "string", "values": [ { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupInternalName": "string", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "internalName": "string", "label": "string", "context": "string", "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z" } ] } ], "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z" } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders. ## Code ```bash curl -X PATCH "https://api.light.inc/v1/contracts/3c90c3cc-0d44-4b50-8888-8dd25736052a" \ -H "Authorization: Basic YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "areLinesWithTax": true, "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "valueIds": [ "3c90c3cc-0d44-4b50-8888-8dd25736052a" ], "inlineValues": [ "string" ] } ], "startDate": "2026-01-15", "endDate": "2026-01-15", "companyEntityId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "invoiceTemplateId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "currency": "USD", "estimatedAmount": 100000, "paymentType": "AIRWALLEX", "payeeBankAccountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "netTerms": 0, "invoiceLeadDays": 0, "billingStart": "2026-01-15", "description": "string", "customerId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "renewalDate": "2026-01-15" }' ``` Full page: https://light.inc/docs/api-reference/v1--contracts/update-contract --- # Delete contract line > Deletes a contract line item `DELETE https://api.light.inc/v1/contracts/{contractId}/lines/{lineId}` ## Note Only while the contract is DRAFT ( CONTRACT_CANNOT_BE_MODIFIED ); unknown line is 404 CONTRACT_LINE_NOT_FOUND . ## Authorization - API key - Bearer token See https://light.inc/docs/getting-started/authentication. ## Path parameters - `contractId` (string, uuid, required) - `lineId` (string, uuid, required) ## Header parameters - `X-Idempotency-Key` (string) ## Response This endpoint returns no content. ## Code ```bash curl -X DELETE "https://api.light.inc/v1/contracts/3c90c3cc-0d44-4b50-8888-8dd25736052a/lines/3c90c3cc-0d44-4b50-8888-8dd25736052a" \ -H "Authorization: Basic YOUR_API_KEY" ``` Full page: https://light.inc/docs/api-reference/v1--contracts/delete-contract-line --- # Update contract line > Updates a contract line item `PATCH https://api.light.inc/v1/contracts/{contractId}/lines/{lineId}` ## Note Only while the contract is DRAFT ( CONTRACT_CANNOT_BE_MODIFIED ). null clears billingEnd , discount , priceOverwrite , productNameOverwrite , quantity and the amortization fields, but leaves productId , billingStart , accountId , taxCodeId and billingRecurrence unchanged. ## Authorization - API key - Bearer token See https://light.inc/docs/getting-started/authentication. ## Path parameters - `contractId` (string, uuid, required) - `lineId` (string, uuid, required) ## Header parameters - `X-Idempotency-Key` (string) ## Request body `application/json;charset=UTF-8` - `customProperties.valueIds` — Catalogue value ids for this group. Required; send `[]` (with an empty `inlineValues`) to clear the group. `SINGLE_SELECT` and `MULTI_SELECT` groups accept nothing else. See [Custom properties on writes](/docs/getting-started/pagination-filtering-errors#custom-properties-on-writes). - `customProperties.inlineValues` — Literal values for `TEXT`, `NUMERIC`, `BOOLEAN` and `DATE` groups, as strings (`yyyy-MM-dd` for dates). Rejected on select groups with `CUSTOM_PROPERTY_VALUE_TYPE_MISMATCH`. See [Custom properties on writes](/docs/getting-started/pagination-filtering-errors#custom-properties-on-writes). - `priceOverwrite` — As on create: the **line total** before discount, in the smallest denomination, standing in for `quantity` × the product's price — not a unit price, so send 10 units at $0.20 each as `200`, not `20`. `null` clears it and returns the line to the product's price. ```json { "productId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "billingStart": "2026-01-15", "accountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "taxCodeId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "valueIds": [ "3c90c3cc-0d44-4b50-8888-8dd25736052a" ], "inlineValues": [ "string" ] } ], "billingRecurrence": "ONE_TIME", "billingEnd": "2026-01-15", "discount": { "startDate": "2026-01-15", "endDate": "2026-01-15", "type": "PERCENTAGE" }, "priceOverwrite": 100000, "productNameOverwrite": "string", "quantity": 0, "amortizationTemplateId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "amortizationStartDate": "2026-01-15", "amortizationEndDate": "2026-01-15" } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders, and fields that exclude each other are all shown. Do not send it unchanged. ## Response - `priceOverwrite` — The **line total** before discount, in the smallest denomination — not a unit price. It stands in for `quantity` × the product's price, and the unit price Light displays is this figure divided by `quantity`. `null` means the line is priced from the product. The model carries no computed amounts (no net, discount or tax figure), so a line's arithmetic is this field, `quantity` and `discount`. ```json { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "contractId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "productId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "billingStart": "2026-01-15", "billingEnd": "2026-01-15", "billingRecurrence": "ONE_TIME", "accountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "taxCodeId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "avataxCode": "string", "discount": { "startDate": "2026-01-15", "endDate": "2026-01-15", "type": "PERCENTAGE" }, "quantity": 0, "priceOverwrite": 100000, "productNameOverwrite": "string", "amortizationTemplateId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "amortizationStartDate": "2026-01-15", "amortizationEndDate": "2026-01-15", "aiValueSuggestions": [ { "field": "string", "fieldValues": [ "string" ], "reasoning": "string" } ], "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupInternalName": "string", "values": [ { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupInternalName": "string", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "internalName": "string", "label": "string", "context": "string", "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z" } ] } ], "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z" } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders. ## Code ```bash curl -X PATCH "https://api.light.inc/v1/contracts/3c90c3cc-0d44-4b50-8888-8dd25736052a/lines/3c90c3cc-0d44-4b50-8888-8dd25736052a" \ -H "Authorization: Basic YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "productId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "billingStart": "2026-01-15", "accountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "taxCodeId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "valueIds": [ "3c90c3cc-0d44-4b50-8888-8dd25736052a" ], "inlineValues": [ "string" ] } ], "billingRecurrence": "ONE_TIME", "billingEnd": "2026-01-15", "discount": { "startDate": "2026-01-15", "endDate": "2026-01-15", "type": "PERCENTAGE" }, "priceOverwrite": 100000, "productNameOverwrite": "string", "quantity": 0, "amortizationTemplateId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "amortizationStartDate": "2026-01-15", "amortizationEndDate": "2026-01-15" }' ``` Full page: https://light.inc/docs/api-reference/v1--contracts/update-contract-line --- # Generate document upload URL > Generates a pre-signed URL to upload the main contract document (PDF). After uploading to this URL, the document will appear in the contract's document preview. `POST https://api.light.inc/v1/contracts/{contractId}/generate-document-upload-url` ## Note Only while the contract is DRAFT ( CONTRACT_CANNOT_BE_MODIFIED ). PUT the PDF to uploadUrl within five minutes with Content-Type: application/pdf and every entry of metadata as a request header (see Files (/docs/getting-started/pagination-filtering-errors files)). The file is attached asynchronously, and only if the contract is still editable at that moment; otherwise it is dropped. Nothing on this API shows the result: GET /v1/contracts/{contractId} has no document field, and the upload does not trigger any parsing or change any field. ## Authorization - API key - Bearer token See https://light.inc/docs/getting-started/authentication. ## Path parameters - `contractId` (string, uuid, required) ## Request body `application/json;charset=UTF-8` ```json { "filename": "string" } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders, and fields that exclude each other are all shown. Do not send it unchanged. ## Response ```json { "uploadUrl": "string", "key": "string", "metadata": null } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders. ## Code ```bash curl -X POST "https://api.light.inc/v1/contracts/3c90c3cc-0d44-4b50-8888-8dd25736052a/generate-document-upload-url" \ -H "Authorization: Basic YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "filename": "string" }' ``` Full page: https://light.inc/docs/api-reference/v1--contracts/generate-document-upload-url --- # Publish contract > Publishes a contract, transitioning it to ACTIVE state `POST https://api.light.inc/v1/contracts/{contractId}/publish` ## Note Required before publishing ( CONTRACT_DETAILS_MISSING_FIELD , CONTRACT_LINE_MISSING_FIELD , CONTRACT_MISSING_LINES ): netTerms , billingStart , companyEntityId , currency , customerId , invoiceTemplateId , paymentType , startDate , a bank account for bank transfer or direct debit, and at least one line with accountId , billingStart , quantity and a tax code for the engine in force. endDate is optional (open-ended contract). Each product needs a price in the contract currency unless priceOverwrite is set, the schedule must total above zero, and the contract may not run longer than 100 years. Publishing moves the contract to ACTIVE and immediately generates every invoice whose billing date has already passed, as DRAFT invoice receivables linked by contractId . From then on a daily job creates each next invoice seven days before its billing date, also as DRAFT , with postingDate on the planned invoice date and dueDate that many netTerms later. Nothing opens or sends them: open each with POST /v1/invoice-receivables/{invoiceReceivableId}/open . The same job terminates a contract whose endDate has passed without a renewalDate . Publishing an ACTIVE contract again with no changes fails with CONTRACT_CANNOT_BE_PUBLISHED . ## Authorization - API key - Bearer token See https://light.inc/docs/getting-started/authentication. ## Path parameters - `contractId` (string, uuid, required) ## Header parameters - `X-Idempotency-Key` (string) ## Response - `terminatedAt` — The termination **date** at 00:00 UTC, not the moment the termination was entered. - `state` — API-created contracts start in `DRAFT` and `reset` returns them there; `CREATED` only occurs for PDFs uploaded for parsing in the app. `PENDING_TERMINATION` is a scheduled termination; `TERMINATED` is terminal. - `lines` — `[]` on the list endpoint; populated only by `GET /v1/contracts/{contractId}`. - `lines.priceOverwrite` — The **line total** before discount, in the smallest denomination — not a unit price. It stands in for `quantity` × the product's price, and the unit price Light displays is this figure divided by `quantity`. `null` means the line is priced from the product. The model carries no computed amounts (no net, discount or tax figure), so a line's arithmetic is this field, `quantity` and `discount`. ```json { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "startDate": "2026-01-15", "endDate": "2026-01-15", "activatedAt": "2026-01-15T09:30:00Z", "terminatedAt": "2026-01-15T09:30:00Z", "terminationReason": "string", "terminationReasonType": "FINISHED", "renewalDate": "2026-01-15", "companyEntityId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "invoiceTemplateId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "currency": "USD", "estimatedAmount": 100000, "paymentType": "AIRWALLEX", "payeeBankAccountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "billingStart": "2026-01-15", "netTerms": 0, "invoiceLeadDays": 0, "description": "string", "customerId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "state": "CREATED", "areLinesWithTax": true, "lines": [ { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "contractId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "productId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "billingStart": "2026-01-15", "billingEnd": "2026-01-15", "billingRecurrence": "ONE_TIME", "accountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "taxCodeId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "avataxCode": "string", "discount": { "startDate": "2026-01-15", "endDate": "2026-01-15", "type": "PERCENTAGE" }, "quantity": 0, "priceOverwrite": 100000, "productNameOverwrite": "string", "amortizationTemplateId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "amortizationStartDate": "2026-01-15", "amortizationEndDate": "2026-01-15", "aiValueSuggestions": [ { "field": "string", "fieldValues": [ "string" ], "reasoning": "string" } ], "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupInternalName": "string", "values": [ {} ] } ], "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z" } ], "taxEngineName": "AVATAX", "externalId": "string", "externalSource": "HUBSPOT", "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupInternalName": "string", "values": [ { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupInternalName": "string", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "internalName": "string", "label": "string", "context": "string", "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z" } ] } ], "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z" } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders. ## Code ```bash curl -X POST "https://api.light.inc/v1/contracts/3c90c3cc-0d44-4b50-8888-8dd25736052a/publish" \ -H "Authorization: Basic YOUR_API_KEY" ``` Full page: https://light.inc/docs/api-reference/v1--contracts/publish-contract --- # Renew contract > Renews a contract by extending its end date `POST https://api.light.inc/v1/contracts/{contractId}/renew` ## Note Only from ACTIVE , and only for a contract that has an endDate ( CONTRACT_CANNOT_RENEW_WITH_NO_END_DATE ). nextEndDate must be on or after both the current endDate and today. It sets endDate , sets renewalDate to nextRenewalDate or clears it when omitted , and extends only the lines whose billingEnd equalled the old endDate ; lines ending earlier are left alone. The renewal re-runs every publish validation. ## Authorization - API key - Bearer token See https://light.inc/docs/getting-started/authentication. ## Path parameters - `contractId` (string, uuid, required) ## Header parameters - `X-Idempotency-Key` (string) ## Request body `application/json;charset=UTF-8` ```json { "nextEndDate": "2026-01-15", "nextRenewalDate": "2026-01-15" } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders, and fields that exclude each other are all shown. Do not send it unchanged. ## Response - `terminatedAt` — The termination **date** at 00:00 UTC, not the moment the termination was entered. - `state` — API-created contracts start in `DRAFT` and `reset` returns them there; `CREATED` only occurs for PDFs uploaded for parsing in the app. `PENDING_TERMINATION` is a scheduled termination; `TERMINATED` is terminal. - `lines` — `[]` on the list endpoint; populated only by `GET /v1/contracts/{contractId}`. - `lines.priceOverwrite` — The **line total** before discount, in the smallest denomination — not a unit price. It stands in for `quantity` × the product's price, and the unit price Light displays is this figure divided by `quantity`. `null` means the line is priced from the product. The model carries no computed amounts (no net, discount or tax figure), so a line's arithmetic is this field, `quantity` and `discount`. ```json { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "startDate": "2026-01-15", "endDate": "2026-01-15", "activatedAt": "2026-01-15T09:30:00Z", "terminatedAt": "2026-01-15T09:30:00Z", "terminationReason": "string", "terminationReasonType": "FINISHED", "renewalDate": "2026-01-15", "companyEntityId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "invoiceTemplateId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "currency": "USD", "estimatedAmount": 100000, "paymentType": "AIRWALLEX", "payeeBankAccountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "billingStart": "2026-01-15", "netTerms": 0, "invoiceLeadDays": 0, "description": "string", "customerId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "state": "CREATED", "areLinesWithTax": true, "lines": [ { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "contractId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "productId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "billingStart": "2026-01-15", "billingEnd": "2026-01-15", "billingRecurrence": "ONE_TIME", "accountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "taxCodeId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "avataxCode": "string", "discount": { "startDate": "2026-01-15", "endDate": "2026-01-15", "type": "PERCENTAGE" }, "quantity": 0, "priceOverwrite": 100000, "productNameOverwrite": "string", "amortizationTemplateId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "amortizationStartDate": "2026-01-15", "amortizationEndDate": "2026-01-15", "aiValueSuggestions": [ { "field": "string", "fieldValues": [ "string" ], "reasoning": "string" } ], "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupInternalName": "string", "values": [ {} ] } ], "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z" } ], "taxEngineName": "AVATAX", "externalId": "string", "externalSource": "HUBSPOT", "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupInternalName": "string", "values": [ { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupInternalName": "string", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "internalName": "string", "label": "string", "context": "string", "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z" } ] } ], "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z" } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders. ## Code ```bash curl -X POST "https://api.light.inc/v1/contracts/3c90c3cc-0d44-4b50-8888-8dd25736052a/renew" \ -H "Authorization: Basic YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "nextEndDate": "2026-01-15", "nextRenewalDate": "2026-01-15" }' ``` Full page: https://light.inc/docs/api-reference/v1--contracts/renew-contract --- # Reset contract > Resets a contract to CREATED state `POST https://api.light.inc/v1/contracts/{contractId}/reset` ## Note Returns the contract to DRAFT (the description says CREATED ), and only from ACTIVE . Side effects: every DRAFT invoice the schedule generated is archived, and every invoice, including opened ones, is unlinked from the contract ( contractId cleared); opened invoices are otherwise untouched. ## Authorization - API key - Bearer token See https://light.inc/docs/getting-started/authentication. ## Path parameters - `contractId` (string, uuid, required) ## Header parameters - `X-Idempotency-Key` (string) ## Response - `terminatedAt` — The termination **date** at 00:00 UTC, not the moment the termination was entered. - `state` — API-created contracts start in `DRAFT` and `reset` returns them there; `CREATED` only occurs for PDFs uploaded for parsing in the app. `PENDING_TERMINATION` is a scheduled termination; `TERMINATED` is terminal. - `lines` — `[]` on the list endpoint; populated only by `GET /v1/contracts/{contractId}`. - `lines.priceOverwrite` — The **line total** before discount, in the smallest denomination — not a unit price. It stands in for `quantity` × the product's price, and the unit price Light displays is this figure divided by `quantity`. `null` means the line is priced from the product. The model carries no computed amounts (no net, discount or tax figure), so a line's arithmetic is this field, `quantity` and `discount`. ```json { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "startDate": "2026-01-15", "endDate": "2026-01-15", "activatedAt": "2026-01-15T09:30:00Z", "terminatedAt": "2026-01-15T09:30:00Z", "terminationReason": "string", "terminationReasonType": "FINISHED", "renewalDate": "2026-01-15", "companyEntityId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "invoiceTemplateId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "currency": "USD", "estimatedAmount": 100000, "paymentType": "AIRWALLEX", "payeeBankAccountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "billingStart": "2026-01-15", "netTerms": 0, "invoiceLeadDays": 0, "description": "string", "customerId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "state": "CREATED", "areLinesWithTax": true, "lines": [ { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "contractId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "productId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "billingStart": "2026-01-15", "billingEnd": "2026-01-15", "billingRecurrence": "ONE_TIME", "accountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "taxCodeId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "avataxCode": "string", "discount": { "startDate": "2026-01-15", "endDate": "2026-01-15", "type": "PERCENTAGE" }, "quantity": 0, "priceOverwrite": 100000, "productNameOverwrite": "string", "amortizationTemplateId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "amortizationStartDate": "2026-01-15", "amortizationEndDate": "2026-01-15", "aiValueSuggestions": [ { "field": "string", "fieldValues": [ "string" ], "reasoning": "string" } ], "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupInternalName": "string", "values": [ {} ] } ], "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z" } ], "taxEngineName": "AVATAX", "externalId": "string", "externalSource": "HUBSPOT", "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupInternalName": "string", "values": [ { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupInternalName": "string", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "internalName": "string", "label": "string", "context": "string", "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z" } ] } ], "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z" } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders. ## Code ```bash curl -X POST "https://api.light.inc/v1/contracts/3c90c3cc-0d44-4b50-8888-8dd25736052a/reset" \ -H "Authorization: Basic YOUR_API_KEY" ``` Full page: https://light.inc/docs/api-reference/v1--contracts/reset-contract --- # Terminate contract > Terminates a contract `POST https://api.light.inc/v1/contracts/{contractId}/terminate` ## Note terminationDate defaults to today. On an ACTIVE contract a future date schedules the termination: state PENDING_TERMINATION , terminatedAt stays null , invoices keep being generated, and a daily job completes it on the date. A date up to today (or a DRAFT contract) terminates immediately, with terminatedAt set to that date at 00:00 UTC; back-dating is allowed down to startDate ( CONTRACT_TERMINATION_DATE_BEFORE_START_DATE ), and a scheduled date past endDate fails with CONTRACT_TERMINATION_DATE_AFTER_END_DATE . Calling it again while PENDING_TERMINATION fails with CONTRACT_INVALID_STATE_TRANSITION ; cancel the scheduled termination first. TERMINATED is terminal. ## Authorization - API key - Bearer token See https://light.inc/docs/getting-started/authentication. ## Path parameters - `contractId` (string, uuid, required) ## Header parameters - `X-Idempotency-Key` (string) ## Request body `application/json;charset=UTF-8` ```json { "terminationDate": "2026-01-15", "terminationReason": "string", "terminationReasonType": "FINISHED" } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders, and fields that exclude each other are all shown. Do not send it unchanged. ## Response - `terminatedAt` — The termination **date** at 00:00 UTC, not the moment the termination was entered. - `state` — API-created contracts start in `DRAFT` and `reset` returns them there; `CREATED` only occurs for PDFs uploaded for parsing in the app. `PENDING_TERMINATION` is a scheduled termination; `TERMINATED` is terminal. - `lines` — `[]` on the list endpoint; populated only by `GET /v1/contracts/{contractId}`. - `lines.priceOverwrite` — The **line total** before discount, in the smallest denomination — not a unit price. It stands in for `quantity` × the product's price, and the unit price Light displays is this figure divided by `quantity`. `null` means the line is priced from the product. The model carries no computed amounts (no net, discount or tax figure), so a line's arithmetic is this field, `quantity` and `discount`. ```json { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "startDate": "2026-01-15", "endDate": "2026-01-15", "activatedAt": "2026-01-15T09:30:00Z", "terminatedAt": "2026-01-15T09:30:00Z", "terminationReason": "string", "terminationReasonType": "FINISHED", "renewalDate": "2026-01-15", "companyEntityId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "invoiceTemplateId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "currency": "USD", "estimatedAmount": 100000, "paymentType": "AIRWALLEX", "payeeBankAccountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "billingStart": "2026-01-15", "netTerms": 0, "invoiceLeadDays": 0, "description": "string", "customerId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "state": "CREATED", "areLinesWithTax": true, "lines": [ { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "contractId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "productId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "billingStart": "2026-01-15", "billingEnd": "2026-01-15", "billingRecurrence": "ONE_TIME", "accountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "taxCodeId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "avataxCode": "string", "discount": { "startDate": "2026-01-15", "endDate": "2026-01-15", "type": "PERCENTAGE" }, "quantity": 0, "priceOverwrite": 100000, "productNameOverwrite": "string", "amortizationTemplateId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "amortizationStartDate": "2026-01-15", "amortizationEndDate": "2026-01-15", "aiValueSuggestions": [ { "field": "string", "fieldValues": [ "string" ], "reasoning": "string" } ], "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupInternalName": "string", "values": [ {} ] } ], "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z" } ], "taxEngineName": "AVATAX", "externalId": "string", "externalSource": "HUBSPOT", "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupInternalName": "string", "values": [ { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupInternalName": "string", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "internalName": "string", "label": "string", "context": "string", "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z" } ] } ], "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z" } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders. ## Code ```bash curl -X POST "https://api.light.inc/v1/contracts/3c90c3cc-0d44-4b50-8888-8dd25736052a/terminate" \ -H "Authorization: Basic YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "terminationDate": "2026-01-15", "terminationReason": "string", "terminationReasonType": "FINISHED" }' ``` Full page: https://light.inc/docs/api-reference/v1--contracts/terminate-contract --- # Credit Notes (resource) Create and list credit notes, and link them to invoice payables. Resource page: https://light.inc/docs/api-reference/v1--credit-notes # Archive credit note > Archives the credit note. If the credit note has been posted, it will be reversed in the ledger. A credit note with active links to invoice payables cannot be archived — unlink first. `POST https://api.light.inc/v1/credit-notes/{creditNoteId}/archive` ## Note A posted credit note is reversed in the ledger and ends in ARCHIVED , not back in DRAFT , and there is no unarchive. A POSTED note with links fails with CREDIT_NOTE_CANNOT_BE_ARCHIVED_WHEN_LINKED : unlink it first, which also reverses any clearing. ## Authorization - API key - Bearer token See https://light.inc/docs/getting-started/authentication. ## Path parameters - `creditNoteId` (string, uuid, required) ## Response - `lines.grossTransactionAmount.amount` — Unsigned integer in minor units. The direction is in `dcSign`; a negative value is rejected. - `lines.netTransactionAmount.amount` — Unsigned integer in minor units. The direction is in `dcSign`; a negative value is rejected. - `lines.taxTransactionAmount.amount` — Unsigned integer in minor units. The direction is in `dcSign`; a negative value is rejected. - `localCurrencyFxRate` — Echoes the override you sent; `null` when Light applies its own rate, not the rate that was applied. - `groupCurrencyFxRate` — Echoes the override you sent; `null` when Light applies its own rate, not the rate that was applied. ```json { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyEntityId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "amount": 100000, "businessPartnerName": "string", "businessPartnerId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "status": "DRAFT", "description": "string", "currency": "USD", "postingDate": "2026-01-15", "documentDate": "2026-01-15", "valuationDate": "2026-01-15", "areLinesWithTax": true, "lines": [ { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "creditNoteId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "grossTransactionAmount": { "amount": 100000, "dcSign": "D" }, "netTransactionAmount": { "amount": 100000, "dcSign": "D" }, "description": "string", "ledgerTaxId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "taxTransactionAmount": { "amount": 100000, "dcSign": "D" }, "ledgerAccountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "costCenterId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z", "accrualTemplateId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "accrualStartDate": "2026-01-15", "accrualEndDate": "2026-01-15", "accrualDefaultDuration": 0 } ], "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z", "updatedBy": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "localCurrencyFxRate": 0, "groupCurrencyFxRate": 0, "senderEmail": "string", "documentName": "string" } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders. ## Code ```bash curl -X POST "https://api.light.inc/v1/credit-notes/3c90c3cc-0d44-4b50-8888-8dd25736052a/archive" \ -H "Authorization: Basic YOUR_API_KEY" ``` Full page: https://light.inc/docs/api-reference/v1--credit-notes/archive-credit-note --- # List credit notes > Returns a paginated list of credit notes `GET https://api.light.inc/v1/credit-notes` ## Note The accounting documents list restricted to CN : same filters and sorts, default order newest first, drafts and archived notes included unless filtered. ## Authorization - API key - Bearer token See https://light.inc/docs/getting-started/authentication. ## Query parameters - `sort` (string) — Sort string in the format field:direction . To provide multiple sort fields, separate them with commas. Available directions: asc , desc . Available fields: amount , businessPartnerName , status , documentDate . - `filter` (string) — Filter string in the format field:operator:value . To provide multiple filters, separate them with commas. Available operators: eq , ne , in , not_in , gt , gte , lt , lte . - For in and not_in operators, provide multiple values separated by the pipe character ( ). Available fields: businessPartnerId , status , companyEntityId , documentDate , toBeAdjustedAccDocType , updatedAt . - `limit` (integer, int32) — Maximum number of items to return. Default is 50, maximum is 200. - `offset` (integer, int64) — Number of items to skip before starting to collect the result set. Deprecated, use 'cursor' instead. - `cursor` (string) — The cursor position to start returning results from. To opt-in into cursor-based pagination, provide 0 for the initial request. For subsequent requests, use nextCursor and prevCursor from the previous response to navigate. Cursor values are opaque and should not be constructed manually. ## Response - `records.lines.grossTransactionAmount.amount` — Unsigned integer in minor units. The direction is in `dcSign`; a negative value is rejected. - `records.lines.netTransactionAmount.amount` — Unsigned integer in minor units. The direction is in `dcSign`; a negative value is rejected. - `records.lines.taxTransactionAmount.amount` — Unsigned integer in minor units. The direction is in `dcSign`; a negative value is rejected. - `records.localCurrencyFxRate` — Echoes the override you sent; `null` when Light applies its own rate, not the rate that was applied. - `records.groupCurrencyFxRate` — Echoes the override you sent; `null` when Light applies its own rate, not the rate that was applied. ```json { "records": [ { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyEntityId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "amount": 100000, "businessPartnerName": "string", "businessPartnerId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "status": "DRAFT", "description": "string", "currency": "USD", "postingDate": "2026-01-15", "documentDate": "2026-01-15", "valuationDate": "2026-01-15", "areLinesWithTax": true, "lines": [ { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "creditNoteId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "grossTransactionAmount": { "amount": 100000, "dcSign": "D" }, "netTransactionAmount": { "amount": 100000, "dcSign": "D" }, "description": "string", "ledgerTaxId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "taxTransactionAmount": { "amount": 100000, "dcSign": "D" }, "ledgerAccountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "costCenterId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z", "accrualTemplateId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "accrualStartDate": "2026-01-15", "accrualEndDate": "2026-01-15", "accrualDefaultDuration": 0 } ], "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z", "updatedBy": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "localCurrencyFxRate": 0, "groupCurrencyFxRate": 0, "senderEmail": "string", "documentName": "string" } ], "hasMore": true, "total": 100000, "nextCursor": "string", "prevCursor": "string" } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders. ## Code ```bash curl -X GET "https://api.light.inc/v1/credit-notes" \ -H "Authorization: Basic YOUR_API_KEY" ``` Full page: https://light.inc/docs/api-reference/v1--credit-notes/list-credit-notes --- # Create credit note > Creates a new credit note in draft status. The credit note can be created with or without line items. When documentNumber is provided, it is used for idempotency — retrying a create with the same documentNumber returns the existing credit note instead of creating a duplicate. The areLinesWithTax field controls whether line amounts include tax (true = gross, tax included) or exclude tax (false = net, tax added on top). A businessPartnerId (vendor) is required if the credit note will be linked to an invoice payable later. The posting date is automatically set to the documentDate . `POST https://api.light.inc/v1/credit-notes` ## Note Created in DRAFT . documentDate is also the posting date; areLinesWithTax defaults to true . Line amounts are { amount, dcSign } objects and a credit note's lines are credits ( "dcSign": "C" ): at post the total must be a credit ( CREDIT_NOTE_NEGATIVE_TOTAL_AMOUNT ). Idempotency: an X-Idempotency-Key header wins; without one the key is derived from documentNumber , so re-sending the same number with a different body is 409 IDEMPOTENCY_VIOLATION . A credit note created here has no PDF , so GET .../document redirects to a file that doesn't exist. Requires a user credential. ## Authorization - API key - Bearer token See https://light.inc/docs/getting-started/authentication. ## Header parameters - `X-Idempotency-Key` (string) ## Request body `application/json;charset=UTF-8` - `customProperties.valueIds` — Catalogue value ids for this group. Required; send `[]` (with an empty `inlineValues`) to clear the group. `SINGLE_SELECT` and `MULTI_SELECT` groups accept nothing else. See [Custom properties on writes](/docs/getting-started/pagination-filtering-errors#custom-properties-on-writes). - `customProperties.inlineValues` — Literal values for `TEXT`, `NUMERIC`, `BOOLEAN` and `DATE` groups, as strings (`yyyy-MM-dd` for dates). Rejected on select groups with `CUSTOM_PROPERTY_VALUE_TYPE_MISMATCH`. See [Custom properties on writes](/docs/getting-started/pagination-filtering-errors#custom-properties-on-writes). - `lines.netTransactionAmount.amount` — Unsigned integer in minor units. The direction is in `dcSign`; a negative value is rejected. - `lines.grossTransactionAmount.amount` — Unsigned integer in minor units. The direction is in `dcSign`; a negative value is rejected. - `lines.taxTransactionAmount.amount` — Unsigned integer in minor units. The direction is in `dcSign`; a negative value is rejected. - `lines.customProperties.valueIds` — Catalogue value ids for this group. Required; send `[]` (with an empty `inlineValues`) to clear the group. `SINGLE_SELECT` and `MULTI_SELECT` groups accept nothing else. See [Custom properties on writes](/docs/getting-started/pagination-filtering-errors#custom-properties-on-writes). - `lines.customProperties.inlineValues` — Literal values for `TEXT`, `NUMERIC`, `BOOLEAN` and `DATE` groups, as strings (`yyyy-MM-dd` for dates). Rejected on select groups with `CUSTOM_PROPERTY_VALUE_TYPE_MISMATCH`. See [Custom properties on writes](/docs/getting-started/pagination-filtering-errors#custom-properties-on-writes). ```json { "companyEntityId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "currency": "USD", "documentDate": "2026-01-15", "businessPartnerId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "description": "string", "amount": 100000, "areLinesWithTax": true, "documentNumber": "string", "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "valueIds": [ "3c90c3cc-0d44-4b50-8888-8dd25736052a" ], "inlineValues": [ "string" ] } ], "lines": [ { "netTransactionAmount": { "amount": 100000, "dcSign": "D" }, "grossTransactionAmount": { "amount": 100000, "dcSign": "D" }, "taxTransactionAmount": { "amount": 100000, "dcSign": "D" }, "description": "string", "ledgerTaxId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "ledgerAccountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "valueIds": [ "3c90c3cc-0d44-4b50-8888-8dd25736052a" ], "inlineValues": [ "string" ] } ], "accrualTemplateId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "accrualStartDate": "2026-01-15", "accrualEndDate": "2026-01-15" } ], "localCurrencyFxRateOverride": 0, "groupCurrencyFxRateOverride": 0 } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders, and fields that exclude each other are all shown. Do not send it unchanged. ## Response - `lines.grossTransactionAmount.amount` — Unsigned integer in minor units. The direction is in `dcSign`; a negative value is rejected. - `lines.netTransactionAmount.amount` — Unsigned integer in minor units. The direction is in `dcSign`; a negative value is rejected. - `lines.taxTransactionAmount.amount` — Unsigned integer in minor units. The direction is in `dcSign`; a negative value is rejected. - `localCurrencyFxRate` — Echoes the override you sent; `null` when Light applies its own rate, not the rate that was applied. - `groupCurrencyFxRate` — Echoes the override you sent; `null` when Light applies its own rate, not the rate that was applied. ```json { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyEntityId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "amount": 100000, "businessPartnerName": "string", "businessPartnerId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "status": "DRAFT", "description": "string", "currency": "USD", "postingDate": "2026-01-15", "documentDate": "2026-01-15", "valuationDate": "2026-01-15", "areLinesWithTax": true, "lines": [ { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "creditNoteId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "grossTransactionAmount": { "amount": 100000, "dcSign": "D" }, "netTransactionAmount": { "amount": 100000, "dcSign": "D" }, "description": "string", "ledgerTaxId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "taxTransactionAmount": { "amount": 100000, "dcSign": "D" }, "ledgerAccountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "costCenterId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z", "accrualTemplateId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "accrualStartDate": "2026-01-15", "accrualEndDate": "2026-01-15", "accrualDefaultDuration": 0 } ], "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z", "updatedBy": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "localCurrencyFxRate": 0, "groupCurrencyFxRate": 0, "senderEmail": "string", "documentName": "string" } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders. ## Code ```bash curl -X POST "https://api.light.inc/v1/credit-notes" \ -H "Authorization: Basic YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "companyEntityId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "currency": "USD", "documentDate": "2026-01-15", "businessPartnerId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "description": "string", "amount": 100000, "areLinesWithTax": true, "documentNumber": "string", "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "valueIds": [ "3c90c3cc-0d44-4b50-8888-8dd25736052a" ], "inlineValues": [ "string" ] } ], "lines": [ { "netTransactionAmount": { "amount": 100000, "dcSign": "D" }, "grossTransactionAmount": { "amount": 100000, "dcSign": "D" }, "taxTransactionAmount": { "amount": 100000, "dcSign": "D" }, "description": "string", "ledgerTaxId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "ledgerAccountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "valueIds": [ "3c90c3cc-0d44-4b50-8888-8dd25736052a" ], "inlineValues": [ "string" ] } ], "accrualTemplateId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "accrualStartDate": "2026-01-15", "accrualEndDate": "2026-01-15" } ], "localCurrencyFxRateOverride": 0, "groupCurrencyFxRateOverride": 0 }' ``` Full page: https://light.inc/docs/api-reference/v1--credit-notes/create-credit-note --- # Create credit note line > Creates a new line item on a credit note in draft status. `POST https://api.light.inc/v1/credit-notes/{creditNoteId}/lines` ## Note Only while the credit note is DRAFT ( CREDIT_NOTE_CANNOT_BE_MODIFIED ). Amounts are { amount, dcSign } objects, normally credits ( C ). costCenterId cannot be set through the API. ## Authorization - API key - Bearer token See https://light.inc/docs/getting-started/authentication. ## Path parameters - `creditNoteId` (string, uuid, required) ## Request body `application/json;charset=UTF-8` - `netTransactionAmount.amount` — Unsigned integer in minor units. The direction is in `dcSign`; a negative value is rejected. - `grossTransactionAmount.amount` — Unsigned integer in minor units. The direction is in `dcSign`; a negative value is rejected. - `taxTransactionAmount.amount` — Unsigned integer in minor units. The direction is in `dcSign`; a negative value is rejected. - `customProperties.valueIds` — Catalogue value ids for this group. Required; send `[]` (with an empty `inlineValues`) to clear the group. `SINGLE_SELECT` and `MULTI_SELECT` groups accept nothing else. See [Custom properties on writes](/docs/getting-started/pagination-filtering-errors#custom-properties-on-writes). - `customProperties.inlineValues` — Literal values for `TEXT`, `NUMERIC`, `BOOLEAN` and `DATE` groups, as strings (`yyyy-MM-dd` for dates). Rejected on select groups with `CUSTOM_PROPERTY_VALUE_TYPE_MISMATCH`. See [Custom properties on writes](/docs/getting-started/pagination-filtering-errors#custom-properties-on-writes). ```json { "netTransactionAmount": { "amount": 100000, "dcSign": "D" }, "grossTransactionAmount": { "amount": 100000, "dcSign": "D" }, "taxTransactionAmount": { "amount": 100000, "dcSign": "D" }, "description": "string", "ledgerTaxId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "ledgerAccountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "valueIds": [ "3c90c3cc-0d44-4b50-8888-8dd25736052a" ], "inlineValues": [ "string" ] } ], "accrualTemplateId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "accrualStartDate": "2026-01-15", "accrualEndDate": "2026-01-15" } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders, and fields that exclude each other are all shown. Do not send it unchanged. ## Response - `grossTransactionAmount.amount` — Unsigned integer in minor units. The direction is in `dcSign`; a negative value is rejected. - `netTransactionAmount.amount` — Unsigned integer in minor units. The direction is in `dcSign`; a negative value is rejected. - `taxTransactionAmount.amount` — Unsigned integer in minor units. The direction is in `dcSign`; a negative value is rejected. ```json { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "creditNoteId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "grossTransactionAmount": { "amount": 100000, "dcSign": "D" }, "netTransactionAmount": { "amount": 100000, "dcSign": "D" }, "description": "string", "ledgerTaxId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "taxTransactionAmount": { "amount": 100000, "dcSign": "D" }, "ledgerAccountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "costCenterId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z", "accrualTemplateId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "accrualStartDate": "2026-01-15", "accrualEndDate": "2026-01-15", "accrualDefaultDuration": 0 } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders. ## Code ```bash curl -X POST "https://api.light.inc/v1/credit-notes/3c90c3cc-0d44-4b50-8888-8dd25736052a/lines" \ -H "Authorization: Basic YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "netTransactionAmount": { "amount": 100000, "dcSign": "D" }, "grossTransactionAmount": { "amount": 100000, "dcSign": "D" }, "taxTransactionAmount": { "amount": 100000, "dcSign": "D" }, "description": "string", "ledgerTaxId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "ledgerAccountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "valueIds": [ "3c90c3cc-0d44-4b50-8888-8dd25736052a" ], "inlineValues": [ "string" ] } ], "accrualTemplateId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "accrualStartDate": "2026-01-15", "accrualEndDate": "2026-01-15" }' ``` Full page: https://light.inc/docs/api-reference/v1--credit-notes/create-credit-note-line --- # Create credit note from invoice payable > Creates a credit note from an existing invoice payable `POST https://api.light.inc/v1/credit-notes/create-from-invoice-payable/{invoicePayableId}` ## Note Destructive : the invoice payable is deleted (a later GET on it is 404 ) and replaced by a DRAFT credit note that copies its entity, vendor, currency, dates, FX overrides, document and lines, with documentNumber set to the invoice number and every amount made positive. The bill must be a vendor or self-billed invoice in IN_DRAFT , have an uploaded document, and have no credit notes linked ( INVALID_INVOICE_PAYABLE_FOR_CREDIT_NOTE ). ## Authorization - API key - Bearer token See https://light.inc/docs/getting-started/authentication. ## Path parameters - `invoicePayableId` (string, uuid, required) ## Response - `lines.grossTransactionAmount.amount` — Unsigned integer in minor units. The direction is in `dcSign`; a negative value is rejected. - `lines.netTransactionAmount.amount` — Unsigned integer in minor units. The direction is in `dcSign`; a negative value is rejected. - `lines.taxTransactionAmount.amount` — Unsigned integer in minor units. The direction is in `dcSign`; a negative value is rejected. - `localCurrencyFxRate` — Echoes the override you sent; `null` when Light applies its own rate, not the rate that was applied. - `groupCurrencyFxRate` — Echoes the override you sent; `null` when Light applies its own rate, not the rate that was applied. ```json { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyEntityId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "amount": 100000, "businessPartnerName": "string", "businessPartnerId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "status": "DRAFT", "description": "string", "currency": "USD", "postingDate": "2026-01-15", "documentDate": "2026-01-15", "valuationDate": "2026-01-15", "areLinesWithTax": true, "lines": [ { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "creditNoteId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "grossTransactionAmount": { "amount": 100000, "dcSign": "D" }, "netTransactionAmount": { "amount": 100000, "dcSign": "D" }, "description": "string", "ledgerTaxId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "taxTransactionAmount": { "amount": 100000, "dcSign": "D" }, "ledgerAccountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "costCenterId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z", "accrualTemplateId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "accrualStartDate": "2026-01-15", "accrualEndDate": "2026-01-15", "accrualDefaultDuration": 0 } ], "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z", "updatedBy": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "localCurrencyFxRate": 0, "groupCurrencyFxRate": 0, "senderEmail": "string", "documentName": "string" } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders. ## Code ```bash curl -X POST "https://api.light.inc/v1/credit-notes/create-from-invoice-payable/3c90c3cc-0d44-4b50-8888-8dd25736052a" \ -H "Authorization: Basic YOUR_API_KEY" ``` Full page: https://light.inc/docs/api-reference/v1--credit-notes/create-credit-note-from-invoice-payable --- # Delete credit note line > Deletes a line item from a credit note in draft status. `DELETE https://api.light.inc/v1/credit-notes/{creditNoteId}/lines/{lineId}` ## Note Only while the credit note is DRAFT ( CREDIT_NOTE_CANNOT_BE_MODIFIED ). Answers 204 with no body. ## Authorization - API key - Bearer token See https://light.inc/docs/getting-started/authentication. ## Path parameters - `creditNoteId` (string, uuid, required) - `lineId` (string, uuid, required) ## Response This endpoint returns no content. ## Code ```bash curl -X DELETE "https://api.light.inc/v1/credit-notes/3c90c3cc-0d44-4b50-8888-8dd25736052a/lines/3c90c3cc-0d44-4b50-8888-8dd25736052a" \ -H "Authorization: Basic YOUR_API_KEY" ``` Full page: https://light.inc/docs/api-reference/v1--credit-notes/delete-credit-note-line --- # Update credit note line > Updates a line item on a credit note in draft status. Fields sent as null clear the value; omitted fields remain unchanged. `PATCH https://api.light.inc/v1/credit-notes/{creditNoteId}/lines/{lineId}` ## Note Only while the credit note is DRAFT ( CREDIT_NOTE_CANNOT_BE_MODIFIED ). null clears every field except customProperties , which null leaves unchanged. ## Authorization - API key - Bearer token See https://light.inc/docs/getting-started/authentication. ## Path parameters - `creditNoteId` (string, uuid, required) - `lineId` (string, uuid, required) ## Request body `application/json;charset=UTF-8` - `customProperties.valueIds` — Catalogue value ids for this group. Required; send `[]` (with an empty `inlineValues`) to clear the group. `SINGLE_SELECT` and `MULTI_SELECT` groups accept nothing else. See [Custom properties on writes](/docs/getting-started/pagination-filtering-errors#custom-properties-on-writes). - `customProperties.inlineValues` — Literal values for `TEXT`, `NUMERIC`, `BOOLEAN` and `DATE` groups, as strings (`yyyy-MM-dd` for dates). Rejected on select groups with `CUSTOM_PROPERTY_VALUE_TYPE_MISMATCH`. See [Custom properties on writes](/docs/getting-started/pagination-filtering-errors#custom-properties-on-writes). - `netTransactionAmount.amount` — Unsigned integer in minor units. The direction is in `dcSign`; a negative value is rejected. - `grossTransactionAmount.amount` — Unsigned integer in minor units. The direction is in `dcSign`; a negative value is rejected. - `taxTransactionAmount.amount` — Unsigned integer in minor units. The direction is in `dcSign`; a negative value is rejected. ```json { "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "valueIds": [ "3c90c3cc-0d44-4b50-8888-8dd25736052a" ], "inlineValues": [ "string" ] } ], "netTransactionAmount": { "amount": 100000, "dcSign": "D" }, "grossTransactionAmount": { "amount": 100000, "dcSign": "D" }, "taxTransactionAmount": { "amount": 100000, "dcSign": "D" }, "description": "string", "ledgerTaxId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "ledgerAccountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "accrualTemplateId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "accrualStartDate": "2026-01-15", "accrualEndDate": "2026-01-15" } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders, and fields that exclude each other are all shown. Do not send it unchanged. ## Response - `grossTransactionAmount.amount` — Unsigned integer in minor units. The direction is in `dcSign`; a negative value is rejected. - `netTransactionAmount.amount` — Unsigned integer in minor units. The direction is in `dcSign`; a negative value is rejected. - `taxTransactionAmount.amount` — Unsigned integer in minor units. The direction is in `dcSign`; a negative value is rejected. ```json { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "creditNoteId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "grossTransactionAmount": { "amount": 100000, "dcSign": "D" }, "netTransactionAmount": { "amount": 100000, "dcSign": "D" }, "description": "string", "ledgerTaxId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "taxTransactionAmount": { "amount": 100000, "dcSign": "D" }, "ledgerAccountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "costCenterId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z", "accrualTemplateId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "accrualStartDate": "2026-01-15", "accrualEndDate": "2026-01-15", "accrualDefaultDuration": 0 } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders. ## Code ```bash curl -X PATCH "https://api.light.inc/v1/credit-notes/3c90c3cc-0d44-4b50-8888-8dd25736052a/lines/3c90c3cc-0d44-4b50-8888-8dd25736052a" \ -H "Authorization: Basic YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "valueIds": [ "3c90c3cc-0d44-4b50-8888-8dd25736052a" ], "inlineValues": [ "string" ] } ], "netTransactionAmount": { "amount": 100000, "dcSign": "D" }, "grossTransactionAmount": { "amount": 100000, "dcSign": "D" }, "taxTransactionAmount": { "amount": 100000, "dcSign": "D" }, "description": "string", "ledgerTaxId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "ledgerAccountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "accrualTemplateId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "accrualStartDate": "2026-01-15", "accrualEndDate": "2026-01-15" }' ``` Full page: https://light.inc/docs/api-reference/v1--credit-notes/update-credit-note-line --- # Get credit note > Returns a credit note by ID `GET https://api.light.inc/v1/credit-notes/{creditNoteId}` ## Note Includes lines. An unknown id, or one from another company, is 404 . ## Authorization - API key - Bearer token See https://light.inc/docs/getting-started/authentication. ## Path parameters - `creditNoteId` (string, uuid, required) ## Response - `lines.grossTransactionAmount.amount` — Unsigned integer in minor units. The direction is in `dcSign`; a negative value is rejected. - `lines.netTransactionAmount.amount` — Unsigned integer in minor units. The direction is in `dcSign`; a negative value is rejected. - `lines.taxTransactionAmount.amount` — Unsigned integer in minor units. The direction is in `dcSign`; a negative value is rejected. - `localCurrencyFxRate` — Echoes the override you sent; `null` when Light applies its own rate, not the rate that was applied. - `groupCurrencyFxRate` — Echoes the override you sent; `null` when Light applies its own rate, not the rate that was applied. ```json { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyEntityId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "amount": 100000, "businessPartnerName": "string", "businessPartnerId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "status": "DRAFT", "description": "string", "currency": "USD", "postingDate": "2026-01-15", "documentDate": "2026-01-15", "valuationDate": "2026-01-15", "areLinesWithTax": true, "lines": [ { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "creditNoteId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "grossTransactionAmount": { "amount": 100000, "dcSign": "D" }, "netTransactionAmount": { "amount": 100000, "dcSign": "D" }, "description": "string", "ledgerTaxId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "taxTransactionAmount": { "amount": 100000, "dcSign": "D" }, "ledgerAccountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "costCenterId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z", "accrualTemplateId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "accrualStartDate": "2026-01-15", "accrualEndDate": "2026-01-15", "accrualDefaultDuration": 0 } ], "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z", "updatedBy": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "localCurrencyFxRate": 0, "groupCurrencyFxRate": 0, "senderEmail": "string", "documentName": "string" } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders. ## Code ```bash curl -X GET "https://api.light.inc/v1/credit-notes/3c90c3cc-0d44-4b50-8888-8dd25736052a" \ -H "Authorization: Basic YOUR_API_KEY" ``` Full page: https://light.inc/docs/api-reference/v1--credit-notes/get-credit-note --- # Update credit note > Updates a credit note in draft status. Fields sent as null clear the value; omitted fields remain unchanged. `PATCH https://api.light.inc/v1/credit-notes/{creditNoteId}` ## Note Only in DRAFT ( CREDIT_NOTE_CANNOT_BE_MODIFIED ). The null rule in the description holds for description , currency , amount , documentNumber and the FX overrides only; companyEntityId , businessPartnerId , documentDate , areLinesWithTax and customProperties cannot be cleared — null leaves them unchanged. Changing businessPartnerId silently clears companyEntityId when the entity isn't one the new vendor is enabled for. documentDate also rewrites the posting date. ## Authorization - API key - Bearer token See https://light.inc/docs/getting-started/authentication. ## Path parameters - `creditNoteId` (string, uuid, required) ## Request body `application/json;charset=UTF-8` - `companyEntityId` — Cannot be cleared: `null` leaves it unchanged, contrary to the endpoint description. - `businessPartnerId` — Cannot be cleared: `null` leaves it unchanged. Changing it clears `companyEntityId` when that entity isn't enabled for the new vendor. - `documentDate` — Cannot be cleared, and also rewrites the posting date. - `customProperties.valueIds` — Catalogue value ids for this group. Required; send `[]` (with an empty `inlineValues`) to clear the group. `SINGLE_SELECT` and `MULTI_SELECT` groups accept nothing else. See [Custom properties on writes](/docs/getting-started/pagination-filtering-errors#custom-properties-on-writes). - `customProperties.inlineValues` — Literal values for `TEXT`, `NUMERIC`, `BOOLEAN` and `DATE` groups, as strings (`yyyy-MM-dd` for dates). Rejected on select groups with `CUSTOM_PROPERTY_VALUE_TYPE_MISMATCH`. See [Custom properties on writes](/docs/getting-started/pagination-filtering-errors#custom-properties-on-writes). ```json { "companyEntityId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "businessPartnerId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "documentDate": "2026-01-15", "areLinesWithTax": true, "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "valueIds": [ "3c90c3cc-0d44-4b50-8888-8dd25736052a" ], "inlineValues": [ "string" ] } ], "description": "string", "currency": "USD", "amount": 100000, "documentNumber": "string", "localCurrencyFxRateOverride": 0, "groupCurrencyFxRateOverride": 0 } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders, and fields that exclude each other are all shown. Do not send it unchanged. ## Response - `lines.grossTransactionAmount.amount` — Unsigned integer in minor units. The direction is in `dcSign`; a negative value is rejected. - `lines.netTransactionAmount.amount` — Unsigned integer in minor units. The direction is in `dcSign`; a negative value is rejected. - `lines.taxTransactionAmount.amount` — Unsigned integer in minor units. The direction is in `dcSign`; a negative value is rejected. - `localCurrencyFxRate` — Echoes the override you sent; `null` when Light applies its own rate, not the rate that was applied. - `groupCurrencyFxRate` — Echoes the override you sent; `null` when Light applies its own rate, not the rate that was applied. ```json { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyEntityId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "amount": 100000, "businessPartnerName": "string", "businessPartnerId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "status": "DRAFT", "description": "string", "currency": "USD", "postingDate": "2026-01-15", "documentDate": "2026-01-15", "valuationDate": "2026-01-15", "areLinesWithTax": true, "lines": [ { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "creditNoteId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "grossTransactionAmount": { "amount": 100000, "dcSign": "D" }, "netTransactionAmount": { "amount": 100000, "dcSign": "D" }, "description": "string", "ledgerTaxId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "taxTransactionAmount": { "amount": 100000, "dcSign": "D" }, "ledgerAccountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "costCenterId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z", "accrualTemplateId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "accrualStartDate": "2026-01-15", "accrualEndDate": "2026-01-15", "accrualDefaultDuration": 0 } ], "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z", "updatedBy": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "localCurrencyFxRate": 0, "groupCurrencyFxRate": 0, "senderEmail": "string", "documentName": "string" } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders. ## Code ```bash curl -X PATCH "https://api.light.inc/v1/credit-notes/3c90c3cc-0d44-4b50-8888-8dd25736052a" \ -H "Authorization: Basic YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "companyEntityId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "businessPartnerId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "documentDate": "2026-01-15", "areLinesWithTax": true, "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "valueIds": [ "3c90c3cc-0d44-4b50-8888-8dd25736052a" ], "inlineValues": [ "string" ] } ], "description": "string", "currency": "USD", "amount": 100000, "documentNumber": "string", "localCurrencyFxRateOverride": 0, "groupCurrencyFxRateOverride": 0 }' ``` Full page: https://light.inc/docs/api-reference/v1--credit-notes/update-credit-note --- # Get credit note document > Returns the attached PDF document for a credit note `GET https://api.light.inc/v1/credit-notes/{creditNoteId}/document` ## Note Answers 307 Temporary Redirect to a pre-signed URL, not the file. A credit note created through this API has no PDF behind that URL; only notes created from an uploaded document have one. ## Authorization - API key - Bearer token See https://light.inc/docs/getting-started/authentication. ## Path parameters - `creditNoteId` (string, uuid, required) ## Response Returns a file (application/pdf) rather than JSON. ## Code ```bash curl -X GET "https://api.light.inc/v1/credit-notes/3c90c3cc-0d44-4b50-8888-8dd25736052a/document" \ -H "Authorization: Basic YOUR_API_KEY" ``` Full page: https://light.inc/docs/api-reference/v1--credit-notes/get-credit-note-document --- # Get linked invoice payables > Returns all invoice payables linked to the credit note `GET https://api.light.inc/v1/credit-notes/{creditNoteId}/invoice-payables` ## Note Not paginated: every bill the credit note is linked to, in one list. ## Authorization - API key - Bearer token See https://light.inc/docs/getting-started/authentication. ## Path parameters - `creditNoteId` (string, uuid, required) ## Response ```json [ { "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "creditNote": { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "documentNumber": "string", "documentDate": "2026-01-15", "status": "DRAFT", "amount": 100000, "currency": "USD" }, "invoicePayable": { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "documentNumber": "string", "documentDate": "2026-01-15", "status": "DRAFT", "amount": 100000, "currency": "USD" }, "amount": 100000, "currency": "USD", "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z" } ] ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders. ## Code ```bash curl -X GET "https://api.light.inc/v1/credit-notes/3c90c3cc-0d44-4b50-8888-8dd25736052a/invoice-payables" \ -H "Authorization: Basic YOUR_API_KEY" ``` Full page: https://light.inc/docs/api-reference/v1--credit-notes/get-linked-invoice-payables --- # Link credit note to invoice payable > Links a credit note to an invoice payable for clearing (offsetting balances). Because credit notes cannot be applied in the ledger until the invoice payable is posted, this creates a 'link' record that will be used during posting to automatically clear the credit note balance against the invoice payable balance. Requirements: credit note must be in POSTED status, both documents must belong to the same company entity, same vendor (businessPartnerId), same currency, and clearing amount cannot exceed available balance on either document. `POST https://api.light.inc/v1/credit-notes/{creditNoteId}/invoice-payables/{invoicePayableId}` ## Note The credit note must be POSTED (or PARTIALLY_CLEARED ); a draft fails with CREDIT_NOTE_CANNOT_BE_LINKED_UPDATED_UNLINKED . What the link does depends on the bill's state. A bill in IN_DRAFT or APPROVAL_PENDING only records the link, applied when the bill is posted; a posted, unpaid bill ( UNPAID , READY_FOR_PAYMENT_RELEASE , SCHEDULED , PENDING_PAYMENT_APPROVAL ) is cleared immediately and moves to PARTIALLY_PAID or COMPLETED — the response doesn't show that, so re-read the bill. amount has no default: it must be above zero ( INVALID_LINKING_AMOUNT ), within the note's unallocated amount ( CREDIT_NOTE_AMOUNT_EXCEEDED ), and for a posted bill within its remaining balance. Vendor, entity and currency must match; a pair already linked is CREDIT_NOTE_ALREADY_LINKED . ## Authorization - API key - Bearer token See https://light.inc/docs/getting-started/authentication. ## Path parameters - `creditNoteId` (string, uuid, required) - `invoicePayableId` (string, uuid, required) ## Request body `application/json;charset=UTF-8` - `amount` — No default. Must be above zero and within both the note's unallocated amount and, for a posted bill, its remaining balance. ```json { "amount": 100000 } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders, and fields that exclude each other are all shown. Do not send it unchanged. ## Response ```json { "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "creditNote": { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "documentNumber": "string", "documentDate": "2026-01-15", "status": "DRAFT", "amount": 100000, "currency": "USD" }, "invoicePayable": { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "documentNumber": "string", "documentDate": "2026-01-15", "status": "DRAFT", "amount": 100000, "currency": "USD" }, "amount": 100000, "currency": "USD", "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z" } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders. ## Code ```bash curl -X POST "https://api.light.inc/v1/credit-notes/3c90c3cc-0d44-4b50-8888-8dd25736052a/invoice-payables/3c90c3cc-0d44-4b50-8888-8dd25736052a" \ -H "Authorization: Basic YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "amount": 100000 }' ``` Full page: https://light.inc/docs/api-reference/v1--credit-notes/link-credit-note-to-invoice-payable --- # Unlink credit note from invoice payable > Removes the link between a credit note and an invoice payable `DELETE https://api.light.inc/v1/credit-notes/{creditNoteId}/invoice-payables/{invoicePayableId}` ## Note On a bill the note has already cleared ( PARTIALLY_PAID , COMPLETED ) or an UNPAID bill, the clearing is reversed in the ledger and the bill returns to UNPAID or PARTIALLY_PAID ; on a draft bill only the link row is removed. ## Authorization - API key - Bearer token See https://light.inc/docs/getting-started/authentication. ## Path parameters - `creditNoteId` (string, uuid, required) - `invoicePayableId` (string, uuid, required) ## Response This endpoint returns no content. ## Code ```bash curl -X DELETE "https://api.light.inc/v1/credit-notes/3c90c3cc-0d44-4b50-8888-8dd25736052a/invoice-payables/3c90c3cc-0d44-4b50-8888-8dd25736052a" \ -H "Authorization: Basic YOUR_API_KEY" ``` Full page: https://light.inc/docs/api-reference/v1--credit-notes/unlink-credit-note-from-invoice-payable --- # Update clearing amount > Updates the clearing amount of a linked invoice payable `PATCH https://api.light.inc/v1/credit-notes/{creditNoteId}/invoice-payables/{invoicePayableId}` ## Note Only while the link has not been applied, i.e. the bill is still a draft or awaiting approval; once the bill is PARTIALLY_PAID or COMPLETED through this note the call fails with INVOICE_PAYABLE_CANNOT_BE_LINKED_UPDATED_UNLINKED . Unlink and relink instead. Sending the current amount is a no-op. ## Authorization - API key - Bearer token See https://light.inc/docs/getting-started/authentication. ## Path parameters - `creditNoteId` (string, uuid, required) - `invoicePayableId` (string, uuid, required) ## Request body `application/json;charset=UTF-8` ```json { "amount": 100000 } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders, and fields that exclude each other are all shown. Do not send it unchanged. ## Response ```json { "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "creditNote": { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "documentNumber": "string", "documentDate": "2026-01-15", "status": "DRAFT", "amount": 100000, "currency": "USD" }, "invoicePayable": { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "documentNumber": "string", "documentDate": "2026-01-15", "status": "DRAFT", "amount": 100000, "currency": "USD" }, "amount": 100000, "currency": "USD", "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z" } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders. ## Code ```bash curl -X PATCH "https://api.light.inc/v1/credit-notes/3c90c3cc-0d44-4b50-8888-8dd25736052a/invoice-payables/3c90c3cc-0d44-4b50-8888-8dd25736052a" \ -H "Authorization: Basic YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "amount": 100000 }' ``` Full page: https://light.inc/docs/api-reference/v1--credit-notes/update-clearing-amount --- # Post credit note > Posts the credit note to the ledger. The credit note must be in draft status with at least one line item. A valid companyEntityId , businessPartnerId , and currency are required. After posting, the credit note can be linked to invoice payables for balance clearing. `POST https://api.light.inc/v1/credit-notes/{creditNoteId}/post` ## Note Beyond the listed prerequisites: the company must use Light's ledger ( CREDIT_NOTE_CANNOT_BE_POSTED ), amount must be set and non-zero and equal the sum of the lines' gross amounts ( CREDIT_NOTE_VALIDATION_ERROR ), the total must be a credit ( CREDIT_NOTE_NEGATIVE_TOTAL_AMOUNT ), and every line needs ledgerAccountId ( CREDIT_NOTE_MISSING_FIELD ). businessPartnerId is not actually checked here; it is required to link. The posting needs an open period and a payables control account for the entity. If the company auto-allocates credits, the response may already be PARTIALLY_CLEARED or CLEARED . ## Authorization - API key - Bearer token See https://light.inc/docs/getting-started/authentication. ## Path parameters - `creditNoteId` (string, uuid, required) ## Response - `lines.grossTransactionAmount.amount` — Unsigned integer in minor units. The direction is in `dcSign`; a negative value is rejected. - `lines.netTransactionAmount.amount` — Unsigned integer in minor units. The direction is in `dcSign`; a negative value is rejected. - `lines.taxTransactionAmount.amount` — Unsigned integer in minor units. The direction is in `dcSign`; a negative value is rejected. - `localCurrencyFxRate` — Echoes the override you sent; `null` when Light applies its own rate, not the rate that was applied. - `groupCurrencyFxRate` — Echoes the override you sent; `null` when Light applies its own rate, not the rate that was applied. ```json { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyEntityId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "amount": 100000, "businessPartnerName": "string", "businessPartnerId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "status": "DRAFT", "description": "string", "currency": "USD", "postingDate": "2026-01-15", "documentDate": "2026-01-15", "valuationDate": "2026-01-15", "areLinesWithTax": true, "lines": [ { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "creditNoteId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "grossTransactionAmount": { "amount": 100000, "dcSign": "D" }, "netTransactionAmount": { "amount": 100000, "dcSign": "D" }, "description": "string", "ledgerTaxId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "taxTransactionAmount": { "amount": 100000, "dcSign": "D" }, "ledgerAccountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "costCenterId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z", "accrualTemplateId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "accrualStartDate": "2026-01-15", "accrualEndDate": "2026-01-15", "accrualDefaultDuration": 0 } ], "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z", "updatedBy": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "localCurrencyFxRate": 0, "groupCurrencyFxRate": 0, "senderEmail": "string", "documentName": "string" } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders. ## Code ```bash curl -X POST "https://api.light.inc/v1/credit-notes/3c90c3cc-0d44-4b50-8888-8dd25736052a/post" \ -H "Authorization: Basic YOUR_API_KEY" ``` Full page: https://light.inc/docs/api-reference/v1--credit-notes/post-credit-note --- # Custom Properties (resource) Access custom property groups. Resource page: https://light.inc/docs/api-reference/v1--custom-properties # List custom property values > Returns a paginated list of custom property values `GET https://api.light.inc/v1/custom-properties/groups/{groupId}/values` ## Note Lists catalogue values only; inline (free-text) values written on records are never returned. Values deleted with DELETE .../values/{valueId} are still returned here and cannot be told apart, because the value model carries no status, whereas the group endpoints hydrate active values only. The value filter and sort field matches internalName . An unknown groupId yields an empty page, not 404 . ## Authorization - API key - Bearer token See https://light.inc/docs/getting-started/authentication. ## Path parameters - `groupId` (string, uuid, required) ## Query parameters - `sort` (string) — Sort string in the format field:direction . To provide multiple sort fields, separate them with commas. Available directions: asc , desc . Available fields: label , value , createdAt . - `filter` (string) — Filter string in the format field:operator:value . To provide multiple filters, separate them with commas. Available operators: eq , ne , in , not_in , gt , gte , lt , lte . - For in and not_in operators, provide multiple values separated by the pipe character ( ). Available fields: id , label , value , createdAt , updatedAt . - `limit` (integer, int32) — Maximum number of items to return. Default is 50, maximum is 200. - `offset` (integer, int64) — Number of items to skip before starting to collect the result set. Deprecated, use 'cursor' instead. - `cursor` (string) — The cursor position to start returning results from. To opt-in into cursor-based pagination, provide 0 for the initial request. For subsequent requests, use nextCursor and prevCursor from the previous response to navigate. Cursor values are opaque and should not be constructed manually. ## Response ```json { "records": [ { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupInternalName": "string", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "internalName": "string", "label": "string", "context": "string", "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z" } ], "hasMore": true, "total": 100000, "nextCursor": "string", "prevCursor": "string" } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders. ## Code ```bash curl -X GET "https://api.light.inc/v1/custom-properties/groups/3c90c3cc-0d44-4b50-8888-8dd25736052a/values" \ -H "Authorization: Basic YOUR_API_KEY" ``` Full page: https://light.inc/docs/api-reference/v1--custom-properties/list-custom-property-values --- # Create custom property value > Creates a new custom property value in the specified group `POST https://api.light.inc/v1/custom-properties/groups/{groupId}/values` ## Note internalName must match ^[a-z0-9_-]+$ ( CUSTOM_PROPERTY_VALUES_INVALID_INTERNAL_NAMES ), must be unique within the group ( CUSTOM_PROPERTY_VALUE_ALREADY_EXISTS ) and cannot be changed later. Blank internalName or label are rejected ( CUSTOM_PROPERTY_VALUE_EMPTY_INTERNAL_NAME , CUSTOM_PROPERTY_VALUE_EMPTY_LABEL ). The group's inputType is not checked, so you can add catalogue values to a TEXT , NUMERIC , DATE or BOOLEAN group; records then reference them through valueIds . Requires the company-admin role. ## Authorization - API key - Bearer token See https://light.inc/docs/getting-started/authentication. ## Path parameters - `groupId` (string, uuid, required) ## Request body `application/json;charset=UTF-8` ```json { "internalName": "string", "label": "string", "context": "string" } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders, and fields that exclude each other are all shown. Do not send it unchanged. ## Response ```json { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupInternalName": "string", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "internalName": "string", "label": "string", "context": "string", "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z" } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders. ## Code ```bash curl -X POST "https://api.light.inc/v1/custom-properties/groups/3c90c3cc-0d44-4b50-8888-8dd25736052a/values" \ -H "Authorization: Basic YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "internalName": "string", "label": "string", "context": "string" }' ``` Full page: https://light.inc/docs/api-reference/v1--custom-properties/create-custom-property-value --- # Get custom property value > Returns a custom property value by ID `GET https://api.light.inc/v1/custom-properties/groups/{groupId}/values/{valueId}` ## Note 404 unless the value belongs to that group. ## Authorization - API key - Bearer token See https://light.inc/docs/getting-started/authentication. ## Path parameters - `groupId` (string, uuid, required) - `valueId` (string, uuid, required) ## Response ```json { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupInternalName": "string", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "internalName": "string", "label": "string", "context": "string", "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z" } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders. ## Code ```bash curl -X GET "https://api.light.inc/v1/custom-properties/groups/3c90c3cc-0d44-4b50-8888-8dd25736052a/values/3c90c3cc-0d44-4b50-8888-8dd25736052a" \ -H "Authorization: Basic YOUR_API_KEY" ``` Full page: https://light.inc/docs/api-reference/v1--custom-properties/get-custom-property-value --- # Delete custom property value > Deletes a custom property value by ID `DELETE https://api.light.inc/v1/custom-properties/groups/{groupId}/values/{valueId}` ## Note A soft delete with no in-use check: records that reference the value keep it, and the value keeps appearing on GET .../values (it disappears from the group's hydrated values ). Repeating the call succeeds again. Answers 204 with no body. Requires the company-admin role. ## Authorization - API key - Bearer token See https://light.inc/docs/getting-started/authentication. ## Path parameters - `groupId` (string, uuid, required) - `valueId` (string, uuid, required) ## Response This endpoint returns no content. ## Code ```bash curl -X DELETE "https://api.light.inc/v1/custom-properties/groups/3c90c3cc-0d44-4b50-8888-8dd25736052a/values/3c90c3cc-0d44-4b50-8888-8dd25736052a" \ -H "Authorization: Basic YOUR_API_KEY" ``` Full page: https://light.inc/docs/api-reference/v1--custom-properties/delete-custom-property-value --- # Update custom property value > Updates an existing custom property value `PATCH https://api.light.inc/v1/custom-properties/groups/{groupId}/values/{valueId}` ## Note label cannot be cleared: sending null leaves it unchanged. context follows the usual rule (omit to keep, null or "" to clear). A value that doesn't belong to the given groupId is 404 CUSTOM_PROPERTY_VALUE_NOT_FOUND . Requires the company-admin role. ## Authorization - API key - Bearer token See https://light.inc/docs/getting-started/authentication. ## Path parameters - `groupId` (string, uuid, required) - `valueId` (string, uuid, required) ## Request body `application/json;charset=UTF-8` ```json { "label": "string", "context": "string" } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders, and fields that exclude each other are all shown. Do not send it unchanged. ## Response ```json { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupInternalName": "string", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "internalName": "string", "label": "string", "context": "string", "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z" } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders. ## Code ```bash curl -X PATCH "https://api.light.inc/v1/custom-properties/groups/3c90c3cc-0d44-4b50-8888-8dd25736052a/values/3c90c3cc-0d44-4b50-8888-8dd25736052a" \ -H "Authorization: Basic YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "label": "string", "context": "string" }' ``` Full page: https://light.inc/docs/api-reference/v1--custom-properties/update-custom-property-value --- # Get custom property group > Returns a custom property group by ID `GET https://api.light.inc/v1/custom-properties/groups/{groupId}` ## Note Always includes values , restricted to active values. A group that was deleted in Light still answers 200 (see the list endpoint for how to tell); only groups your company defined are visible, everything else is 404 CUSTOM_PROPERTY_GROUP_NOT_FOUND . ## Authorization - API key - Bearer token See https://light.inc/docs/getting-started/authentication. ## Path parameters - `groupId` (string, uuid, required) ## Response - `objectTypeStatuses` — A map of record type to `ACTIVE` or `DELETED`. This is how a deleted group shows up: there is no status field, and a group deleted in Light has every entry set to `DELETED` yet is still listed. - `values` — `null` when not requested (`includeValues` is off on the list endpoint). `[]` when requested and the group has no active values, or when the catalogue exceeds the 15,000-value hydration cap; page through `GET .../groups/{groupId}/values` in that case. ```json { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "label": "string", "internalName": "string", "inputType": "SINGLE_SELECT", "objectLevel": "HEADER", "objectTypes": [ "BILL" ], "objectTypeStatuses": null, "isRequired": true, "context": "string", "values": [ { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupInternalName": "string", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "internalName": "string", "label": "string", "context": "string", "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z" } ], "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z" } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders. ## Code ```bash curl -X GET "https://api.light.inc/v1/custom-properties/groups/3c90c3cc-0d44-4b50-8888-8dd25736052a" \ -H "Authorization: Basic YOUR_API_KEY" ``` Full page: https://light.inc/docs/api-reference/v1--custom-properties/get-custom-property-group --- # List custom property groups > Returns a paginated list of custom property groups `GET https://api.light.inc/v1/custom-properties/groups` ## Note Only groups your company defined are listed; Light's system-provided definitions never appear here. values is null unless includeValues=true , and even then only active values are included, capped at 15,000 per group — a larger catalogue comes back with an empty values , so use GET .../groups/{groupId}/values for those. There is no status on a group. A group deleted in Light is still listed : every entry of its objectTypeStatuses reads DELETED . Exclude those with filter=isDeleted:eq:false . Two filter quirks: objectType:in:INVOICE BILL matches groups enabled for all of the listed types, not any of them; and objectTypeStatus on its own matches a group where any record type has that status — pair it with objectType to scope it. Default order is label:asc . ## Authorization - API key - Bearer token See https://light.inc/docs/getting-started/authentication. ## Query parameters - `sort` (string) — Sort string in the format field:direction . To provide multiple sort fields, separate them with commas. Available directions: asc , desc . Available fields: label , createdAt . - `filter` (string) — Filter string in the format field:operator:value . To provide multiple filters, separate them with commas. Available operators: eq , ne , in , not_in , gt , gte , lt , lte . - For in and not_in operators, provide multiple values separated by the pipe character ( ). Available fields: id , internalName , label , objectLevel , objectType , objectTypeStatus , inputType , isRequired , isDeleted , createdAt , updatedAt . - `limit` (integer, int32) — Maximum number of items to return. Default is 50, maximum is 200. - `offset` (integer, int64) — Number of items to skip before starting to collect the result set. Deprecated, use 'cursor' instead. - `cursor` (string) — The cursor position to start returning results from. To opt-in into cursor-based pagination, provide 0 for the initial request. For subsequent requests, use nextCursor and prevCursor from the previous response to navigate. Cursor values are opaque and should not be constructed manually. - `includeValues` (boolean) ## Response - `records.objectTypeStatuses` — A map of record type to `ACTIVE` or `DELETED`. This is how a deleted group shows up: there is no status field, and a group deleted in Light has every entry set to `DELETED` yet is still listed. - `records.values` — `null` when not requested (`includeValues` is off on the list endpoint). `[]` when requested and the group has no active values, or when the catalogue exceeds the 15,000-value hydration cap; page through `GET .../groups/{groupId}/values` in that case. ```json { "records": [ { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "label": "string", "internalName": "string", "inputType": "SINGLE_SELECT", "objectLevel": "HEADER", "objectTypes": [ "BILL" ], "objectTypeStatuses": null, "isRequired": true, "context": "string", "values": [ { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupInternalName": "string", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "internalName": "string", "label": "string", "context": "string", "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z" } ], "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z" } ], "hasMore": true, "total": 100000, "nextCursor": "string", "prevCursor": "string" } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders. ## Code ```bash curl -X GET "https://api.light.inc/v1/custom-properties/groups" \ -H "Authorization: Basic YOUR_API_KEY" ``` Full page: https://light.inc/docs/api-reference/v1--custom-properties/list-custom-property-groups --- # Customer Credits (resource) Manage customer credit documents. Resource page: https://light.inc/docs/api-reference/v1--customer-credits # Archive customer credit > Archives the given customer credit `POST https://api.light.inc/v1/customer-credits/{customerCreditId}/archive` ## Note From DRAFT it simply archives; from POSTED it reverses the ledger posting first. A PARTIALLY_CLEARED or CLEARED credit cannot be archived ( ACCOUNTING_DOCUMENT_CANNOT_BE_ARCHIVED ): unlink it from its invoices first. ## Authorization - API key - Bearer token See https://light.inc/docs/getting-started/authentication. ## Path parameters - `customerCreditId` (string, uuid, required) ## Response - `amount` — The header amount available to allocate, independent of the line totals; the link validations compare against it. - `lines.grossTransactionAmount.amount` — Unsigned integer in minor units. The direction is in `dcSign`; a negative value is rejected. - `lines.netTransactionAmount.amount` — Unsigned integer in minor units. The direction is in `dcSign`; a negative value is rejected. - `lines.taxTransactionAmount.amount` — Unsigned integer in minor units. The direction is in `dcSign`; a negative value is rejected. - `linkedInvoiceReceivable` — The linked **invoice receivable** (the description says payable). `null` when there are no links or more than one; on the list endpoint also `null` unless `include=INVOICE_RECEIVABLE`. ```json { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyEntityId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "amount": 100000, "customerName": "string", "customerId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "status": "DRAFT", "description": "string", "currency": "USD", "documentDate": "2026-01-15", "valuationDate": "2026-01-15", "areLinesWithTax": true, "lines": [ { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "customerCreditId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "grossTransactionAmount": { "amount": 100000, "dcSign": "D" }, "netTransactionAmount": { "amount": 100000, "dcSign": "D" }, "description": "string", "ledgerTaxId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "taxTransactionAmount": { "amount": 100000, "dcSign": "D" }, "ledgerAccountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "avataxCode": "string", "productId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "quantity": 0, "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z", "accrualTemplateId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "accrualStartDate": "2026-01-15", "accrualEndDate": "2026-01-15", "accrualDefaultDuration": 0 } ], "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z", "updatedBy": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "linkedInvoiceReceivable": { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "documentNumber": "string", "documentDate": "2026-01-15", "status": "DRAFT", "amount": 100000, "currency": "USD" } } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders. ## Code ```bash curl -X POST "https://api.light.inc/v1/customer-credits/3c90c3cc-0d44-4b50-8888-8dd25736052a/archive" \ -H "Authorization: Basic YOUR_API_KEY" ``` Full page: https://light.inc/docs/api-reference/v1--customer-credits/archive-customer-credit --- # List customer credits > Returns a paginated list of customer credits `GET https://api.light.inc/v1/customer-credits` ## Note Cursor pagination only: there is no offset , no total , and prevCursor is always null . Rows include lines . linkedInvoiceReceivable is populated only with include=INVOICE_RECEIVABLE and exactly one linked invoice; with two or more links it is null . Statuses a credit actually uses: DRAFT , POSTED , PARTIALLY_CLEARED , CLEARED , ARCHIVED . ## Authorization - API key - Bearer token See https://light.inc/docs/getting-started/authentication. ## Query parameters - `sort` (string) — Sort string in the format field:direction . To provide multiple sort fields, separate them with commas. Available directions: asc , desc . Available fields: amount , businessPartnerName , documentDate , postingDate , status . - `filter` (string) — Filter string in the format field:operator:value . To provide multiple filters, separate them with commas. Available operators: eq , ne , in , not_in , gt , gte , lt , lte . - For in and not_in operators, provide multiple values separated by the pipe character ( ). Available fields: businessPartnerId , companyEntityId , currency , documentDate , einvoiceStatus , id , postingDate , status , updatedAt . - `limit` (integer, int32) — Maximum number of items to return. Default is 50, maximum is 200. - `cursor` (string) — The cursor position to start returning results from. To opt-in into cursor-based pagination, provide 0 for the initial request. For subsequent requests, use nextCursor and prevCursor from the previous response to navigate. Cursor values are opaque and should not be constructed manually. - `include` (array) — Related objects to include on every customer credit. Supported value can be INVOICE_RECEIVABLE ## Response - `records.amount` — The header amount available to allocate, independent of the line totals; the link validations compare against it. - `records.lines.grossTransactionAmount.amount` — Unsigned integer in minor units. The direction is in `dcSign`; a negative value is rejected. - `records.lines.netTransactionAmount.amount` — Unsigned integer in minor units. The direction is in `dcSign`; a negative value is rejected. - `records.lines.taxTransactionAmount.amount` — Unsigned integer in minor units. The direction is in `dcSign`; a negative value is rejected. - `records.linkedInvoiceReceivable` — The linked **invoice receivable** (the description says payable). `null` when there are no links or more than one; on the list endpoint also `null` unless `include=INVOICE_RECEIVABLE`. ```json { "records": [ { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyEntityId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "amount": 100000, "customerName": "string", "customerId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "status": "DRAFT", "description": "string", "currency": "USD", "documentDate": "2026-01-15", "valuationDate": "2026-01-15", "areLinesWithTax": true, "lines": [ { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "customerCreditId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "grossTransactionAmount": { "amount": 100000, "dcSign": "D" }, "netTransactionAmount": { "amount": 100000, "dcSign": "D" }, "description": "string", "ledgerTaxId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "taxTransactionAmount": { "amount": 100000, "dcSign": "D" }, "ledgerAccountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "avataxCode": "string", "productId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "quantity": 0, "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z", "accrualTemplateId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "accrualStartDate": "2026-01-15", "accrualEndDate": "2026-01-15", "accrualDefaultDuration": 0 } ], "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z", "updatedBy": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "linkedInvoiceReceivable": { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "documentNumber": "string", "documentDate": "2026-01-15", "status": "DRAFT", "amount": 100000, "currency": "USD" } } ], "hasMore": true, "nextCursor": "string", "prevCursor": "string" } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders. ## Code ```bash curl -X GET "https://api.light.inc/v1/customer-credits" \ -H "Authorization: Basic YOUR_API_KEY" ``` Full page: https://light.inc/docs/api-reference/v1--customer-credits/list-customer-credits --- # Create customer credit > Creates a new customer credit `POST https://api.light.inc/v1/customer-credits` ## Note documentNumber is assigned when the credit is posted , not "when the invoice is opened" as the description says. documentDate is also used as the posting date. lines and areLinesWithTax are required, though lines may be [] . Line amounts are { amount, dcSign } objects; for a credit the gross line amount is normally a debit ( "dcSign": "D" ). Omitted line tax and account fields take the product's defaults for the tax engine in force. Requires a user credential. An X-Idempotency-Key makes retries safe; without one nothing is de-duplicated. ## Authorization - API key - Bearer token See https://light.inc/docs/getting-started/authentication. ## Header parameters - `X-Idempotency-Key` (string) ## Request body `application/json;charset=UTF-8` - `lines.netTransactionAmount.amount` — Unsigned integer in minor units. The direction is in `dcSign`; a negative value is rejected. - `lines.grossTransactionAmount.amount` — Unsigned integer in minor units. The direction is in `dcSign`; a negative value is rejected. - `lines.taxTransactionAmount.amount` — Unsigned integer in minor units. The direction is in `dcSign`; a negative value is rejected. - `lines.customProperties.valueIds` — Catalogue value ids for this group. Required; send `[]` (with an empty `inlineValues`) to clear the group. `SINGLE_SELECT` and `MULTI_SELECT` groups accept nothing else. See [Custom properties on writes](/docs/getting-started/pagination-filtering-errors#custom-properties-on-writes). - `lines.customProperties.inlineValues` — Literal values for `TEXT`, `NUMERIC`, `BOOLEAN` and `DATE` groups, as strings (`yyyy-MM-dd` for dates). Rejected on select groups with `CUSTOM_PROPERTY_VALUE_TYPE_MISMATCH`. See [Custom properties on writes](/docs/getting-started/pagination-filtering-errors#custom-properties-on-writes). - `customProperties.valueIds` — Catalogue value ids for this group. Required; send `[]` (with an empty `inlineValues`) to clear the group. `SINGLE_SELECT` and `MULTI_SELECT` groups accept nothing else. See [Custom properties on writes](/docs/getting-started/pagination-filtering-errors#custom-properties-on-writes). - `customProperties.inlineValues` — Literal values for `TEXT`, `NUMERIC`, `BOOLEAN` and `DATE` groups, as strings (`yyyy-MM-dd` for dates). Rejected on select groups with `CUSTOM_PROPERTY_VALUE_TYPE_MISMATCH`. See [Custom properties on writes](/docs/getting-started/pagination-filtering-errors#custom-properties-on-writes). ```json { "companyEntityId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "documentNumber": "string", "description": "string", "currency": "USD", "localCurrencyFxRate": 0, "groupCurrencyFxRate": 0, "documentDate": "2026-01-15", "documentTemplateId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "areLinesWithTax": true, "customerId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "amount": 100000, "lines": [ { "productId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "quantity": 0, "netTransactionAmount": { "amount": 100000, "dcSign": "D" }, "grossTransactionAmount": { "amount": 100000, "dcSign": "D" }, "taxTransactionAmount": { "amount": 100000, "dcSign": "D" }, "description": "string", "ledgerTaxId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "ledgerAccountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "avataxCode": "string", "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "valueIds": [ "3c90c3cc-0d44-4b50-8888-8dd25736052a" ], "inlineValues": [ "string" ] } ], "accrualTemplateId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "accrualStartDate": "2026-01-15", "accrualEndDate": "2026-01-15" } ], "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "valueIds": [ "3c90c3cc-0d44-4b50-8888-8dd25736052a" ], "inlineValues": [ "string" ] } ] } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders, and fields that exclude each other are all shown. Do not send it unchanged. ## Response - `amount` — The header amount available to allocate, independent of the line totals; the link validations compare against it. - `lines.grossTransactionAmount.amount` — Unsigned integer in minor units. The direction is in `dcSign`; a negative value is rejected. - `lines.netTransactionAmount.amount` — Unsigned integer in minor units. The direction is in `dcSign`; a negative value is rejected. - `lines.taxTransactionAmount.amount` — Unsigned integer in minor units. The direction is in `dcSign`; a negative value is rejected. - `linkedInvoiceReceivable` — The linked **invoice receivable** (the description says payable). `null` when there are no links or more than one; on the list endpoint also `null` unless `include=INVOICE_RECEIVABLE`. ```json { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyEntityId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "amount": 100000, "customerName": "string", "customerId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "status": "DRAFT", "description": "string", "currency": "USD", "documentDate": "2026-01-15", "valuationDate": "2026-01-15", "areLinesWithTax": true, "lines": [ { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "customerCreditId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "grossTransactionAmount": { "amount": 100000, "dcSign": "D" }, "netTransactionAmount": { "amount": 100000, "dcSign": "D" }, "description": "string", "ledgerTaxId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "taxTransactionAmount": { "amount": 100000, "dcSign": "D" }, "ledgerAccountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "avataxCode": "string", "productId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "quantity": 0, "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z", "accrualTemplateId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "accrualStartDate": "2026-01-15", "accrualEndDate": "2026-01-15", "accrualDefaultDuration": 0 } ], "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z", "updatedBy": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "linkedInvoiceReceivable": { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "documentNumber": "string", "documentDate": "2026-01-15", "status": "DRAFT", "amount": 100000, "currency": "USD" } } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders. ## Code ```bash curl -X POST "https://api.light.inc/v1/customer-credits" \ -H "Authorization: Basic YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "companyEntityId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "documentNumber": "string", "description": "string", "currency": "USD", "localCurrencyFxRate": 0, "groupCurrencyFxRate": 0, "documentDate": "2026-01-15", "documentTemplateId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "areLinesWithTax": true, "customerId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "amount": 100000, "lines": [ { "productId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "quantity": 0, "netTransactionAmount": { "amount": 100000, "dcSign": "D" }, "grossTransactionAmount": { "amount": 100000, "dcSign": "D" }, "taxTransactionAmount": { "amount": 100000, "dcSign": "D" }, "description": "string", "ledgerTaxId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "ledgerAccountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "avataxCode": "string", "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "valueIds": [ "3c90c3cc-0d44-4b50-8888-8dd25736052a" ], "inlineValues": [ "string" ] } ], "accrualTemplateId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "accrualStartDate": "2026-01-15", "accrualEndDate": "2026-01-15" } ], "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "valueIds": [ "3c90c3cc-0d44-4b50-8888-8dd25736052a" ], "inlineValues": [ "string" ] } ] }' ``` Full page: https://light.inc/docs/api-reference/v1--customer-credits/create-customer-credit --- # Create customer credit line > Creates a new line for the given customer credit `POST https://api.light.inc/v1/customer-credits/{customerCreditId}/lines` ## Note Only while the credit is DRAFT ( CUSTOMER_CREDIT_CANNOT_BE_MODIFIED ). ledgerTaxId only with Light's tax engine, avataxCode only with Avalara ( CUSTOMER_CREDIT_INVALID_TAX_UPDATE ). ## Authorization - API key - Bearer token See https://light.inc/docs/getting-started/authentication. ## Path parameters - `customerCreditId` (string, uuid, required) ## Request body `application/json;charset=UTF-8` - `netTransactionAmount.amount` — Unsigned integer in minor units. The direction is in `dcSign`; a negative value is rejected. - `grossTransactionAmount.amount` — Unsigned integer in minor units. The direction is in `dcSign`; a negative value is rejected. - `taxTransactionAmount.amount` — Unsigned integer in minor units. The direction is in `dcSign`; a negative value is rejected. - `customProperties.valueIds` — Catalogue value ids for this group. Required; send `[]` (with an empty `inlineValues`) to clear the group. `SINGLE_SELECT` and `MULTI_SELECT` groups accept nothing else. See [Custom properties on writes](/docs/getting-started/pagination-filtering-errors#custom-properties-on-writes). - `customProperties.inlineValues` — Literal values for `TEXT`, `NUMERIC`, `BOOLEAN` and `DATE` groups, as strings (`yyyy-MM-dd` for dates). Rejected on select groups with `CUSTOM_PROPERTY_VALUE_TYPE_MISMATCH`. See [Custom properties on writes](/docs/getting-started/pagination-filtering-errors#custom-properties-on-writes). ```json { "productId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "quantity": 0, "netTransactionAmount": { "amount": 100000, "dcSign": "D" }, "grossTransactionAmount": { "amount": 100000, "dcSign": "D" }, "taxTransactionAmount": { "amount": 100000, "dcSign": "D" }, "description": "string", "ledgerTaxId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "ledgerAccountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "avataxCode": "string", "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "valueIds": [ "3c90c3cc-0d44-4b50-8888-8dd25736052a" ], "inlineValues": [ "string" ] } ], "accrualTemplateId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "accrualStartDate": "2026-01-15", "accrualEndDate": "2026-01-15" } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders, and fields that exclude each other are all shown. Do not send it unchanged. ## Response - `grossTransactionAmount.amount` — Unsigned integer in minor units. The direction is in `dcSign`; a negative value is rejected. - `netTransactionAmount.amount` — Unsigned integer in minor units. The direction is in `dcSign`; a negative value is rejected. - `taxTransactionAmount.amount` — Unsigned integer in minor units. The direction is in `dcSign`; a negative value is rejected. ```json { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "customerCreditId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "grossTransactionAmount": { "amount": 100000, "dcSign": "D" }, "netTransactionAmount": { "amount": 100000, "dcSign": "D" }, "description": "string", "ledgerTaxId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "taxTransactionAmount": { "amount": 100000, "dcSign": "D" }, "ledgerAccountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "avataxCode": "string", "productId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "quantity": 0, "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z", "accrualTemplateId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "accrualStartDate": "2026-01-15", "accrualEndDate": "2026-01-15", "accrualDefaultDuration": 0 } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders. ## Code ```bash curl -X POST "https://api.light.inc/v1/customer-credits/3c90c3cc-0d44-4b50-8888-8dd25736052a/lines" \ -H "Authorization: Basic YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "productId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "quantity": 0, "netTransactionAmount": { "amount": 100000, "dcSign": "D" }, "grossTransactionAmount": { "amount": 100000, "dcSign": "D" }, "taxTransactionAmount": { "amount": 100000, "dcSign": "D" }, "description": "string", "ledgerTaxId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "ledgerAccountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "avataxCode": "string", "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "valueIds": [ "3c90c3cc-0d44-4b50-8888-8dd25736052a" ], "inlineValues": [ "string" ] } ], "accrualTemplateId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "accrualStartDate": "2026-01-15", "accrualEndDate": "2026-01-15" }' ``` Full page: https://light.inc/docs/api-reference/v1--customer-credits/create-customer-credit-line --- # Delete customer credit line > Deletes the given customer credit line `DELETE https://api.light.inc/v1/customer-credits/{customerCreditId}/lines/{lineId}` ## Note Only while the credit is DRAFT . Answers with an empty body. ## Authorization - API key - Bearer token See https://light.inc/docs/getting-started/authentication. ## Path parameters - `customerCreditId` (string, uuid, required) - `lineId` (string, uuid, required) ## Response This endpoint returns no content. ## Code ```bash curl -X DELETE "https://api.light.inc/v1/customer-credits/3c90c3cc-0d44-4b50-8888-8dd25736052a/lines/3c90c3cc-0d44-4b50-8888-8dd25736052a" \ -H "Authorization: Basic YOUR_API_KEY" ``` Full page: https://light.inc/docs/api-reference/v1--customer-credits/delete-customer-credit-line --- # Update customer credit line > Updates the given customer credit line `PATCH https://api.light.inc/v1/customer-credits/{customerCreditId}/lines/{lineId}` ## Note Only while the credit is DRAFT . null clears the amounts, description , ledgerTaxId , ledgerAccountId , avataxCode and the accrual fields, but leaves productId and quantity unchanged. Unknown line: CUSTOMER_CREDIT_LINE_NOT_FOUND . ## Authorization - API key - Bearer token See https://light.inc/docs/getting-started/authentication. ## Path parameters - `customerCreditId` (string, uuid, required) - `lineId` (string, uuid, required) ## Request body `application/json;charset=UTF-8` - `customProperties.valueIds` — Catalogue value ids for this group. Required; send `[]` (with an empty `inlineValues`) to clear the group. `SINGLE_SELECT` and `MULTI_SELECT` groups accept nothing else. See [Custom properties on writes](/docs/getting-started/pagination-filtering-errors#custom-properties-on-writes). - `customProperties.inlineValues` — Literal values for `TEXT`, `NUMERIC`, `BOOLEAN` and `DATE` groups, as strings (`yyyy-MM-dd` for dates). Rejected on select groups with `CUSTOM_PROPERTY_VALUE_TYPE_MISMATCH`. See [Custom properties on writes](/docs/getting-started/pagination-filtering-errors#custom-properties-on-writes). - `netTransactionAmount.amount` — Unsigned integer in minor units. The direction is in `dcSign`; a negative value is rejected. - `grossTransactionAmount.amount` — Unsigned integer in minor units. The direction is in `dcSign`; a negative value is rejected. - `taxTransactionAmount.amount` — Unsigned integer in minor units. The direction is in `dcSign`; a negative value is rejected. ```json { "productId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "quantity": 0, "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "valueIds": [ "3c90c3cc-0d44-4b50-8888-8dd25736052a" ], "inlineValues": [ "string" ] } ], "netTransactionAmount": { "amount": 100000, "dcSign": "D" }, "grossTransactionAmount": { "amount": 100000, "dcSign": "D" }, "taxTransactionAmount": { "amount": 100000, "dcSign": "D" }, "description": "string", "ledgerTaxId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "ledgerAccountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "avataxCode": "string", "accrualTemplateId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "accrualStartDate": "2026-01-15", "accrualEndDate": "2026-01-15" } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders, and fields that exclude each other are all shown. Do not send it unchanged. ## Response - `grossTransactionAmount.amount` — Unsigned integer in minor units. The direction is in `dcSign`; a negative value is rejected. - `netTransactionAmount.amount` — Unsigned integer in minor units. The direction is in `dcSign`; a negative value is rejected. - `taxTransactionAmount.amount` — Unsigned integer in minor units. The direction is in `dcSign`; a negative value is rejected. ```json { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "customerCreditId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "grossTransactionAmount": { "amount": 100000, "dcSign": "D" }, "netTransactionAmount": { "amount": 100000, "dcSign": "D" }, "description": "string", "ledgerTaxId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "taxTransactionAmount": { "amount": 100000, "dcSign": "D" }, "ledgerAccountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "avataxCode": "string", "productId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "quantity": 0, "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z", "accrualTemplateId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "accrualStartDate": "2026-01-15", "accrualEndDate": "2026-01-15", "accrualDefaultDuration": 0 } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders. ## Code ```bash curl -X PATCH "https://api.light.inc/v1/customer-credits/3c90c3cc-0d44-4b50-8888-8dd25736052a/lines/3c90c3cc-0d44-4b50-8888-8dd25736052a" \ -H "Authorization: Basic YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "productId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "quantity": 0, "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "valueIds": [ "3c90c3cc-0d44-4b50-8888-8dd25736052a" ], "inlineValues": [ "string" ] } ], "netTransactionAmount": { "amount": 100000, "dcSign": "D" }, "grossTransactionAmount": { "amount": 100000, "dcSign": "D" }, "taxTransactionAmount": { "amount": 100000, "dcSign": "D" }, "description": "string", "ledgerTaxId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "ledgerAccountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "avataxCode": "string", "accrualTemplateId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "accrualStartDate": "2026-01-15", "accrualEndDate": "2026-01-15" }' ``` Full page: https://light.inc/docs/api-reference/v1--customer-credits/update-customer-credit-line --- # Get customer credit > Returns a customer credit by ID `GET https://api.light.inc/v1/customer-credits/{customerCreditId}` ## Note Always includes lines and, when there is exactly one linked invoice, linkedInvoiceReceivable . ## Authorization - API key - Bearer token See https://light.inc/docs/getting-started/authentication. ## Path parameters - `customerCreditId` (string, uuid, required) ## Response - `amount` — The header amount available to allocate, independent of the line totals; the link validations compare against it. - `lines.grossTransactionAmount.amount` — Unsigned integer in minor units. The direction is in `dcSign`; a negative value is rejected. - `lines.netTransactionAmount.amount` — Unsigned integer in minor units. The direction is in `dcSign`; a negative value is rejected. - `lines.taxTransactionAmount.amount` — Unsigned integer in minor units. The direction is in `dcSign`; a negative value is rejected. - `linkedInvoiceReceivable` — The linked **invoice receivable** (the description says payable). `null` when there are no links or more than one; on the list endpoint also `null` unless `include=INVOICE_RECEIVABLE`. ```json { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyEntityId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "amount": 100000, "customerName": "string", "customerId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "status": "DRAFT", "description": "string", "currency": "USD", "documentDate": "2026-01-15", "valuationDate": "2026-01-15", "areLinesWithTax": true, "lines": [ { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "customerCreditId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "grossTransactionAmount": { "amount": 100000, "dcSign": "D" }, "netTransactionAmount": { "amount": 100000, "dcSign": "D" }, "description": "string", "ledgerTaxId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "taxTransactionAmount": { "amount": 100000, "dcSign": "D" }, "ledgerAccountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "avataxCode": "string", "productId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "quantity": 0, "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z", "accrualTemplateId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "accrualStartDate": "2026-01-15", "accrualEndDate": "2026-01-15", "accrualDefaultDuration": 0 } ], "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z", "updatedBy": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "linkedInvoiceReceivable": { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "documentNumber": "string", "documentDate": "2026-01-15", "status": "DRAFT", "amount": 100000, "currency": "USD" } } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders. ## Code ```bash curl -X GET "https://api.light.inc/v1/customer-credits/3c90c3cc-0d44-4b50-8888-8dd25736052a" \ -H "Authorization: Basic YOUR_API_KEY" ``` Full page: https://light.inc/docs/api-reference/v1--customer-credits/get-customer-credit --- # Update customer credit > Updates the given customer credit `PATCH https://api.light.inc/v1/customer-credits/{customerCreditId}` ## Note Only in DRAFT ( CUSTOMER_CREDIT_CANNOT_BE_MODIFIED ). null clears description , currency , amount , documentNumber and documentTemplateId but leaves companyEntityId , customerId , documentDate and areLinesWithTax unchanged; documentDate also rewrites the posting date. While any invoice is linked, customerId , companyEntityId and currency cannot change ( CUSTOMER_CREDIT_CANNOT_CHANGE_SCOPE_WHILE_LINKED ) and amount cannot drop below the linked total ( CUSTOMER_CREDIT_AMOUNT_BELOW_LINKED_SUM ). ## Authorization - API key - Bearer token See https://light.inc/docs/getting-started/authentication. ## Path parameters - `customerCreditId` (string, uuid, required) ## Header parameters - `X-Idempotency-Key` (string) ## Request body `application/json;charset=UTF-8` - `customProperties.valueIds` — Catalogue value ids for this group. Required; send `[]` (with an empty `inlineValues`) to clear the group. `SINGLE_SELECT` and `MULTI_SELECT` groups accept nothing else. See [Custom properties on writes](/docs/getting-started/pagination-filtering-errors#custom-properties-on-writes). - `customProperties.inlineValues` — Literal values for `TEXT`, `NUMERIC`, `BOOLEAN` and `DATE` groups, as strings (`yyyy-MM-dd` for dates). Rejected on select groups with `CUSTOM_PROPERTY_VALUE_TYPE_MISMATCH`. See [Custom properties on writes](/docs/getting-started/pagination-filtering-errors#custom-properties-on-writes). ```json { "companyEntityId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "customerId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "documentDate": "2026-01-15", "areLinesWithTax": true, "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "valueIds": [ "3c90c3cc-0d44-4b50-8888-8dd25736052a" ], "inlineValues": [ "string" ] } ], "description": "string", "currency": "USD", "amount": 100000, "documentNumber": "string", "documentTemplateId": "3c90c3cc-0d44-4b50-8888-8dd25736052a" } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders, and fields that exclude each other are all shown. Do not send it unchanged. ## Response - `amount` — The header amount available to allocate, independent of the line totals; the link validations compare against it. - `lines.grossTransactionAmount.amount` — Unsigned integer in minor units. The direction is in `dcSign`; a negative value is rejected. - `lines.netTransactionAmount.amount` — Unsigned integer in minor units. The direction is in `dcSign`; a negative value is rejected. - `lines.taxTransactionAmount.amount` — Unsigned integer in minor units. The direction is in `dcSign`; a negative value is rejected. - `linkedInvoiceReceivable` — The linked **invoice receivable** (the description says payable). `null` when there are no links or more than one; on the list endpoint also `null` unless `include=INVOICE_RECEIVABLE`. ```json { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyEntityId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "amount": 100000, "customerName": "string", "customerId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "status": "DRAFT", "description": "string", "currency": "USD", "documentDate": "2026-01-15", "valuationDate": "2026-01-15", "areLinesWithTax": true, "lines": [ { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "customerCreditId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "grossTransactionAmount": { "amount": 100000, "dcSign": "D" }, "netTransactionAmount": { "amount": 100000, "dcSign": "D" }, "description": "string", "ledgerTaxId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "taxTransactionAmount": { "amount": 100000, "dcSign": "D" }, "ledgerAccountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "avataxCode": "string", "productId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "quantity": 0, "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z", "accrualTemplateId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "accrualStartDate": "2026-01-15", "accrualEndDate": "2026-01-15", "accrualDefaultDuration": 0 } ], "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z", "updatedBy": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "linkedInvoiceReceivable": { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "documentNumber": "string", "documentDate": "2026-01-15", "status": "DRAFT", "amount": 100000, "currency": "USD" } } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders. ## Code ```bash curl -X PATCH "https://api.light.inc/v1/customer-credits/3c90c3cc-0d44-4b50-8888-8dd25736052a" \ -H "Authorization: Basic YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "companyEntityId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "customerId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "documentDate": "2026-01-15", "areLinesWithTax": true, "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "valueIds": [ "3c90c3cc-0d44-4b50-8888-8dd25736052a" ], "inlineValues": [ "string" ] } ], "description": "string", "currency": "USD", "amount": 100000, "documentNumber": "string", "documentTemplateId": "3c90c3cc-0d44-4b50-8888-8dd25736052a" }' ``` Full page: https://light.inc/docs/api-reference/v1--customer-credits/update-customer-credit --- # Link customer credit to invoice > Links a customer credit to a sales invoice `POST https://api.light.inc/v1/customer-credits/{customerCreditId}/invoice-receivables/{invoiceReceivableId}/link` ## Note Identical to POST .../invoice-receivables/{invoiceReceivableId} ; this is the newer path. When the credit is applied depends on its status : linking a POSTED credit clears the invoice immediately (it moves to PARTIALLY_PAID or PAID in this call), while linking a DRAFT credit only records the link, applied when the credit is posted. Requirements: invoice OPEN or PARTIALLY_PAID ; credit DRAFT or POSTED ; same customer, entity and currency; the credit's header amount set ( CUSTOMER_CREDIT_AMOUNT_NOT_SET ); not already linked ( CUSTOMER_CREDIT_ALREADY_LINKED ). The description of amount has it backwards: partial allocation is a capability granted by the entity's e-invoicing configuration, and an entity without one gets one link per credit with amount omitted or equal to the whole available credit ( CUSTOMER_CREDIT_PARTIAL_ALLOCATION_NOT_ENABLED ). The response's amount is what was actually linked: the requested amount, else the smaller of the credit and the invoice balance. ## Authorization - API key - Bearer token See https://light.inc/docs/getting-started/authentication. ## Path parameters - `customerCreditId` (string, uuid, required) - `invoiceReceivableId` (string, uuid, required) ## Request body `application/json;charset=UTF-8` ```json { "amount": 100000 } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders, and fields that exclude each other are all shown. Do not send it unchanged. ## Response ```json { "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "customerCredit": { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "documentNumber": "string", "documentDate": "2026-01-15", "status": "DRAFT", "amount": 100000, "currency": "USD" }, "invoiceReceivable": { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "documentNumber": "string", "documentDate": "2026-01-15", "status": "DRAFT", "amount": 100000, "currency": "USD" }, "amount": 100000, "linkedAt": "2026-01-15T09:30:00Z" } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders. ## Code ```bash curl -X POST "https://api.light.inc/v1/customer-credits/3c90c3cc-0d44-4b50-8888-8dd25736052a/invoice-receivables/3c90c3cc-0d44-4b50-8888-8dd25736052a/link" \ -H "Authorization: Basic YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "amount": 100000 }' ``` Full page: https://light.inc/docs/api-reference/v1--customer-credits/link-customer-credit-to-invoice --- # Link customer credit > Links a customer credit to a sales invoice `POST https://api.light.inc/v1/customer-credits/{customerCreditId}/invoice-receivables/{invoiceReceivableId}` ## Note Identical to POST .../invoice-receivables/{invoiceReceivableId}/link , which is the newer path; see that endpoint for when the credit is applied and what is validated. ## Authorization - API key - Bearer token See https://light.inc/docs/getting-started/authentication. ## Path parameters - `customerCreditId` (string, uuid, required) - `invoiceReceivableId` (string, uuid, required) ## Request body `application/json;charset=UTF-8` ```json { "amount": 100000 } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders, and fields that exclude each other are all shown. Do not send it unchanged. ## Response ```json { "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "customerCredit": { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "documentNumber": "string", "documentDate": "2026-01-15", "status": "DRAFT", "amount": 100000, "currency": "USD" }, "invoiceReceivable": { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "documentNumber": "string", "documentDate": "2026-01-15", "status": "DRAFT", "amount": 100000, "currency": "USD" }, "amount": 100000, "linkedAt": "2026-01-15T09:30:00Z" } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders. ## Code ```bash curl -X POST "https://api.light.inc/v1/customer-credits/3c90c3cc-0d44-4b50-8888-8dd25736052a/invoice-receivables/3c90c3cc-0d44-4b50-8888-8dd25736052a" \ -H "Authorization: Basic YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "amount": 100000 }' ``` Full page: https://light.inc/docs/api-reference/v1--customer-credits/link-customer-credit --- # Unlink customer credit > Deprecated: Use POST /{customerCreditId}/invoice-receivables/{invoiceReceivableId}/unlink instead. Unlinks a customer credit from a sales invoice. If the customer credit has already been applied (CLEARED or PARTIALLY_CLEARED status), this will reverse the clearing entries in the ledger. `DELETE https://api.light.inc/v1/customer-credits/{customerCreditId}/invoice-receivables/{invoiceReceivableId}` **Deprecated.** This endpoint may be removed. ## Note Identical to POST .../invoice-receivables/{invoiceReceivableId}/unlink ; only the path is deprecated. If the credit has already been applied, the clearing on the invoice is reversed first (the invoice goes back to OPEN or PARTIALLY_PAID ) and the credit returns to POSTED . Answers with an empty body. ## Authorization - API key - Bearer token See https://light.inc/docs/getting-started/authentication. ## Path parameters - `customerCreditId` (string, uuid, required) - `invoiceReceivableId` (string, uuid, required) ## Response This endpoint returns no content. ## Code ```bash curl -X DELETE "https://api.light.inc/v1/customer-credits/3c90c3cc-0d44-4b50-8888-8dd25736052a/invoice-receivables/3c90c3cc-0d44-4b50-8888-8dd25736052a" \ -H "Authorization: Basic YOUR_API_KEY" ``` Full page: https://light.inc/docs/api-reference/v1--customer-credits/unlink-customer-credit --- # Post and send customer credit > Posts the customer credit and sends it via email. Optionally submits to e-invoicing if shouldSubmitEInvoice is set. `POST https://api.light.inc/v1/customer-credits/{customerCreditId}/post-and-send-email` ## Note Same as post , plus a required emailInfo that is validated before posting, so a bad subject or recipient list leaves the credit in DRAFT ( CUSTOMER_CREDIT_EMAIL_INVALID_SUBJECT , CUSTOMER_CREDIT_EMAIL_MISSING_RECIPIENTS , at most 20 recipients and 20 cc). The email itself is sent after the call returns. ## Authorization - API key - Bearer token See https://light.inc/docs/getting-started/authentication. ## Path parameters - `customerCreditId` (string, uuid, required) ## Request body `application/json;charset=UTF-8` ```json { "emailInfo": { "subject": "string", "replyTo": "string", "recipients": [ "string" ], "cc": [ "string" ], "customMessage": "string" }, "shouldSubmitEInvoice": true } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders, and fields that exclude each other are all shown. Do not send it unchanged. ## Response - `amount` — The header amount available to allocate, independent of the line totals; the link validations compare against it. - `lines.grossTransactionAmount.amount` — Unsigned integer in minor units. The direction is in `dcSign`; a negative value is rejected. - `lines.netTransactionAmount.amount` — Unsigned integer in minor units. The direction is in `dcSign`; a negative value is rejected. - `lines.taxTransactionAmount.amount` — Unsigned integer in minor units. The direction is in `dcSign`; a negative value is rejected. - `linkedInvoiceReceivable` — The linked **invoice receivable** (the description says payable). `null` when there are no links or more than one; on the list endpoint also `null` unless `include=INVOICE_RECEIVABLE`. ```json { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyEntityId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "amount": 100000, "customerName": "string", "customerId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "status": "DRAFT", "description": "string", "currency": "USD", "documentDate": "2026-01-15", "valuationDate": "2026-01-15", "areLinesWithTax": true, "lines": [ { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "customerCreditId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "grossTransactionAmount": { "amount": 100000, "dcSign": "D" }, "netTransactionAmount": { "amount": 100000, "dcSign": "D" }, "description": "string", "ledgerTaxId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "taxTransactionAmount": { "amount": 100000, "dcSign": "D" }, "ledgerAccountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "avataxCode": "string", "productId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "quantity": 0, "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z", "accrualTemplateId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "accrualStartDate": "2026-01-15", "accrualEndDate": "2026-01-15", "accrualDefaultDuration": 0 } ], "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z", "updatedBy": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "linkedInvoiceReceivable": { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "documentNumber": "string", "documentDate": "2026-01-15", "status": "DRAFT", "amount": 100000, "currency": "USD" } } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders. ## Code ```bash curl -X POST "https://api.light.inc/v1/customer-credits/3c90c3cc-0d44-4b50-8888-8dd25736052a/post-and-send-email" \ -H "Authorization: Basic YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "emailInfo": { "subject": "string", "replyTo": "string", "recipients": [ "string" ], "cc": [ "string" ], "customMessage": "string" }, "shouldSubmitEInvoice": true }' ``` Full page: https://light.inc/docs/api-reference/v1--customer-credits/post-and-send-customer-credit --- # Post customer credit > Posts the given customer credit and applies to invoice if linked `POST https://api.light.inc/v1/customer-credits/{customerCreditId}/post` ## Note Only from DRAFT , and only when the company's ledger is enabled ( CUSTOMER_CREDIT_CANNOT_BE_POSTED ). The body is optional. Posting assigns documentNumber if empty, writes the ledger entries, applies every link recorded while the credit was a draft (those invoices move to PARTIALLY_PAID or PAID , the credit to PARTIALLY_CLEARED or CLEARED ), and, if the company auto-allocates credits, may apply the remainder to the customer's other open invoices. An e-credit-note is queued when shouldSubmitEInvoice is true , or when it is omitted and a linked invoice was e-invoiced; true on an entity without that capability fails synchronously with CUSTOMER_CREDIT_E_INVOICING_NOT_ENABLED . The response reflects the state after links are applied. ## Authorization - API key - Bearer token See https://light.inc/docs/getting-started/authentication. ## Path parameters - `customerCreditId` (string, uuid, required) ## Request body `application/json;charset=UTF-8` ```json { "shouldSubmitEInvoice": true } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders, and fields that exclude each other are all shown. Do not send it unchanged. ## Response - `amount` — The header amount available to allocate, independent of the line totals; the link validations compare against it. - `lines.grossTransactionAmount.amount` — Unsigned integer in minor units. The direction is in `dcSign`; a negative value is rejected. - `lines.netTransactionAmount.amount` — Unsigned integer in minor units. The direction is in `dcSign`; a negative value is rejected. - `lines.taxTransactionAmount.amount` — Unsigned integer in minor units. The direction is in `dcSign`; a negative value is rejected. - `linkedInvoiceReceivable` — The linked **invoice receivable** (the description says payable). `null` when there are no links or more than one; on the list endpoint also `null` unless `include=INVOICE_RECEIVABLE`. ```json { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyEntityId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "amount": 100000, "customerName": "string", "customerId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "status": "DRAFT", "description": "string", "currency": "USD", "documentDate": "2026-01-15", "valuationDate": "2026-01-15", "areLinesWithTax": true, "lines": [ { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "customerCreditId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "grossTransactionAmount": { "amount": 100000, "dcSign": "D" }, "netTransactionAmount": { "amount": 100000, "dcSign": "D" }, "description": "string", "ledgerTaxId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "taxTransactionAmount": { "amount": 100000, "dcSign": "D" }, "ledgerAccountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "avataxCode": "string", "productId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "quantity": 0, "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z", "accrualTemplateId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "accrualStartDate": "2026-01-15", "accrualEndDate": "2026-01-15", "accrualDefaultDuration": 0 } ], "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z", "updatedBy": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "linkedInvoiceReceivable": { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "documentNumber": "string", "documentDate": "2026-01-15", "status": "DRAFT", "amount": 100000, "currency": "USD" } } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders. ## Code ```bash curl -X POST "https://api.light.inc/v1/customer-credits/3c90c3cc-0d44-4b50-8888-8dd25736052a/post" \ -H "Authorization: Basic YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "shouldSubmitEInvoice": true }' ``` Full page: https://light.inc/docs/api-reference/v1--customer-credits/post-customer-credit --- # Submit e-invoice for customer credit > Submits an e-invoice for the given customer credit. The customer credit must be posted. `POST https://api.light.inc/v1/customer-credits/{customerCreditId}/submit-einvoice` ## Note The credit must be posted ( CUSTOMER_CREDIT_INVALID_STATUS_FOR_EINVOICE_SUBMISSION ), not already submitted ( CUSTOMER_CREDIT_EINVOICE_ALREADY_SUBMITTED ), and its entity must have e-credit-note submission enabled ( CUSTOMER_CREDIT_E_INVOICING_NOT_ENABLED ). Unlike post , the submission runs synchronously inside this call. Returns an empty body. ## Authorization - API key - Bearer token See https://light.inc/docs/getting-started/authentication. ## Path parameters - `customerCreditId` (string, uuid, required) ## Response This endpoint returns no content. ## Code ```bash curl -X POST "https://api.light.inc/v1/customer-credits/3c90c3cc-0d44-4b50-8888-8dd25736052a/submit-einvoice" \ -H "Authorization: Basic YOUR_API_KEY" ``` Full page: https://light.inc/docs/api-reference/v1--customer-credits/submit-e-invoice-for-customer-credit --- # Unarchive customer credit > Unarchives the given customer credit and reverts it to draft `POST https://api.light.inc/v1/customer-credits/{customerCreditId}/unarchive` ## Note Only from ARCHIVED ( CUSTOMER_CREDIT_INVALID_STATUS_FOR_UNARCHIVE ). Lands in DRAFT and deletes every invoice link the credit still had. ## Authorization - API key - Bearer token See https://light.inc/docs/getting-started/authentication. ## Path parameters - `customerCreditId` (string, uuid, required) ## Response - `amount` — The header amount available to allocate, independent of the line totals; the link validations compare against it. - `lines.grossTransactionAmount.amount` — Unsigned integer in minor units. The direction is in `dcSign`; a negative value is rejected. - `lines.netTransactionAmount.amount` — Unsigned integer in minor units. The direction is in `dcSign`; a negative value is rejected. - `lines.taxTransactionAmount.amount` — Unsigned integer in minor units. The direction is in `dcSign`; a negative value is rejected. - `linkedInvoiceReceivable` — The linked **invoice receivable** (the description says payable). `null` when there are no links or more than one; on the list endpoint also `null` unless `include=INVOICE_RECEIVABLE`. ```json { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyEntityId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "amount": 100000, "customerName": "string", "customerId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "status": "DRAFT", "description": "string", "currency": "USD", "documentDate": "2026-01-15", "valuationDate": "2026-01-15", "areLinesWithTax": true, "lines": [ { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "customerCreditId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "grossTransactionAmount": { "amount": 100000, "dcSign": "D" }, "netTransactionAmount": { "amount": 100000, "dcSign": "D" }, "description": "string", "ledgerTaxId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "taxTransactionAmount": { "amount": 100000, "dcSign": "D" }, "ledgerAccountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "avataxCode": "string", "productId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "quantity": 0, "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z", "accrualTemplateId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "accrualStartDate": "2026-01-15", "accrualEndDate": "2026-01-15", "accrualDefaultDuration": 0 } ], "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z", "updatedBy": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "linkedInvoiceReceivable": { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "documentNumber": "string", "documentDate": "2026-01-15", "status": "DRAFT", "amount": 100000, "currency": "USD" } } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders. ## Code ```bash curl -X POST "https://api.light.inc/v1/customer-credits/3c90c3cc-0d44-4b50-8888-8dd25736052a/unarchive" \ -H "Authorization: Basic YOUR_API_KEY" ``` Full page: https://light.inc/docs/api-reference/v1--customer-credits/unarchive-customer-credit --- # Unlink customer credit from invoice > Unlinks a customer credit from a sales invoice. If the customer credit has already been applied (CLEARED or PARTIALLY_CLEARED status), this will reverse the clearing entries in the ledger. `POST https://api.light.inc/v1/customer-credits/{customerCreditId}/invoice-receivables/{invoiceReceivableId}/unlink` ## Note If the credit has already been applied, the clearing on the invoice is reversed first (the invoice goes back to OPEN or PARTIALLY_PAID ) and the credit returns to POSTED . A link that doesn't exist is CUSTOMER_CREDIT_INVOICE_RECEIVABLE_NOT_FOUND . Answers with an empty body. ## Authorization - API key - Bearer token See https://light.inc/docs/getting-started/authentication. ## Path parameters - `customerCreditId` (string, uuid, required) - `invoiceReceivableId` (string, uuid, required) ## Response This endpoint returns no content. ## Code ```bash curl -X POST "https://api.light.inc/v1/customer-credits/3c90c3cc-0d44-4b50-8888-8dd25736052a/invoice-receivables/3c90c3cc-0d44-4b50-8888-8dd25736052a/unlink" \ -H "Authorization: Basic YOUR_API_KEY" ``` Full page: https://light.inc/docs/api-reference/v1--customer-credits/unlink-customer-credit-from-invoice --- # Customers (resource) Customers are entities that purchase goods or services from a company. They can be used on invoices and contracts. Resource page: https://light.inc/docs/api-reference/v1--customers # Activate customer > Activate the given customer `POST https://api.light.inc/v1/customers/{customerId}/activate` ## Note Idempotent: activating an active customer returns 200 unchanged. ## Authorization - API key - Bearer token See https://light.inc/docs/getting-started/authentication. ## Path parameters - `customerId` (string, uuid, required) ## Response - `address` — Deprecated alias of `billingAddress`: the two are one value. - `address.city` — City. - `address.state` — State or region, where the country uses one. - `address.zipcode` — Postal code. - `address.street` — First address line. - `address.street2` — Second address line. - `billingAddress` — The address printed on invoices. - `billingAddress.city` — City. - `billingAddress.state` — State or region, where the country uses one. - `billingAddress.zipcode` — Postal code. - `billingAddress.street` — First address line. - `billingAddress.street2` — Second address line. - `shippingAddress` — Delivery address, when different from the billing address. - `shippingAddress.city` — City. - `shippingAddress.state` — State or region, where the country uses one. - `shippingAddress.zipcode` — Postal code. - `shippingAddress.street` — First address line. - `shippingAddress.street2` — Second address line. - `externalSource` — Set when the customer was imported from another system: the system's name and the customer's id there. ```json { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "name": "string", "email": "string", "address": { "country": "UNDEFINED", "city": "string", "state": "string", "zipcode": "string", "street": "string", "street2": "string" }, "billingAddress": { "country": "UNDEFINED", "city": "string", "state": "string", "zipcode": "string", "street": "string", "street2": "string" }, "shippingAddress": { "country": "UNDEFINED", "city": "string", "state": "string", "zipcode": "string", "street": "string", "street2": "string" }, "status": "ACTIVE", "description": "string", "vatNumber": "string", "businessRegistrationNumber": "string", "easCode": "string", "einvoiceAddress": "string", "einvoiceNetwork": "FR_PA", "type": "BUSINESS", "logoUrl": "string", "domain": "string", "externalSource": { "name": "CHARGEBEE", "externalId": "string" }, "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z", "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupInternalName": "string", "values": [ { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupInternalName": "string", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "internalName": "string", "label": "string", "context": "string", "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z" } ] } ], "recipientEmails": [ "string" ], "ccEmails": [ "string" ] } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders. ## Code ```bash curl -X POST "https://api.light.inc/v1/customers/3c90c3cc-0d44-4b50-8888-8dd25736052a/activate" \ -H "Authorization: Basic YOUR_API_KEY" ``` Full page: https://light.inc/docs/api-reference/v1--customers/activate-customer --- # Archive customer > Archive the given customer `POST https://api.light.inc/v1/customers/{customerId}/archive` ## Note Idempotent: archiving an archived customer returns 200 unchanged. Existing invoices and contracts are not affected, but the customer can no longer be updated until activated again. Statuses are ACTIVE and ARCHIVED . ## Authorization - API key - Bearer token See https://light.inc/docs/getting-started/authentication. ## Path parameters - `customerId` (string, uuid, required) ## Response - `address` — Deprecated alias of `billingAddress`: the two are one value. - `address.city` — City. - `address.state` — State or region, where the country uses one. - `address.zipcode` — Postal code. - `address.street` — First address line. - `address.street2` — Second address line. - `billingAddress` — The address printed on invoices. - `billingAddress.city` — City. - `billingAddress.state` — State or region, where the country uses one. - `billingAddress.zipcode` — Postal code. - `billingAddress.street` — First address line. - `billingAddress.street2` — Second address line. - `shippingAddress` — Delivery address, when different from the billing address. - `shippingAddress.city` — City. - `shippingAddress.state` — State or region, where the country uses one. - `shippingAddress.zipcode` — Postal code. - `shippingAddress.street` — First address line. - `shippingAddress.street2` — Second address line. - `externalSource` — Set when the customer was imported from another system: the system's name and the customer's id there. ```json { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "name": "string", "email": "string", "address": { "country": "UNDEFINED", "city": "string", "state": "string", "zipcode": "string", "street": "string", "street2": "string" }, "billingAddress": { "country": "UNDEFINED", "city": "string", "state": "string", "zipcode": "string", "street": "string", "street2": "string" }, "shippingAddress": { "country": "UNDEFINED", "city": "string", "state": "string", "zipcode": "string", "street": "string", "street2": "string" }, "status": "ACTIVE", "description": "string", "vatNumber": "string", "businessRegistrationNumber": "string", "easCode": "string", "einvoiceAddress": "string", "einvoiceNetwork": "FR_PA", "type": "BUSINESS", "logoUrl": "string", "domain": "string", "externalSource": { "name": "CHARGEBEE", "externalId": "string" }, "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z", "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupInternalName": "string", "values": [ { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupInternalName": "string", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "internalName": "string", "label": "string", "context": "string", "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z" } ] } ], "recipientEmails": [ "string" ], "ccEmails": [ "string" ] } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders. ## Code ```bash curl -X POST "https://api.light.inc/v1/customers/3c90c3cc-0d44-4b50-8888-8dd25736052a/archive" \ -H "Authorization: Basic YOUR_API_KEY" ``` Full page: https://light.inc/docs/api-reference/v1--customers/archive-customer --- # List customers > Returns a paginated list of customers `GET https://api.light.inc/v1/customers` ## Note Default order is name:asc ; searchTerm is supported. ## Authorization - API key - Bearer token See https://light.inc/docs/getting-started/authentication. ## Query parameters - `sort` (string) — Sort string in the format field:direction . To provide multiple sort fields, separate them with commas. Available directions: asc , desc . Available fields: name , email , createdAt , updatedAt . - `filter` (string) — Filter string in the format field:operator:value . To provide multiple filters, separate them with commas. Available operators: eq , ne , in , not_in , gt , gte , lt , lte . - For in and not_in operators, provide multiple values separated by the pipe character ( ). Available fields: billingAddressCity , billingAddressCountry , businessRegistrationNumber , createdAt , description , email , externalSourceId , externalSourceName , id , name , status , updatedAt , vatNumber . These fields accept only a subset of the operators: externalSourceId ( eq , in ), externalSourceName ( eq , in ). - `searchTerm` (string) — Search term to filter results by. Performs a case-insensitive partial match across searchable fields. - `limit` (integer, int32) — Maximum number of items to return. Default is 50, maximum is 200. - `offset` (integer, int64) — Number of items to skip before starting to collect the result set. Deprecated, use 'cursor' instead. - `cursor` (string) — The cursor position to start returning results from. To opt-in into cursor-based pagination, provide 0 for the initial request. For subsequent requests, use nextCursor and prevCursor from the previous response to navigate. Cursor values are opaque and should not be constructed manually. ## Response - `records.address` — Deprecated alias of `billingAddress`: the two are one value. - `records.address.city` — City. - `records.address.state` — State or region, where the country uses one. - `records.address.zipcode` — Postal code. - `records.address.street` — First address line. - `records.address.street2` — Second address line. - `records.billingAddress` — The address printed on invoices. - `records.billingAddress.city` — City. - `records.billingAddress.state` — State or region, where the country uses one. - `records.billingAddress.zipcode` — Postal code. - `records.billingAddress.street` — First address line. - `records.billingAddress.street2` — Second address line. - `records.shippingAddress` — Delivery address, when different from the billing address. - `records.shippingAddress.city` — City. - `records.shippingAddress.state` — State or region, where the country uses one. - `records.shippingAddress.zipcode` — Postal code. - `records.shippingAddress.street` — First address line. - `records.shippingAddress.street2` — Second address line. - `records.externalSource` — Set when the customer was imported from another system: the system's name and the customer's id there. ```json { "records": [ { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "name": "string", "email": "string", "address": { "country": "UNDEFINED", "city": "string", "state": "string", "zipcode": "string", "street": "string", "street2": "string" }, "billingAddress": { "country": "UNDEFINED", "city": "string", "state": "string", "zipcode": "string", "street": "string", "street2": "string" }, "shippingAddress": { "country": "UNDEFINED", "city": "string", "state": "string", "zipcode": "string", "street": "string", "street2": "string" }, "status": "ACTIVE", "description": "string", "vatNumber": "string", "businessRegistrationNumber": "string", "easCode": "string", "einvoiceAddress": "string", "einvoiceNetwork": "FR_PA", "type": "BUSINESS", "logoUrl": "string", "domain": "string", "externalSource": { "name": "CHARGEBEE", "externalId": "string" }, "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z", "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupInternalName": "string", "values": [ {} ] } ], "recipientEmails": [ "string" ], "ccEmails": [ "string" ] } ], "hasMore": true, "total": 100000, "nextCursor": "string", "prevCursor": "string" } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders. ## Code ```bash curl -X GET "https://api.light.inc/v1/customers" \ -H "Authorization: Basic YOUR_API_KEY" ``` Full page: https://light.inc/docs/api-reference/v1--customers/list-customers --- # Create customer > Creates a new customer `POST https://api.light.inc/v1/customers` ## Note Nothing is checked for uniqueness: the same name, email or VAT number can be created any number of times, so de-duplicate on your side. address is a deprecated alias of billingAddress (one value, returned under both names). email must be a valid address ( CUSTOMER_INVALID_EMAIL ). For a French billing address the VAT number and registration number are cross-checked ( CUSTOMER_INVALID_FRENCH_IDENTIFIERS ) and a missing SIREN is derived from the VAT number. Created ACTIVE . ## Authorization - API key - Bearer token See https://light.inc/docs/getting-started/authentication. ## Header parameters - `X-Idempotency-Key` (string) ## Request body `application/json;charset=UTF-8` - `address.city` — City. - `address.state` — State or region, where the country uses one. - `address.zipcode` — Postal code. - `address.street` — First address line. - `address.street2` — Second address line. - `billingAddress.city` — City. - `billingAddress.state` — State or region, where the country uses one. - `billingAddress.zipcode` — Postal code. - `billingAddress.street` — First address line. - `billingAddress.street2` — Second address line. - `shippingAddress.city` — City. - `shippingAddress.state` — State or region, where the country uses one. - `shippingAddress.zipcode` — Postal code. - `shippingAddress.street` — First address line. - `shippingAddress.street2` — Second address line. - `customProperties.valueIds` — Catalogue value ids for this group. Required; send `[]` (with an empty `inlineValues`) to clear the group. `SINGLE_SELECT` and `MULTI_SELECT` groups accept nothing else. See [Custom properties on writes](/docs/getting-started/pagination-filtering-errors#custom-properties-on-writes). - `customProperties.inlineValues` — Literal values for `TEXT`, `NUMERIC`, `BOOLEAN` and `DATE` groups, as strings (`yyyy-MM-dd` for dates). Rejected on select groups with `CUSTOM_PROPERTY_VALUE_TYPE_MISMATCH`. See [Custom properties on writes](/docs/getting-started/pagination-filtering-errors#custom-properties-on-writes). ```json { "name": "Acme Industries Ltd", "email": "accounts@acme.example", "type": "BUSINESS", "vatNumber": "GB123456789", "billingAddress": { "country": "GB", "street": "1 Example Street", "city": "London", "zipcode": "EC1A 1BB" } } ``` This example is hand-written and valid as shown, with placeholder ids. ## Response - `address` — Deprecated alias of `billingAddress`: the two are one value. - `address.city` — City. - `address.state` — State or region, where the country uses one. - `address.zipcode` — Postal code. - `address.street` — First address line. - `address.street2` — Second address line. - `billingAddress` — The address printed on invoices. - `billingAddress.city` — City. - `billingAddress.state` — State or region, where the country uses one. - `billingAddress.zipcode` — Postal code. - `billingAddress.street` — First address line. - `billingAddress.street2` — Second address line. - `shippingAddress` — Delivery address, when different from the billing address. - `shippingAddress.city` — City. - `shippingAddress.state` — State or region, where the country uses one. - `shippingAddress.zipcode` — Postal code. - `shippingAddress.street` — First address line. - `shippingAddress.street2` — Second address line. - `externalSource` — Set when the customer was imported from another system: the system's name and the customer's id there. ```json { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "name": "string", "email": "string", "address": { "country": "UNDEFINED", "city": "string", "state": "string", "zipcode": "string", "street": "string", "street2": "string" }, "billingAddress": { "country": "UNDEFINED", "city": "string", "state": "string", "zipcode": "string", "street": "string", "street2": "string" }, "shippingAddress": { "country": "UNDEFINED", "city": "string", "state": "string", "zipcode": "string", "street": "string", "street2": "string" }, "status": "ACTIVE", "description": "string", "vatNumber": "string", "businessRegistrationNumber": "string", "easCode": "string", "einvoiceAddress": "string", "einvoiceNetwork": "FR_PA", "type": "BUSINESS", "logoUrl": "string", "domain": "string", "externalSource": { "name": "CHARGEBEE", "externalId": "string" }, "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z", "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupInternalName": "string", "values": [ { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupInternalName": "string", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "internalName": "string", "label": "string", "context": "string", "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z" } ] } ], "recipientEmails": [ "string" ], "ccEmails": [ "string" ] } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders. ## Code ```bash curl -X POST "https://api.light.inc/v1/customers" \ -H "Authorization: Basic YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "name": "Acme Industries Ltd", "email": "accounts@acme.example", "type": "BUSINESS", "vatNumber": "GB123456789", "billingAddress": { "country": "GB", "street": "1 Example Street", "city": "London", "zipcode": "EC1A 1BB" } }' ``` Full page: https://light.inc/docs/api-reference/v1--customers/create-customer --- # Get customer > Returns a customer by ID `GET https://api.light.inc/v1/customers/{customerId}` ## Note Returns the customer whatever its status, archived included. An unknown id, or one from another company, is 404 . ## Authorization - API key - Bearer token See https://light.inc/docs/getting-started/authentication. ## Path parameters - `customerId` (string, uuid, required) ## Response - `address` — Deprecated alias of `billingAddress`: the two are one value. - `address.city` — City. - `address.state` — State or region, where the country uses one. - `address.zipcode` — Postal code. - `address.street` — First address line. - `address.street2` — Second address line. - `billingAddress` — The address printed on invoices. - `billingAddress.city` — City. - `billingAddress.state` — State or region, where the country uses one. - `billingAddress.zipcode` — Postal code. - `billingAddress.street` — First address line. - `billingAddress.street2` — Second address line. - `shippingAddress` — Delivery address, when different from the billing address. - `shippingAddress.city` — City. - `shippingAddress.state` — State or region, where the country uses one. - `shippingAddress.zipcode` — Postal code. - `shippingAddress.street` — First address line. - `shippingAddress.street2` — Second address line. - `externalSource` — Set when the customer was imported from another system: the system's name and the customer's id there. ```json { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "name": "string", "email": "string", "address": { "country": "UNDEFINED", "city": "string", "state": "string", "zipcode": "string", "street": "string", "street2": "string" }, "billingAddress": { "country": "UNDEFINED", "city": "string", "state": "string", "zipcode": "string", "street": "string", "street2": "string" }, "shippingAddress": { "country": "UNDEFINED", "city": "string", "state": "string", "zipcode": "string", "street": "string", "street2": "string" }, "status": "ACTIVE", "description": "string", "vatNumber": "string", "businessRegistrationNumber": "string", "easCode": "string", "einvoiceAddress": "string", "einvoiceNetwork": "FR_PA", "type": "BUSINESS", "logoUrl": "string", "domain": "string", "externalSource": { "name": "CHARGEBEE", "externalId": "string" }, "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z", "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupInternalName": "string", "values": [ { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupInternalName": "string", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "internalName": "string", "label": "string", "context": "string", "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z" } ] } ], "recipientEmails": [ "string" ], "ccEmails": [ "string" ] } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders. ## Code ```bash curl -X GET "https://api.light.inc/v1/customers/3c90c3cc-0d44-4b50-8888-8dd25736052a" \ -H "Authorization: Basic YOUR_API_KEY" ``` Full page: https://light.inc/docs/api-reference/v1--customers/get-customer --- # Update customer > Updates an existing customer `PATCH https://api.light.inc/v1/customers/{customerId}` ## Note An ARCHIVED customer cannot be updated ( CUSTOMER_CANNOT_BE_MODIFIED ); activate it first. null clears shippingAddress , domain , description , vatNumber , businessRegistrationNumber , the e-invoicing fields, type and logoUrl , but leaves name , email and the billing address unchanged. recipientEmails and ccEmails : omit to keep, [] to clear. ## Authorization - API key - Bearer token See https://light.inc/docs/getting-started/authentication. ## Path parameters - `customerId` (string, uuid, required) ## Header parameters - `X-Idempotency-Key` (string) ## Request body `application/json;charset=UTF-8` - `address.city` — City. - `address.state` — State or region, where the country uses one. - `address.zipcode` — Postal code. - `address.street` — First address line. - `address.street2` — Second address line. - `billingAddress.city` — City. - `billingAddress.state` — State or region, where the country uses one. - `billingAddress.zipcode` — Postal code. - `billingAddress.street` — First address line. - `billingAddress.street2` — Second address line. - `customProperties.valueIds` — Catalogue value ids for this group. Required; send `[]` (with an empty `inlineValues`) to clear the group. `SINGLE_SELECT` and `MULTI_SELECT` groups accept nothing else. See [Custom properties on writes](/docs/getting-started/pagination-filtering-errors#custom-properties-on-writes). - `customProperties.inlineValues` — Literal values for `TEXT`, `NUMERIC`, `BOOLEAN` and `DATE` groups, as strings (`yyyy-MM-dd` for dates). Rejected on select groups with `CUSTOM_PROPERTY_VALUE_TYPE_MISMATCH`. See [Custom properties on writes](/docs/getting-started/pagination-filtering-errors#custom-properties-on-writes). - `shippingAddress.city` — City. - `shippingAddress.state` — State or region, where the country uses one. - `shippingAddress.zipcode` — Postal code. - `shippingAddress.street` — First address line. - `shippingAddress.street2` — Second address line. ```json { "name": "string", "email": "string", "address": { "country": "UNDEFINED", "city": "string", "state": "string", "zipcode": "string", "street": "string", "street2": "string" }, "billingAddress": { "country": "UNDEFINED", "city": "string", "state": "string", "zipcode": "string", "street": "string", "street2": "string" }, "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "valueIds": [ "3c90c3cc-0d44-4b50-8888-8dd25736052a" ], "inlineValues": [ "string" ] } ], "shippingAddress": { "country": "UNDEFINED", "city": "string", "state": "string", "zipcode": "string", "street": "string", "street2": "string" }, "domain": "string", "description": "string", "vatNumber": "string", "businessRegistrationNumber": "string", "easCode": "string", "einvoiceAddress": "string", "einvoiceNetwork": "FR_PA", "type": "BUSINESS", "logoUrl": "string", "recipientEmails": [ "string" ], "ccEmails": [ "string" ] } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders, and fields that exclude each other are all shown. Do not send it unchanged. ## Response - `address` — Deprecated alias of `billingAddress`: the two are one value. - `address.city` — City. - `address.state` — State or region, where the country uses one. - `address.zipcode` — Postal code. - `address.street` — First address line. - `address.street2` — Second address line. - `billingAddress` — The address printed on invoices. - `billingAddress.city` — City. - `billingAddress.state` — State or region, where the country uses one. - `billingAddress.zipcode` — Postal code. - `billingAddress.street` — First address line. - `billingAddress.street2` — Second address line. - `shippingAddress` — Delivery address, when different from the billing address. - `shippingAddress.city` — City. - `shippingAddress.state` — State or region, where the country uses one. - `shippingAddress.zipcode` — Postal code. - `shippingAddress.street` — First address line. - `shippingAddress.street2` — Second address line. - `externalSource` — Set when the customer was imported from another system: the system's name and the customer's id there. ```json { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "name": "string", "email": "string", "address": { "country": "UNDEFINED", "city": "string", "state": "string", "zipcode": "string", "street": "string", "street2": "string" }, "billingAddress": { "country": "UNDEFINED", "city": "string", "state": "string", "zipcode": "string", "street": "string", "street2": "string" }, "shippingAddress": { "country": "UNDEFINED", "city": "string", "state": "string", "zipcode": "string", "street": "string", "street2": "string" }, "status": "ACTIVE", "description": "string", "vatNumber": "string", "businessRegistrationNumber": "string", "easCode": "string", "einvoiceAddress": "string", "einvoiceNetwork": "FR_PA", "type": "BUSINESS", "logoUrl": "string", "domain": "string", "externalSource": { "name": "CHARGEBEE", "externalId": "string" }, "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z", "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupInternalName": "string", "values": [ { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupInternalName": "string", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "internalName": "string", "label": "string", "context": "string", "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z" } ] } ], "recipientEmails": [ "string" ], "ccEmails": [ "string" ] } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders. ## Code ```bash curl -X PATCH "https://api.light.inc/v1/customers/3c90c3cc-0d44-4b50-8888-8dd25736052a" \ -H "Authorization: Basic YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "name": "string", "email": "string", "address": { "country": "UNDEFINED", "city": "string", "state": "string", "zipcode": "string", "street": "string", "street2": "string" }, "billingAddress": { "country": "UNDEFINED", "city": "string", "state": "string", "zipcode": "string", "street": "string", "street2": "string" }, "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "valueIds": [ "3c90c3cc-0d44-4b50-8888-8dd25736052a" ], "inlineValues": [ "string" ] } ], "shippingAddress": { "country": "UNDEFINED", "city": "string", "state": "string", "zipcode": "string", "street": "string", "street2": "string" }, "domain": "string", "description": "string", "vatNumber": "string", "businessRegistrationNumber": "string", "easCode": "string", "einvoiceAddress": "string", "einvoiceNetwork": "FR_PA", "type": "BUSINESS", "logoUrl": "string", "recipientEmails": [ "string" ], "ccEmails": [ "string" ] }' ``` Full page: https://light.inc/docs/api-reference/v1--customers/update-customer --- # Exchange (resource) Retrieve currency exchange rates. Resource page: https://light.inc/docs/api-reference/v1--exchange # Get exchange rate > Returns an exchange rate between base and target currencies for a given date `GET https://api.light.inc/v1/exchange/rates/{base}/{target}` ## Note rate is the number of target units per one unit of base ( amountInTarget = amountInBase × rate ). Rates are the European Central Bank's daily reference rates (a second provider covers currencies the ECB doesn't publish), stored by Light once a day and served from that store: the endpoint never calls a provider live, and company-specific rate overrides are ignored. date omitted means today; a future date is clamped to the latest stored day ( effectiveDate says which); weekends and holidays resolve to the last published rate. A past date with no stored row fails with EXCHANGE_RATE_NOT_AVAILABLE . ## Authorization - API key - Bearer token See https://light.inc/docs/getting-started/authentication. ## Path parameters - `base` (string, required) — Base currency of the exchange rate - `target` (string, required) — Target currency of the exchange rate ## Query parameters - `date` (string) — Date the exchange rate is requested for. If omitted, defaults to today ## Response ```json { "base": "USD", "target": "USD", "rate": 0, "effectiveDate": "2026-01-15", "requestedDate": "2026-01-15" } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders. ## Code ```bash curl -X GET "https://api.light.inc/v1/exchange/rates/string/string" \ -H "Authorization: Basic YOUR_API_KEY" ``` Full page: https://light.inc/docs/api-reference/v1--exchange/get-exchange-rate --- # Get currency exchange rates > Returns exchange rates for the given currency against all available currencies `GET https://api.light.inc/v1/exchange/rates/{currency}` ## Note Same source and date handling as the pair endpoint: one entry per currency available on the resolved date, including currency itself at 1 . Any currency missing on that date fails the whole request with EXCHANGE_RATE_NOT_AVAILABLE . ## Authorization - API key - Bearer token See https://light.inc/docs/getting-started/authentication. ## Path parameters - `currency` (string, required) — Currency for which available exchange rates are requested for ## Query parameters - `date` (string, date) — Date the exchange rate is requested for. If omitted, defaults to today ## Response ```json [ { "base": "USD", "target": "USD", "rate": 0, "effectiveDate": "2026-01-15", "requestedDate": "2026-01-15" } ] ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders. ## Code ```bash curl -X GET "https://api.light.inc/v1/exchange/rates/string" \ -H "Authorization: Basic YOUR_API_KEY" ``` Full page: https://light.inc/docs/api-reference/v1--exchange/get-currency-exchange-rates --- # Expenses (resource) List expenses and submit reimbursements. Resource page: https://light.inc/docs/api-reference/v1--expenses # Cancel expense > Cancels an existing expense `POST https://api.light.inc/v1/expenses/{expenseId}/cancel` ## Note Allowed only in IN_DRAFT or CREATED ; a submitted expense fails with EXPENSE_NOT_EDITABLE . CANCELLED is terminal. ## Authorization - API key - Bearer token See https://light.inc/docs/getting-started/authentication. ## Path parameters - `expenseId` (string, uuid, required) ## Response ```json { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "receiptDocumentKey": "string", "originalCurrency": "USD", "billingCurrency": "USD", "status": "CREATED", "userId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "performedDate": "2026-01-15", "detailedDescription": "string", "lineItems": [ { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "expenseId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "originalAmount": 100000, "billingAmount": 100000, "accountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "costCenterId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "description": "string", "reimbursementCategoryId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z" } ], "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z" } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders. ## Code ```bash curl -X POST "https://api.light.inc/v1/expenses/3c90c3cc-0d44-4b50-8888-8dd25736052a/cancel" \ -H "Authorization: Basic YOUR_API_KEY" ``` Full page: https://light.inc/docs/api-reference/v1--expenses/cancel-expense --- # List expenses > Returns a paginated list of expenses `GET https://api.light.inc/v1/expenses` ## Note A credential with only the reimbursement role must filter userId:eq: Creates an expense synchronously from a receipt uploaded with shouldAutoCreateExpense: false and the given line items. No OCR runs: the fields you send are what is stored. A PDF receipt is kept as-is; JPEG, PNG, HEIC and TIFF receipts are converted to PDF first. The expense is created as a draft for the authenticated user and is included in the next POST /v1/expenses/submit. `POST https://api.light.inc/v1/expenses` ## Note Requires a user credential with the reimbursement role; under an API key it fails with USER_NOT_RECOGNIZED . The user needs an active reimbursement configuration first ( PUT /v1/users/{userId}/reimbursement-config ), or the call fails with MISSING_USER_REIMBURSEMENT_CONFIG . receiptDocumentKey must be a key from POST /v1/expenses/upload-url with shouldAutoCreateExpense: false , uploaded by the same user: anything else is 404 EXPENSE_RECEIPT_NOT_FOUND . An empty file or one over 10 MB fails with EXPENSE_RECEIPT_INVALID ; a key already used by another expense is 409 EXPENSE_RECEIPT_ALREADY_USED . Images are converted to PDF synchronously, so the stored receiptDocumentKey may differ from the one you sent. Validation ( EXPENSE_VALIDATION_FAILED , with a path per error): 1 to 50 lines, originalAmount above zero, non-blank descriptions, and each reimbursementCategoryId belonging to the user's own entity. costCenterId is ignored: every line takes the default cost centre from the user's reimbursement configuration. When originalCurrency differs from the user's reimbursement currency and no billingAmount is given, it is derived from the exchange rate on performedDate , and a missing rate fails the whole call with EXPENSE_BILLING_AMOUNT_DERIVATION_FAILED . X-Idempotency-Key is honoured per user: the same key and body returns the existing expense; the same key with a different body is 409 IDEMPOTENCY_VIOLATION . The expense is created in IN_DRAFT . ## Authorization - API key - Bearer token See https://light.inc/docs/getting-started/authentication. ## Header parameters - `X-Idempotency-Key` (string) ## Request body `application/json;charset=UTF-8` ```json { "receiptDocumentKey": "string", "originalCurrency": "USD", "performedDate": "2026-01-15", "detailedDescription": "string", "lineItems": [ { "originalAmount": 100000, "billingAmount": 100000, "description": "string", "reimbursementCategoryId": "3c90c3cc-0d44-4b50-8888-8dd25736052a" } ] } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders, and fields that exclude each other are all shown. Do not send it unchanged. ## Response ```json { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "receiptDocumentKey": "string", "originalCurrency": "USD", "billingCurrency": "USD", "status": "CREATED", "userId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "performedDate": "2026-01-15", "detailedDescription": "string", "lineItems": [ { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "expenseId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "originalAmount": 100000, "billingAmount": 100000, "accountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "costCenterId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "description": "string", "reimbursementCategoryId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z" } ], "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z" } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders. ## Code ```bash curl -X POST "https://api.light.inc/v1/expenses" \ -H "Authorization: Basic YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "receiptDocumentKey": "string", "originalCurrency": "USD", "performedDate": "2026-01-15", "detailedDescription": "string", "lineItems": [ { "originalAmount": 100000, "billingAmount": 100000, "description": "string", "reimbursementCategoryId": "3c90c3cc-0d44-4b50-8888-8dd25736052a" } ] }' ``` Full page: https://light.inc/docs/api-reference/v1--expenses/create-expense --- # Create line item > Creates a new line item `POST https://api.light.inc/v1/expenses/{expenseId}/line-items` ## Note Every field is optional here; reimbursementCategoryId , originalAmount and description only become mandatory at POST /v1/expenses/submit . What is given is validated: the category (and any accountId ) must belong to the user's entity ( EXPENSE_VALIDATION_FAILED ). billingAmount is derived from originalAmount when the expense already has a currency and date. Only while the expense is IN_DRAFT or CREATED . ## Authorization - API key - Bearer token See https://light.inc/docs/getting-started/authentication. ## Path parameters - `expenseId` (string, uuid, required) ## Request body `application/json;charset=UTF-8` ```json { "originalAmount": 100000, "billingAmount": 100000, "accountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "costCenterId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "description": "string", "reimbursementCategoryId": "3c90c3cc-0d44-4b50-8888-8dd25736052a" } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders, and fields that exclude each other are all shown. Do not send it unchanged. ## Response ```json { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "expenseId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "originalAmount": 100000, "billingAmount": 100000, "accountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "costCenterId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "description": "string", "reimbursementCategoryId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z" } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders. ## Code ```bash curl -X POST "https://api.light.inc/v1/expenses/3c90c3cc-0d44-4b50-8888-8dd25736052a/line-items" \ -H "Authorization: Basic YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "originalAmount": 100000, "billingAmount": 100000, "accountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "costCenterId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "description": "string", "reimbursementCategoryId": "3c90c3cc-0d44-4b50-8888-8dd25736052a" }' ``` Full page: https://light.inc/docs/api-reference/v1--expenses/create-line-item --- # Delete line item > Deletes an existing line item `DELETE https://api.light.inc/v1/expenses/{expenseId}/line-items/{lineItemId}` ## Note Only while the expense is IN_DRAFT or CREATED ( EXPENSE_NOT_EDITABLE ). Answers with an empty body. ## Authorization - API key - Bearer token See https://light.inc/docs/getting-started/authentication. ## Path parameters - `expenseId` (string, uuid, required) - `lineItemId` (string, uuid, required) ## Response This endpoint returns no content. ## Code ```bash curl -X DELETE "https://api.light.inc/v1/expenses/3c90c3cc-0d44-4b50-8888-8dd25736052a/line-items/3c90c3cc-0d44-4b50-8888-8dd25736052a" \ -H "Authorization: Basic YOUR_API_KEY" ``` Full page: https://light.inc/docs/api-reference/v1--expenses/delete-line-item --- # Update line item > Updates an existing expense line item `PATCH https://api.light.inc/v1/expenses/{expenseId}/line-items/{lineItemId}` ## Note Omit a field to keep it, send null to clear it. Only while the expense is IN_DRAFT or CREATED ( EXPENSE_NOT_EDITABLE ); unknown line is 404 EXPENSE_LINE_ITEM_NOT_FOUND . ## Authorization - API key - Bearer token See https://light.inc/docs/getting-started/authentication. ## Path parameters - `expenseId` (string, uuid, required) - `lineItemId` (string, uuid, required) ## Request body `application/json;charset=UTF-8` ```json { "originalAmount": 100000, "billingAmount": 100000, "accountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "costCenterId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "description": "string", "reimbursementCategoryId": "3c90c3cc-0d44-4b50-8888-8dd25736052a" } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders, and fields that exclude each other are all shown. Do not send it unchanged. ## Response ```json { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "expenseId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "originalAmount": 100000, "billingAmount": 100000, "accountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "costCenterId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "description": "string", "reimbursementCategoryId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z" } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders. ## Code ```bash curl -X PATCH "https://api.light.inc/v1/expenses/3c90c3cc-0d44-4b50-8888-8dd25736052a/line-items/3c90c3cc-0d44-4b50-8888-8dd25736052a" \ -H "Authorization: Basic YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "originalAmount": 100000, "billingAmount": 100000, "accountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "costCenterId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "description": "string", "reimbursementCategoryId": "3c90c3cc-0d44-4b50-8888-8dd25736052a" }' ``` Full page: https://light.inc/docs/api-reference/v1--expenses/update-line-item --- # Create upload URL > Creates a pre-signed URL for uploading an expense receipt document `POST https://api.light.inc/v1/expenses/upload-url` ## Note Requires a user credential with the reimbursement role; an API key is a service account, and with one the upload succeeds but no expense ever appears. The URL is valid for five minutes; PUT the bytes with the declared Content-Type and every entry of metadata as a request header (see Files (/docs/getting-started/pagination-filtering-errors files)). Two modes. With shouldAutoCreateExpense omitted or true , Light creates an expense for the uploading user in status CREATED , runs OCR, and moves it to IN_DRAFT with the extracted fields; nothing returns its id, so find it with GET /v1/expenses?filter=userId:eq: Returns an expense by ID including all line items `GET https://api.light.inc/v1/expenses/{expenseId}` ## Note Includes line items. Company admins and auditors can read any expense; a user with the reimbursement role only their own. A key with neither gets 403 . ## Authorization - API key - Bearer token See https://light.inc/docs/getting-started/authentication. ## Path parameters - `expenseId` (string, uuid, required) ## Response ```json { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "receiptDocumentKey": "string", "originalCurrency": "USD", "billingCurrency": "USD", "status": "CREATED", "userId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "performedDate": "2026-01-15", "detailedDescription": "string", "lineItems": [ { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "expenseId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "originalAmount": 100000, "billingAmount": 100000, "accountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "costCenterId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "description": "string", "reimbursementCategoryId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z" } ], "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z" } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders. ## Code ```bash curl -X GET "https://api.light.inc/v1/expenses/3c90c3cc-0d44-4b50-8888-8dd25736052a" \ -H "Authorization: Basic YOUR_API_KEY" ``` Full page: https://light.inc/docs/api-reference/v1--expenses/get-expense --- # Update expense > Updates an existing expense `PATCH https://api.light.inc/v1/expenses/{expenseId}` ## Note Allowed only in IN_DRAFT or CREATED ( EXPENSE_NOT_EDITABLE otherwise). Both fields follow the omit-to-keep, null -to-clear rule, but sending neither fails with EMPTY_EXPENSE_UPDATE_EXCEPTION . Changing originalCurrency or performedDate recalculates every line's billingAmount from the exchange rate; clearing either sets them all to null . ## Authorization - API key - Bearer token See https://light.inc/docs/getting-started/authentication. ## Path parameters - `expenseId` (string, uuid, required) ## Request body `application/json;charset=UTF-8` ```json { "originalCurrency": "USD", "performedDate": "2026-01-15" } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders, and fields that exclude each other are all shown. Do not send it unchanged. ## Response ```json { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "receiptDocumentKey": "string", "originalCurrency": "USD", "billingCurrency": "USD", "status": "CREATED", "userId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "performedDate": "2026-01-15", "detailedDescription": "string", "lineItems": [ { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "expenseId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "originalAmount": 100000, "billingAmount": 100000, "accountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "costCenterId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "description": "string", "reimbursementCategoryId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z" } ], "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z" } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders. ## Code ```bash curl -X PATCH "https://api.light.inc/v1/expenses/3c90c3cc-0d44-4b50-8888-8dd25736052a" \ -H "Authorization: Basic YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "originalCurrency": "USD", "performedDate": "2026-01-15" }' ``` Full page: https://light.inc/docs/api-reference/v1--expenses/update-expense --- # Get expense document > Returns the attached receipt document as a PDF download `GET https://api.light.inc/v1/expenses/{expenseId}/document` ## Note Answers 307 Temporary Redirect to a pre-signed download URL valid for two hours, not the PDF bytes; follow it without your Light Authorization header. ## Authorization - API key - Bearer token See https://light.inc/docs/getting-started/authentication. ## Path parameters - `expenseId` (string, uuid, required) ## Response Returns a file (application/pdf) rather than JSON. ## Code ```bash curl -X GET "https://api.light.inc/v1/expenses/3c90c3cc-0d44-4b50-8888-8dd25736052a/document" \ -H "Authorization: Basic YOUR_API_KEY" ``` Full page: https://light.inc/docs/api-reference/v1--expenses/get-expense-document --- # Submit reimbursement > Submits all pending expenses from the current user for administrator review and approval `POST https://api.light.inc/v1/expenses/submit` ## Note Acts on the credential's user , so it needs a user credential with the reimbursement role; an API key fails with USER_NOT_RECOGNIZED . It submits every expense of that user in IN_DRAFT — those still in CREATED (OCR not finished) are skipped — moves them to SUBMITTED_FOR_REVIEW , creates one reimbursement in IN_PROGRESS and starts the company's approval workflow. It returns an empty body; read the result with GET /v1/users/{userId}/reimbursements/latest . With no drafts it is a silent no-op. All-or-nothing preconditions: the user has an address and postcode ( USER_MISSING_ADDRESS ); the reimbursement configuration has bank details, either domestic code and number or IBAN and BIC ( USER_INVALID_BANK_DETAILS ); and every draft has originalCurrency , performedDate , and on each line originalAmount , billingAmount , description and a category ( EXPENSE_MISSING_FIELD , EXPENSE_LINE_MISSING_FIELD ). One incomplete draft blocks the whole submission. ## Authorization - API key - Bearer token See https://light.inc/docs/getting-started/authentication. ## Response This endpoint returns no content. ## Code ```bash curl -X POST "https://api.light.inc/v1/expenses/submit" \ -H "Authorization: Basic YOUR_API_KEY" ``` Full page: https://light.inc/docs/api-reference/v1--expenses/submit-reimbursement --- # General Ledger Summary (resource) Read the general ledger summary. Resource page: https://light.inc/docs/api-reference/v1--general-ledger-summary # Get general ledger summary > Returns the opening balance, net movement and closing balance of every account over a date range. Each account carries one figure per entity in scope, the subtotal of those entities' own books, the intercompany elimination the selection is entitled to, and their total . Without a company entity filter the scope is every entity of the company, including inactive ones. An elimination between two entities applies only when both are in scope; one belonging to the group as a whole applies only when the scope covers the whole company. `GET https://api.light.inc/v1/general-ledger-summary` ## Note The cursor description below is wrong for this endpoint. Sending cursor=0 is rejected with {"name": "InvalidCursorException", "errors": [{"type": "INVALID_CURSOR"}]} . Omit cursor on the first request and pass nextCursor back verbatim; there is no offset parameter, no total , and prevCursor is always null . Only accountCode is sortable, and limit cannot exceed 200. Balances are debit-positive (a credit balance is negative), the opposite polarity to the signed amounts on GET /v1/ledger-transaction-lines . from and to are both required ( MISSING_PARAMETER ), from must not be after to , the opening balance covers every posting before from , and the movement covers from to to inclusive. Entity filters ( companyEntityId , companyEntityCode ) accept only eq , ne , in and not_in ( UNSUPPORTED_GENERAL_LEDGER_SUMMARY_FILTER_OPERATOR ); an entity filter that matches nothing returns rows with empty entities and zero figures. At most two concurrent calls per credential ( 429 beyond that). Reading amounts (/docs/concepts/reading-amounts) sets out the polarity rules. ## Authorization - API key - Bearer token See https://light.inc/docs/getting-started/authentication. ## Query parameters - `from` (string, date) — First day included in the movement figures, inclusive. A UTC calendar date in YYYY-MM-DD format. - `to` (string, date) — Last day included in the movement figures, inclusive. A UTC calendar date in YYYY-MM-DD format. - `sort` (string) — Sort string in the format field:direction . To provide multiple sort fields, separate them with commas. Available directions: asc , desc . Available fields: accountCode . - `filter` (string) — Filter string in the format field:operator:value . To provide multiple filters, separate them with commas. Available operators: eq , ne , in , not_in , gt , gte , lt , lte . - For in and not_in operators, provide multiple values separated by the pipe character ( ). Available fields: accountCode , accountId , accountType , companyEntityCode , companyEntityId . - `limit` (integer, int32) — Maximum number of items to return. Default is 50, maximum is 200. - `cursor` (string) — The cursor position to start returning results from. Omit it, or provide 0 , for the initial request. For subsequent requests, use nextCursor from the previous response to navigate. Cursor values are opaque and should not be constructed manually. This endpoint paginates by cursor only and has no offset parameter. ## Response - `records.accountId` — The ledger account. - `records.accountCode` — Its numeric code in the chart of accounts. - `records.accountLabel` — Its name. - `records.entities.companyEntityId` — The entity. - `records.entities.companyEntityCode` — Its three-digit code. - `records.entities.companyEntityName` — Its name. - `records.entities.localCurrency` — The entity's local currency, which its `localAmount` figures are in. - `records.entities.amounts` — Opening balance, movement and closing balance for this entity alone. - `records.entities.amounts.openingBalance` — Balance carried into the period, from inception. - `records.entities.amounts.movement` — Net of the period's postings. - `records.entities.amounts.closingBalance` — Balance at the end of the period: opening balance plus movement. - `records.subtotal` — The entities' own books added together, before elimination. - `records.subtotal.openingBalance` — Balance carried into the period, from inception. - `records.subtotal.movement` — Net of the period's postings. - `records.subtotal.closingBalance` — Balance at the end of the period: opening balance plus movement. - `records.elimination` — Postings on the elimination ledger for this account. - `records.elimination.openingBalance` — Balance carried into the period, from inception. - `records.elimination.movement` — Net of the period's postings. - `records.elimination.closingBalance` — Balance at the end of the period: opening balance plus movement. - `records.total` — `subtotal` plus `elimination`: the consolidated figure. - `records.total.openingBalance` — Balance carried into the period, from inception. - `records.total.movement` — Net of the period's postings. - `records.total.closingBalance` — Balance at the end of the period: opening balance plus movement. - `records.groupCurrency` — The currency of every `groupAmount` in the row. ```json { "records": [ { "accountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "accountCode": 0, "accountLabel": "string", "accountType": "BANK", "entities": [ { "companyEntityId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyEntityCode": "string", "companyEntityName": "string", "localCurrency": "USD", "amounts": { "openingBalance": {}, "movement": {}, "closingBalance": {} } } ], "subtotal": { "openingBalance": { "groupAmount": 100000, "localAmount": 100000 }, "movement": { "groupAmount": 100000, "localAmount": 100000 }, "closingBalance": { "groupAmount": 100000, "localAmount": 100000 } }, "elimination": { "openingBalance": { "groupAmount": 100000, "localAmount": 100000 }, "movement": { "groupAmount": 100000, "localAmount": 100000 }, "closingBalance": { "groupAmount": 100000, "localAmount": 100000 } }, "total": { "openingBalance": { "groupAmount": 100000, "localAmount": 100000 }, "movement": { "groupAmount": 100000, "localAmount": 100000 }, "closingBalance": { "groupAmount": 100000, "localAmount": 100000 } }, "groupCurrency": "USD" } ], "hasMore": true, "nextCursor": "string", "prevCursor": "string" } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders. ## Code ```bash curl -X GET "https://api.light.inc/v1/general-ledger-summary" \ -H "Authorization: Basic YOUR_API_KEY" ``` Full page: https://light.inc/docs/api-reference/v1--general-ledger-summary/get-general-ledger-summary --- # Invoice Approvals (resource) Retrieve the approval status of an invoice. Resource page: https://light.inc/docs/api-reference/v1--invoice-approvals # Get invoice approvals > Returns approval records for specified invoice payables `GET https://api.light.inc/v1/invoice-approval` ## Note There is no request body ; the LightPrincipal shape below is the authenticated caller leaking into the spec. invoicePayableId may be repeated and is effectively required: with none the result is an empty list, not all approvals. Only the latest approval per bill is returned, with userApprovals in priority order; a group approver has userGroupId set and userId null. Needs a user credential with the AP-preparation or auditor role, or one that is an approver on every requested bill ( 403 otherwise). ## Authorization - API key - Bearer token See https://light.inc/docs/getting-started/authentication. ## Query parameters - `invoicePayableId` (array) ## Request body `application/json;charset=UTF-8` ```json { "roles": [ "string" ], "name": "string" } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders, and fields that exclude each other are all shown. Do not send it unchanged. ## Response ```json [ { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "invoicePayableId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "invoiceDocumentKey": "string", "invoiceNumber": "string", "invoiceAmount": 100000, "invoiceCurrency": "USD", "invoiceIssuedAt": "2026-01-15T09:30:00Z", "invoiceIssuedDate": "2026-01-15", "invoiceDueAt": "2026-01-15T09:30:00Z", "invoiceDueDate": "2026-01-15", "userApprovals": [ { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "approvalId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "userId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "userGroupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "priority": 0, "status": "APPROVED", "note": "string", "completedAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z", "createdAt": "2026-01-15T09:30:00Z", "notifiedAt": "2026-01-15T09:30:00Z" } ], "note": "string", "status": "APPROVED", "completedAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z", "createdAt": "2026-01-15T09:30:00Z" } ] ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders. ## Code ```bash curl -X GET "https://api.light.inc/v1/invoice-approval" \ -H "Authorization: Basic YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "roles": [ "string" ], "name": "string" }' ``` Full page: https://light.inc/docs/api-reference/v1--invoice-approvals/get-invoice-approvals --- # Invoice Receivables (resource) Invoice receivables represent a sale transaction between the company and a customer. Create, update, open, reset and send them. Resource page: https://light.inc/docs/api-reference/v1--invoice-receivables # Archive invoice > Archives an invoice receivable `POST https://api.light.inc/v1/invoice-receivables/{invoiceReceivableId}/archive` ## Note Only from DRAFT or OPEN ( INVOICE_RECEIVABLE_CANNOT_BE_ARCHIVED otherwise): a partially or fully paid invoice must have its clearings reversed first. Archiving an OPEN invoice reverses its ledger posting. The invoice number is retained. ## Authorization - API key - Bearer token See https://light.inc/docs/getting-started/authentication. ## Path parameters - `invoiceReceivableId` (string, uuid, required) ## Response - `amount` — Gross total after discounts and tax, signed: a debit-side line (for example a negative `priceOverwrite`) reduces it. - `invoiceNumber` — `null` on a draft unless you set one; assigned synchronously by `open` and kept across `reset` and `archive`. - `currency` — The invoice currency. - `lines` — `null` on the list endpoint; populated only by `GET /v1/invoice-receivables/{invoiceReceivableId}`. - `lines.discount` — Discount applied to the line, by percentage or by amount. - `lines.netAmount` — Signed: credit-side lines are positive, debit-side lines (a negative `priceOverwrite`) are negative. `discountAmount` is unsigned. - `lines.taxAmount` — Signed the same way as `netAmount`: negative on a debit-side line. - `externalSource` — Set when the invoice was imported from another system (for example Chargebee): the system's name and the invoice's id there. - `failureContext` — Set when a background open fails and the invoice drops back to `DRAFT`; cleared by the next successful open. The description about vendor onboarding is a copy-paste from another model. ```json { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "contractId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyEntityId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "amount": 100000, "paymentType": "AIRWALLEX", "payeeBankAccountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "invoiceDate": "2026-01-15", "effectiveInvoiceDate": "2026-01-15", "postingDate": "2026-01-15", "dueDate": "2026-01-15", "netTerms": 0, "customerId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "invoiceTemplateId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "invoiceTemplateAdditionalText": "string", "invoiceNumber": "string", "type": "STANDARD", "state": "CREATED", "openedAt": "2026-01-15T09:30:00Z", "poNumber": "string", "reference": "string", "description": "string", "currency": "USD", "taxEngineName": "AVATAX", "areLinesWithTax": true, "localCurrencyFxRate": 0, "groupCurrencyFxRate": 0, "lines": [ { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "invoiceReceivableId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "productId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "quantity": 0, "taxCodeId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "accountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "discount": { "type": "PERCENTAGE" }, "discountAmount": 100000, "netAmount": 100000, "taxAmount": 100000, "avataxCode": "string", "billingStart": "2026-01-15", "billingEnd": "2026-01-15", "priceOverwrite": 100000, "productNameOverwrite": "string", "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z", "accrualTemplateId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "accrualStartDate": "2026-01-15", "accrualEndDate": "2026-01-15", "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupInternalName": "string", "values": [ {} ] } ] } ], "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupInternalName": "string", "values": [ { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupInternalName": "string", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "internalName": "string", "label": "string", "context": "string", "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z" } ] } ], "externalSource": { "name": "CHARGEBEE", "externalId": "string" }, "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z", "updatedBy": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "failureContext": { "name": "string", "type": "BAD_REQUEST", "errors": [ { "type": "string", "message": "string", "path": [ "string" ], "context": null } ] } } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders. ## Code ```bash curl -X POST "https://api.light.inc/v1/invoice-receivables/3c90c3cc-0d44-4b50-8888-8dd25736052a/archive" \ -H "Authorization: Basic YOUR_API_KEY" ``` Full page: https://light.inc/docs/api-reference/v1--invoice-receivables/archive-invoice --- # List invoices > Returns a paginated list of invoice receivables `GET https://api.light.inc/v1/invoice-receivables` ## Note lines is always null in list rows; only GET /v1/invoice-receivables/{invoiceReceivableId} returns them. No searchTerm and no default order. States: DRAFT (editable), OPEN_IN_PROGRESS (opening in the background), OPEN , PARTIALLY_PAID , PAID , PAYMENT_PENDING (a customer payment is in flight), ARCHIVED , and the terminal REVERSED ; CREATED is an uploaded PDF still being read and is not editable either. ## Authorization - API key - Bearer token See https://light.inc/docs/getting-started/authentication. ## Query parameters - `sort` (string) — Sort string in the format field:direction . To provide multiple sort fields, separate them with commas. Available directions: asc , desc . Available fields: amount , companyEntityId , createdAt , customer , description , dueDate , effectiveInvoiceDate , invoiceDate , invoiceNumber , openedAt , postingDate , state , updatedAt . - `filter` (string) — Filter string in the format field:operator:value . To provide multiple filters, separate them with commas. Available operators: eq , ne , in , not_in , gt , gte , lt , lte . - For in and not_in operators, provide multiple values separated by the pipe character ( ). Available fields: companyEntityId , contractId , currency , customerId , invoiceTemplateId , payeeBankAccountId , paymentType , openedAt , documentNumber , documentStatus , dueDate , effectiveInvoiceDate , einvoiceStatus , externalSourceId , externalSourceName , id , invoiceDate , postingDate , state , updatedAt . These fields accept only a subset of the operators: externalSourceId ( eq , in , not_in , is_null , is_not_null ), externalSourceName ( eq , in , not_in , is_null , is_not_null ). - `limit` (integer, int32) — Maximum number of items to return. Default is 50, maximum is 200. - `offset` (integer, int64) — Number of items to skip before starting to collect the result set. Deprecated, use 'cursor' instead. - `cursor` (string) — The cursor position to start returning results from. To opt-in into cursor-based pagination, provide 0 for the initial request. For subsequent requests, use nextCursor and prevCursor from the previous response to navigate. Cursor values are opaque and should not be constructed manually. ## Response - `records.amount` — Gross total after discounts and tax, signed: a debit-side line (for example a negative `priceOverwrite`) reduces it. - `records.invoiceNumber` — `null` on a draft unless you set one; assigned synchronously by `open` and kept across `reset` and `archive`. - `records.currency` — The invoice currency. - `records.lines` — `null` on the list endpoint; populated only by `GET /v1/invoice-receivables/{invoiceReceivableId}`. - `records.lines.discount` — Discount applied to the line, by percentage or by amount. - `records.lines.netAmount` — Signed: credit-side lines are positive, debit-side lines (a negative `priceOverwrite`) are negative. `discountAmount` is unsigned. - `records.lines.taxAmount` — Signed the same way as `netAmount`: negative on a debit-side line. - `records.externalSource` — Set when the invoice was imported from another system (for example Chargebee): the system's name and the invoice's id there. - `records.failureContext` — Set when a background open fails and the invoice drops back to `DRAFT`; cleared by the next successful open. The description about vendor onboarding is a copy-paste from another model. ```json { "records": [ { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "contractId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyEntityId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "amount": 100000, "paymentType": "AIRWALLEX", "payeeBankAccountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "invoiceDate": "2026-01-15", "effectiveInvoiceDate": "2026-01-15", "postingDate": "2026-01-15", "dueDate": "2026-01-15", "netTerms": 0, "customerId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "invoiceTemplateId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "invoiceTemplateAdditionalText": "string", "invoiceNumber": "string", "type": "STANDARD", "state": "CREATED", "openedAt": "2026-01-15T09:30:00Z", "poNumber": "string", "reference": "string", "description": "string", "currency": "USD", "taxEngineName": "AVATAX", "areLinesWithTax": true, "localCurrencyFxRate": 0, "groupCurrencyFxRate": 0, "lines": [ { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "invoiceReceivableId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "productId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "quantity": 0, "taxCodeId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "accountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "discount": { "type": "PERCENTAGE" }, "discountAmount": 100000, "netAmount": 100000, "taxAmount": 100000, "avataxCode": "string", "billingStart": "2026-01-15", "billingEnd": "2026-01-15", "priceOverwrite": 100000, "productNameOverwrite": "string", "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z", "accrualTemplateId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "accrualStartDate": "2026-01-15", "accrualEndDate": "2026-01-15", "customProperties": [ {} ] } ], "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupInternalName": "string", "values": [ {} ] } ], "externalSource": { "name": "CHARGEBEE", "externalId": "string" }, "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z", "updatedBy": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "failureContext": { "name": "string", "type": "BAD_REQUEST", "errors": [ { "type": "string", "message": "string", "path": [], "context": null } ] } } ], "hasMore": true, "total": 100000, "nextCursor": "string", "prevCursor": "string" } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders. ## Code ```bash curl -X GET "https://api.light.inc/v1/invoice-receivables" \ -H "Authorization: Basic YOUR_API_KEY" ``` Full page: https://light.inc/docs/api-reference/v1--invoice-receivables/list-invoices --- # Create invoice > Creates a new sales invoice `POST https://api.light.inc/v1/invoice-receivables` ## Note Created in DRAFT . Defaults when omitted: postingDate is invoiceDate , else today; paymentType is BANK_TRANSFER ; currency comes from the customer, else the entity; payeeBankAccountId and invoiceTemplateId fall back to the entity's defaults; areLinesWithTax is true ; line quantity is 1 . Line tax fields must match the tax engine of the entity and customer: taxCodeId only for Light's own engine, avataxCode only for Avalara, neither for Sphere, otherwise INVOICE_RECEIVABLE_INVALID_TAX_UPDATE with the offending line in path . Every line's product needs a price in the invoice currency unless priceOverwrite is set ( INVOICE_RECEIVABLE_PRODUCT_CURRENCY_MISMATCH ); a missing product is 404 PRODUCT_NOT_FOUND even with a price override. netTerms must be 0 to 9999. Send an X-Idempotency-Key to make retries safe; without it nothing is de-duplicated, and reusing a key with a different body is 409 IDEMPOTENCY_VIOLATION . invoiceNumber stays null until the invoice is opened unless you set one. ## Authorization - API key - Bearer token See https://light.inc/docs/getting-started/authentication. ## Header parameters - `X-Idempotency-Key` (string) ## Request body `application/json;charset=UTF-8` - `currency` — ISO 4217 code. Defaults to the customer's currency, else the entity's. - `lines.discount` — Optional discount on the line, by percentage or by amount. - `lines.customProperties.valueIds` — Catalogue value ids for this group. Required; send `[]` (with an empty `inlineValues`) to clear the group. `SINGLE_SELECT` and `MULTI_SELECT` groups accept nothing else. See [Custom properties on writes](/docs/getting-started/pagination-filtering-errors#custom-properties-on-writes). - `lines.customProperties.inlineValues` — Literal values for `TEXT`, `NUMERIC`, `BOOLEAN` and `DATE` groups, as strings (`yyyy-MM-dd` for dates). Rejected on select groups with `CUSTOM_PROPERTY_VALUE_TYPE_MISMATCH`. See [Custom properties on writes](/docs/getting-started/pagination-filtering-errors#custom-properties-on-writes). - `customProperties.valueIds` — Catalogue value ids for this group. Required; send `[]` (with an empty `inlineValues`) to clear the group. `SINGLE_SELECT` and `MULTI_SELECT` groups accept nothing else. See [Custom properties on writes](/docs/getting-started/pagination-filtering-errors#custom-properties-on-writes). - `customProperties.inlineValues` — Literal values for `TEXT`, `NUMERIC`, `BOOLEAN` and `DATE` groups, as strings (`yyyy-MM-dd` for dates). Rejected on select groups with `CUSTOM_PROPERTY_VALUE_TYPE_MISMATCH`. See [Custom properties on writes](/docs/getting-started/pagination-filtering-errors#custom-properties-on-writes). ```json { "companyEntityId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "invoiceNumber": "string", "description": "string", "currency": "USD", "paymentType": "AIRWALLEX", "payeeBankAccountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "invoiceDate": "2026-01-15", "postingDate": "2026-01-15", "dueDate": "2026-01-15", "customerId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "invoiceTemplateId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "netTerms": 0, "poNumber": "string", "reference": "string", "invoiceTemplateAdditionalText": "string", "areLinesWithTax": true, "localCurrencyFxRate": 0, "groupCurrencyFxRate": 0, "lines": [ { "productId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "quantity": 0, "taxCodeId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "accountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "discount": { "type": "PERCENTAGE" }, "priceOverwrite": 100000, "productNameOverwrite": "string", "taxAmountOverwrite": 100000, "avataxCode": "string", "billingStart": "2026-01-15", "billingEnd": "2026-01-15", "accrualTemplateId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "accrualStartDate": "2026-01-15", "accrualEndDate": "2026-01-15", "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "valueIds": [ "3c90c3cc-0d44-4b50-8888-8dd25736052a" ], "inlineValues": [ "string" ] } ] } ], "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "valueIds": [ "3c90c3cc-0d44-4b50-8888-8dd25736052a" ], "inlineValues": [ "string" ] } ] } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders, and fields that exclude each other are all shown. Do not send it unchanged. ## Response - `amount` — Gross total after discounts and tax, signed: a debit-side line (for example a negative `priceOverwrite`) reduces it. - `invoiceNumber` — `null` on a draft unless you set one; assigned synchronously by `open` and kept across `reset` and `archive`. - `currency` — The invoice currency. - `lines` — `null` on the list endpoint; populated only by `GET /v1/invoice-receivables/{invoiceReceivableId}`. - `lines.discount` — Discount applied to the line, by percentage or by amount. - `lines.netAmount` — Signed: credit-side lines are positive, debit-side lines (a negative `priceOverwrite`) are negative. `discountAmount` is unsigned. - `lines.taxAmount` — Signed the same way as `netAmount`: negative on a debit-side line. - `externalSource` — Set when the invoice was imported from another system (for example Chargebee): the system's name and the invoice's id there. - `failureContext` — Set when a background open fails and the invoice drops back to `DRAFT`; cleared by the next successful open. The description about vendor onboarding is a copy-paste from another model. ```json { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "contractId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyEntityId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "amount": 100000, "paymentType": "AIRWALLEX", "payeeBankAccountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "invoiceDate": "2026-01-15", "effectiveInvoiceDate": "2026-01-15", "postingDate": "2026-01-15", "dueDate": "2026-01-15", "netTerms": 0, "customerId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "invoiceTemplateId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "invoiceTemplateAdditionalText": "string", "invoiceNumber": "string", "type": "STANDARD", "state": "CREATED", "openedAt": "2026-01-15T09:30:00Z", "poNumber": "string", "reference": "string", "description": "string", "currency": "USD", "taxEngineName": "AVATAX", "areLinesWithTax": true, "localCurrencyFxRate": 0, "groupCurrencyFxRate": 0, "lines": [ { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "invoiceReceivableId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "productId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "quantity": 0, "taxCodeId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "accountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "discount": { "type": "PERCENTAGE" }, "discountAmount": 100000, "netAmount": 100000, "taxAmount": 100000, "avataxCode": "string", "billingStart": "2026-01-15", "billingEnd": "2026-01-15", "priceOverwrite": 100000, "productNameOverwrite": "string", "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z", "accrualTemplateId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "accrualStartDate": "2026-01-15", "accrualEndDate": "2026-01-15", "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupInternalName": "string", "values": [ {} ] } ] } ], "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupInternalName": "string", "values": [ { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupInternalName": "string", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "internalName": "string", "label": "string", "context": "string", "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z" } ] } ], "externalSource": { "name": "CHARGEBEE", "externalId": "string" }, "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z", "updatedBy": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "failureContext": { "name": "string", "type": "BAD_REQUEST", "errors": [ { "type": "string", "message": "string", "path": [ "string" ], "context": null } ] } } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders. ## Code ```bash curl -X POST "https://api.light.inc/v1/invoice-receivables" \ -H "Authorization: Basic YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "companyEntityId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "invoiceNumber": "string", "description": "string", "currency": "USD", "paymentType": "AIRWALLEX", "payeeBankAccountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "invoiceDate": "2026-01-15", "postingDate": "2026-01-15", "dueDate": "2026-01-15", "customerId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "invoiceTemplateId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "netTerms": 0, "poNumber": "string", "reference": "string", "invoiceTemplateAdditionalText": "string", "areLinesWithTax": true, "localCurrencyFxRate": 0, "groupCurrencyFxRate": 0, "lines": [ { "productId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "quantity": 0, "taxCodeId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "accountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "discount": { "type": "PERCENTAGE" }, "priceOverwrite": 100000, "productNameOverwrite": "string", "taxAmountOverwrite": 100000, "avataxCode": "string", "billingStart": "2026-01-15", "billingEnd": "2026-01-15", "accrualTemplateId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "accrualStartDate": "2026-01-15", "accrualEndDate": "2026-01-15", "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "valueIds": [ "3c90c3cc-0d44-4b50-8888-8dd25736052a" ], "inlineValues": [ "string" ] } ] } ], "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "valueIds": [ "3c90c3cc-0d44-4b50-8888-8dd25736052a" ], "inlineValues": [ "string" ] } ] }' ``` Full page: https://light.inc/docs/api-reference/v1--invoice-receivables/create-invoice --- # Create line > Creates a new invoice line item `POST https://api.light.inc/v1/invoice-receivables/{invoiceReceivableId}/lines` ## Note Only while the invoice is DRAFT ( INVOICE_RECEIVABLE_CANNOT_BE_MODIFIED ). Omitted accountId and tax fields take the product's defaults; a tax field for the wrong engine fails with INVOICE_RECEIVABLE_INVALID_TAX_UPDATE . Archived products are accepted. taxAmountOverwrite is applied once and not stored, so re-send it on any later line update that changes amounts. ## Authorization - API key - Bearer token See https://light.inc/docs/getting-started/authentication. ## Path parameters - `invoiceReceivableId` (string, uuid, required) ## Request body `application/json;charset=UTF-8` - `discount` — Optional discount on the line, by percentage or by amount. - `customProperties.valueIds` — Catalogue value ids for this group. Required; send `[]` (with an empty `inlineValues`) to clear the group. `SINGLE_SELECT` and `MULTI_SELECT` groups accept nothing else. See [Custom properties on writes](/docs/getting-started/pagination-filtering-errors#custom-properties-on-writes). - `customProperties.inlineValues` — Literal values for `TEXT`, `NUMERIC`, `BOOLEAN` and `DATE` groups, as strings (`yyyy-MM-dd` for dates). Rejected on select groups with `CUSTOM_PROPERTY_VALUE_TYPE_MISMATCH`. See [Custom properties on writes](/docs/getting-started/pagination-filtering-errors#custom-properties-on-writes). ```json { "productId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "quantity": 0, "taxCodeId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "accountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "discount": { "type": "PERCENTAGE" }, "priceOverwrite": 100000, "productNameOverwrite": "string", "taxAmountOverwrite": 100000, "avataxCode": "string", "billingStart": "2026-01-15", "billingEnd": "2026-01-15", "accrualTemplateId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "accrualStartDate": "2026-01-15", "accrualEndDate": "2026-01-15", "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "valueIds": [ "3c90c3cc-0d44-4b50-8888-8dd25736052a" ], "inlineValues": [ "string" ] } ] } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders, and fields that exclude each other are all shown. Do not send it unchanged. ## Response - `discount` — Discount applied to the line, by percentage or by amount. - `netAmount` — Signed: credit-side lines are positive, debit-side lines (a negative `priceOverwrite`) are negative. `discountAmount` is unsigned. - `taxAmount` — Signed the same way as `netAmount`: negative on a debit-side line. ```json { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "invoiceReceivableId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "productId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "quantity": 0, "taxCodeId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "accountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "discount": { "type": "PERCENTAGE" }, "discountAmount": 100000, "netAmount": 100000, "taxAmount": 100000, "avataxCode": "string", "billingStart": "2026-01-15", "billingEnd": "2026-01-15", "priceOverwrite": 100000, "productNameOverwrite": "string", "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z", "accrualTemplateId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "accrualStartDate": "2026-01-15", "accrualEndDate": "2026-01-15", "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupInternalName": "string", "values": [ { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupInternalName": "string", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "internalName": "string", "label": "string", "context": "string", "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z" } ] } ] } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders. ## Code ```bash curl -X POST "https://api.light.inc/v1/invoice-receivables/3c90c3cc-0d44-4b50-8888-8dd25736052a/lines" \ -H "Authorization: Basic YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "productId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "quantity": 0, "taxCodeId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "accountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "discount": { "type": "PERCENTAGE" }, "priceOverwrite": 100000, "productNameOverwrite": "string", "taxAmountOverwrite": 100000, "avataxCode": "string", "billingStart": "2026-01-15", "billingEnd": "2026-01-15", "accrualTemplateId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "accrualStartDate": "2026-01-15", "accrualEndDate": "2026-01-15", "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "valueIds": [ "3c90c3cc-0d44-4b50-8888-8dd25736052a" ], "inlineValues": [ "string" ] } ] }' ``` Full page: https://light.inc/docs/api-reference/v1--invoice-receivables/create-line --- # Delete invoice line > Deletes an invoice line item `DELETE https://api.light.inc/v1/invoice-receivables/{invoiceReceivableId}/lines/{lineId}` ## Note Only while the invoice is DRAFT ( INVOICE_RECEIVABLE_CANNOT_BE_MODIFIED ). Answers with an empty body; unknown line is 404 INVOICE_RECEIVABLE_LINE_NOT_FOUND . ## Authorization - API key - Bearer token See https://light.inc/docs/getting-started/authentication. ## Path parameters - `invoiceReceivableId` (string, uuid, required) - `lineId` (string, uuid, required) ## Response This endpoint returns no content. ## Code ```bash curl -X DELETE "https://api.light.inc/v1/invoice-receivables/3c90c3cc-0d44-4b50-8888-8dd25736052a/lines/3c90c3cc-0d44-4b50-8888-8dd25736052a" \ -H "Authorization: Basic YOUR_API_KEY" ``` Full page: https://light.inc/docs/api-reference/v1--invoice-receivables/delete-invoice-line --- # Update invoice line > Updates an invoice line item `PATCH https://api.light.inc/v1/invoice-receivables/{invoiceReceivableId}/lines/{lineId}` ## Note Only while the invoice is DRAFT . null clears accountId , taxCodeId , discount , priceOverwrite , productNameOverwrite , avataxCode , billingStart , billingEnd and the accrual fields, but leaves productId , quantity and taxAmountOverwrite unchanged. Changing productId resets priceOverwrite to the new product's price unless you send one in the same request. taxAmountOverwrite is not persisted: a later update that changes quantity , priceOverwrite , discount or productId without it recalculates tax from the tax code. A discount that would make the line negative is silently dropped. ## Authorization - API key - Bearer token See https://light.inc/docs/getting-started/authentication. ## Path parameters - `invoiceReceivableId` (string, uuid, required) - `lineId` (string, uuid, required) ## Request body `application/json;charset=UTF-8` - `taxAmountOverwrite` — Applied once and not stored. Re-send it with any later update that changes `quantity`, `priceOverwrite`, `discount` or `productId`, or the tax is recalculated from the tax code. - `customProperties.valueIds` — Catalogue value ids for this group. Required; send `[]` (with an empty `inlineValues`) to clear the group. `SINGLE_SELECT` and `MULTI_SELECT` groups accept nothing else. See [Custom properties on writes](/docs/getting-started/pagination-filtering-errors#custom-properties-on-writes). - `customProperties.inlineValues` — Literal values for `TEXT`, `NUMERIC`, `BOOLEAN` and `DATE` groups, as strings (`yyyy-MM-dd` for dates). Rejected on select groups with `CUSTOM_PROPERTY_VALUE_TYPE_MISMATCH`. See [Custom properties on writes](/docs/getting-started/pagination-filtering-errors#custom-properties-on-writes). ```json { "productId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "quantity": 0, "accountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "taxCodeId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "discount": { "type": "PERCENTAGE" }, "priceOverwrite": 100000, "productNameOverwrite": "string", "taxAmountOverwrite": 100000, "avataxCode": "string", "billingStart": "2026-01-15", "billingEnd": "2026-01-15", "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "valueIds": [ "3c90c3cc-0d44-4b50-8888-8dd25736052a" ], "inlineValues": [ "string" ] } ], "accrualTemplateId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "accrualStartDate": "2026-01-15", "accrualEndDate": "2026-01-15" } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders, and fields that exclude each other are all shown. Do not send it unchanged. ## Response - `discount` — Discount applied to the line, by percentage or by amount. - `netAmount` — Signed: credit-side lines are positive, debit-side lines (a negative `priceOverwrite`) are negative. `discountAmount` is unsigned. - `taxAmount` — Signed the same way as `netAmount`: negative on a debit-side line. ```json { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "invoiceReceivableId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "productId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "quantity": 0, "taxCodeId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "accountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "discount": { "type": "PERCENTAGE" }, "discountAmount": 100000, "netAmount": 100000, "taxAmount": 100000, "avataxCode": "string", "billingStart": "2026-01-15", "billingEnd": "2026-01-15", "priceOverwrite": 100000, "productNameOverwrite": "string", "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z", "accrualTemplateId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "accrualStartDate": "2026-01-15", "accrualEndDate": "2026-01-15", "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupInternalName": "string", "values": [ { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupInternalName": "string", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "internalName": "string", "label": "string", "context": "string", "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z" } ] } ] } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders. ## Code ```bash curl -X PATCH "https://api.light.inc/v1/invoice-receivables/3c90c3cc-0d44-4b50-8888-8dd25736052a/lines/3c90c3cc-0d44-4b50-8888-8dd25736052a" \ -H "Authorization: Basic YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "productId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "quantity": 0, "accountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "taxCodeId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "discount": { "type": "PERCENTAGE" }, "priceOverwrite": 100000, "productNameOverwrite": "string", "taxAmountOverwrite": 100000, "avataxCode": "string", "billingStart": "2026-01-15", "billingEnd": "2026-01-15", "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "valueIds": [ "3c90c3cc-0d44-4b50-8888-8dd25736052a" ], "inlineValues": [ "string" ] } ], "accrualTemplateId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "accrualStartDate": "2026-01-15", "accrualEndDate": "2026-01-15" }' ``` Full page: https://light.inc/docs/api-reference/v1--invoice-receivables/update-invoice-line --- # Generate invoice PDF > Generates the PDF document for an invoice receivable. Poll this endpoint until status is READY , then use the url field to download the PDF. The signed URL is temporary and should not be stored and reused. To download again, call this endpoint to get a fresh URL. `POST https://api.light.inc/v1/invoice-receivables/{invoiceReceivableId}/document` ## Note Idempotent on content: the first call answers GENERATING with url: null , and you poll this same POST until READY . A new PDF is generated only when none exists, the last attempt FAILED , or the invoice changed since; otherwise the existing one is returned with a fresh link. The url is a pre-signed link valid for five minutes . Works on drafts too, but needs invoiceTemplateId ( INVOICE_RECEIVABLE_MISSING_TEMPLATE ). If an original PDF was uploaded for the invoice, that file is returned instead of a generated one. ## Authorization - API key - Bearer token See https://light.inc/docs/getting-started/authentication. ## Path parameters - `invoiceReceivableId` (string, uuid, required) ## Response - `url` — A pre-signed link valid for five minutes; call the endpoint again for a fresh one. ```json { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "invoiceReceivableId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "status": "GENERATING", "url": "https://example.com", "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z" } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders. ## Code ```bash curl -X POST "https://api.light.inc/v1/invoice-receivables/3c90c3cc-0d44-4b50-8888-8dd25736052a/document" \ -H "Authorization: Basic YOUR_API_KEY" ``` Full page: https://light.inc/docs/api-reference/v1--invoice-receivables/generate-invoice-pdf --- # Get invoice > Returns a specific invoice receivable by ID `GET https://api.light.inc/v1/invoice-receivables/{invoiceReceivableId}` ## Note Any state, with lines. An unknown id, or one from another company, is 404 . ## Authorization - API key - Bearer token See https://light.inc/docs/getting-started/authentication. ## Path parameters - `invoiceReceivableId` (string, uuid, required) ## Response - `amount` — Gross total after discounts and tax, signed: a debit-side line (for example a negative `priceOverwrite`) reduces it. - `invoiceNumber` — `null` on a draft unless you set one; assigned synchronously by `open` and kept across `reset` and `archive`. - `currency` — The invoice currency. - `lines` — `null` on the list endpoint; populated only by `GET /v1/invoice-receivables/{invoiceReceivableId}`. - `lines.discount` — Discount applied to the line, by percentage or by amount. - `lines.netAmount` — Signed: credit-side lines are positive, debit-side lines (a negative `priceOverwrite`) are negative. `discountAmount` is unsigned. - `lines.taxAmount` — Signed the same way as `netAmount`: negative on a debit-side line. - `externalSource` — Set when the invoice was imported from another system (for example Chargebee): the system's name and the invoice's id there. - `failureContext` — Set when a background open fails and the invoice drops back to `DRAFT`; cleared by the next successful open. The description about vendor onboarding is a copy-paste from another model. ```json { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "contractId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyEntityId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "amount": 100000, "paymentType": "AIRWALLEX", "payeeBankAccountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "invoiceDate": "2026-01-15", "effectiveInvoiceDate": "2026-01-15", "postingDate": "2026-01-15", "dueDate": "2026-01-15", "netTerms": 0, "customerId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "invoiceTemplateId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "invoiceTemplateAdditionalText": "string", "invoiceNumber": "string", "type": "STANDARD", "state": "CREATED", "openedAt": "2026-01-15T09:30:00Z", "poNumber": "string", "reference": "string", "description": "string", "currency": "USD", "taxEngineName": "AVATAX", "areLinesWithTax": true, "localCurrencyFxRate": 0, "groupCurrencyFxRate": 0, "lines": [ { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "invoiceReceivableId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "productId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "quantity": 0, "taxCodeId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "accountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "discount": { "type": "PERCENTAGE" }, "discountAmount": 100000, "netAmount": 100000, "taxAmount": 100000, "avataxCode": "string", "billingStart": "2026-01-15", "billingEnd": "2026-01-15", "priceOverwrite": 100000, "productNameOverwrite": "string", "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z", "accrualTemplateId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "accrualStartDate": "2026-01-15", "accrualEndDate": "2026-01-15", "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupInternalName": "string", "values": [ {} ] } ] } ], "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupInternalName": "string", "values": [ { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupInternalName": "string", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "internalName": "string", "label": "string", "context": "string", "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z" } ] } ], "externalSource": { "name": "CHARGEBEE", "externalId": "string" }, "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z", "updatedBy": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "failureContext": { "name": "string", "type": "BAD_REQUEST", "errors": [ { "type": "string", "message": "string", "path": [ "string" ], "context": null } ] } } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders. ## Code ```bash curl -X GET "https://api.light.inc/v1/invoice-receivables/3c90c3cc-0d44-4b50-8888-8dd25736052a" \ -H "Authorization: Basic YOUR_API_KEY" ``` Full page: https://light.inc/docs/api-reference/v1--invoice-receivables/get-invoice --- # Update invoice > Updates an invoice receivable `PATCH https://api.light.inc/v1/invoice-receivables/{invoiceReceivableId}` ## Note Only in DRAFT ; anything else fails with INVOICE_RECEIVABLE_CANNOT_BE_MODIFIED . Sending null clears invoiceNumber , payeeBankAccountId , invoiceTemplateId , description , poNumber , reference and invoiceTemplateAdditionalText but leaves companyEntityId , currency , paymentType , invoiceDate , postingDate , dueDate , customerId , areLinesWithTax and netTerms unchanged. Three side effects to expect: with netTerms set, changing invoiceDate or postingDate moves dueDate (an explicit dueDate wins); changing companyEntityId drops a payeeBankAccountId or invoiceTemplateId that doesn't belong to the new entity; changing currency reprices every line from the product's price in that currency and removes lines whose product has no such price . The FX rates set at creation cannot be changed. ## Authorization - API key - Bearer token See https://light.inc/docs/getting-started/authentication. ## Path parameters - `invoiceReceivableId` (string, uuid, required) ## Request body `application/json;charset=UTF-8` - `customProperties.valueIds` — Catalogue value ids for this group. Required; send `[]` (with an empty `inlineValues`) to clear the group. `SINGLE_SELECT` and `MULTI_SELECT` groups accept nothing else. See [Custom properties on writes](/docs/getting-started/pagination-filtering-errors#custom-properties-on-writes). - `customProperties.inlineValues` — Literal values for `TEXT`, `NUMERIC`, `BOOLEAN` and `DATE` groups, as strings (`yyyy-MM-dd` for dates). Rejected on select groups with `CUSTOM_PROPERTY_VALUE_TYPE_MISMATCH`. See [Custom properties on writes](/docs/getting-started/pagination-filtering-errors#custom-properties-on-writes). ```json { "companyEntityId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "currency": "USD", "paymentType": "AIRWALLEX", "invoiceDate": "2026-01-15", "postingDate": "2026-01-15", "dueDate": "2026-01-15", "customerId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "areLinesWithTax": true, "netTerms": 0, "invoiceNumber": "string", "payeeBankAccountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "invoiceTemplateId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "description": "string", "poNumber": "string", "reference": "string", "invoiceTemplateAdditionalText": "string", "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "valueIds": [ "3c90c3cc-0d44-4b50-8888-8dd25736052a" ], "inlineValues": [ "string" ] } ] } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders, and fields that exclude each other are all shown. Do not send it unchanged. ## Response - `amount` — Gross total after discounts and tax, signed: a debit-side line (for example a negative `priceOverwrite`) reduces it. - `invoiceNumber` — `null` on a draft unless you set one; assigned synchronously by `open` and kept across `reset` and `archive`. - `currency` — The invoice currency. - `lines` — `null` on the list endpoint; populated only by `GET /v1/invoice-receivables/{invoiceReceivableId}`. - `lines.discount` — Discount applied to the line, by percentage or by amount. - `lines.netAmount` — Signed: credit-side lines are positive, debit-side lines (a negative `priceOverwrite`) are negative. `discountAmount` is unsigned. - `lines.taxAmount` — Signed the same way as `netAmount`: negative on a debit-side line. - `externalSource` — Set when the invoice was imported from another system (for example Chargebee): the system's name and the invoice's id there. - `failureContext` — Set when a background open fails and the invoice drops back to `DRAFT`; cleared by the next successful open. The description about vendor onboarding is a copy-paste from another model. ```json { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "contractId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyEntityId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "amount": 100000, "paymentType": "AIRWALLEX", "payeeBankAccountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "invoiceDate": "2026-01-15", "effectiveInvoiceDate": "2026-01-15", "postingDate": "2026-01-15", "dueDate": "2026-01-15", "netTerms": 0, "customerId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "invoiceTemplateId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "invoiceTemplateAdditionalText": "string", "invoiceNumber": "string", "type": "STANDARD", "state": "CREATED", "openedAt": "2026-01-15T09:30:00Z", "poNumber": "string", "reference": "string", "description": "string", "currency": "USD", "taxEngineName": "AVATAX", "areLinesWithTax": true, "localCurrencyFxRate": 0, "groupCurrencyFxRate": 0, "lines": [ { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "invoiceReceivableId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "productId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "quantity": 0, "taxCodeId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "accountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "discount": { "type": "PERCENTAGE" }, "discountAmount": 100000, "netAmount": 100000, "taxAmount": 100000, "avataxCode": "string", "billingStart": "2026-01-15", "billingEnd": "2026-01-15", "priceOverwrite": 100000, "productNameOverwrite": "string", "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z", "accrualTemplateId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "accrualStartDate": "2026-01-15", "accrualEndDate": "2026-01-15", "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupInternalName": "string", "values": [ {} ] } ] } ], "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupInternalName": "string", "values": [ { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupInternalName": "string", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "internalName": "string", "label": "string", "context": "string", "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z" } ] } ], "externalSource": { "name": "CHARGEBEE", "externalId": "string" }, "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z", "updatedBy": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "failureContext": { "name": "string", "type": "BAD_REQUEST", "errors": [ { "type": "string", "message": "string", "path": [ "string" ], "context": null } ] } } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders. ## Code ```bash curl -X PATCH "https://api.light.inc/v1/invoice-receivables/3c90c3cc-0d44-4b50-8888-8dd25736052a" \ -H "Authorization: Basic YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "companyEntityId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "currency": "USD", "paymentType": "AIRWALLEX", "invoiceDate": "2026-01-15", "postingDate": "2026-01-15", "dueDate": "2026-01-15", "customerId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "areLinesWithTax": true, "netTerms": 0, "invoiceNumber": "string", "payeeBankAccountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "invoiceTemplateId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "description": "string", "poNumber": "string", "reference": "string", "invoiceTemplateAdditionalText": "string", "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "valueIds": [ "3c90c3cc-0d44-4b50-8888-8dd25736052a" ], "inlineValues": [ "string" ] } ] }' ``` Full page: https://light.inc/docs/api-reference/v1--invoice-receivables/update-invoice --- # List invoice payments > Returns a list of payments for an invoice receivable `GET https://api.light.inc/v1/invoice-receivables/{invoiceReceivableId}/payments` ## Note A plain array, not paginated. Each entry is a clearing on the ledger: amount and paymentDate are in the invoice currency; a bank payment ( payment.type: BP ) also carries the bank amount and currency, while a customer credit ( CC ) carries its document number. To reverse one, pass payment.accountingDocumentId to reverse-clearing ; the top-level id is the clearing event and is not accepted there. ## Authorization - API key - Bearer token See https://light.inc/docs/getting-started/authentication. ## Path parameters - `invoiceReceivableId` (string, uuid, required) ## Response ```json [ { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "invoiceReceivableId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "amount": 100000, "paymentDate": "2026-01-15", "currency": "USD", "payment": {}, "createdAt": "2026-01-15T09:30:00Z" } ] ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders. ## Code ```bash curl -X GET "https://api.light.inc/v1/invoice-receivables/3c90c3cc-0d44-4b50-8888-8dd25736052a/payments" \ -H "Authorization: Basic YOUR_API_KEY" ``` Full page: https://light.inc/docs/api-reference/v1--invoice-receivables/list-invoice-payments --- # Enter invoice payment > Enters a payment for an invoice receivable. If the total amount paid equals the invoice total, the invoice status will be changed to PAID, otherwise it will be PARTIALLY_PAID. `POST https://api.light.inc/v1/invoice-receivables/{invoiceReceivableId}/payments` ## Note Only from OPEN , PARTIALLY_PAID or PAYMENT_PENDING ( INVOICE_RECEIVABLE_INVALID_STATE_TRANSITION ). Exactly one of bankAccountId (deprecated) or ledgerAccountId ( INVOICE_RECEIVABLE_MARK_AS_PAID_MISSING_ACCOUNT ). An amount above the remaining balance is rejected with INVOICE_RECEIVABLE_INVALID_PAYMENT_AMOUNT , so overpayments are impossible; the invoice becomes PAID only when the amount equals the balance exactly, PARTIALLY_PAID otherwise. A bank-payment document is created and posted to the ledger; when the bank account's currency differs from the invoice's, the company rate on paymentDate is used and a missing rate fails the call. Requires a user credential. ## Authorization - API key - Bearer token See https://light.inc/docs/getting-started/authentication. ## Path parameters - `invoiceReceivableId` (string, uuid, required) ## Request body `application/json;charset=UTF-8` ```json { "paymentDate": "2026-01-15", "bankAccountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "ledgerAccountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "amountInInvoiceCurrency": 100000 } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders, and fields that exclude each other are all shown. Do not send it unchanged. ## Response - `amount` — Gross total after discounts and tax, signed: a debit-side line (for example a negative `priceOverwrite`) reduces it. - `invoiceNumber` — `null` on a draft unless you set one; assigned synchronously by `open` and kept across `reset` and `archive`. - `currency` — The invoice currency. - `lines` — `null` on the list endpoint; populated only by `GET /v1/invoice-receivables/{invoiceReceivableId}`. - `lines.discount` — Discount applied to the line, by percentage or by amount. - `lines.netAmount` — Signed: credit-side lines are positive, debit-side lines (a negative `priceOverwrite`) are negative. `discountAmount` is unsigned. - `lines.taxAmount` — Signed the same way as `netAmount`: negative on a debit-side line. - `externalSource` — Set when the invoice was imported from another system (for example Chargebee): the system's name and the invoice's id there. - `failureContext` — Set when a background open fails and the invoice drops back to `DRAFT`; cleared by the next successful open. The description about vendor onboarding is a copy-paste from another model. ```json { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "contractId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyEntityId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "amount": 100000, "paymentType": "AIRWALLEX", "payeeBankAccountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "invoiceDate": "2026-01-15", "effectiveInvoiceDate": "2026-01-15", "postingDate": "2026-01-15", "dueDate": "2026-01-15", "netTerms": 0, "customerId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "invoiceTemplateId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "invoiceTemplateAdditionalText": "string", "invoiceNumber": "string", "type": "STANDARD", "state": "CREATED", "openedAt": "2026-01-15T09:30:00Z", "poNumber": "string", "reference": "string", "description": "string", "currency": "USD", "taxEngineName": "AVATAX", "areLinesWithTax": true, "localCurrencyFxRate": 0, "groupCurrencyFxRate": 0, "lines": [ { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "invoiceReceivableId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "productId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "quantity": 0, "taxCodeId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "accountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "discount": { "type": "PERCENTAGE" }, "discountAmount": 100000, "netAmount": 100000, "taxAmount": 100000, "avataxCode": "string", "billingStart": "2026-01-15", "billingEnd": "2026-01-15", "priceOverwrite": 100000, "productNameOverwrite": "string", "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z", "accrualTemplateId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "accrualStartDate": "2026-01-15", "accrualEndDate": "2026-01-15", "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupInternalName": "string", "values": [ {} ] } ] } ], "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupInternalName": "string", "values": [ { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupInternalName": "string", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "internalName": "string", "label": "string", "context": "string", "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z" } ] } ], "externalSource": { "name": "CHARGEBEE", "externalId": "string" }, "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z", "updatedBy": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "failureContext": { "name": "string", "type": "BAD_REQUEST", "errors": [ { "type": "string", "message": "string", "path": [ "string" ], "context": null } ] } } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders. ## Code ```bash curl -X POST "https://api.light.inc/v1/invoice-receivables/3c90c3cc-0d44-4b50-8888-8dd25736052a/payments" \ -H "Authorization: Basic YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "paymentDate": "2026-01-15", "bankAccountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "ledgerAccountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "amountInInvoiceCurrency": 100000 }' ``` Full page: https://light.inc/docs/api-reference/v1--invoice-receivables/enter-invoice-payment --- # Open invoice > Initiates the process of opening an invoice receivable. This assigns an invoice number, locks the invoice for editing, and optionally sends it via email or submits it to e-invoicing systems. The request body is optional - if not provided, the invoice will be opened with default settings (no email sent, no e-invoice submission). `POST https://api.light.inc/v1/invoice-receivables/{invoiceReceivableId}/open` ## Note Two phases. Synchronously the invoice is validated ( paymentType , dueDate , customerId , invoiceTemplateId , entity, currency, a bank account for bank transfer or direct debit, at least one line with product, account and tax, a total above zero, required custom properties — errors such as INVOICE_RECEIVABLE_DETAILS_MISSING_FIELD , INVOICE_RECEIVABLE_LINE_MISSING_FIELD , INVOICE_RECEIVABLE_MISSING_LINES ), the ledger posting is previewed against open accounting periods, the invoice number is assigned , and the response comes back in OPEN_IN_PROGRESS with invoiceNumber set. In the background the e-invoice is submitted (if requested), the email is sent (if requested), and only then is the invoice posted to the ledger and moved to OPEN with openedAt . Poll GET /v1/invoice-receivables/{invoiceReceivableId} until the state leaves OPEN_IN_PROGRESS . A validation failure in the background (for example shouldSubmitEInvoice on an entity without e-invoicing) sends it back to DRAFT with failureContext , keeping the number for the next attempt. If the company auto-allocates customer credits, an invoice can land in PARTIALLY_PAID or PAID straight away. With shouldSendEmail , emailInfo is required. ## Authorization - API key - Bearer token See https://light.inc/docs/getting-started/authentication. ## Path parameters - `invoiceReceivableId` (string, uuid, required) ## Request body `application/json;charset=UTF-8` ```json { "emailInfo": { "subject": "string", "replyTo": "string", "recipients": [ "string" ], "cc": [ "string" ], "customMessage": "string" }, "shouldSendEmail": true, "shouldSubmitEInvoice": true } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders, and fields that exclude each other are all shown. Do not send it unchanged. ## Response - `amount` — Gross total after discounts and tax, signed: a debit-side line (for example a negative `priceOverwrite`) reduces it. - `invoiceNumber` — `null` on a draft unless you set one; assigned synchronously by `open` and kept across `reset` and `archive`. - `currency` — The invoice currency. - `lines` — `null` on the list endpoint; populated only by `GET /v1/invoice-receivables/{invoiceReceivableId}`. - `lines.discount` — Discount applied to the line, by percentage or by amount. - `lines.netAmount` — Signed: credit-side lines are positive, debit-side lines (a negative `priceOverwrite`) are negative. `discountAmount` is unsigned. - `lines.taxAmount` — Signed the same way as `netAmount`: negative on a debit-side line. - `externalSource` — Set when the invoice was imported from another system (for example Chargebee): the system's name and the invoice's id there. - `failureContext` — Set when a background open fails and the invoice drops back to `DRAFT`; cleared by the next successful open. The description about vendor onboarding is a copy-paste from another model. ```json { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "contractId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyEntityId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "amount": 100000, "paymentType": "AIRWALLEX", "payeeBankAccountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "invoiceDate": "2026-01-15", "effectiveInvoiceDate": "2026-01-15", "postingDate": "2026-01-15", "dueDate": "2026-01-15", "netTerms": 0, "customerId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "invoiceTemplateId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "invoiceTemplateAdditionalText": "string", "invoiceNumber": "string", "type": "STANDARD", "state": "CREATED", "openedAt": "2026-01-15T09:30:00Z", "poNumber": "string", "reference": "string", "description": "string", "currency": "USD", "taxEngineName": "AVATAX", "areLinesWithTax": true, "localCurrencyFxRate": 0, "groupCurrencyFxRate": 0, "lines": [ { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "invoiceReceivableId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "productId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "quantity": 0, "taxCodeId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "accountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "discount": { "type": "PERCENTAGE" }, "discountAmount": 100000, "netAmount": 100000, "taxAmount": 100000, "avataxCode": "string", "billingStart": "2026-01-15", "billingEnd": "2026-01-15", "priceOverwrite": 100000, "productNameOverwrite": "string", "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z", "accrualTemplateId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "accrualStartDate": "2026-01-15", "accrualEndDate": "2026-01-15", "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupInternalName": "string", "values": [ {} ] } ] } ], "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupInternalName": "string", "values": [ { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupInternalName": "string", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "internalName": "string", "label": "string", "context": "string", "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z" } ] } ], "externalSource": { "name": "CHARGEBEE", "externalId": "string" }, "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z", "updatedBy": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "failureContext": { "name": "string", "type": "BAD_REQUEST", "errors": [ { "type": "string", "message": "string", "path": [ "string" ], "context": null } ] } } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders. ## Code ```bash curl -X POST "https://api.light.inc/v1/invoice-receivables/3c90c3cc-0d44-4b50-8888-8dd25736052a/open" \ -H "Authorization: Basic YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "emailInfo": { "subject": "string", "replyTo": "string", "recipients": [ "string" ], "cc": [ "string" ], "customMessage": "string" }, "shouldSendEmail": true, "shouldSubmitEInvoice": true }' ``` Full page: https://light.inc/docs/api-reference/v1--invoice-receivables/open-invoice --- # Reset invoice > Resets an invoice receivable to draft `POST https://api.light.inc/v1/invoice-receivables/{invoiceReceivableId}/reset` ## Note Only from OPEN . A PARTIALLY_PAID or PAID invoice cannot be reset until every clearing is reversed, and an invoice already sent to the customer is locked in countries where Light enforces invoice immutability ( INVOICE_RECEIVABLE_LOCKED ; use reverse and reissue instead). Reset reverses the ledger posting and returns the invoice to DRAFT , but keeps the invoice number : reopening reuses it. ## Authorization - API key - Bearer token See https://light.inc/docs/getting-started/authentication. ## Path parameters - `invoiceReceivableId` (string, uuid, required) ## Response - `amount` — Gross total after discounts and tax, signed: a debit-side line (for example a negative `priceOverwrite`) reduces it. - `invoiceNumber` — `null` on a draft unless you set one; assigned synchronously by `open` and kept across `reset` and `archive`. - `currency` — The invoice currency. - `lines` — `null` on the list endpoint; populated only by `GET /v1/invoice-receivables/{invoiceReceivableId}`. - `lines.discount` — Discount applied to the line, by percentage or by amount. - `lines.netAmount` — Signed: credit-side lines are positive, debit-side lines (a negative `priceOverwrite`) are negative. `discountAmount` is unsigned. - `lines.taxAmount` — Signed the same way as `netAmount`: negative on a debit-side line. - `externalSource` — Set when the invoice was imported from another system (for example Chargebee): the system's name and the invoice's id there. - `failureContext` — Set when a background open fails and the invoice drops back to `DRAFT`; cleared by the next successful open. The description about vendor onboarding is a copy-paste from another model. ```json { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "contractId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyEntityId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "amount": 100000, "paymentType": "AIRWALLEX", "payeeBankAccountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "invoiceDate": "2026-01-15", "effectiveInvoiceDate": "2026-01-15", "postingDate": "2026-01-15", "dueDate": "2026-01-15", "netTerms": 0, "customerId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "invoiceTemplateId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "invoiceTemplateAdditionalText": "string", "invoiceNumber": "string", "type": "STANDARD", "state": "CREATED", "openedAt": "2026-01-15T09:30:00Z", "poNumber": "string", "reference": "string", "description": "string", "currency": "USD", "taxEngineName": "AVATAX", "areLinesWithTax": true, "localCurrencyFxRate": 0, "groupCurrencyFxRate": 0, "lines": [ { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "invoiceReceivableId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "productId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "quantity": 0, "taxCodeId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "accountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "discount": { "type": "PERCENTAGE" }, "discountAmount": 100000, "netAmount": 100000, "taxAmount": 100000, "avataxCode": "string", "billingStart": "2026-01-15", "billingEnd": "2026-01-15", "priceOverwrite": 100000, "productNameOverwrite": "string", "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z", "accrualTemplateId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "accrualStartDate": "2026-01-15", "accrualEndDate": "2026-01-15", "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupInternalName": "string", "values": [ {} ] } ] } ], "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupInternalName": "string", "values": [ { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupInternalName": "string", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "internalName": "string", "label": "string", "context": "string", "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z" } ] } ], "externalSource": { "name": "CHARGEBEE", "externalId": "string" }, "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z", "updatedBy": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "failureContext": { "name": "string", "type": "BAD_REQUEST", "errors": [ { "type": "string", "message": "string", "path": [ "string" ], "context": null } ] } } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders. ## Code ```bash curl -X POST "https://api.light.inc/v1/invoice-receivables/3c90c3cc-0d44-4b50-8888-8dd25736052a/reset" \ -H "Authorization: Basic YOUR_API_KEY" ``` Full page: https://light.inc/docs/api-reference/v1--invoice-receivables/reset-invoice --- # Reverse invoice payment > Reverses a clearing applied to an invoice receivable — either a bank payment ( BP ) or a customer credit ( CC ) — identified by its accounting document ID. Use the List invoice payments endpoint to obtain the accountingDocumentId and type of the clearing to reverse. Reversing removes the clearing's effect from the ledger and transitions the invoice back to OPEN or PARTIALLY_PAID depending on the remaining outstanding balance. Optionally set shouldArchiveClearingDocument to also archive the underlying bank payment or customer credit. `POST https://api.light.inc/v1/invoice-receivables/{invoiceReceivableId}/reverse-clearing` ## Note Only from PARTIALLY_PAID or PAID ; on an OPEN invoice it fails with INVOICE_RECEIVABLE_INVALID_STATE_TRANSITION . accountingDocumentId is the payment.accountingDocumentId from GET .../payments . The resulting state follows what is still cleared: PARTIALLY_PAID if anything remains, else OPEN . With shouldArchiveClearingDocument: true the bank payment or credit is archived; with false a customer credit returns to POSTED and stays linked. ## Authorization - API key - Bearer token See https://light.inc/docs/getting-started/authentication. ## Path parameters - `invoiceReceivableId` (string, uuid, required) ## Request body `application/json;charset=UTF-8` ```json { "clearingAccountingDocumentId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "clearingType": "BP", "shouldArchiveClearingDocument": true } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders, and fields that exclude each other are all shown. Do not send it unchanged. ## Response - `amount` — Gross total after discounts and tax, signed: a debit-side line (for example a negative `priceOverwrite`) reduces it. - `invoiceNumber` — `null` on a draft unless you set one; assigned synchronously by `open` and kept across `reset` and `archive`. - `currency` — The invoice currency. - `lines` — `null` on the list endpoint; populated only by `GET /v1/invoice-receivables/{invoiceReceivableId}`. - `lines.discount` — Discount applied to the line, by percentage or by amount. - `lines.netAmount` — Signed: credit-side lines are positive, debit-side lines (a negative `priceOverwrite`) are negative. `discountAmount` is unsigned. - `lines.taxAmount` — Signed the same way as `netAmount`: negative on a debit-side line. - `externalSource` — Set when the invoice was imported from another system (for example Chargebee): the system's name and the invoice's id there. - `failureContext` — Set when a background open fails and the invoice drops back to `DRAFT`; cleared by the next successful open. The description about vendor onboarding is a copy-paste from another model. ```json { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "contractId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyEntityId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "amount": 100000, "paymentType": "AIRWALLEX", "payeeBankAccountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "invoiceDate": "2026-01-15", "effectiveInvoiceDate": "2026-01-15", "postingDate": "2026-01-15", "dueDate": "2026-01-15", "netTerms": 0, "customerId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "invoiceTemplateId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "invoiceTemplateAdditionalText": "string", "invoiceNumber": "string", "type": "STANDARD", "state": "CREATED", "openedAt": "2026-01-15T09:30:00Z", "poNumber": "string", "reference": "string", "description": "string", "currency": "USD", "taxEngineName": "AVATAX", "areLinesWithTax": true, "localCurrencyFxRate": 0, "groupCurrencyFxRate": 0, "lines": [ { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "invoiceReceivableId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "productId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "quantity": 0, "taxCodeId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "accountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "discount": { "type": "PERCENTAGE" }, "discountAmount": 100000, "netAmount": 100000, "taxAmount": 100000, "avataxCode": "string", "billingStart": "2026-01-15", "billingEnd": "2026-01-15", "priceOverwrite": 100000, "productNameOverwrite": "string", "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z", "accrualTemplateId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "accrualStartDate": "2026-01-15", "accrualEndDate": "2026-01-15", "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupInternalName": "string", "values": [ {} ] } ] } ], "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupInternalName": "string", "values": [ { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupInternalName": "string", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "internalName": "string", "label": "string", "context": "string", "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z" } ] } ], "externalSource": { "name": "CHARGEBEE", "externalId": "string" }, "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z", "updatedBy": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "failureContext": { "name": "string", "type": "BAD_REQUEST", "errors": [ { "type": "string", "message": "string", "path": [ "string" ], "context": null } ] } } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders. ## Code ```bash curl -X POST "https://api.light.inc/v1/invoice-receivables/3c90c3cc-0d44-4b50-8888-8dd25736052a/reverse-clearing" \ -H "Authorization: Basic YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "clearingAccountingDocumentId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "clearingType": "BP", "shouldArchiveClearingDocument": true }' ``` Full page: https://light.inc/docs/api-reference/v1--invoice-receivables/reverse-invoice-payment --- # Send invoice email > Sends an invoice receivable email with the given email information `POST https://api.light.inc/v1/invoice-receivables/{invoiceReceivableId}/send-email` ## Note Only for an opened invoice ( OPEN , PARTIALLY_PAID , PAYMENT_PENDING , PAID ); otherwise INVOICE_RECEIVABLE_EMAIL_INVALID_STATE . The email is queued , so a 2xx means accepted, not delivered, and a delivery failure is not reported back. recipients must be non-empty and valid, and subject and customMessage may not contain HTML ( INVOICE_RECEIVABLE_HTML_NOT_ALLOWED ). Returns an empty body. ## Authorization - API key - Bearer token See https://light.inc/docs/getting-started/authentication. ## Path parameters - `invoiceReceivableId` (string, uuid, required) ## Request body `application/json;charset=UTF-8` ```json { "subject": "string", "replyTo": "string", "recipients": [ "string" ], "cc": [ "string" ], "customMessage": "string" } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders, and fields that exclude each other are all shown. Do not send it unchanged. ## Response This endpoint returns no content. ## Code ```bash curl -X POST "https://api.light.inc/v1/invoice-receivables/3c90c3cc-0d44-4b50-8888-8dd25736052a/send-email" \ -H "Authorization: Basic YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "subject": "string", "replyTo": "string", "recipients": [ "string" ], "cc": [ "string" ], "customMessage": "string" }' ``` Full page: https://light.inc/docs/api-reference/v1--invoice-receivables/send-invoice-email --- # Unarchive invoice > Unarchives an invoice receivable and reverts it to draft `POST https://api.light.inc/v1/invoice-receivables/{invoiceReceivableId}/unarchive` ## Note Only from ARCHIVED ( INVOICE_RECEIVABLE_CANNOT_BE_UNARCHIVED ). Always lands in DRAFT , even if the invoice was OPEN when archived; open it again to post. Blocked with INVOICE_RECEIVABLE_LOCKED where invoice immutability applies. ## Authorization - API key - Bearer token See https://light.inc/docs/getting-started/authentication. ## Path parameters - `invoiceReceivableId` (string, uuid, required) ## Response - `amount` — Gross total after discounts and tax, signed: a debit-side line (for example a negative `priceOverwrite`) reduces it. - `invoiceNumber` — `null` on a draft unless you set one; assigned synchronously by `open` and kept across `reset` and `archive`. - `currency` — The invoice currency. - `lines` — `null` on the list endpoint; populated only by `GET /v1/invoice-receivables/{invoiceReceivableId}`. - `lines.discount` — Discount applied to the line, by percentage or by amount. - `lines.netAmount` — Signed: credit-side lines are positive, debit-side lines (a negative `priceOverwrite`) are negative. `discountAmount` is unsigned. - `lines.taxAmount` — Signed the same way as `netAmount`: negative on a debit-side line. - `externalSource` — Set when the invoice was imported from another system (for example Chargebee): the system's name and the invoice's id there. - `failureContext` — Set when a background open fails and the invoice drops back to `DRAFT`; cleared by the next successful open. The description about vendor onboarding is a copy-paste from another model. ```json { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "contractId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyEntityId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "amount": 100000, "paymentType": "AIRWALLEX", "payeeBankAccountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "invoiceDate": "2026-01-15", "effectiveInvoiceDate": "2026-01-15", "postingDate": "2026-01-15", "dueDate": "2026-01-15", "netTerms": 0, "customerId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "invoiceTemplateId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "invoiceTemplateAdditionalText": "string", "invoiceNumber": "string", "type": "STANDARD", "state": "CREATED", "openedAt": "2026-01-15T09:30:00Z", "poNumber": "string", "reference": "string", "description": "string", "currency": "USD", "taxEngineName": "AVATAX", "areLinesWithTax": true, "localCurrencyFxRate": 0, "groupCurrencyFxRate": 0, "lines": [ { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "invoiceReceivableId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "productId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "quantity": 0, "taxCodeId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "accountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "discount": { "type": "PERCENTAGE" }, "discountAmount": 100000, "netAmount": 100000, "taxAmount": 100000, "avataxCode": "string", "billingStart": "2026-01-15", "billingEnd": "2026-01-15", "priceOverwrite": 100000, "productNameOverwrite": "string", "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z", "accrualTemplateId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "accrualStartDate": "2026-01-15", "accrualEndDate": "2026-01-15", "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupInternalName": "string", "values": [ {} ] } ] } ], "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupInternalName": "string", "values": [ { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupInternalName": "string", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "internalName": "string", "label": "string", "context": "string", "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z" } ] } ], "externalSource": { "name": "CHARGEBEE", "externalId": "string" }, "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z", "updatedBy": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "failureContext": { "name": "string", "type": "BAD_REQUEST", "errors": [ { "type": "string", "message": "string", "path": [ "string" ], "context": null } ] } } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders. ## Code ```bash curl -X POST "https://api.light.inc/v1/invoice-receivables/3c90c3cc-0d44-4b50-8888-8dd25736052a/unarchive" \ -H "Authorization: Basic YOUR_API_KEY" ``` Full page: https://light.inc/docs/api-reference/v1--invoice-receivables/unarchive-invoice --- # Journal Entries (resource) Create journal entries programmatically. Resource page: https://light.inc/docs/api-reference/v1--journal-entries # Archive journal entry > Archives the given journal entry. Drafts are archived directly; posted entries are reversed and marked as archived. `POST https://api.light.inc/v1/journal-entries/{journalEntryId}/archive` ## Note Only a DRAFT or an entry whose status is exactly POSTED can be archived; PARTIALLY_CLEARED , CLEARED , APPROVAL_PENDING and ARCHIVED fail with JOURNAL_ENTRY_CANNOT_BE_ARCHIVED . The reversal of a posted entry is written synchronously with the original postingDate , not today's, so that period must still be open ( ACCOUNTING_PERIOD_CLOSED ). Both the original and the reversing lines then appear on GET /v1/ledger-transaction-lines . A second archive without an X-Idempotency-Key fails rather than no-ops. Periods and locks (/docs/concepts/periods-and-locks) explains the period check. ## Authorization - API key - Bearer token See https://light.inc/docs/getting-started/authentication. ## Path parameters - `journalEntryId` (string, uuid, required) ## Header parameters - `X-Idempotency-Key` (string) ## Response - `id` — The journal entry id, also its accounting document id. - `companyId` — Your company id. - `documentNumber` — Your own free-text reference for the entry. Not the number Light assigns; that is `documentSequenceId`. - `companyEntityId` — The entity whose books the entry posts to. - `createdBy` — The principal that created the entry: a user or an API key. - `updatedBy` — The principal that last changed it. - `documentSequenceId` — `null` until the entry is posted. - `description` — The entry's description. - `currency` — The currency of the line amounts. - `postingDate` — The ledger date; the accounting period covering it must be open to post. - `documentDate` — The date on the underlying document, informational. - `valuationDate` — The date whose exchange rate converted the lines to local and group currency; resolved at posting when not set. - `localCurrencyFxRate` — Echoes the override you sent; `null` when Light applied its own rate, not the rate that was applied. - `groupCurrencyFxRate` — Echoes the override you sent; `null` when Light applied its own rate, not the rate that was applied. - `areLinesWithTax` — Whether line amounts were entered gross of tax (`true`) or net (`false`, the default). - `failureContext` — The error of the last failed posting attempt, typically from the approval workflow; cleared on the next successful post. The description about vendor onboarding is a copy-paste from another model. - `lines` — The lines as entered. The ledger lines Light derived (tax, rounding) are not here; read them from ledger transaction lines. - `lines.id` — The line id. - `lines.journalEntryId` — The entry the line belongs to. - `lines.netTransactionAmount` — The line amount excluding tax, unsigned with `dcSign`, in the entry's currency. - `lines.netTransactionAmount.amount` — Unsigned integer in minor units. The direction is in `dcSign`; a negative value is rejected. - `lines.grossTransactionAmount` — The line amount including tax. - `lines.grossTransactionAmount.amount` — Unsigned integer in minor units. The direction is in `dcSign`; a negative value is rejected. - `lines.taxTransactionAmount` — The tax portion; `null` without a tax code. - `lines.taxTransactionAmount.amount` — Unsigned integer in minor units. The direction is in `dcSign`; a negative value is rejected. - `lines.description` — The line description. - `lines.targetCompanyEntityId` — For an intercompany line, the entity on the other side ("To entity" in the product). `null` on ordinary lines. - `lines.ledgerTaxId` — Tax code id. Other documents call the same id `taxCodeId`. - `lines.ledgerAccountId` — The ledger account the line posts to. - `lines.costCenterId` — Cost center on the line; `null` when none. - `lines.customProperties` — Custom property values on the line. - `lines.createdAt` — When the line was created. - `lines.updatedAt` — When it was last changed. - `lines.amortizationTemplateId` — Release template id when the line is spread over a schedule instead of hitting the account at once; `null` otherwise. - `lines.amortizationStartDate` — First date of that schedule. - `lines.amortizationEndDate` — Last date of that schedule. - `customProperties` — Custom property values on the entry header. - `businessPartnerName` — Optional vendor or customer shown on the entry. - `businessPartnerId` — Id of that vendor or customer. - `createdAt` — When the entry was created. - `updatedAt` — When it was last changed. - `totalNetTransactionAmount` — Sum of the lines' net amounts as one directed figure. Read the magnitude as the entry's size; its `dcSign` carries no accounting meaning on a balanced entry. - `totalNetTransactionAmount.amount` — Unsigned integer in minor units. The direction is in `dcSign`; a negative value is rejected. - `totalTaxTransactionAmount` — Sum of the lines' tax amounts, read like the net total. - `totalTaxTransactionAmount.amount` — Unsigned integer in minor units. The direction is in `dcSign`; a negative value is rejected. - `totalGrossTransactionAmount` — Sum of the lines' gross amounts, read like the net total. - `totalGrossTransactionAmount.amount` — Unsigned integer in minor units. The direction is in `dcSign`; a negative value is rejected. - `multiJournalEntryId` — Set when this entry is one entity's part of a multi-entity journal entry made in the product; entries sharing the id were entered together. `null` for entries created through the API. ```json { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "documentNumber": "string", "companyEntityId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "ledgerName": "PRIMARY", "createdBy": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "updatedBy": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "documentSequenceId": "string", "status": "DRAFT", "description": "string", "currency": "USD", "postingDate": "2026-01-15", "documentDate": "2026-01-15", "valuationDate": "2026-01-15", "localCurrencyFxRate": 0, "groupCurrencyFxRate": 0, "areLinesWithTax": true, "failureContext": { "name": "string", "type": "BAD_REQUEST", "errors": [ { "type": "string", "message": "string", "path": [ "string" ], "context": null } ] }, "lines": [ { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "journalEntryId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "netTransactionAmount": { "amount": 100000, "dcSign": "D" }, "grossTransactionAmount": { "amount": 100000, "dcSign": "D" }, "taxTransactionAmount": { "amount": 100000, "dcSign": "D" }, "description": "string", "targetCompanyEntityId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "ledgerTaxId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "ledgerAccountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "costCenterId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupInternalName": "string", "values": [ {} ] } ], "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z", "amortizationTemplateId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "amortizationStartDate": "2026-01-15", "amortizationEndDate": "2026-01-15" } ], "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupInternalName": "string", "values": [ { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupInternalName": "string", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "internalName": "string", "label": "string", "context": "string", "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z" } ] } ], "businessPartnerName": "string", "businessPartnerId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z", "totalNetTransactionAmount": { "amount": 100000, "dcSign": "D" }, "totalTaxTransactionAmount": { "amount": 100000, "dcSign": "D" }, "totalGrossTransactionAmount": { "amount": 100000, "dcSign": "D" }, "multiJournalEntryId": "3c90c3cc-0d44-4b50-8888-8dd25736052a" } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders. ## Code ```bash curl -X POST "https://api.light.inc/v1/journal-entries/3c90c3cc-0d44-4b50-8888-8dd25736052a/archive" \ -H "Authorization: Basic YOUR_API_KEY" ``` Full page: https://light.inc/docs/api-reference/v1--journal-entries/archive-journal-entry --- # Create journal entry > Creates a new journal entry `POST https://api.light.inc/v1/journal-entries` ## Note This is the only way to post a journal entry through the API. There is no endpoint to post an existing draft, to add or change lines, or to read an entry back; a draft can only be archived. Create it with shouldPost: true when it must reach the ledger. If the company has a journal-entry approval workflow, shouldPost: true leaves it in APPROVAL_PENDING for approval in Light instead of POSTED . To read it back later: the header via GET /v1/accounting-documents/accounting-documents?filter=id:eq:{journalEntryId} , the posted lines via GET /v1/ledger-transaction-lines?filter=accDocId:eq:{journalEntryId} ; draft lines are not readable anywhere. Rules enforced only when posting: the lines' grossTransactionAmount in the transaction currency must net to zero ( ACCOUNTING_DOCUMENT_LINES_DEBITS_AND_CREDITS_NOT_ZERO_SUM ), with at least two lines and both a D and a C ( ACCOUNTING_DOCUMENT_TOO_FEW_LINES , ACCOUNTING_DOCUMENT_LINES_NO_CREDIT_AND_DEBIT ); every line needs ledgerAccountId and the header currency and companyEntityId ; the accounting period of postingDate must be open ( ACCOUNTING_PERIOD_CLOSED ). areLinesWithTax decides which amount each line carries: false (the default) takes netTransactionAmount and rejects a gross amount ( ACCOUNTING_DOCUMENT_LINE_GROSS_AMOUNT_SET ), true the reverse. Amounts are unsigned with dcSign ; a negative amount is ACCOUNTING_DOCUMENT_LINE_NEGATIVE_AMOUNT . Defaults: postingDate today, ledgerName PRIMARY ; currency has no default. Send an X-Idempotency-Key : without one every retry creates another entry; with one, a different body is 409 IDEMPOTENCY_VIOLATION . How Light records money (/docs/concepts/how-light-records-money) explains why the lines must balance, Document lifecycle (/docs/concepts/document-lifecycle) what the statuses mean, and Periods and locks (/docs/concepts/periods-and-locks) why a period can reject the posting. ## Authorization - API key - Bearer token See https://light.inc/docs/getting-started/authentication. ## Header parameters - `X-Idempotency-Key` (string) ## Request body `application/json;charset=UTF-8` - `companyEntityId` — Required. The entity whose books the entry posts to. - `documentNumber` — Optional free-text reference of your own. Light assigns `documentSequenceId` separately at posting. - `description` — Optional description for the entry. - `currency` — No default, and required to post. - `postingDate` — The ledger date. Defaults to today; the accounting period covering it must be open to post. - `valuationDate` — The date whose exchange rate converts the lines. Defaults to the posting date. - `documentDate` — The date on the underlying document, informational. - `areLinesWithTax` — Decides which amount each line carries: `false` (default) takes `netTransactionAmount` and rejects a gross amount, `true` takes `grossTransactionAmount` and rejects a net one. - `lines` — To post: at least two lines that net to zero in the entry's currency, with at least one `D` and one `C`, each with a `ledgerAccountId`. - `lines.netTransactionAmount` — Send this when `areLinesWithTax` is `false` (the default): the amount excluding tax, unsigned, with `dcSign`. - `lines.netTransactionAmount.amount` — Unsigned integer in minor units. The direction is in `dcSign`; a negative value is rejected. - `lines.grossTransactionAmount` — Send this instead when `areLinesWithTax` is `true`: the amount including tax. Sending both is rejected. - `lines.grossTransactionAmount.amount` — Unsigned integer in minor units. The direction is in `dcSign`; a negative value is rejected. - `lines.taxAmount` — Optional explicit tax amount. Left out, Light derives it from the line's tax code. - `lines.taxAmount.amount` — Unsigned integer in minor units. The direction is in `dcSign`; a negative value is rejected. - `lines.description` — Optional line description. - `lines.targetCompanyEntityId` — For an intercompany line, the entity on the other side ("To entity" in the product). Leave out on ordinary lines. - `lines.ledgerTaxId` — Tax code id; leave out for no tax. - `lines.ledgerAccountId` — The ledger account to post to. Required to post. - `lines.costCenterId` — Optional cost center. - `lines.amortizationTemplateId` — Spread the line over a release schedule: the template id, sent together with the start and end dates. - `lines.amortizationStartDate` — First date of the release schedule; required with the template. - `lines.amortizationEndDate` — Last date of the release schedule; required with the template. - `lines.customProperties` — Custom property values for the line. See [Custom properties on writes](/docs/getting-started/pagination-filtering-errors#custom-properties-on-writes). - `lines.customProperties.valueIds` — Catalogue value ids for this group. Required; send `[]` (with an empty `inlineValues`) to clear the group. `SINGLE_SELECT` and `MULTI_SELECT` groups accept nothing else. See [Custom properties on writes](/docs/getting-started/pagination-filtering-errors#custom-properties-on-writes). - `lines.customProperties.inlineValues` — Literal values for `TEXT`, `NUMERIC`, `BOOLEAN` and `DATE` groups, as strings (`yyyy-MM-dd` for dates). Rejected on select groups with `CUSTOM_PROPERTY_VALUE_TYPE_MISMATCH`. See [Custom properties on writes](/docs/getting-started/pagination-filtering-errors#custom-properties-on-writes). - `businessPartnerName` — Optional vendor or customer name to show on the entry. - `businessPartnerId` — Optional vendor or customer id. - `shouldPost` — `false` (the default) creates a draft that the API can never post afterwards, only archive. Set `true` to post now; with a journal-entry approval workflow in place the result is `APPROVAL_PENDING` instead of `POSTED`. - `customProperties` — Custom property values for the entry header. See [Custom properties on writes](/docs/getting-started/pagination-filtering-errors#custom-properties-on-writes). - `customProperties.valueIds` — Catalogue value ids for this group. Required; send `[]` (with an empty `inlineValues`) to clear the group. `SINGLE_SELECT` and `MULTI_SELECT` groups accept nothing else. See [Custom properties on writes](/docs/getting-started/pagination-filtering-errors#custom-properties-on-writes). - `customProperties.inlineValues` — Literal values for `TEXT`, `NUMERIC`, `BOOLEAN` and `DATE` groups, as strings (`yyyy-MM-dd` for dates). Rejected on select groups with `CUSTOM_PROPERTY_VALUE_TYPE_MISMATCH`. See [Custom properties on writes](/docs/getting-started/pagination-filtering-errors#custom-properties-on-writes). ```json { "companyEntityId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "description": "March software accrual", "currency": "EUR", "postingDate": "2026-03-31", "areLinesWithTax": false, "shouldPost": true, "lines": [ { "ledgerAccountId": "0a4b7c1e-6d2f-4e8a-9b3c-5d7e9f1a2b3c", "description": "Software subscriptions, March", "netTransactionAmount": { "amount": 125000, "dcSign": "D" } }, { "ledgerAccountId": "7e2c9a5d-1b3f-4c6e-8d0a-2f4b6c8e0a1d", "description": "Accrued expenses", "netTransactionAmount": { "amount": 125000, "dcSign": "C" } } ] } ``` This example is hand-written and valid as shown, with placeholder ids. ## Response - `id` — The journal entry id, also its accounting document id. - `companyId` — Your company id. - `documentNumber` — Your own free-text reference for the entry. Not the number Light assigns; that is `documentSequenceId`. - `companyEntityId` — The entity whose books the entry posts to. - `createdBy` — The principal that created the entry: a user or an API key. - `updatedBy` — The principal that last changed it. - `documentSequenceId` — `null` until the entry is posted. - `description` — The entry's description. - `currency` — The currency of the line amounts. - `postingDate` — The ledger date; the accounting period covering it must be open to post. - `documentDate` — The date on the underlying document, informational. - `valuationDate` — The date whose exchange rate converted the lines to local and group currency; resolved at posting when not set. - `localCurrencyFxRate` — Echoes the override you sent; `null` when Light applied its own rate, not the rate that was applied. - `groupCurrencyFxRate` — Echoes the override you sent; `null` when Light applied its own rate, not the rate that was applied. - `areLinesWithTax` — Whether line amounts were entered gross of tax (`true`) or net (`false`, the default). - `failureContext` — The error of the last failed posting attempt, typically from the approval workflow; cleared on the next successful post. The description about vendor onboarding is a copy-paste from another model. - `lines` — The lines as entered. The ledger lines Light derived (tax, rounding) are not here; read them from ledger transaction lines. - `lines.id` — The line id. - `lines.journalEntryId` — The entry the line belongs to. - `lines.netTransactionAmount` — The line amount excluding tax, unsigned with `dcSign`, in the entry's currency. - `lines.netTransactionAmount.amount` — Unsigned integer in minor units. The direction is in `dcSign`; a negative value is rejected. - `lines.grossTransactionAmount` — The line amount including tax. - `lines.grossTransactionAmount.amount` — Unsigned integer in minor units. The direction is in `dcSign`; a negative value is rejected. - `lines.taxTransactionAmount` — The tax portion; `null` without a tax code. - `lines.taxTransactionAmount.amount` — Unsigned integer in minor units. The direction is in `dcSign`; a negative value is rejected. - `lines.description` — The line description. - `lines.targetCompanyEntityId` — For an intercompany line, the entity on the other side ("To entity" in the product). `null` on ordinary lines. - `lines.ledgerTaxId` — Tax code id. Other documents call the same id `taxCodeId`. - `lines.ledgerAccountId` — The ledger account the line posts to. - `lines.costCenterId` — Cost center on the line; `null` when none. - `lines.customProperties` — Custom property values on the line. - `lines.createdAt` — When the line was created. - `lines.updatedAt` — When it was last changed. - `lines.amortizationTemplateId` — Release template id when the line is spread over a schedule instead of hitting the account at once; `null` otherwise. - `lines.amortizationStartDate` — First date of that schedule. - `lines.amortizationEndDate` — Last date of that schedule. - `customProperties` — Custom property values on the entry header. - `businessPartnerName` — Optional vendor or customer shown on the entry. - `businessPartnerId` — Id of that vendor or customer. - `createdAt` — When the entry was created. - `updatedAt` — When it was last changed. - `totalNetTransactionAmount` — Sum of the lines' net amounts as one directed figure. Read the magnitude as the entry's size; its `dcSign` carries no accounting meaning on a balanced entry. - `totalNetTransactionAmount.amount` — Unsigned integer in minor units. The direction is in `dcSign`; a negative value is rejected. - `totalTaxTransactionAmount` — Sum of the lines' tax amounts, read like the net total. - `totalTaxTransactionAmount.amount` — Unsigned integer in minor units. The direction is in `dcSign`; a negative value is rejected. - `totalGrossTransactionAmount` — Sum of the lines' gross amounts, read like the net total. - `totalGrossTransactionAmount.amount` — Unsigned integer in minor units. The direction is in `dcSign`; a negative value is rejected. - `multiJournalEntryId` — Set when this entry is one entity's part of a multi-entity journal entry made in the product; entries sharing the id were entered together. `null` for entries created through the API. ```json { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "documentNumber": "string", "companyEntityId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "ledgerName": "PRIMARY", "createdBy": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "updatedBy": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "documentSequenceId": "string", "status": "DRAFT", "description": "string", "currency": "USD", "postingDate": "2026-01-15", "documentDate": "2026-01-15", "valuationDate": "2026-01-15", "localCurrencyFxRate": 0, "groupCurrencyFxRate": 0, "areLinesWithTax": true, "failureContext": { "name": "string", "type": "BAD_REQUEST", "errors": [ { "type": "string", "message": "string", "path": [ "string" ], "context": null } ] }, "lines": [ { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "journalEntryId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "netTransactionAmount": { "amount": 100000, "dcSign": "D" }, "grossTransactionAmount": { "amount": 100000, "dcSign": "D" }, "taxTransactionAmount": { "amount": 100000, "dcSign": "D" }, "description": "string", "targetCompanyEntityId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "ledgerTaxId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "ledgerAccountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "costCenterId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupInternalName": "string", "values": [ {} ] } ], "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z", "amortizationTemplateId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "amortizationStartDate": "2026-01-15", "amortizationEndDate": "2026-01-15" } ], "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupInternalName": "string", "values": [ { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupInternalName": "string", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "internalName": "string", "label": "string", "context": "string", "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z" } ] } ], "businessPartnerName": "string", "businessPartnerId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z", "totalNetTransactionAmount": { "amount": 100000, "dcSign": "D" }, "totalTaxTransactionAmount": { "amount": 100000, "dcSign": "D" }, "totalGrossTransactionAmount": { "amount": 100000, "dcSign": "D" }, "multiJournalEntryId": "3c90c3cc-0d44-4b50-8888-8dd25736052a" } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders. ## Code ```bash curl -X POST "https://api.light.inc/v1/journal-entries" \ -H "Authorization: Basic YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "companyEntityId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "description": "March software accrual", "currency": "EUR", "postingDate": "2026-03-31", "areLinesWithTax": false, "shouldPost": true, "lines": [ { "ledgerAccountId": "0a4b7c1e-6d2f-4e8a-9b3c-5d7e9f1a2b3c", "description": "Software subscriptions, March", "netTransactionAmount": { "amount": 125000, "dcSign": "D" } }, { "ledgerAccountId": "7e2c9a5d-1b3f-4c6e-8d0a-2f4b6c8e0a1d", "description": "Accrued expenses", "netTransactionAmount": { "amount": 125000, "dcSign": "C" } } ] }' ``` Full page: https://light.inc/docs/api-reference/v1--journal-entries/create-journal-entry --- # Update journal entry > Updates the given draft journal entry. Only the fields present in the request body are modified; fields set explicitly to null are cleared. `PATCH https://api.light.inc/v1/journal-entries/{journalEntryId}` ## Note The "null clears" rule in the description holds for valuationDate , documentNumber , description , currency , businessPartnerName , businessPartnerId and the FX overrides only; companyEntityId , ledgerName , postingDate , documentDate , areLinesWithTax and customProperties cannot be cleared. Lines cannot be changed at all (there is no lines field). On anything but a DRAFT , only customProperties may change; sending any other field fails with JOURNAL_ENTRY_CANNOT_BE_MODIFIED . ## Authorization - API key - Bearer token See https://light.inc/docs/getting-started/authentication. ## Path parameters - `journalEntryId` (string, uuid, required) ## Header parameters - `X-Idempotency-Key` (string) ## Request body `application/json;charset=UTF-8` - `customProperties.valueIds` — Catalogue value ids for this group. Required; send `[]` (with an empty `inlineValues`) to clear the group. `SINGLE_SELECT` and `MULTI_SELECT` groups accept nothing else. See [Custom properties on writes](/docs/getting-started/pagination-filtering-errors#custom-properties-on-writes). - `customProperties.inlineValues` — Literal values for `TEXT`, `NUMERIC`, `BOOLEAN` and `DATE` groups, as strings (`yyyy-MM-dd` for dates). Rejected on select groups with `CUSTOM_PROPERTY_VALUE_TYPE_MISMATCH`. See [Custom properties on writes](/docs/getting-started/pagination-filtering-errors#custom-properties-on-writes). ```json { "companyEntityId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "ledgerName": "PRIMARY", "postingDate": "2026-01-15", "documentDate": "2026-01-15", "areLinesWithTax": true, "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "valueIds": [ "3c90c3cc-0d44-4b50-8888-8dd25736052a" ], "inlineValues": [ "string" ] } ], "valuationDate": "2026-01-15", "localCurrencyFxRateOverride": 0, "groupCurrencyFxRateOverride": 0, "documentNumber": "string", "businessPartnerName": "string", "businessPartnerId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "description": "string", "currency": "USD" } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders, and fields that exclude each other are all shown. Do not send it unchanged. ## Response - `id` — The journal entry id, also its accounting document id. - `companyId` — Your company id. - `documentNumber` — Your own free-text reference for the entry. Not the number Light assigns; that is `documentSequenceId`. - `companyEntityId` — The entity whose books the entry posts to. - `createdBy` — The principal that created the entry: a user or an API key. - `updatedBy` — The principal that last changed it. - `documentSequenceId` — `null` until the entry is posted. - `description` — The entry's description. - `currency` — The currency of the line amounts. - `postingDate` — The ledger date; the accounting period covering it must be open to post. - `documentDate` — The date on the underlying document, informational. - `valuationDate` — The date whose exchange rate converted the lines to local and group currency; resolved at posting when not set. - `localCurrencyFxRate` — Echoes the override you sent; `null` when Light applied its own rate, not the rate that was applied. - `groupCurrencyFxRate` — Echoes the override you sent; `null` when Light applied its own rate, not the rate that was applied. - `areLinesWithTax` — Whether line amounts were entered gross of tax (`true`) or net (`false`, the default). - `failureContext` — The error of the last failed posting attempt, typically from the approval workflow; cleared on the next successful post. The description about vendor onboarding is a copy-paste from another model. - `lines` — The lines as entered. The ledger lines Light derived (tax, rounding) are not here; read them from ledger transaction lines. - `lines.id` — The line id. - `lines.journalEntryId` — The entry the line belongs to. - `lines.netTransactionAmount` — The line amount excluding tax, unsigned with `dcSign`, in the entry's currency. - `lines.netTransactionAmount.amount` — Unsigned integer in minor units. The direction is in `dcSign`; a negative value is rejected. - `lines.grossTransactionAmount` — The line amount including tax. - `lines.grossTransactionAmount.amount` — Unsigned integer in minor units. The direction is in `dcSign`; a negative value is rejected. - `lines.taxTransactionAmount` — The tax portion; `null` without a tax code. - `lines.taxTransactionAmount.amount` — Unsigned integer in minor units. The direction is in `dcSign`; a negative value is rejected. - `lines.description` — The line description. - `lines.targetCompanyEntityId` — For an intercompany line, the entity on the other side ("To entity" in the product). `null` on ordinary lines. - `lines.ledgerTaxId` — Tax code id. Other documents call the same id `taxCodeId`. - `lines.ledgerAccountId` — The ledger account the line posts to. - `lines.costCenterId` — Cost center on the line; `null` when none. - `lines.customProperties` — Custom property values on the line. - `lines.createdAt` — When the line was created. - `lines.updatedAt` — When it was last changed. - `lines.amortizationTemplateId` — Release template id when the line is spread over a schedule instead of hitting the account at once; `null` otherwise. - `lines.amortizationStartDate` — First date of that schedule. - `lines.amortizationEndDate` — Last date of that schedule. - `customProperties` — Custom property values on the entry header. - `businessPartnerName` — Optional vendor or customer shown on the entry. - `businessPartnerId` — Id of that vendor or customer. - `createdAt` — When the entry was created. - `updatedAt` — When it was last changed. - `totalNetTransactionAmount` — Sum of the lines' net amounts as one directed figure. Read the magnitude as the entry's size; its `dcSign` carries no accounting meaning on a balanced entry. - `totalNetTransactionAmount.amount` — Unsigned integer in minor units. The direction is in `dcSign`; a negative value is rejected. - `totalTaxTransactionAmount` — Sum of the lines' tax amounts, read like the net total. - `totalTaxTransactionAmount.amount` — Unsigned integer in minor units. The direction is in `dcSign`; a negative value is rejected. - `totalGrossTransactionAmount` — Sum of the lines' gross amounts, read like the net total. - `totalGrossTransactionAmount.amount` — Unsigned integer in minor units. The direction is in `dcSign`; a negative value is rejected. - `multiJournalEntryId` — Set when this entry is one entity's part of a multi-entity journal entry made in the product; entries sharing the id were entered together. `null` for entries created through the API. ```json { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "documentNumber": "string", "companyEntityId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "ledgerName": "PRIMARY", "createdBy": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "updatedBy": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "documentSequenceId": "string", "status": "DRAFT", "description": "string", "currency": "USD", "postingDate": "2026-01-15", "documentDate": "2026-01-15", "valuationDate": "2026-01-15", "localCurrencyFxRate": 0, "groupCurrencyFxRate": 0, "areLinesWithTax": true, "failureContext": { "name": "string", "type": "BAD_REQUEST", "errors": [ { "type": "string", "message": "string", "path": [ "string" ], "context": null } ] }, "lines": [ { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "journalEntryId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "netTransactionAmount": { "amount": 100000, "dcSign": "D" }, "grossTransactionAmount": { "amount": 100000, "dcSign": "D" }, "taxTransactionAmount": { "amount": 100000, "dcSign": "D" }, "description": "string", "targetCompanyEntityId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "ledgerTaxId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "ledgerAccountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "costCenterId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupInternalName": "string", "values": [ {} ] } ], "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z", "amortizationTemplateId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "amortizationStartDate": "2026-01-15", "amortizationEndDate": "2026-01-15" } ], "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupInternalName": "string", "values": [ { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupInternalName": "string", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "internalName": "string", "label": "string", "context": "string", "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z" } ] } ], "businessPartnerName": "string", "businessPartnerId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z", "totalNetTransactionAmount": { "amount": 100000, "dcSign": "D" }, "totalTaxTransactionAmount": { "amount": 100000, "dcSign": "D" }, "totalGrossTransactionAmount": { "amount": 100000, "dcSign": "D" }, "multiJournalEntryId": "3c90c3cc-0d44-4b50-8888-8dd25736052a" } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders. ## Code ```bash curl -X PATCH "https://api.light.inc/v1/journal-entries/3c90c3cc-0d44-4b50-8888-8dd25736052a" \ -H "Authorization: Basic YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "companyEntityId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "ledgerName": "PRIMARY", "postingDate": "2026-01-15", "documentDate": "2026-01-15", "areLinesWithTax": true, "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "valueIds": [ "3c90c3cc-0d44-4b50-8888-8dd25736052a" ], "inlineValues": [ "string" ] } ], "valuationDate": "2026-01-15", "localCurrencyFxRateOverride": 0, "groupCurrencyFxRateOverride": 0, "documentNumber": "string", "businessPartnerName": "string", "businessPartnerId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "description": "string", "currency": "USD" }' ``` Full page: https://light.inc/docs/api-reference/v1--journal-entries/update-journal-entry --- # Ledger accounts (resource) List the chart of accounts. Resource page: https://light.inc/docs/api-reference/v1--ledger-accounts # List ledger accounts > Returns a paginated list of ledger accounts `GET https://api.light.inc/v1/ledger-accounts` ## Note A hidden filter restricts the list to category: STANDARD_ACCOUNT : header and sum accounts are never returned, and asking for them yields an empty page. ledgerFeature values INVOICE_PAYABLES , CARD_TRANSACTIONS , PURCHASE_ORDERS and REIMBURSEMENTS also restrict to accounts synced from an external accounting system; ALL , INVOICE_RECEIVABLES and JOURNAL_ENTRIES add nothing. Default order is code:asc , and includeCustomProperties defaults to false (the opposite of GET /v1/ledger-transaction-lines ). ## Authorization - API key - Bearer token See https://light.inc/docs/getting-started/authentication. ## Query parameters - `sort` (string) — Sort string in the format field:direction . To provide multiple sort fields, separate them with commas. Available directions: asc , desc . Available fields: code , label , context , type , category , status , createdAt , updatedAt . - `filter` (string) — Filter string in the format field:operator:value . To provide multiple filters, separate them with commas. Available operators: eq , ne , in , not_in , gt , gte , lt , lte . - For in and not_in operators, provide multiple values separated by the pipe character ( ). Available fields: id , companyEntityId , code , sourceType , status , type , category , createdAt , updatedAt . - `limit` (integer, int32) — Maximum number of items to return. Default is 50, maximum is 200. - `offset` (integer, int64) — Number of items to skip before starting to collect the result set. Deprecated, use 'cursor' instead. - `cursor` (string) — The cursor position to start returning results from. To opt-in into cursor-based pagination, provide 0 for the initial request. For subsequent requests, use nextCursor and prevCursor from the previous response to navigate. Cursor values are opaque and should not be constructed manually. - `ledgerFeature` (string) — ⚠️ This enum is not exhaustive; new values may be added in the future. - `includeCustomProperties` (boolean) — Whether to include custom properties in the response ## Response - `records.companyEntities.address.city` — City. - `records.companyEntities.address.state` — State or region, where the country uses one. - `records.companyEntities.address.zipcode` — Postal code. - `records.companyEntities.address.street` — First address line. - `records.companyEntities.address.street2` — Second address line. ```json { "records": [ { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "bankAccountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "cardAccountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "cashAndEquivalentsAccountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "code": 0, "label": "string", "type": "BANK", "status": "ACTIVE", "context": "string", "revaluateFxBalance": true, "companyEntities": [ { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "code": "string", "parentCompanyEntityId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "localCurrency": "USD", "displayName": "string", "vatNumber": "string", "name": "string", "address": { "country": "UNDEFINED", "city": "string", "state": "string", "zipcode": "string", "street": "string", "street2": "string" }, "status": "ACTIVE", "seedInvoiceNumber": 100000, "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z" } ], "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupInternalName": "string", "values": [ {} ] } ], "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z" } ], "hasMore": true, "total": 100000, "nextCursor": "string", "prevCursor": "string" } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders. ## Code ```bash curl -X GET "https://api.light.inc/v1/ledger-accounts" \ -H "Authorization: Basic YOUR_API_KEY" ``` Full page: https://light.inc/docs/api-reference/v1--ledger-accounts/list-ledger-accounts --- # Ledger Transactions (resource) Query ledger transaction lines. Resource page: https://light.inc/docs/api-reference/v1--ledger-transactions # List ledger transaction lines > Returns a paginated list of ledger transaction lines `GET https://api.light.inc/v1/ledger-transaction-lines` ## Note Signed amounts on these lines are credit-positive : signedLocalAmount , signedGroupAmount and signedTransactionAmount are negative for a debit and positive for a credit. That is the opposite polarity to the debit-positive balances GET /v1/general-ledger-summary and GET /v1/bank-accounts/{bankAccountId}/balance return, so reconciling one against the other means flipping the sign on one side. dcSign , debit and credit are returned too and say the same thing. Reversal lines are included and cannot be told apart: archiving a posted document leaves the original lines and negated reversing lines with the same accountingDocumentId and postingDate , netting to zero. includeCustomProperties defaults to true . includeMaxLineAmount reports the largest transactionAmount across the whole filtered set, not the page. postingDate is the ledger date; valuationDate is the date whose FX rate produced the local and group amounts, equal to postingDate unless the document overrides it. Default order is newest line first. limit above 200 fails with INVALID_LIMIT_SIZE unless Light has raised the cap for your company, and then only with a single postingDate sort. How Light records money (/docs/concepts/how-light-records-money) explains what these lines are, and Reading amounts (/docs/concepts/reading-amounts) the sign and currency rules. ## Authorization - API key - Bearer token See https://light.inc/docs/getting-started/authentication. ## Query parameters - `sort` (string) — Sort string in the format field:direction . To provide multiple sort fields, separate them with commas. Available directions: asc , desc . Available fields: accountingDocumentNumber , transactionSequenceId , documentSequenceId , documentType , accountCode , accountLabel , postingDate , accountType , taxTagLabel , createdAt . - `filter` (string) — Filter string in the format field:operator:value . To provide multiple filters, separate them with commas. Available operators: eq , ne , in , not_in , gt , gte , lt , lte . - For in and not_in operators, provide multiple values separated by the pipe character ( ). Available fields: accountCode , accountId , accountType , accDocId , businessPartnerId , businessPartnerName , companyEntityCode , companyEntityId , createdAt , customPropertyValueId , documentSequenceId , documentType , eliminationOffset , groupAmount , groupCurrency , id , ledgerName , lineType , localAmount , localCurrency , postingDate , taxTagLabel , transactionCurrency , transactionId , transactionSequenceId . These fields accept only a subset of the operators: customPropertyValueId ( eq , in ). - `limit` (integer, int32) — Maximum number of items to return. Default is 50, maximum is 200. - `offset` (integer, int64) — Number of items to skip before starting to collect the result set. Deprecated, use 'cursor' instead. - `cursor` (string) — The cursor position to start returning results from. To opt-in into cursor-based pagination, provide 0 for the initial request. For subsequent requests, use nextCursor and prevCursor from the previous response to navigate. Cursor values are opaque and should not be constructed manually. - `includeCustomProperties` (boolean) - `includeMaxLineAmount` (boolean) — If true, includes the maximum line amount in the response. This field is deprecated and will be removed, please fetch all lines and compute this locally if needed ## Response - `records.id` — Id of this ledger line. Lines are never edited or deleted, so it is stable; corrections arrive as new reversing lines. - `records.ledgerTransactionId` — The ledger transaction this line belongs to. Lines sharing it were written together and balance to zero in every currency. - `records.transactionSequenceId` — The transaction's number, `TX/` plus nine digits, assigned per company when the transaction was written. - `records.companyId` — Your company id, the same on every line. - `records.companyEntityId` — The legal entity whose books this line sits in. - `records.companyEntityCode` — The entity's three-digit code, the middle segment of document numbers such as `AP/001/000000042`. - `records.companyEntityName` — The entity's name. - `records.accountId` — The ledger account the line posts to. - `records.accountCode` — The account's numeric code in the chart of accounts. - `records.accountLabel` — The account's name. - `records.accountingDocumentLineId` — The document line this ledger line came from. `null` on lines Light derived at posting: tax, rounding and discount lines. - `records.documentSequenceId` — The document's number, `//<9 digits>`, for example `AP/001/000000042`. - `records.accountingDocumentId` — Id of the posted document. Filter on `accDocId` to get every ledger line of one document. - `records.accountingDocumentNumber` — The document's external number: the vendor's invoice number on a bill, the invoice number on a sales invoice, the free-text reference on a journal entry. `null` when there is none. - `records.postingDate` — The ledger date, which decides the accounting period the line falls in. - `records.valuationDate` — The date whose exchange rate produced the local and group amounts. Equal to `postingDate` unless the document set its own. - `records.description` — The line's own description, as entered on the document line. - `records.documentDescription` — The description on the document header. - `records.amounts` — The amount in the document, local and group currencies, unsigned, with one direction in `dcSign`. See [Reading amounts](/docs/concepts/reading-amounts). - `records.amounts.dcSign` — `D` or `C`. Redundant with the sign of `signedLocalAmount` (`D` is negative there) and with `debit`/`credit`. - `records.amounts.transactionAmount` — Unsigned magnitude. The direction lives in the sign of `signedTransactionAmount`, not here. - `records.amounts.transactionAmountInMajors` — `transactionAmount` as a decimal, unsigned. For display, not arithmetic. - `records.amounts.signedTransactionAmount` — **Credit-positive**: a credit is positive, a debit is negative, in minor units. This is the opposite polarity to the balances `GET /v1/general-ledger-summary` returns, which are debit-positive — reconciling one against the other means flipping the sign on one side. There is no `InMajors` counterpart to this field; the unsigned `*InMajors` value beside it carries the magnitude only. - `records.amounts.transactionCurrency` — The document's currency. `null` on lines with no transaction amount: rounding, revaluation and translation-adjustment lines. - `records.amounts.localAmount` — Unsigned magnitude. The direction lives in the sign of `signedLocalAmount`, not here. - `records.amounts.localAmountInMajors` — `localAmount` as a decimal, unsigned. - `records.amounts.signedLocalAmount` — **Credit-positive**: a credit is positive, a debit is negative, in minor units. This is the opposite polarity to the balances `GET /v1/general-ledger-summary` returns, which are debit-positive — reconciling one against the other means flipping the sign on one side. There is no `InMajors` counterpart to this field; the unsigned `*InMajors` value beside it carries the magnitude only. - `records.amounts.localCurrency` — The entity's local currency. - `records.amounts.groupAmount` — Unsigned magnitude. The direction lives in the sign of `signedGroupAmount`, not here. - `records.amounts.groupAmountInMajors` — `groupAmount` as a decimal, unsigned. - `records.amounts.signedGroupAmount` — **Credit-positive**: a credit is positive, a debit is negative, in minor units. This is the opposite polarity to the balances `GET /v1/general-ledger-summary` returns, which are debit-positive — reconciling one against the other means flipping the sign on one side. There is no `InMajors` counterpart to this field; the unsigned `*InMajors` value beside it carries the magnitude only. - `records.amounts.groupCurrency` — The company's group currency, the same on every line. - `records.amounts.debit` — `true` on a debit line. Redundant with `dcSign` and with a negative `signedLocalAmount`. - `records.amounts.credit` — `true` on a credit line. Redundant with `dcSign` and with a positive `signedLocalAmount`. - `records.taxId` — Id of the tax code on the line; `null` without one. - `records.taxTagLabel` — Label of the tax code's base tag, the VAT-return box the line reports into; `null` without a tax code. - `records.taxCode` — The tax code's code as shown in the product; `null` without one. - `records.businessPartnerName` — The vendor or customer on the document, when it has one. - `records.businessPartnerId` — Id of that vendor or customer. - `records.costCenterId` — Cost center on the line; `null` when none. - `records.accruedLedgerTransactionLineId` — On a release line (one instalment of a deferral, accrual or depreciation schedule): the id of the original line it releases. Legacy name; `null` on every other line. - `records.isAmortized` — `true` on a line that carries a release schedule, meaning release lines draw it down over time. Legacy name for "is released". - `records.accountingReleaseStartDate` — First date of the release schedule on this line; `null` without one. - `records.accountingReleaseEndDate` — Last date of the release schedule on this line; `null` without one. - `records.createdAt` — When the line was written to the ledger. Not the posting date. - `records.createdBy` — The principal that posted the document: a user or an API key. `null` when the system posted it. - `records.customProperties` — Custom property values from the document line, returned when `includeCustomProperties` is true (the default on this endpoint). ```json { "maxTransactionAmount": 100000, "records": [ { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "ledgerTransactionId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "transactionSequenceId": "string", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyEntityId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyEntityCode": "string", "companyEntityName": "string", "ledgerName": "PRIMARY", "accountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "accountCode": 0, "accountLabel": "string", "accountType": "BANK", "accountingDocumentLineId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "documentSequenceId": "string", "accountingDocumentId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "accountingDocumentNumber": "string", "documentType": "AP", "postingDate": "2026-01-15", "valuationDate": "2026-01-15", "description": "string", "documentDescription": "string", "amounts": { "dcSign": "D", "transactionAmount": 100000, "transactionAmountInMajors": 0, "signedTransactionAmount": 100000, "transactionCurrency": "USD", "localAmount": 100000, "localAmountInMajors": 0, "signedLocalAmount": 100000, "localCurrency": "USD", "groupAmount": 100000, "groupAmountInMajors": 0, "signedGroupAmount": 100000, "groupCurrency": "USD", "debit": true, "credit": true }, "taxId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "taxTagLabel": "string", "taxCode": "string", "businessPartnerName": "string", "businessPartnerId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "costCenterId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "accruedLedgerTransactionLineId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "ledgerTransactionType": "DEFAULT", "isAmortized": true, "accountingReleaseStartDate": "2026-01-15", "accountingReleaseEndDate": "2026-01-15", "createdAt": "2026-01-15T09:30:00Z", "createdBy": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupInternalName": "string", "values": [ {} ] } ] } ], "hasMore": true, "total": 100000, "nextCursor": "string", "prevCursor": "string" } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders. ## Code ```bash curl -X GET "https://api.light.inc/v1/ledger-transaction-lines" \ -H "Authorization: Basic YOUR_API_KEY" ``` Full page: https://light.inc/docs/api-reference/v1--ledger-transactions/list-ledger-transaction-lines --- # Products (resource) Products are goods or services that a company offers to its customers. They can be used on invoices and contracts. Resource page: https://light.inc/docs/api-reference/v1--products # Archive product > Archive the given product `POST https://api.light.inc/v1/products/{productId}/archive` ## Note Idempotent, but refused for one-off products with PRODUCT_IS_ONE_OFF . Contrary to the description, nothing stops an archived product being used on new invoice or contract lines; the only effect is state: ARCHIVED , which hides it in the app. There is no unarchive endpoint. ## Authorization - API key - Bearer token See https://light.inc/docs/getting-started/authentication. ## Path parameters - `productId` (string, uuid, required) ## Response ```json { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "name": "string", "pricingType": "FIXED", "billingRecurrence": "ONE_TIME", "pricings": [ { "currency": "USD", "amount": 100000 } ], "state": "ACTIVE", "defaultTaxId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "defaultAvataxCode": "string", "defaultLedgerAccountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "externalSource": { "name": "CHARGEBEE", "externalId": "string" }, "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z", "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupInternalName": "string", "values": [ { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupInternalName": "string", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "internalName": "string", "label": "string", "context": "string", "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z" } ] } ] } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders. ## Code ```bash curl -X POST "https://api.light.inc/v1/products/3c90c3cc-0d44-4b50-8888-8dd25736052a/archive" \ -H "Authorization: Basic YOUR_API_KEY" ``` Full page: https://light.inc/docs/api-reference/v1--products/archive-product --- # List products > Returns a list of products `GET https://api.light.inc/v1/products` ## Note Default order is createdAt:desc . The list also includes one-off products created from invoice lines (those with an invoiceReceivableId ), and there is no way to filter them out because is_null is not a filter operator. ## Authorization - API key - Bearer token See https://light.inc/docs/getting-started/authentication. ## Query parameters - `sort` (string) — Sort string in the format field:direction . To provide multiple sort fields, separate them with commas. Available directions: asc , desc . Available fields: name , createdAt , updatedAt . - `filter` (string) — Filter string in the format field:operator:value . To provide multiple filters, separate them with commas. Available operators: eq , ne , in , not_in , gt , gte , lt , lte . - For in and not_in operators, provide multiple values separated by the pipe character ( ). Available fields: id , name , pricingType , recurrence , state , invoiceReceivableId , updatedAt . - `limit` (integer, int32) — Maximum number of items to return. Default is 50, maximum is 200. - `offset` (integer, int64) — Number of items to skip before starting to collect the result set. Deprecated, use 'cursor' instead. - `cursor` (string) — The cursor position to start returning results from. To opt-in into cursor-based pagination, provide 0 for the initial request. For subsequent requests, use nextCursor and prevCursor from the previous response to navigate. Cursor values are opaque and should not be constructed manually. ## Response ```json { "records": [ { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "name": "string", "pricingType": "FIXED", "billingRecurrence": "ONE_TIME", "pricings": [ { "currency": "USD", "amount": 100000 } ], "state": "ACTIVE", "defaultTaxId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "defaultAvataxCode": "string", "defaultLedgerAccountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "externalSource": { "name": "CHARGEBEE", "externalId": "string" }, "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z", "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupInternalName": "string", "values": [ {} ] } ] } ], "hasMore": true, "total": 100000, "nextCursor": "string", "prevCursor": "string" } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders. ## Code ```bash curl -X GET "https://api.light.inc/v1/products" \ -H "Authorization: Basic YOUR_API_KEY" ``` Full page: https://light.inc/docs/api-reference/v1--products/list-products --- # Create product > Creates a new product `POST https://api.light.inc/v1/products` ## Note name must be unique among catalogue products of the company, case-sensitively, and an archived product still holds its name ( PRODUCT_NAME_CONFLICT , returned as 400 ). pricings needs at least one entry and at most one per currency; amounts are in minor units of that currency. defaultTaxId and defaultLedgerAccountId must exist ( PRODUCT_TAX_NOT_FOUND , PRODUCT_LEDGER_ACCOUNT_NOT_FOUND ). The default tax is only applied to invoice lines when Light's own tax engine is in force. ## Authorization - API key - Bearer token See https://light.inc/docs/getting-started/authentication. ## Header parameters - `X-Idempotency-Key` (string) ## Request body `application/json;charset=UTF-8` - `customProperties.valueIds` — Catalogue value ids for this group. Required; send `[]` (with an empty `inlineValues`) to clear the group. `SINGLE_SELECT` and `MULTI_SELECT` groups accept nothing else. See [Custom properties on writes](/docs/getting-started/pagination-filtering-errors#custom-properties-on-writes). - `customProperties.inlineValues` — Literal values for `TEXT`, `NUMERIC`, `BOOLEAN` and `DATE` groups, as strings (`yyyy-MM-dd` for dates). Rejected on select groups with `CUSTOM_PROPERTY_VALUE_TYPE_MISMATCH`. See [Custom properties on writes](/docs/getting-started/pagination-filtering-errors#custom-properties-on-writes). ```json { "name": "string", "pricingType": "FIXED", "billingRecurrence": "ONE_TIME", "pricings": [ { "currency": "USD", "amount": 100000 } ], "defaultAvataxCode": "string", "defaultTaxId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "defaultLedgerAccountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "valueIds": [ "3c90c3cc-0d44-4b50-8888-8dd25736052a" ], "inlineValues": [ "string" ] } ] } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders, and fields that exclude each other are all shown. Do not send it unchanged. ## Response ```json { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "name": "string", "pricingType": "FIXED", "billingRecurrence": "ONE_TIME", "pricings": [ { "currency": "USD", "amount": 100000 } ], "state": "ACTIVE", "defaultTaxId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "defaultAvataxCode": "string", "defaultLedgerAccountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "externalSource": { "name": "CHARGEBEE", "externalId": "string" }, "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z", "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupInternalName": "string", "values": [ { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupInternalName": "string", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "internalName": "string", "label": "string", "context": "string", "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z" } ] } ] } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders. ## Code ```bash curl -X POST "https://api.light.inc/v1/products" \ -H "Authorization: Basic YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "name": "string", "pricingType": "FIXED", "billingRecurrence": "ONE_TIME", "pricings": [ { "currency": "USD", "amount": 100000 } ], "defaultAvataxCode": "string", "defaultTaxId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "defaultLedgerAccountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "valueIds": [ "3c90c3cc-0d44-4b50-8888-8dd25736052a" ], "inlineValues": [ "string" ] } ] }' ``` Full page: https://light.inc/docs/api-reference/v1--products/create-product --- # Get product > Returns a product by ID `GET https://api.light.inc/v1/products/{productId}` ## Note Any status. An unknown id, or one from another company, is 404 . ## Authorization - API key - Bearer token See https://light.inc/docs/getting-started/authentication. ## Path parameters - `productId` (string, uuid, required) ## Response ```json { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "name": "string", "pricingType": "FIXED", "billingRecurrence": "ONE_TIME", "pricings": [ { "currency": "USD", "amount": 100000 } ], "state": "ACTIVE", "defaultTaxId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "defaultAvataxCode": "string", "defaultLedgerAccountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "externalSource": { "name": "CHARGEBEE", "externalId": "string" }, "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z", "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupInternalName": "string", "values": [ { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupInternalName": "string", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "internalName": "string", "label": "string", "context": "string", "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z" } ] } ] } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders. ## Code ```bash curl -X GET "https://api.light.inc/v1/products/3c90c3cc-0d44-4b50-8888-8dd25736052a" \ -H "Authorization: Basic YOUR_API_KEY" ``` Full page: https://light.inc/docs/api-reference/v1--products/get-product --- # Update product > Updates an existing product `PATCH https://api.light.inc/v1/products/{productId}` ## Note An ARCHIVED product cannot be updated ( PRODUCT_CANNOT_BE_MODIFIED ), and there is no unarchive endpoint , so archiving is one-way through this API. null clears defaultAvataxCode , defaultTaxId and defaultLedgerAccountId ; name , pricingType , billingRecurrence and pricings cannot be cleared, and pricings replaces the whole list when present. ## Authorization - API key - Bearer token See https://light.inc/docs/getting-started/authentication. ## Path parameters - `productId` (string, uuid, required) ## Header parameters - `X-Idempotency-Key` (string) ## Request body `application/json;charset=UTF-8` - `customProperties.valueIds` — Catalogue value ids for this group. Required; send `[]` (with an empty `inlineValues`) to clear the group. `SINGLE_SELECT` and `MULTI_SELECT` groups accept nothing else. See [Custom properties on writes](/docs/getting-started/pagination-filtering-errors#custom-properties-on-writes). - `customProperties.inlineValues` — Literal values for `TEXT`, `NUMERIC`, `BOOLEAN` and `DATE` groups, as strings (`yyyy-MM-dd` for dates). Rejected on select groups with `CUSTOM_PROPERTY_VALUE_TYPE_MISMATCH`. See [Custom properties on writes](/docs/getting-started/pagination-filtering-errors#custom-properties-on-writes). ```json { "name": "string", "pricingType": "FIXED", "billingRecurrence": "ONE_TIME", "pricings": [ { "currency": "USD", "amount": 100000 } ], "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "valueIds": [ "3c90c3cc-0d44-4b50-8888-8dd25736052a" ], "inlineValues": [ "string" ] } ], "defaultAvataxCode": "string", "defaultTaxId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "defaultLedgerAccountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a" } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders, and fields that exclude each other are all shown. Do not send it unchanged. ## Response ```json { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "name": "string", "pricingType": "FIXED", "billingRecurrence": "ONE_TIME", "pricings": [ { "currency": "USD", "amount": 100000 } ], "state": "ACTIVE", "defaultTaxId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "defaultAvataxCode": "string", "defaultLedgerAccountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "externalSource": { "name": "CHARGEBEE", "externalId": "string" }, "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z", "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupInternalName": "string", "values": [ { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupInternalName": "string", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "internalName": "string", "label": "string", "context": "string", "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z" } ] } ] } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders. ## Code ```bash curl -X PATCH "https://api.light.inc/v1/products/3c90c3cc-0d44-4b50-8888-8dd25736052a" \ -H "Authorization: Basic YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "name": "string", "pricingType": "FIXED", "billingRecurrence": "ONE_TIME", "pricings": [ { "currency": "USD", "amount": 100000 } ], "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "valueIds": [ "3c90c3cc-0d44-4b50-8888-8dd25736052a" ], "inlineValues": [ "string" ] } ], "defaultAvataxCode": "string", "defaultTaxId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "defaultLedgerAccountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a" }' ``` Full page: https://light.inc/docs/api-reference/v1--products/update-product --- # Purchase Orders (resource) Create, close, cancel and manage purchase orders and their lines. Resource page: https://light.inc/docs/api-reference/v1--purchase-orders # Batch update purchase order lines > Updates multiple purchase order line items `PUT https://api.light.inc/v1/purchase-orders/{purchaseOrderId}/lines/bulk` ## Note Not a replace-all, and not a merge either. Only the lines whose lineId you list are touched (unknown id: PURCHASE_ORDER_LINE_NOT_RECOGNIZED ; the same id twice: PURCHASE_ORDER_LINE_DUPLICATE_UPDATE ), but for each listed line every scalar field is overwritten with what you send , so an omitted description , costCenterId , accountId , taxCodeId , quantity or unitPrice becomes null . customProperties is the one field null leaves unchanged. The single-line PATCH uses the usual omit-to-keep rule instead. ## Authorization - API key - Bearer token See https://light.inc/docs/getting-started/authentication. ## Path parameters - `purchaseOrderId` (string, uuid, required) ## Request body `application/json;charset=UTF-8` - `description` — Overwritten with whatever you send, so an omitted value becomes `null`. The same applies to `costCenterId`, `accountId`, `taxCodeId`, `quantity` and `unitPrice` in this batch body; only `customProperties` keeps its value on `null`. - `customProperties.valueIds` — Catalogue value ids for this group. Required; send `[]` (with an empty `inlineValues`) to clear the group. `SINGLE_SELECT` and `MULTI_SELECT` groups accept nothing else. See [Custom properties on writes](/docs/getting-started/pagination-filtering-errors#custom-properties-on-writes). - `customProperties.inlineValues` — Literal values for `TEXT`, `NUMERIC`, `BOOLEAN` and `DATE` groups, as strings (`yyyy-MM-dd` for dates). Rejected on select groups with `CUSTOM_PROPERTY_VALUE_TYPE_MISMATCH`. See [Custom properties on writes](/docs/getting-started/pagination-filtering-errors#custom-properties-on-writes). ```json [ { "lineId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "description": "string", "costCenterId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "accountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "taxCodeId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "quantity": 0, "unitPrice": 100000, "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "valueIds": [ "3c90c3cc-0d44-4b50-8888-8dd25736052a" ], "inlineValues": [ "string" ] } ] } ] ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders, and fields that exclude each other are all shown. Do not send it unchanged. ## Response ```json [ { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "purchaseOrderId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "description": "string", "costCenterId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "accountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "taxCodeId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "quantity": 0, "unitPrice": 100000, "amount": 100000, "netAmount": 100000, "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z", "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupInternalName": "string", "values": [ { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupInternalName": "string", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "internalName": "string", "label": "string", "context": "string", "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z" } ] } ] } ] ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders. ## Code ```bash curl -X PUT "https://api.light.inc/v1/purchase-orders/3c90c3cc-0d44-4b50-8888-8dd25736052a/lines/bulk" \ -H "Authorization: Basic YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '[ { "lineId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "description": "string", "costCenterId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "accountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "taxCodeId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "quantity": 0, "unitPrice": 100000, "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "valueIds": [ "3c90c3cc-0d44-4b50-8888-8dd25736052a" ], "inlineValues": [ "string" ] } ] } ]' ``` Full page: https://light.inc/docs/api-reference/v1--purchase-orders/batch-update-purchase-order-lines --- # Bulk create purchase order lines > Creates multiple purchase order line items `POST https://api.light.inc/v1/purchase-orders/{purchaseOrderId}/lines/bulk` ## Note Same rules as the single create; an empty list returns [] and changes nothing. ## Authorization - API key - Bearer token See https://light.inc/docs/getting-started/authentication. ## Path parameters - `purchaseOrderId` (string, uuid, required) ## Request body `application/json;charset=UTF-8` - `customProperties.valueIds` — Catalogue value ids for this group. Required; send `[]` (with an empty `inlineValues`) to clear the group. `SINGLE_SELECT` and `MULTI_SELECT` groups accept nothing else. See [Custom properties on writes](/docs/getting-started/pagination-filtering-errors#custom-properties-on-writes). - `customProperties.inlineValues` — Literal values for `TEXT`, `NUMERIC`, `BOOLEAN` and `DATE` groups, as strings (`yyyy-MM-dd` for dates). Rejected on select groups with `CUSTOM_PROPERTY_VALUE_TYPE_MISMATCH`. See [Custom properties on writes](/docs/getting-started/pagination-filtering-errors#custom-properties-on-writes). ```json [ { "description": "string", "costCenterId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "accountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "taxCodeId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "quantity": 0, "unitPrice": 100000, "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "valueIds": [ "3c90c3cc-0d44-4b50-8888-8dd25736052a" ], "inlineValues": [ "string" ] } ] } ] ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders, and fields that exclude each other are all shown. Do not send it unchanged. ## Response ```json [ { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "purchaseOrderId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "description": "string", "costCenterId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "accountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "taxCodeId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "quantity": 0, "unitPrice": 100000, "amount": 100000, "netAmount": 100000, "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z", "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupInternalName": "string", "values": [ { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupInternalName": "string", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "internalName": "string", "label": "string", "context": "string", "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z" } ] } ] } ] ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders. ## Code ```bash curl -X POST "https://api.light.inc/v1/purchase-orders/3c90c3cc-0d44-4b50-8888-8dd25736052a/lines/bulk" \ -H "Authorization: Basic YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '[ { "description": "string", "costCenterId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "accountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "taxCodeId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "quantity": 0, "unitPrice": 100000, "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "valueIds": [ "3c90c3cc-0d44-4b50-8888-8dd25736052a" ], "inlineValues": [ "string" ] } ] } ]' ``` Full page: https://light.inc/docs/api-reference/v1--purchase-orders/bulk-create-purchase-order-lines --- # Cancel purchase order > Cancels a purchase order `POST https://api.light.inc/v1/purchase-orders/{purchaseOrderId}/cancel` ## Note From IN_DRAFT or APPROVED_ACCOUNTING_ENTRY_PENDING the order is cancelled immediately; from OPEN it goes through CANCEL_PENDING and is cancelled in the background. Blocked while any live bill is matched to the order ( PURCHASE_ORDER_CANCELLATION_BLOCKED_BY_MATCHED_BILL ); unmatch in Light first. Cancelling also cancels the purchase request it came from. ## Authorization - API key - Bearer token See https://light.inc/docs/getting-started/authentication. ## Path parameters - `purchaseOrderId` (string, uuid, required) ## Response - `erpNumber` — Assigned when the order reaches `OPEN`, after the ERP confirms the lock in the background; `null` before that. - `editStatus` — `ALL_EDITS_LOCKED` from `lock` onwards; `CORE_EDITS_LOCKED` on drafts created from a purchase request (vendor, entity, currency, line quantities and prices, and adding or removing lines are frozen). Not returned by the list endpoint. ```json { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "createdBy": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyEntityId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "purchaseRequestId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "state": "IN_DRAFT", "totalAmount": 100000, "totalNetAmount": 100000, "totalTaxAmount": 100000, "erpNumber": "string", "description": "string", "currency": "USD", "ownerId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "vendorId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "vendorEmail": "string", "deliveryAddress": "string", "deliveryDate": "2026-01-15", "documentKey": "string", "failureContext": { "name": "string", "type": "BAD_REQUEST", "errors": [ { "type": "string", "message": "string", "path": [ "string" ], "context": null } ] }, "editStatus": "ALL_EDITS_ALLOWED", "purchaseOrderDate": "2026-01-15", "erpSyncedAt": "2026-01-15T09:30:00Z", "lockedAt": "2026-01-15T09:30:00Z", "closedAt": "2026-01-15T09:30:00Z", "cancelledAt": "2026-01-15T09:30:00Z", "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z", "lines": [ { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "purchaseOrderId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "description": "string", "costCenterId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "accountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "taxCodeId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "quantity": 0, "unitPrice": 100000, "amount": 100000, "netAmount": 100000, "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z", "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupInternalName": "string", "values": [ {} ] } ] } ], "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupInternalName": "string", "values": [ { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupInternalName": "string", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "internalName": "string", "label": "string", "context": "string", "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z" } ] } ] } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders. ## Code ```bash curl -X POST "https://api.light.inc/v1/purchase-orders/3c90c3cc-0d44-4b50-8888-8dd25736052a/cancel" \ -H "Authorization: Basic YOUR_API_KEY" ``` Full page: https://light.inc/docs/api-reference/v1--purchase-orders/cancel-purchase-order --- # Close purchase order > Closes a purchase order `POST https://api.light.inc/v1/purchase-orders/{purchaseOrderId}/close` ## Note Only from OPEN , giving CLOSE_PENDING (with closedAt set) and then CLOSED in the background. Matched bills are not affected. A bill's submit-for-approval with closePurchaseOrder: true closes the matched order the same way. ## Authorization - API key - Bearer token See https://light.inc/docs/getting-started/authentication. ## Path parameters - `purchaseOrderId` (string, uuid, required) ## Response - `erpNumber` — Assigned when the order reaches `OPEN`, after the ERP confirms the lock in the background; `null` before that. - `editStatus` — `ALL_EDITS_LOCKED` from `lock` onwards; `CORE_EDITS_LOCKED` on drafts created from a purchase request (vendor, entity, currency, line quantities and prices, and adding or removing lines are frozen). Not returned by the list endpoint. ```json { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "createdBy": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyEntityId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "purchaseRequestId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "state": "IN_DRAFT", "totalAmount": 100000, "totalNetAmount": 100000, "totalTaxAmount": 100000, "erpNumber": "string", "description": "string", "currency": "USD", "ownerId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "vendorId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "vendorEmail": "string", "deliveryAddress": "string", "deliveryDate": "2026-01-15", "documentKey": "string", "failureContext": { "name": "string", "type": "BAD_REQUEST", "errors": [ { "type": "string", "message": "string", "path": [ "string" ], "context": null } ] }, "editStatus": "ALL_EDITS_ALLOWED", "purchaseOrderDate": "2026-01-15", "erpSyncedAt": "2026-01-15T09:30:00Z", "lockedAt": "2026-01-15T09:30:00Z", "closedAt": "2026-01-15T09:30:00Z", "cancelledAt": "2026-01-15T09:30:00Z", "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z", "lines": [ { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "purchaseOrderId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "description": "string", "costCenterId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "accountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "taxCodeId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "quantity": 0, "unitPrice": 100000, "amount": 100000, "netAmount": 100000, "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z", "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupInternalName": "string", "values": [ {} ] } ] } ], "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupInternalName": "string", "values": [ { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupInternalName": "string", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "internalName": "string", "label": "string", "context": "string", "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z" } ] } ] } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders. ## Code ```bash curl -X POST "https://api.light.inc/v1/purchase-orders/3c90c3cc-0d44-4b50-8888-8dd25736052a/close" \ -H "Authorization: Basic YOUR_API_KEY" ``` Full page: https://light.inc/docs/api-reference/v1--purchase-orders/close-purchase-order --- # List purchase orders > Returns a paginated list of purchase orders `GET https://api.light.inc/v1/purchase-orders` ## Note Guarded by the create permission (company-admin or AP-preparation roles), so a purchase-requester or auditor who can read a single order gets 403 on the list. List rows are a different shape from the single read: they add vendorName , ownerName , totalMatchedAmount and line labels, and lack editStatus and customProperties . No searchTerm . ## Authorization - API key - Bearer token See https://light.inc/docs/getting-started/authentication. ## Query parameters - `sort` (string) — Sort string in the format field:direction . To provide multiple sort fields, separate them with commas. Available directions: asc , desc . Available fields: purchaseOrderId , erpNumber , vendorName , ownerName , ownerId , companyEntityId , state , closedAt , cancelledAt , createdAt , totalAmount . - `filter` (string) — Filter string in the format field:operator:value . To provide multiple filters, separate them with commas. Available operators: eq , ne , in , not_in , gt , gte , lt , lte . - For in and not_in operators, provide multiple values separated by the pipe character ( ). Available fields: purchaseOrderId , vendorId , ownerId , state , erpNumber , updatedAt . - `limit` (integer, int32) — Maximum number of items to return. Default is 50, maximum is 200. - `offset` (integer, int64) — Number of items to skip before starting to collect the result set. Deprecated, use 'cursor' instead. - `cursor` (string) — The cursor position to start returning results from. To opt-in into cursor-based pagination, provide 0 for the initial request. For subsequent requests, use nextCursor and prevCursor from the previous response to navigate. Cursor values are opaque and should not be constructed manually. ## Response - `records.id` — The purchase order id. - `records.companyId` — Your company id. - `records.createdBy` — The principal that created the order. - `records.companyEntityId` — The entity the order belongs to. - `records.purchaseRequestId` — The purchase request the order was raised from, if any. - `records.erpNumber` — The purchase order number shown to the vendor and printed on the order; assigned when the order is opened. - `records.description` — The order description. - `records.currency` — The order currency. - `records.totalAmount` — Gross total of the lines, minor units. - `records.totalNetAmount` — Total excluding tax, minor units. - `records.totalTaxAmount` — Total tax, minor units. - `records.totalMatchedAmount` — Amount of bills matched to this order so far, minor units. - `records.ownerId` — The person responsible for the order. - `records.ownerName` — Their name. - `records.vendorId` — The vendor the order is placed with. - `records.vendorEmail` — The vendor's email address. - `records.vendorName` — The vendor's name. - `records.vendorAvatarUrl` — Logo URL. - `records.documentKey` — Storage key of the order PDF. Download it through the order's document endpoint, not with this key. - `records.failureContext` — The error of the last failed step, if any. - `records.purchaseOrderDate` — The order date. - `records.deliveryAddress` — Where the goods or services are to be delivered. - `records.deliveryDate` — Expected delivery date. - `records.lockedAt` — When the order was locked against edits with the lock action; `null` while editable. - `records.closedAt` — When the order was closed; `null` while open. - `records.cancelledAt` — When the order was cancelled; `null` otherwise. - `records.createdAt` — When the order was created. - `records.updatedAt` — When it was last changed. - `records.lines` — The order lines. - `records.lines.id` — The line id. - `records.lines.companyId` — Your company id. - `records.lines.purchaseOrderId` — The order the line belongs to. - `records.lines.description` — The line description. - `records.lines.quantity` — Quantity ordered. - `records.lines.unitPrice` — Price per unit, minor units. - `records.lines.accountId` — The expense account for the line. - `records.lines.accountLabel` — Its name. - `records.lines.taxCodeId` — The tax code on the line. - `records.lines.amount` — Gross line amount, minor units. - `records.lines.taxAmount` — Tax on the line, minor units. - `records.lines.netAmount` — Line amount excluding tax, minor units. - `records.lines.taxCodeLabel` — The tax code's name. - `records.lines.costCenterId` — Cost center on the line. - `records.lines.costCenterName` — Its name. - `records.lines.createdAt` — When the line was created. - `records.lines.updatedAt` — When it was last changed. ```json { "records": [ { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "createdBy": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyEntityId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "purchaseRequestId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "state": "IN_DRAFT", "erpNumber": "string", "description": "string", "currency": "USD", "totalAmount": 100000, "totalNetAmount": 100000, "totalTaxAmount": 100000, "totalMatchedAmount": 100000, "ownerId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "ownerName": "string", "vendorId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "vendorEmail": "string", "vendorName": "string", "vendorAvatarUrl": "string", "documentKey": "string", "failureContext": { "name": "string", "type": "BAD_REQUEST", "errors": [ { "type": "string", "message": "string", "path": [], "context": null } ] }, "purchaseOrderDate": "2026-01-15", "deliveryAddress": "string", "deliveryDate": "2026-01-15", "erpSyncedAt": "2026-01-15T09:30:00Z", "lockedAt": "2026-01-15T09:30:00Z", "closedAt": "2026-01-15T09:30:00Z", "cancelledAt": "2026-01-15T09:30:00Z", "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z", "lines": [ { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "purchaseOrderId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "description": "string", "quantity": 100000, "unitPrice": 100000, "accountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "accountLabel": "string", "taxCodeId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "amount": 100000, "taxAmount": 100000, "netAmount": 100000, "taxCodeLabel": "string", "costCenterId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "costCenterName": "string", "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z" } ] } ], "hasMore": true, "total": 100000, "nextCursor": "string", "prevCursor": "string" } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders. ## Code ```bash curl -X GET "https://api.light.inc/v1/purchase-orders" \ -H "Authorization: Basic YOUR_API_KEY" ``` Full page: https://light.inc/docs/api-reference/v1--purchase-orders/list-purchase-orders --- # Create purchase order > Creates a new purchase order `POST https://api.light.inc/v1/purchase-orders` ## Note Nothing is required at creation — vendor, entity, owner and even lines may be empty; everything is checked at lock . At most 500 lines ( PURCHASE_ORDER_LINES_COUNT_EXCEEDED ). unitPrice is net; per-line taxAmount is computed from taxCodeId only once the order has a companyEntityId , and cannot be overridden. Most response fields marked required below are null on a fresh draft. States: IN_DRAFT → lock → APPROVED_ACCOUNTING_ENTRY_PENDING → OPEN (in the background, when the ERP confirms; erpNumber and documentKey appear then) → close → CLOSE_PENDING → CLOSED , or cancel → CANCEL_PENDING → CANCELLED , or reset → RESET_PENDING → IN_DRAFT . A wrong-state call fails with PURCHASE_ORDER_INVALID_STATE_TRANSITION . ## Authorization - API key - Bearer token See https://light.inc/docs/getting-started/authentication. ## Request body `application/json;charset=UTF-8` - `lines.customProperties.valueIds` — Catalogue value ids for this group. Required; send `[]` (with an empty `inlineValues`) to clear the group. `SINGLE_SELECT` and `MULTI_SELECT` groups accept nothing else. See [Custom properties on writes](/docs/getting-started/pagination-filtering-errors#custom-properties-on-writes). - `lines.customProperties.inlineValues` — Literal values for `TEXT`, `NUMERIC`, `BOOLEAN` and `DATE` groups, as strings (`yyyy-MM-dd` for dates). Rejected on select groups with `CUSTOM_PROPERTY_VALUE_TYPE_MISMATCH`. See [Custom properties on writes](/docs/getting-started/pagination-filtering-errors#custom-properties-on-writes). - `customProperties.valueIds` — Catalogue value ids for this group. Required; send `[]` (with an empty `inlineValues`) to clear the group. `SINGLE_SELECT` and `MULTI_SELECT` groups accept nothing else. See [Custom properties on writes](/docs/getting-started/pagination-filtering-errors#custom-properties-on-writes). - `customProperties.inlineValues` — Literal values for `TEXT`, `NUMERIC`, `BOOLEAN` and `DATE` groups, as strings (`yyyy-MM-dd` for dates). Rejected on select groups with `CUSTOM_PROPERTY_VALUE_TYPE_MISMATCH`. See [Custom properties on writes](/docs/getting-started/pagination-filtering-errors#custom-properties-on-writes). ```json { "vendorId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyEntityId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "ownerId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "currency": "USD", "purchaseOrderDate": "2026-01-15", "deliveryAddress": "string", "deliveryDate": "2026-01-15", "description": "string", "lines": [ { "description": "string", "costCenterId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "accountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "taxCodeId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "quantity": 0, "unitPrice": 100000, "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "valueIds": [ "3c90c3cc-0d44-4b50-8888-8dd25736052a" ], "inlineValues": [ "string" ] } ] } ], "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "valueIds": [ "3c90c3cc-0d44-4b50-8888-8dd25736052a" ], "inlineValues": [ "string" ] } ] } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders, and fields that exclude each other are all shown. Do not send it unchanged. ## Response - `erpNumber` — Assigned when the order reaches `OPEN`, after the ERP confirms the lock in the background; `null` before that. - `editStatus` — `ALL_EDITS_LOCKED` from `lock` onwards; `CORE_EDITS_LOCKED` on drafts created from a purchase request (vendor, entity, currency, line quantities and prices, and adding or removing lines are frozen). Not returned by the list endpoint. ```json { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "createdBy": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyEntityId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "purchaseRequestId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "state": "IN_DRAFT", "totalAmount": 100000, "totalNetAmount": 100000, "totalTaxAmount": 100000, "erpNumber": "string", "description": "string", "currency": "USD", "ownerId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "vendorId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "vendorEmail": "string", "deliveryAddress": "string", "deliveryDate": "2026-01-15", "documentKey": "string", "failureContext": { "name": "string", "type": "BAD_REQUEST", "errors": [ { "type": "string", "message": "string", "path": [ "string" ], "context": null } ] }, "editStatus": "ALL_EDITS_ALLOWED", "purchaseOrderDate": "2026-01-15", "erpSyncedAt": "2026-01-15T09:30:00Z", "lockedAt": "2026-01-15T09:30:00Z", "closedAt": "2026-01-15T09:30:00Z", "cancelledAt": "2026-01-15T09:30:00Z", "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z", "lines": [ { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "purchaseOrderId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "description": "string", "costCenterId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "accountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "taxCodeId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "quantity": 0, "unitPrice": 100000, "amount": 100000, "netAmount": 100000, "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z", "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupInternalName": "string", "values": [ {} ] } ] } ], "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupInternalName": "string", "values": [ { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupInternalName": "string", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "internalName": "string", "label": "string", "context": "string", "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z" } ] } ] } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders. ## Code ```bash curl -X POST "https://api.light.inc/v1/purchase-orders" \ -H "Authorization: Basic YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "vendorId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyEntityId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "ownerId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "currency": "USD", "purchaseOrderDate": "2026-01-15", "deliveryAddress": "string", "deliveryDate": "2026-01-15", "description": "string", "lines": [ { "description": "string", "costCenterId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "accountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "taxCodeId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "quantity": 0, "unitPrice": 100000, "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "valueIds": [ "3c90c3cc-0d44-4b50-8888-8dd25736052a" ], "inlineValues": [ "string" ] } ] } ], "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "valueIds": [ "3c90c3cc-0d44-4b50-8888-8dd25736052a" ], "inlineValues": [ "string" ] } ] }' ``` Full page: https://light.inc/docs/api-reference/v1--purchase-orders/create-purchase-order --- # Create purchase order line > Creates a new purchase order line item `POST https://api.light.inc/v1/purchase-orders/{purchaseOrderId}/lines` ## Note Only while the order is unlocked ( PURCHASE_ORDER_LOCKED ) and not core-locked ( PURCHASE_ORDER_CORE_EDITS_LOCKED ). Tax is computed only when the order has an entity. ## Authorization - API key - Bearer token See https://light.inc/docs/getting-started/authentication. ## Path parameters - `purchaseOrderId` (string, uuid, required) ## Request body `application/json;charset=UTF-8` - `customProperties.valueIds` — Catalogue value ids for this group. Required; send `[]` (with an empty `inlineValues`) to clear the group. `SINGLE_SELECT` and `MULTI_SELECT` groups accept nothing else. See [Custom properties on writes](/docs/getting-started/pagination-filtering-errors#custom-properties-on-writes). - `customProperties.inlineValues` — Literal values for `TEXT`, `NUMERIC`, `BOOLEAN` and `DATE` groups, as strings (`yyyy-MM-dd` for dates). Rejected on select groups with `CUSTOM_PROPERTY_VALUE_TYPE_MISMATCH`. See [Custom properties on writes](/docs/getting-started/pagination-filtering-errors#custom-properties-on-writes). ```json { "description": "string", "costCenterId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "accountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "taxCodeId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "quantity": 0, "unitPrice": 100000, "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "valueIds": [ "3c90c3cc-0d44-4b50-8888-8dd25736052a" ], "inlineValues": [ "string" ] } ] } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders, and fields that exclude each other are all shown. Do not send it unchanged. ## Response ```json { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "purchaseOrderId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "description": "string", "costCenterId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "accountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "taxCodeId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "quantity": 0, "unitPrice": 100000, "amount": 100000, "netAmount": 100000, "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z", "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupInternalName": "string", "values": [ { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupInternalName": "string", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "internalName": "string", "label": "string", "context": "string", "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z" } ] } ] } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders. ## Code ```bash curl -X POST "https://api.light.inc/v1/purchase-orders/3c90c3cc-0d44-4b50-8888-8dd25736052a/lines" \ -H "Authorization: Basic YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "description": "string", "costCenterId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "accountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "taxCodeId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "quantity": 0, "unitPrice": 100000, "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "valueIds": [ "3c90c3cc-0d44-4b50-8888-8dd25736052a" ], "inlineValues": [ "string" ] } ] }' ``` Full page: https://light.inc/docs/api-reference/v1--purchase-orders/create-purchase-order-line --- # Get purchase order > Returns a purchase order by ID `GET https://api.light.inc/v1/purchase-orders/{purchaseOrderId}` ## Note Any state, with lines. An unknown id, or one from another company, is 404 . ## Authorization - API key - Bearer token See https://light.inc/docs/getting-started/authentication. ## Path parameters - `purchaseOrderId` (string, uuid, required) ## Response - `erpNumber` — Assigned when the order reaches `OPEN`, after the ERP confirms the lock in the background; `null` before that. - `editStatus` — `ALL_EDITS_LOCKED` from `lock` onwards; `CORE_EDITS_LOCKED` on drafts created from a purchase request (vendor, entity, currency, line quantities and prices, and adding or removing lines are frozen). Not returned by the list endpoint. ```json { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "createdBy": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyEntityId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "purchaseRequestId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "state": "IN_DRAFT", "totalAmount": 100000, "totalNetAmount": 100000, "totalTaxAmount": 100000, "erpNumber": "string", "description": "string", "currency": "USD", "ownerId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "vendorId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "vendorEmail": "string", "deliveryAddress": "string", "deliveryDate": "2026-01-15", "documentKey": "string", "failureContext": { "name": "string", "type": "BAD_REQUEST", "errors": [ { "type": "string", "message": "string", "path": [ "string" ], "context": null } ] }, "editStatus": "ALL_EDITS_ALLOWED", "purchaseOrderDate": "2026-01-15", "erpSyncedAt": "2026-01-15T09:30:00Z", "lockedAt": "2026-01-15T09:30:00Z", "closedAt": "2026-01-15T09:30:00Z", "cancelledAt": "2026-01-15T09:30:00Z", "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z", "lines": [ { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "purchaseOrderId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "description": "string", "costCenterId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "accountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "taxCodeId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "quantity": 0, "unitPrice": 100000, "amount": 100000, "netAmount": 100000, "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z", "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupInternalName": "string", "values": [ {} ] } ] } ], "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupInternalName": "string", "values": [ { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupInternalName": "string", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "internalName": "string", "label": "string", "context": "string", "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z" } ] } ] } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders. ## Code ```bash curl -X GET "https://api.light.inc/v1/purchase-orders/3c90c3cc-0d44-4b50-8888-8dd25736052a" \ -H "Authorization: Basic YOUR_API_KEY" ``` Full page: https://light.inc/docs/api-reference/v1--purchase-orders/get-purchase-order --- # Update purchase order > Updates an existing purchase order `PATCH https://api.light.inc/v1/purchase-orders/{purchaseOrderId}` ## Note Only while unlocked, which in practice means IN_DRAFT ; every other state fails with PURCHASE_ORDER_LOCKED . An order created from an approved purchase request is CORE_EDITS_LOCKED even as a draft: vendorId , companyEntityId and currency cannot change and lines cannot be added or removed ( PURCHASE_ORDER_CORE_EDITS_LOCKED , with forbiddenFields in the context). Fields follow the omit-to-keep, null -to-clear rule. Changing vendorId deletes every bill matching on the order; changing currency recomputes them. ## Authorization - API key - Bearer token See https://light.inc/docs/getting-started/authentication. ## Path parameters - `purchaseOrderId` (string, uuid, required) ## Request body `application/json;charset=UTF-8` - `customProperties.valueIds` — Catalogue value ids for this group. Required; send `[]` (with an empty `inlineValues`) to clear the group. `SINGLE_SELECT` and `MULTI_SELECT` groups accept nothing else. See [Custom properties on writes](/docs/getting-started/pagination-filtering-errors#custom-properties-on-writes). - `customProperties.inlineValues` — Literal values for `TEXT`, `NUMERIC`, `BOOLEAN` and `DATE` groups, as strings (`yyyy-MM-dd` for dates). Rejected on select groups with `CUSTOM_PROPERTY_VALUE_TYPE_MISMATCH`. See [Custom properties on writes](/docs/getting-started/pagination-filtering-errors#custom-properties-on-writes). ```json { "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "valueIds": [ "3c90c3cc-0d44-4b50-8888-8dd25736052a" ], "inlineValues": [ "string" ] } ], "vendorId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyEntityId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "ownerId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "currency": "USD", "purchaseOrderDate": "2026-01-15", "deliveryAddress": "string", "deliveryDate": "2026-01-15", "description": "string" } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders, and fields that exclude each other are all shown. Do not send it unchanged. ## Response - `erpNumber` — Assigned when the order reaches `OPEN`, after the ERP confirms the lock in the background; `null` before that. - `editStatus` — `ALL_EDITS_LOCKED` from `lock` onwards; `CORE_EDITS_LOCKED` on drafts created from a purchase request (vendor, entity, currency, line quantities and prices, and adding or removing lines are frozen). Not returned by the list endpoint. ```json { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "createdBy": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyEntityId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "purchaseRequestId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "state": "IN_DRAFT", "totalAmount": 100000, "totalNetAmount": 100000, "totalTaxAmount": 100000, "erpNumber": "string", "description": "string", "currency": "USD", "ownerId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "vendorId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "vendorEmail": "string", "deliveryAddress": "string", "deliveryDate": "2026-01-15", "documentKey": "string", "failureContext": { "name": "string", "type": "BAD_REQUEST", "errors": [ { "type": "string", "message": "string", "path": [ "string" ], "context": null } ] }, "editStatus": "ALL_EDITS_ALLOWED", "purchaseOrderDate": "2026-01-15", "erpSyncedAt": "2026-01-15T09:30:00Z", "lockedAt": "2026-01-15T09:30:00Z", "closedAt": "2026-01-15T09:30:00Z", "cancelledAt": "2026-01-15T09:30:00Z", "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z", "lines": [ { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "purchaseOrderId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "description": "string", "costCenterId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "accountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "taxCodeId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "quantity": 0, "unitPrice": 100000, "amount": 100000, "netAmount": 100000, "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z", "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupInternalName": "string", "values": [ {} ] } ] } ], "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupInternalName": "string", "values": [ { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupInternalName": "string", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "internalName": "string", "label": "string", "context": "string", "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z" } ] } ] } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders. ## Code ```bash curl -X PATCH "https://api.light.inc/v1/purchase-orders/3c90c3cc-0d44-4b50-8888-8dd25736052a" \ -H "Authorization: Basic YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "valueIds": [ "3c90c3cc-0d44-4b50-8888-8dd25736052a" ], "inlineValues": [ "string" ] } ], "vendorId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyEntityId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "ownerId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "currency": "USD", "purchaseOrderDate": "2026-01-15", "deliveryAddress": "string", "deliveryDate": "2026-01-15", "description": "string" }' ``` Full page: https://light.inc/docs/api-reference/v1--purchase-orders/update-purchase-order --- # Lock purchase order > Locks a purchase order to prevent modifications `POST https://api.light.inc/v1/purchase-orders/{purchaseOrderId}/lock` ## Note Lock is the approval step. It requires companyEntityId , currency , ownerId and vendorId ( PURCHASE_ORDER_HEADER_MISSING_FIELD ), a vendor enabled for that entity, at least one line ( PURCHASE_ORDER_EMPTY_LINES ), each with description , accountId , taxCodeId , quantity and unitPrice ( PURCHASE_ORDER_LINE_MISSING_FIELD ), and required custom properties. The response is APPROVED_ACCOUNTING_ENTRY_PENDING ; the order becomes OPEN , gets its erpNumber and PDF, and the vendor is notified only after the ERP confirms in the background. A failure there leaves it pending with failureContext set. Poll GET . ## Authorization - API key - Bearer token See https://light.inc/docs/getting-started/authentication. ## Path parameters - `purchaseOrderId` (string, uuid, required) ## Response - `erpNumber` — Assigned when the order reaches `OPEN`, after the ERP confirms the lock in the background; `null` before that. - `editStatus` — `ALL_EDITS_LOCKED` from `lock` onwards; `CORE_EDITS_LOCKED` on drafts created from a purchase request (vendor, entity, currency, line quantities and prices, and adding or removing lines are frozen). Not returned by the list endpoint. ```json { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "createdBy": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyEntityId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "purchaseRequestId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "state": "IN_DRAFT", "totalAmount": 100000, "totalNetAmount": 100000, "totalTaxAmount": 100000, "erpNumber": "string", "description": "string", "currency": "USD", "ownerId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "vendorId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "vendorEmail": "string", "deliveryAddress": "string", "deliveryDate": "2026-01-15", "documentKey": "string", "failureContext": { "name": "string", "type": "BAD_REQUEST", "errors": [ { "type": "string", "message": "string", "path": [ "string" ], "context": null } ] }, "editStatus": "ALL_EDITS_ALLOWED", "purchaseOrderDate": "2026-01-15", "erpSyncedAt": "2026-01-15T09:30:00Z", "lockedAt": "2026-01-15T09:30:00Z", "closedAt": "2026-01-15T09:30:00Z", "cancelledAt": "2026-01-15T09:30:00Z", "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z", "lines": [ { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "purchaseOrderId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "description": "string", "costCenterId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "accountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "taxCodeId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "quantity": 0, "unitPrice": 100000, "amount": 100000, "netAmount": 100000, "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z", "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupInternalName": "string", "values": [ {} ] } ] } ], "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupInternalName": "string", "values": [ { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupInternalName": "string", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "internalName": "string", "label": "string", "context": "string", "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z" } ] } ] } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders. ## Code ```bash curl -X POST "https://api.light.inc/v1/purchase-orders/3c90c3cc-0d44-4b50-8888-8dd25736052a/lock" \ -H "Authorization: Basic YOUR_API_KEY" ``` Full page: https://light.inc/docs/api-reference/v1--purchase-orders/lock-purchase-order --- # Delete purchase order line > Deletes a purchase order line item `DELETE https://api.light.inc/v1/purchase-orders/{purchaseOrderId}/lines/{lineId}` ## Note Only while unlocked and not core-locked; the last line cannot be deleted ( PURCHASE_ORDER_AT_LEAST_ONE_LINE ). Answers 204 with no body. ## Authorization - API key - Bearer token See https://light.inc/docs/getting-started/authentication. ## Path parameters - `purchaseOrderId` (string, uuid, required) - `lineId` (string, uuid, required) ## Response This endpoint returns no content. ## Code ```bash curl -X DELETE "https://api.light.inc/v1/purchase-orders/3c90c3cc-0d44-4b50-8888-8dd25736052a/lines/3c90c3cc-0d44-4b50-8888-8dd25736052a" \ -H "Authorization: Basic YOUR_API_KEY" ``` Full page: https://light.inc/docs/api-reference/v1--purchase-orders/delete-purchase-order-line --- # Update purchase order line > Updates a purchase order line item `PATCH https://api.light.inc/v1/purchase-orders/{purchaseOrderId}/lines/{lineId}` ## Note Omit a field to keep it, send null to clear it ( customProperties : null keeps). Only while the order is unlocked ( PURCHASE_ORDER_LOCKED ); on a core-locked order quantity and unitPrice cannot change. Tax is recomputed only when unitPrice or taxCodeId is in the request. ## Authorization - API key - Bearer token See https://light.inc/docs/getting-started/authentication. ## Path parameters - `purchaseOrderId` (string, uuid, required) - `lineId` (string, uuid, required) ## Request body `application/json;charset=UTF-8` - `customProperties.valueIds` — Catalogue value ids for this group. Required; send `[]` (with an empty `inlineValues`) to clear the group. `SINGLE_SELECT` and `MULTI_SELECT` groups accept nothing else. See [Custom properties on writes](/docs/getting-started/pagination-filtering-errors#custom-properties-on-writes). - `customProperties.inlineValues` — Literal values for `TEXT`, `NUMERIC`, `BOOLEAN` and `DATE` groups, as strings (`yyyy-MM-dd` for dates). Rejected on select groups with `CUSTOM_PROPERTY_VALUE_TYPE_MISMATCH`. See [Custom properties on writes](/docs/getting-started/pagination-filtering-errors#custom-properties-on-writes). ```json { "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "valueIds": [ "3c90c3cc-0d44-4b50-8888-8dd25736052a" ], "inlineValues": [ "string" ] } ], "description": "string", "costCenterId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "accountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "taxCodeId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "quantity": 0, "unitPrice": 100000 } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders, and fields that exclude each other are all shown. Do not send it unchanged. ## Response ```json { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "purchaseOrderId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "description": "string", "costCenterId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "accountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "taxCodeId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "quantity": 0, "unitPrice": 100000, "amount": 100000, "netAmount": 100000, "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z", "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupInternalName": "string", "values": [ { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupInternalName": "string", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "internalName": "string", "label": "string", "context": "string", "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z" } ] } ] } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders. ## Code ```bash curl -X PATCH "https://api.light.inc/v1/purchase-orders/3c90c3cc-0d44-4b50-8888-8dd25736052a/lines/3c90c3cc-0d44-4b50-8888-8dd25736052a" \ -H "Authorization: Basic YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "valueIds": [ "3c90c3cc-0d44-4b50-8888-8dd25736052a" ], "inlineValues": [ "string" ] } ], "description": "string", "costCenterId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "accountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "taxCodeId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "quantity": 0, "unitPrice": 100000 }' ``` Full page: https://light.inc/docs/api-reference/v1--purchase-orders/update-purchase-order-line --- # Reset purchase order > Resets a purchase order to its initial state `POST https://api.light.inc/v1/purchase-orders/{purchaseOrderId}/reset` ## Note From OPEN it goes through RESET_PENDING and returns to IN_DRAFT in the background, unlocked, with the ERP entry deleted and the PDF cleared; from APPROVED_ACCOUNTING_ENTRY_PENDING it returns immediately; on a draft it is a no-op. Not allowed from CLOSED or CANCELLED . ## Authorization - API key - Bearer token See https://light.inc/docs/getting-started/authentication. ## Path parameters - `purchaseOrderId` (string, uuid, required) ## Response - `erpNumber` — Assigned when the order reaches `OPEN`, after the ERP confirms the lock in the background; `null` before that. - `editStatus` — `ALL_EDITS_LOCKED` from `lock` onwards; `CORE_EDITS_LOCKED` on drafts created from a purchase request (vendor, entity, currency, line quantities and prices, and adding or removing lines are frozen). Not returned by the list endpoint. ```json { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "createdBy": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyEntityId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "purchaseRequestId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "state": "IN_DRAFT", "totalAmount": 100000, "totalNetAmount": 100000, "totalTaxAmount": 100000, "erpNumber": "string", "description": "string", "currency": "USD", "ownerId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "vendorId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "vendorEmail": "string", "deliveryAddress": "string", "deliveryDate": "2026-01-15", "documentKey": "string", "failureContext": { "name": "string", "type": "BAD_REQUEST", "errors": [ { "type": "string", "message": "string", "path": [ "string" ], "context": null } ] }, "editStatus": "ALL_EDITS_ALLOWED", "purchaseOrderDate": "2026-01-15", "erpSyncedAt": "2026-01-15T09:30:00Z", "lockedAt": "2026-01-15T09:30:00Z", "closedAt": "2026-01-15T09:30:00Z", "cancelledAt": "2026-01-15T09:30:00Z", "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z", "lines": [ { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "purchaseOrderId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "description": "string", "costCenterId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "accountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "taxCodeId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "quantity": 0, "unitPrice": 100000, "amount": 100000, "netAmount": 100000, "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z", "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupInternalName": "string", "values": [ {} ] } ] } ], "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupInternalName": "string", "values": [ { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupInternalName": "string", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "internalName": "string", "label": "string", "context": "string", "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z" } ] } ] } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders. ## Code ```bash curl -X POST "https://api.light.inc/v1/purchase-orders/3c90c3cc-0d44-4b50-8888-8dd25736052a/reset" \ -H "Authorization: Basic YOUR_API_KEY" ``` Full page: https://light.inc/docs/api-reference/v1--purchase-orders/reset-purchase-order --- # Reimbursement categories (resource) List the reimbursement categories that decide the GL account and tax code on a reimbursement. Resource page: https://light.inc/docs/api-reference/v1--reimbursement-categories # List reimbursement categories > Returns a paginated list of the company's reimbursement categories. Every expense line needs one: the category decides the GL account and tax code its reimbursement books to. `GET https://api.light.inc/v1/reimbursement-categories` ## Note entityIds is optional and an empty value means no entity filter. Because an expense line's category must belong to the user's own entity, pass that user's companyEntityId to get the categories you can actually use. Default order is label:asc ; searchTerm matches label case-insensitively. ## Authorization - API key - Bearer token See https://light.inc/docs/getting-started/authentication. ## Query parameters - `entityIds` (array) — Restrict to categories available for these company entities - `sort` (string) — Sort string in the format field:direction . To provide multiple sort fields, separate them with commas. Available directions: asc , desc . Available fields: createdAt , label . - `filter` (string) — Filter string in the format field:operator:value . To provide multiple filters, separate them with commas. Available operators: eq , ne , in , not_in , gt , gte , lt , lte . - For in and not_in operators, provide multiple values separated by the pipe character ( ). Available fields: label , status , id , createdAt . - `searchTerm` (string) — Matches against the category label - `limit` (integer, int32) — Maximum number of items to return. Default is 50, maximum is 200. - `offset` (integer, int64) — Number of items to skip before starting to collect the result set. Deprecated, use 'cursor' instead. - `cursor` (string) — The cursor position to start returning results from. To opt-in into cursor-based pagination, provide 0 for the initial request. For subsequent requests, use nextCursor and prevCursor from the previous response to navigate. Cursor values are opaque and should not be constructed manually. ## Response ```json { "records": [ { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyEntityIds": [ "3c90c3cc-0d44-4b50-8888-8dd25736052a" ], "label": "string", "accountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "taxCodeId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "context": "string", "status": "ACTIVE", "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z" } ], "hasMore": true, "total": 100000, "nextCursor": "string", "prevCursor": "string" } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders. ## Code ```bash curl -X GET "https://api.light.inc/v1/reimbursement-categories" \ -H "Authorization: Basic YOUR_API_KEY" ``` Full page: https://light.inc/docs/api-reference/v1--reimbursement-categories/list-reimbursement-categories --- # User Comments (resource) Create, list and manage comments on records. Resource page: https://light.inc/docs/api-reference/v1--user-comments # List user comments > List user comments for a given resource `GET https://api.light.inc/v1/user-comments` ## Note resourceId is required. Comments come back newest first by default; createdAt is the only sortable field. ## Authorization - API key - Bearer token See https://light.inc/docs/getting-started/authentication. ## Query parameters - `resourceId` (string, uuid) — ID of the resource this comment is attached to (e.g. vendor, customer, etc.). - `sort` (string) — Sort string in the format field:direction . To provide multiple sort fields, separate them with commas. Available directions: asc , desc . Available fields: createdAt . - `filter` (string) — Filter string in the format field:operator:value . To provide multiple filters, separate them with commas. Available operators: eq , ne , in , not_in , gt , gte , lt , lte . - For in and not_in operators, provide multiple values separated by the pipe character ( ). Available fields: createdBy , createdAt . - `limit` (integer, int32) — Maximum number of items to return. Default is 50, maximum is 200. - `offset` (integer, int64) — Number of items to skip before starting to collect the result set. Deprecated, use 'cursor' instead. - `cursor` (string) — The cursor position to start returning results from. To opt-in into cursor-based pagination, provide 0 for the initial request. For subsequent requests, use nextCursor and prevCursor from the previous response to navigate. Cursor values are opaque and should not be constructed manually. ## Response ```json { "records": [ { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "resourceId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "content": "string", "createdBy": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z" } ], "hasMore": true, "total": 100000, "nextCursor": "string", "prevCursor": "string" } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders. ## Code ```bash curl -X GET "https://api.light.inc/v1/user-comments" \ -H "Authorization: Basic YOUR_API_KEY" ``` Full page: https://light.inc/docs/api-reference/v1--user-comments/list-user-comments --- # Create user comment > Creates a new user comment `POST https://api.light.inc/v1/user-comments` ## Note resourceId is the id of the record being commented on (any record type; there is no resourceType ), and it is not validated — a wrong id is accepted silently. content is stored and returned verbatim with no length limit and no mention syntax. createdBy is always the caller; for an API key that is the key's service-account id. ## Authorization - API key - Bearer token See https://light.inc/docs/getting-started/authentication. ## Request body `application/json;charset=UTF-8` ```json { "resourceId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "content": "string" } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders, and fields that exclude each other are all shown. Do not send it unchanged. ## Response ```json { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "resourceId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "content": "string", "createdBy": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z" } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders. ## Code ```bash curl -X POST "https://api.light.inc/v1/user-comments" \ -H "Authorization: Basic YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "resourceId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "content": "string" }' ``` Full page: https://light.inc/docs/api-reference/v1--user-comments/create-user-comment --- # Delete user comment > Deletes the given user comment `DELETE https://api.light.inc/v1/user-comments/{userCommentId}` ## Note Author-only ( 403 for anyone else, 404 USER_COMMENT_NOT_FOUND if unknown). The delete is permanent and answers 204 with no body. ## Authorization - API key - Bearer token See https://light.inc/docs/getting-started/authentication. ## Path parameters - `userCommentId` (string, uuid, required) ## Response This endpoint returns no content. ## Code ```bash curl -X DELETE "https://api.light.inc/v1/user-comments/3c90c3cc-0d44-4b50-8888-8dd25736052a" \ -H "Authorization: Basic YOUR_API_KEY" ``` Full page: https://light.inc/docs/api-reference/v1--user-comments/delete-user-comment --- # Update user comment > Updates the given user comment `PATCH https://api.light.inc/v1/user-comments/{userCommentId}` ## Note Author-only: a comment created by another user (or another API key) fails with 403 ; an unknown id with 404 USER_COMMENT_NOT_FOUND . content is required and replaces the text entirely. ## Authorization - API key - Bearer token See https://light.inc/docs/getting-started/authentication. ## Path parameters - `userCommentId` (string, uuid, required) ## Request body `application/json;charset=UTF-8` ```json { "content": "string" } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders, and fields that exclude each other are all shown. Do not send it unchanged. ## Response ```json { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "resourceId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "content": "string", "createdBy": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z" } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders. ## Code ```bash curl -X PATCH "https://api.light.inc/v1/user-comments/3c90c3cc-0d44-4b50-8888-8dd25736052a" \ -H "Authorization: Basic YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "content": "string" }' ``` Full page: https://light.inc/docs/api-reference/v1--user-comments/update-user-comment --- # Users (resource) List users and manage their reimbursement configuration. Resource page: https://light.inc/docs/api-reference/v1--users # List users > Returns a paginated list of users `GET https://api.light.inc/v1/users` ## Note Deactivated users are hidden unless you filter on status yourself (for example status:eq:DEACTIVATED ). roles , groups and managerIds are null unless includeRoles , includeGroups or includeManagers is true . The role filter matches through the role hierarchy; assignedRole matches only roles assigned directly. ## Authorization - API key - Bearer token See https://light.inc/docs/getting-started/authentication. ## Query parameters - `sort` (string) — Sort string in the format field:direction . To provide multiple sort fields, separate them with commas. Available directions: asc , desc . Available fields: firstName , lastName , status , createdAt , updatedAt . - `filter` (string) — Filter string in the format field:operator:value . To provide multiple filters, separate them with commas. Available operators: eq , ne , in , not_in , gt , gte , lt , lte . - For in and not_in operators, provide multiple values separated by the pipe character ( ). Available fields: id , userGroupId , status , email , createdAt , updatedAt , role , assignedRole . - `limit` (integer, int32) - `offset` (integer, int64) — Number of items to skip before starting to collect the result set. Deprecated, use 'cursor' instead. - `cursor` (string) — The cursor position to start returning results from. To opt-in into cursor-based pagination, provide 0 for the initial request. For subsequent requests, use nextCursor and prevCursor from the previous response to navigate. Cursor values are opaque and should not be constructed manually. - `includeRoles` (boolean) - `includeGroups` (boolean) - `includeManagers` (boolean) ## Response - `records.phoneNumber` — May be `null`. `PATCH /v1/users/{userId}` clears it with an explicit `null`, and leaves it unchanged when the field is omitted. - `records.phoneNumber.localNumber` — The number without the country code. ```json { "records": [ { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyEntityId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "email": "string", "firstName": "string", "lastName": "string", "phoneNumber": { "countryCode": "UNDEFINED", "localNumber": "string" }, "avatarUrl": "string", "country": "UNDEFINED", "city": "string", "zipcode": "string", "address": "string", "status": "ACTIVE", "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z", "roles": [ "SUPERUSER" ], "groups": [ { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "name": "string", "description": "string", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "memberCount": 100000, "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z" } ], "managerIds": [ "3c90c3cc-0d44-4b50-8888-8dd25736052a" ] } ], "hasMore": true, "total": 100000, "nextCursor": "string", "prevCursor": "string" } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders. ## Code ```bash curl -X GET "https://api.light.inc/v1/users" \ -H "Authorization: Basic YOUR_API_KEY" ``` Full page: https://light.inc/docs/api-reference/v1--users/list-users --- # Create user > Creates a new user `POST https://api.light.inc/v1/users` ## Note The user is created ACTIVE straight away; no acceptance step. A welcome email goes out when sendWelcomeEmail is true , or when it is omitted and the company setting to send them is on; false suppresses it. email must be unique across Light ( USER_ALREADY_REGISTERED ). roles is required; Light-internal roles such as SUPERUSER are rejected with USER_HAS_ILLEGAL_ROLE even though the enum lists them. Company-admin role only. ## Authorization - API key - Bearer token See https://light.inc/docs/getting-started/authentication. ## Request body `application/json;charset=UTF-8` - `phoneNumber.localNumber` — The number without the country code. ```json { "firstName": "string", "lastName": "string", "email": "string", "companyEntityId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "phoneNumber": { "countryCode": "UNDEFINED", "localNumber": "string" }, "avatarUrl": "string", "country": "UNDEFINED", "city": "string", "address": "string", "zipcode": "string", "roles": [ "SUPERUSER" ], "sendWelcomeEmail": true } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders, and fields that exclude each other are all shown. Do not send it unchanged. ## Response - `phoneNumber` — May be `null`. `PATCH /v1/users/{userId}` clears it with an explicit `null`, and leaves it unchanged when the field is omitted. - `phoneNumber.localNumber` — The number without the country code. ```json { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyEntityId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "email": "string", "firstName": "string", "lastName": "string", "phoneNumber": { "countryCode": "UNDEFINED", "localNumber": "string" }, "avatarUrl": "string", "country": "UNDEFINED", "city": "string", "zipcode": "string", "address": "string", "status": "ACTIVE", "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z", "roles": [ "SUPERUSER" ], "groups": [ { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "name": "string", "description": "string", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "memberCount": 100000, "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z" } ], "managerIds": [ "3c90c3cc-0d44-4b50-8888-8dd25736052a" ] } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders. ## Code ```bash curl -X POST "https://api.light.inc/v1/users" \ -H "Authorization: Basic YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "firstName": "string", "lastName": "string", "email": "string", "companyEntityId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "phoneNumber": { "countryCode": "UNDEFINED", "localNumber": "string" }, "avatarUrl": "string", "country": "UNDEFINED", "city": "string", "address": "string", "zipcode": "string", "roles": [ "SUPERUSER" ], "sendWelcomeEmail": true }' ``` Full page: https://light.inc/docs/api-reference/v1--users/create-user --- # Get latest reimbursement > Returns the most recent reimbursement for a user `GET https://api.light.inc/v1/users/{userId}/reimbursements/latest` ## Note The most recently created reimbursement for the user, i.e. the result of their last POST /v1/expenses/submit . status is IN_PROGRESS after submission, then SUCCEEDED when paid, REJECTED when an administrator rejects it, or FAILED when the submission workflow failed (its expenses return to IN_DRAFT ). A user who never submitted is 404 REIMBURSEMENTS_NOT_FOUND_FOR_USER . ## Authorization - API key - Bearer token See https://light.inc/docs/getting-started/authentication. ## Path parameters - `userId` (string, uuid, required) ## Response - `id` — The reimbursement id. - `companyId` — Your company id. - `userId` — The employee being repaid. - `expenseIds` — The expenses this reimbursement repays. - `createdAt` — When the reimbursement was created. ```json { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "userId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "expenseIds": [ "3c90c3cc-0d44-4b50-8888-8dd25736052a" ], "status": "IN_PROGRESS", "createdAt": "2026-01-15T09:30:00Z" } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders. ## Code ```bash curl -X GET "https://api.light.inc/v1/users/3c90c3cc-0d44-4b50-8888-8dd25736052a/reimbursements/latest" \ -H "Authorization: Basic YOUR_API_KEY" ``` Full page: https://light.inc/docs/api-reference/v1--users/get-latest-reimbursement --- # Get reimbursement config > Returns the reimbursement configuration for a user `GET https://api.light.inc/v1/users/{userId}/reimbursement-config` ## Note 404 USER_REIMBURSEMENT_CONFIG_NOT_FOUND until one has been created with the PUT . ## Authorization - API key - Bearer token See https://light.inc/docs/getting-started/authentication. ## Path parameters - `userId` (string, uuid, required) ## Response ```json { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "userId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "currency": "USD", "defaultCostCenterId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "bankCountry": "UNDEFINED", "bankName": "string", "bankCity": "string", "bankAddress": "string", "bankZipcode": "string", "bankAccountNumber": "string", "bankAccountBic": "string", "domesticBankAccountNumber": "string", "domesticBankAccountCode": "string", "status": "ACTIVE", "failureContext": { "name": "string", "type": "BAD_REQUEST", "errors": [ { "type": "string", "message": "string", "path": [ "string" ], "context": null } ] }, "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z" } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders. ## Code ```bash curl -X GET "https://api.light.inc/v1/users/3c90c3cc-0d44-4b50-8888-8dd25736052a/reimbursement-config" \ -H "Authorization: Basic YOUR_API_KEY" ``` Full page: https://light.inc/docs/api-reference/v1--users/get-reimbursement-config --- # Update reimbursement config > Creates or updates the reimbursement configuration for a user `PUT https://api.light.inc/v1/users/{userId}/reimbursement-config` ## Note bankCountry is required. status is always ACTIVE and cannot be set. Bank details are not validated here; they are checked when the user submits ( USER_INVALID_BANK_DETAILS ). defaultCostCenterId becomes the cost centre of every expense line the user creates through the API. Changing currency rewrites the billing currency of all of the user's unsubmitted expenses and recalculates their line amounts. Company-admin role, or the user themself with the reimbursement role. ## Authorization - API key - Bearer token See https://light.inc/docs/getting-started/authentication. ## Path parameters - `userId` (string, uuid, required) ## Request body `application/json;charset=UTF-8` ```json { "currency": "USD", "bankCountry": "UNDEFINED", "defaultCostCenterId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "bankName": "string", "bankCity": "string", "bankAddress": "string", "bankZipcode": "string", "bankAccountNumber": "string", "bankAccountBic": "string", "domesticBankAccountNumber": "string", "domesticBankAccountCode": "string" } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders, and fields that exclude each other are all shown. Do not send it unchanged. ## Response ```json { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "userId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "currency": "USD", "defaultCostCenterId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "bankCountry": "UNDEFINED", "bankName": "string", "bankCity": "string", "bankAddress": "string", "bankZipcode": "string", "bankAccountNumber": "string", "bankAccountBic": "string", "domesticBankAccountNumber": "string", "domesticBankAccountCode": "string", "status": "ACTIVE", "failureContext": { "name": "string", "type": "BAD_REQUEST", "errors": [ { "type": "string", "message": "string", "path": [ "string" ], "context": null } ] }, "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z" } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders. ## Code ```bash curl -X PUT "https://api.light.inc/v1/users/3c90c3cc-0d44-4b50-8888-8dd25736052a/reimbursement-config" \ -H "Authorization: Basic YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "currency": "USD", "bankCountry": "UNDEFINED", "defaultCostCenterId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "bankName": "string", "bankCity": "string", "bankAddress": "string", "bankZipcode": "string", "bankAccountNumber": "string", "bankAccountBic": "string", "domesticBankAccountNumber": "string", "domesticBankAccountCode": "string" }' ``` Full page: https://light.inc/docs/api-reference/v1--users/update-reimbursement-config --- # Update user > Updates the given user `PATCH https://api.light.inc/v1/users/{userId}` ## Note Two kinds of field. firstName , lastName , email and companyEntityId cannot be cleared: null leaves them unchanged. phoneNumber , avatarUrl , country , city , address and zipcode follow the usual rule ( null clears). A credential without the company-admin role may only update its own user and cannot change email . A new email already in use fails with USER_ALREADY_REGISTERED . ## Authorization - API key - Bearer token See https://light.inc/docs/getting-started/authentication. ## Path parameters - `userId` (string, uuid, required) ## Request body `application/json;charset=UTF-8` - `phoneNumber.localNumber` — The number without the country code. ```json { "firstName": "string", "lastName": "string", "email": "string", "companyEntityId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "phoneNumber": { "countryCode": "UNDEFINED", "localNumber": "string" }, "avatarUrl": "string", "country": "UNDEFINED", "city": "string", "address": "string", "zipcode": "string" } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders, and fields that exclude each other are all shown. Do not send it unchanged. ## Response - `phoneNumber` — May be `null`. `PATCH /v1/users/{userId}` clears it with an explicit `null`, and leaves it unchanged when the field is omitted. - `phoneNumber.localNumber` — The number without the country code. ```json { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyEntityId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "email": "string", "firstName": "string", "lastName": "string", "phoneNumber": { "countryCode": "UNDEFINED", "localNumber": "string" }, "avatarUrl": "string", "country": "UNDEFINED", "city": "string", "zipcode": "string", "address": "string", "status": "ACTIVE", "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z", "roles": [ "SUPERUSER" ], "groups": [ { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "name": "string", "description": "string", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "memberCount": 100000, "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z" } ], "managerIds": [ "3c90c3cc-0d44-4b50-8888-8dd25736052a" ] } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders. ## Code ```bash curl -X PATCH "https://api.light.inc/v1/users/3c90c3cc-0d44-4b50-8888-8dd25736052a" \ -H "Authorization: Basic YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "firstName": "string", "lastName": "string", "email": "string", "companyEntityId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "phoneNumber": { "countryCode": "UNDEFINED", "localNumber": "string" }, "avatarUrl": "string", "country": "UNDEFINED", "city": "string", "address": "string", "zipcode": "string" }' ``` Full page: https://light.inc/docs/api-reference/v1--users/update-user --- # Update user managers > Updates the given user's managers `PUT https://api.light.inc/v1/users/{userId}/managers` ## Note A full replacement: the list you send becomes the manager list, and [] clears it. At most five managers ( USER_HAS_TOO_MANY_MANAGERS ), each an active user of the company other than the user themself ( USER_HAS_INVALID_MANAGER ). Company-admin role only. ## Authorization - API key - Bearer token See https://light.inc/docs/getting-started/authentication. ## Path parameters - `userId` (string, uuid, required) ## Request body `application/json;charset=UTF-8` ```json { "managerIds": [ "3c90c3cc-0d44-4b50-8888-8dd25736052a" ] } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders, and fields that exclude each other are all shown. Do not send it unchanged. ## Response - `phoneNumber` — May be `null`. `PATCH /v1/users/{userId}` clears it with an explicit `null`, and leaves it unchanged when the field is omitted. - `phoneNumber.localNumber` — The number without the country code. ```json { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyEntityId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "email": "string", "firstName": "string", "lastName": "string", "phoneNumber": { "countryCode": "UNDEFINED", "localNumber": "string" }, "avatarUrl": "string", "country": "UNDEFINED", "city": "string", "zipcode": "string", "address": "string", "status": "ACTIVE", "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z", "roles": [ "SUPERUSER" ], "groups": [ { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "name": "string", "description": "string", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "memberCount": 100000, "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z" } ], "managerIds": [ "3c90c3cc-0d44-4b50-8888-8dd25736052a" ] } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders. ## Code ```bash curl -X PUT "https://api.light.inc/v1/users/3c90c3cc-0d44-4b50-8888-8dd25736052a/managers" \ -H "Authorization: Basic YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "managerIds": [ "3c90c3cc-0d44-4b50-8888-8dd25736052a" ] }' ``` Full page: https://light.inc/docs/api-reference/v1--users/update-user-managers --- # Update user status > Updates the given user's status `PUT https://api.light.inc/v1/users/{userId}/status` ## Note ACTIVE or DEACTIVATED , in either direction; setting the current status again is a no-op. You cannot change the status of the credential's own user ( USER_SELF_STATUS_UPDATE ). Deactivating a user freezes every card they own , drops them from GET /v1/users by default, and makes them ineligible as a card owner or manager. ## Authorization - API key - Bearer token See https://light.inc/docs/getting-started/authentication. ## Path parameters - `userId` (string, uuid, required) ## Request body `application/json;charset=UTF-8` ```json { "status": "ACTIVE" } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders, and fields that exclude each other are all shown. Do not send it unchanged. ## Response - `phoneNumber` — May be `null`. `PATCH /v1/users/{userId}` clears it with an explicit `null`, and leaves it unchanged when the field is omitted. - `phoneNumber.localNumber` — The number without the country code. ```json { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyEntityId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "email": "string", "firstName": "string", "lastName": "string", "phoneNumber": { "countryCode": "UNDEFINED", "localNumber": "string" }, "avatarUrl": "string", "country": "UNDEFINED", "city": "string", "zipcode": "string", "address": "string", "status": "ACTIVE", "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z", "roles": [ "SUPERUSER" ], "groups": [ { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "name": "string", "description": "string", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "memberCount": 100000, "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z" } ], "managerIds": [ "3c90c3cc-0d44-4b50-8888-8dd25736052a" ] } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders. ## Code ```bash curl -X PUT "https://api.light.inc/v1/users/3c90c3cc-0d44-4b50-8888-8dd25736052a/status" \ -H "Authorization: Basic YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "status": "ACTIVE" }' ``` Full page: https://light.inc/docs/api-reference/v1--users/update-user-status --- # Vendors (resource) Create, list, update and manage vendors. Resource page: https://light.inc/docs/api-reference/v1--vendors # List vendors > Returns a paginated list of vendors `GET https://api.light.inc/v1/vendors` ## Note Without a filter , only active external vendors are returned (the default is status:eq:ACTIVE,type:eq:EXTERNAL ). Any filter you send replaces that default , so filter=id:eq:... also returns IN_REVIEW , ONBOARDING , FAILED and employee ( USER ) vendors. Default order is name:asc ; searchTerm is supported. lastMtdSpendInGroupCurrency and groupCurrency are populated only here, never on the create, update or single-read responses; notes is always [] . ## Authorization - API key - Bearer token See https://light.inc/docs/getting-started/authentication. ## Query parameters - `sort` (string) — Sort string in the format field:direction . To provide multiple sort fields, separate them with commas. Available directions: asc , desc . Available fields: name , spendLastMtd , createdAt , updatedAt . - `filter` (string) — Filter string in the format field:operator:value . To provide multiple filters, separate them with commas. Available operators: eq , ne , in , not_in , gt , gte , lt , lte . - For in and not_in operators, provide multiple values separated by the pipe character ( ). Available fields: id , status , type , ledgerAccountId , ledgerTaxId , spendLastMtd , createdAt , updatedAt . - `searchTerm` (string) — Search term to filter results by. Performs a case-insensitive partial match across searchable fields. - `limit` (integer, int32) — Maximum number of items to return. Default is 50, maximum is 200. - `offset` (integer, int64) — Number of items to skip before starting to collect the result set. Deprecated, use 'cursor' instead. - `cursor` (string) — The cursor position to start returning results from. To opt-in into cursor-based pagination, provide 0 for the initial request. For subsequent requests, use nextCursor and prevCursor from the previous response to navigate. Cursor values are opaque and should not be constructed manually. ## Response - `records.defaultCompanyEntity` — The entity and the defaults (expense account, tax code, cost center, paying bank account) used when a bill from this vendor is created. - `records.phoneNumber` — The vendor's phone number. May be `null`. `PUT /v1/vendors/{vendorId}` is a full replacement, so leaving it out clears it. - `records.phoneNumber.localNumber` — The number without the country code. - `records.notes.id` — The note id. - `records.notes.vendorId` — The vendor the note is on. - `records.notes.authorId` — The user who wrote the note. - `records.notes.companyId` — Your company id. - `records.notes.content` — The note text. - `records.notes.createdAt` — When the note was written. - `records.notes.updatedAt` — When it was last edited. - `records.currency` — The vendor's invoicing currency. - `records.status` — `ONBOARDING` (vendor portal in progress), `IN_REVIEW` (awaiting approval in Light; updates rejected), `ACTIVE`, `FAILED` (rejected; an update re-submits it). Not settable, and there is no archive endpoint. - `records.failureContext` — The error of the last failed step, if any. - `records.groupCurrency` — Your company's group currency, in which the vendor's group-currency figures are expressed. ```json { "records": [ { "type": "EXTERNAL", "vendorId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyEntityIds": [ "3c90c3cc-0d44-4b50-8888-8dd25736052a" ], "defaultCompanyEntity": { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "vendorId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyEntityId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "accountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "taxCodeId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "costCenterId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "senderBankAccountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z" }, "vatId": "string", "businessRegistrationNumber": "string", "identifier": "string", "name": "string", "description": "string", "avatarUrl": "string", "email": "string", "phoneNumber": { "countryCode": "UNDEFINED", "localNumber": "string" }, "website": "string", "country": "UNDEFINED", "city": "string", "address": "string", "zipcode": "string", "bankName": "string", "bankCountry": "UNDEFINED", "bankCity": "string", "bankAddress": "string", "bankZipcode": "string", "bankAccountNumber": "string", "bankAccountBic": "string", "domesticBankAccountNumber": "string", "domesticBankAccountCode": "string", "swedishBankgiroNumber": "string", "swedishPlusgiroNumber": "string", "bankRecipientName": "string", "vendorCreatedAt": "2026-01-15T09:30:00Z", "approvers": [ { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "userId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "vendorId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "priority": 0, "createdAt": "2026-01-15T09:30:00Z" } ], "notes": [ { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "vendorId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "authorId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "channel": "WEB_APP", "content": "string", "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z" } ], "currency": "USD", "contractValue": 100000, "createdBy": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "status": "ONBOARDING", "failureContext": { "name": "string", "type": "BAD_REQUEST", "errors": [ { "type": "string", "message": "string", "path": [], "context": null } ] }, "version": 0, "updatedAt": "2026-01-15T09:30:00Z", "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupInternalName": "string", "values": [ {} ] } ], "lastMtdSpendInGroupCurrency": 100000, "groupCurrency": "USD" } ], "hasMore": true, "total": 100000, "nextCursor": "string", "prevCursor": "string" } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders. ## Code ```bash curl -X GET "https://api.light.inc/v1/vendors" \ -H "Authorization: Basic YOUR_API_KEY" ``` Full page: https://light.inc/docs/api-reference/v1--vendors/list-vendors --- # Create vendor > Creates a new vendor `POST https://api.light.inc/v1/vendors` ## Note The resulting status depends on the company's vendor-approval workflow: with one published the vendor is created IN_REVIEW and must be approved in Light before it can be updated ( VENDOR_PENDING_APPROVAL_UPDATE_NOT_ALLOWED ); otherwise it is ACTIVE . Uniqueness is on name only ( DUPLICATE_VENDOR ); VAT id, IBAN and identifier may repeat. Bank details are validated by country (IBAN/BIC or domestic formats, errors pathed to the field); French vendors get their VAT number and SIREN cross-checked ( VENDOR_INVALID_FRENCH_IDENTIFIERS ). Missing contact fields ( description , email , phoneNumber , address , ...) are back-filled from a lookup of website when given. type is always EXTERNAL ; defaultCompanyEntity.companyEntityId is added to companyEntityIds automatically. Requires the vendor-management role. ## Authorization - API key - Bearer token See https://light.inc/docs/getting-started/authentication. ## Request body `application/json;charset=UTF-8` - `phoneNumber.localNumber` — The number without the country code. - `customProperties.valueIds` — Catalogue value ids for this group. Required; send `[]` (with an empty `inlineValues`) to clear the group. `SINGLE_SELECT` and `MULTI_SELECT` groups accept nothing else. See [Custom properties on writes](/docs/getting-started/pagination-filtering-errors#custom-properties-on-writes). - `customProperties.inlineValues` — Literal values for `TEXT`, `NUMERIC`, `BOOLEAN` and `DATE` groups, as strings (`yyyy-MM-dd` for dates). Rejected on select groups with `CUSTOM_PROPERTY_VALUE_TYPE_MISMATCH`. See [Custom properties on writes](/docs/getting-started/pagination-filtering-errors#custom-properties-on-writes). ```json { "defaultCompanyEntity": { "companyEntityId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "accountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "taxCodeId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "costCenterId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "senderBankAccountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a" }, "companyEntityIds": [ "3c90c3cc-0d44-4b50-8888-8dd25736052a" ], "vatId": "string", "businessRegistrationNumber": "string", "identifier": "string", "name": "string", "description": "string", "avatarUrl": "string", "email": "string", "phoneNumber": { "countryCode": "UNDEFINED", "localNumber": "string" }, "website": "string", "country": "UNDEFINED", "city": "string", "address": "string", "zipcode": "string", "bankName": "string", "bankCountry": "UNDEFINED", "bankCity": "string", "bankAddress": "string", "bankZipcode": "string", "bankAccountNumber": "string", "bankAccountBic": "string", "domesticBankAccountNumber": "string", "domesticBankAccountCode": "string", "swedishBankgiroNumber": "string", "swedishPlusgiroNumber": "string", "bankRecipientName": "string", "currency": "USD", "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "valueIds": [ "3c90c3cc-0d44-4b50-8888-8dd25736052a" ], "inlineValues": [ "string" ] } ] } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders, and fields that exclude each other are all shown. Do not send it unchanged. ## Response - `defaultCompanyEntity` — The entity and the defaults (expense account, tax code, cost center, paying bank account) used when a bill from this vendor is created. - `phoneNumber` — The vendor's phone number. May be `null`. `PUT /v1/vendors/{vendorId}` is a full replacement, so leaving it out clears it. - `phoneNumber.localNumber` — The number without the country code. - `notes.id` — The note id. - `notes.vendorId` — The vendor the note is on. - `notes.authorId` — The user who wrote the note. - `notes.companyId` — Your company id. - `notes.content` — The note text. - `notes.createdAt` — When the note was written. - `notes.updatedAt` — When it was last edited. - `currency` — The vendor's invoicing currency. - `status` — `ONBOARDING` (vendor portal in progress), `IN_REVIEW` (awaiting approval in Light; updates rejected), `ACTIVE`, `FAILED` (rejected; an update re-submits it). Not settable, and there is no archive endpoint. - `failureContext` — The error of the last failed step, if any. - `groupCurrency` — Your company's group currency, in which the vendor's group-currency figures are expressed. ```json { "type": "EXTERNAL", "vendorId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyEntityIds": [ "3c90c3cc-0d44-4b50-8888-8dd25736052a" ], "defaultCompanyEntity": { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "vendorId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyEntityId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "accountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "taxCodeId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "costCenterId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "senderBankAccountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z" }, "vatId": "string", "businessRegistrationNumber": "string", "identifier": "string", "name": "string", "description": "string", "avatarUrl": "string", "email": "string", "phoneNumber": { "countryCode": "UNDEFINED", "localNumber": "string" }, "website": "string", "country": "UNDEFINED", "city": "string", "address": "string", "zipcode": "string", "bankName": "string", "bankCountry": "UNDEFINED", "bankCity": "string", "bankAddress": "string", "bankZipcode": "string", "bankAccountNumber": "string", "bankAccountBic": "string", "domesticBankAccountNumber": "string", "domesticBankAccountCode": "string", "swedishBankgiroNumber": "string", "swedishPlusgiroNumber": "string", "bankRecipientName": "string", "vendorCreatedAt": "2026-01-15T09:30:00Z", "approvers": [ { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "userId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "vendorId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "priority": 0, "createdAt": "2026-01-15T09:30:00Z" } ], "notes": [ { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "vendorId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "authorId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "channel": "WEB_APP", "content": "string", "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z" } ], "currency": "USD", "contractValue": 100000, "createdBy": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "status": "ONBOARDING", "failureContext": { "name": "string", "type": "BAD_REQUEST", "errors": [ { "type": "string", "message": "string", "path": [ "string" ], "context": null } ] }, "version": 0, "updatedAt": "2026-01-15T09:30:00Z", "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupInternalName": "string", "values": [ { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupInternalName": "string", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "internalName": "string", "label": "string", "context": "string", "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z" } ] } ], "lastMtdSpendInGroupCurrency": 100000, "groupCurrency": "USD" } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders. ## Code ```bash curl -X POST "https://api.light.inc/v1/vendors" \ -H "Authorization: Basic YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "defaultCompanyEntity": { "companyEntityId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "accountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "taxCodeId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "costCenterId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "senderBankAccountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a" }, "companyEntityIds": [ "3c90c3cc-0d44-4b50-8888-8dd25736052a" ], "vatId": "string", "businessRegistrationNumber": "string", "identifier": "string", "name": "string", "description": "string", "avatarUrl": "string", "email": "string", "phoneNumber": { "countryCode": "UNDEFINED", "localNumber": "string" }, "website": "string", "country": "UNDEFINED", "city": "string", "address": "string", "zipcode": "string", "bankName": "string", "bankCountry": "UNDEFINED", "bankCity": "string", "bankAddress": "string", "bankZipcode": "string", "bankAccountNumber": "string", "bankAccountBic": "string", "domesticBankAccountNumber": "string", "domesticBankAccountCode": "string", "swedishBankgiroNumber": "string", "swedishPlusgiroNumber": "string", "bankRecipientName": "string", "currency": "USD", "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "valueIds": [ "3c90c3cc-0d44-4b50-8888-8dd25736052a" ], "inlineValues": [ "string" ] } ] }' ``` Full page: https://light.inc/docs/api-reference/v1--vendors/create-vendor --- # Get vendor > Returns a vendor by ID `GET https://api.light.inc/v1/vendors/{vendorId}` ## Note Any status, IN_REVIEW , ONBOARDING and FAILED included. Readable with any of the vendor-management, AP preparation, invoice approver, cardholder, purchase requester or auditor roles. ## Authorization - API key - Bearer token See https://light.inc/docs/getting-started/authentication. ## Path parameters - `vendorId` (string, uuid, required) ## Response - `defaultCompanyEntity` — The entity and the defaults (expense account, tax code, cost center, paying bank account) used when a bill from this vendor is created. - `phoneNumber` — The vendor's phone number. May be `null`. `PUT /v1/vendors/{vendorId}` is a full replacement, so leaving it out clears it. - `phoneNumber.localNumber` — The number without the country code. - `notes.id` — The note id. - `notes.vendorId` — The vendor the note is on. - `notes.authorId` — The user who wrote the note. - `notes.companyId` — Your company id. - `notes.content` — The note text. - `notes.createdAt` — When the note was written. - `notes.updatedAt` — When it was last edited. - `currency` — The vendor's invoicing currency. - `status` — `ONBOARDING` (vendor portal in progress), `IN_REVIEW` (awaiting approval in Light; updates rejected), `ACTIVE`, `FAILED` (rejected; an update re-submits it). Not settable, and there is no archive endpoint. - `failureContext` — The error of the last failed step, if any. - `groupCurrency` — Your company's group currency, in which the vendor's group-currency figures are expressed. ```json { "type": "EXTERNAL", "vendorId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyEntityIds": [ "3c90c3cc-0d44-4b50-8888-8dd25736052a" ], "defaultCompanyEntity": { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "vendorId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyEntityId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "accountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "taxCodeId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "costCenterId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "senderBankAccountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z" }, "vatId": "string", "businessRegistrationNumber": "string", "identifier": "string", "name": "string", "description": "string", "avatarUrl": "string", "email": "string", "phoneNumber": { "countryCode": "UNDEFINED", "localNumber": "string" }, "website": "string", "country": "UNDEFINED", "city": "string", "address": "string", "zipcode": "string", "bankName": "string", "bankCountry": "UNDEFINED", "bankCity": "string", "bankAddress": "string", "bankZipcode": "string", "bankAccountNumber": "string", "bankAccountBic": "string", "domesticBankAccountNumber": "string", "domesticBankAccountCode": "string", "swedishBankgiroNumber": "string", "swedishPlusgiroNumber": "string", "bankRecipientName": "string", "vendorCreatedAt": "2026-01-15T09:30:00Z", "approvers": [ { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "userId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "vendorId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "priority": 0, "createdAt": "2026-01-15T09:30:00Z" } ], "notes": [ { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "vendorId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "authorId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "channel": "WEB_APP", "content": "string", "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z" } ], "currency": "USD", "contractValue": 100000, "createdBy": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "status": "ONBOARDING", "failureContext": { "name": "string", "type": "BAD_REQUEST", "errors": [ { "type": "string", "message": "string", "path": [ "string" ], "context": null } ] }, "version": 0, "updatedAt": "2026-01-15T09:30:00Z", "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupInternalName": "string", "values": [ { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupInternalName": "string", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "internalName": "string", "label": "string", "context": "string", "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z" } ] } ], "lastMtdSpendInGroupCurrency": 100000, "groupCurrency": "USD" } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders. ## Code ```bash curl -X GET "https://api.light.inc/v1/vendors/3c90c3cc-0d44-4b50-8888-8dd25736052a" \ -H "Authorization: Basic YOUR_API_KEY" ``` Full page: https://light.inc/docs/api-reference/v1--vendors/get-vendor --- # Update vendor > Updates an existing vendor `PUT https://api.light.inc/v1/vendors/{vendorId}` ## Note A full replacement : every field you omit or send as null is cleared ( vatId , identifier , defaultCompanyEntity , all bank fields, ...), and companyEntityIds is replaced. Two exceptions: the web-enrichable contact fields fall back to the website lookup, and a null customProperties keeps the existing set. Send the full current record with your change applied. status cannot be set and there is no archive or delete endpoint . Values: ONBOARDING , IN_REVIEW , ACTIVE , FAILED (rejected). An IN_REVIEW vendor cannot be updated ( VENDOR_PENDING_APPROVAL_UPDATE_NOT_ALLOWED ); updating a FAILED one re-submits it for review. When a vendor-approval workflow is published, bank-detail changes on an active vendor are not applied : they are parked as a change request until approved in Light, and a second change meanwhile fails with VENDOR_BANK_DATA_APPROVAL_ALREADY_IN_PROGRESS ; other fields apply immediately. Companies on an external ledger cannot rename a vendor ( FIELD_UPDATE_NOT_SUPPORTED_IN_EXTERNAL_LEDGER ). ## Authorization - API key - Bearer token See https://light.inc/docs/getting-started/authentication. ## Path parameters - `vendorId` (string, uuid, required) ## Request body `application/json;charset=UTF-8` - `phoneNumber.localNumber` — The number without the country code. - `customProperties.valueIds` — Catalogue value ids for this group. Required; send `[]` (with an empty `inlineValues`) to clear the group. `SINGLE_SELECT` and `MULTI_SELECT` groups accept nothing else. See [Custom properties on writes](/docs/getting-started/pagination-filtering-errors#custom-properties-on-writes). - `customProperties.inlineValues` — Literal values for `TEXT`, `NUMERIC`, `BOOLEAN` and `DATE` groups, as strings (`yyyy-MM-dd` for dates). Rejected on select groups with `CUSTOM_PROPERTY_VALUE_TYPE_MISMATCH`. See [Custom properties on writes](/docs/getting-started/pagination-filtering-errors#custom-properties-on-writes). ```json { "name": "string", "defaultCompanyEntity": { "companyEntityId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "accountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "taxCodeId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "costCenterId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "senderBankAccountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a" }, "companyEntityIds": [ "3c90c3cc-0d44-4b50-8888-8dd25736052a" ], "vatId": "string", "businessRegistrationNumber": "string", "identifier": "string", "description": "string", "avatarUrl": "string", "email": "string", "phoneNumber": { "countryCode": "UNDEFINED", "localNumber": "string" }, "website": "string", "country": "UNDEFINED", "city": "string", "address": "string", "zipcode": "string", "bankName": "string", "bankCountry": "UNDEFINED", "bankCity": "string", "bankAddress": "string", "bankZipcode": "string", "bankAccountNumber": "string", "bankAccountBic": "string", "domesticBankAccountNumber": "string", "domesticBankAccountCode": "string", "swedishBankgiroNumber": "string", "swedishPlusgiroNumber": "string", "bankRecipientName": "string", "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "valueIds": [ "3c90c3cc-0d44-4b50-8888-8dd25736052a" ], "inlineValues": [ "string" ] } ] } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders, and fields that exclude each other are all shown. Do not send it unchanged. ## Response - `defaultCompanyEntity` — The entity and the defaults (expense account, tax code, cost center, paying bank account) used when a bill from this vendor is created. - `phoneNumber` — The vendor's phone number. May be `null`. `PUT /v1/vendors/{vendorId}` is a full replacement, so leaving it out clears it. - `phoneNumber.localNumber` — The number without the country code. - `notes.id` — The note id. - `notes.vendorId` — The vendor the note is on. - `notes.authorId` — The user who wrote the note. - `notes.companyId` — Your company id. - `notes.content` — The note text. - `notes.createdAt` — When the note was written. - `notes.updatedAt` — When it was last edited. - `currency` — The vendor's invoicing currency. - `status` — `ONBOARDING` (vendor portal in progress), `IN_REVIEW` (awaiting approval in Light; updates rejected), `ACTIVE`, `FAILED` (rejected; an update re-submits it). Not settable, and there is no archive endpoint. - `failureContext` — The error of the last failed step, if any. - `groupCurrency` — Your company's group currency, in which the vendor's group-currency figures are expressed. ```json { "type": "EXTERNAL", "vendorId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyEntityIds": [ "3c90c3cc-0d44-4b50-8888-8dd25736052a" ], "defaultCompanyEntity": { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "vendorId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyEntityId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "accountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "taxCodeId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "costCenterId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "senderBankAccountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z" }, "vatId": "string", "businessRegistrationNumber": "string", "identifier": "string", "name": "string", "description": "string", "avatarUrl": "string", "email": "string", "phoneNumber": { "countryCode": "UNDEFINED", "localNumber": "string" }, "website": "string", "country": "UNDEFINED", "city": "string", "address": "string", "zipcode": "string", "bankName": "string", "bankCountry": "UNDEFINED", "bankCity": "string", "bankAddress": "string", "bankZipcode": "string", "bankAccountNumber": "string", "bankAccountBic": "string", "domesticBankAccountNumber": "string", "domesticBankAccountCode": "string", "swedishBankgiroNumber": "string", "swedishPlusgiroNumber": "string", "bankRecipientName": "string", "vendorCreatedAt": "2026-01-15T09:30:00Z", "approvers": [ { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "userId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "vendorId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "priority": 0, "createdAt": "2026-01-15T09:30:00Z" } ], "notes": [ { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "vendorId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "authorId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "channel": "WEB_APP", "content": "string", "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z" } ], "currency": "USD", "contractValue": 100000, "createdBy": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "status": "ONBOARDING", "failureContext": { "name": "string", "type": "BAD_REQUEST", "errors": [ { "type": "string", "message": "string", "path": [ "string" ], "context": null } ] }, "version": 0, "updatedAt": "2026-01-15T09:30:00Z", "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupInternalName": "string", "values": [ { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "groupInternalName": "string", "companyId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "internalName": "string", "label": "string", "context": "string", "createdAt": "2026-01-15T09:30:00Z", "updatedAt": "2026-01-15T09:30:00Z" } ] } ], "lastMtdSpendInGroupCurrency": 100000, "groupCurrency": "USD" } ``` Values above are generated from the schema: the shapes and types are real, the values are placeholders. ## Code ```bash curl -X PUT "https://api.light.inc/v1/vendors/3c90c3cc-0d44-4b50-8888-8dd25736052a" \ -H "Authorization: Basic YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "name": "string", "defaultCompanyEntity": { "companyEntityId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "accountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "taxCodeId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "costCenterId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "senderBankAccountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a" }, "companyEntityIds": [ "3c90c3cc-0d44-4b50-8888-8dd25736052a" ], "vatId": "string", "businessRegistrationNumber": "string", "identifier": "string", "description": "string", "avatarUrl": "string", "email": "string", "phoneNumber": { "countryCode": "UNDEFINED", "localNumber": "string" }, "website": "string", "country": "UNDEFINED", "city": "string", "address": "string", "zipcode": "string", "bankName": "string", "bankCountry": "UNDEFINED", "bankCity": "string", "bankAddress": "string", "bankZipcode": "string", "bankAccountNumber": "string", "bankAccountBic": "string", "domesticBankAccountNumber": "string", "domesticBankAccountCode": "string", "swedishBankgiroNumber": "string", "swedishPlusgiroNumber": "string", "bankRecipientName": "string", "customProperties": [ { "groupId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "valueIds": [ "3c90c3cc-0d44-4b50-8888-8dd25736052a" ], "inlineValues": [ "string" ] } ] }' ``` Full page: https://light.inc/docs/api-reference/v1--vendors/update-vendor ---