# F-sąskaita API > Create and manage invoices and expenses for a Lithuanian business programmatically. REST, JSON, bearer tokens, webhooks. The F-sąskaita API lets you issue invoices, record expenses and download documents for the business you run in [app.fsaskaita.lt](https://app.fsaskaita.lt). It is a small REST API: JSON in, JSON out, bearer tokens scoped to one business. ``` https://app.fsaskaita.lt/api ``` ## What you can do | Resource | Operations | |---|---| | Invoices | list, create, read, update, delete, download PDF | | Expenses | list, create with a file, read, update, replace file, delete, download file | | Profile | read the business behind the token | | Currencies | list accepted currency codes | | Webhooks | receive `invoice.*` and `expense.*` events at your HTTPS endpoint | ## Start here 1. [Authentication](/guides/authentication): create a Business token and make the first request. 2. [Invoices](/guides/invoices): the invoice model, numbering and the create request. 3. [Expenses](/guides/expenses): multipart uploads and file replacement. 4. [Webhooks](/guides/webhooks): subscribe, verify the signature, handle retries. 5. [Conventions](/guides/conventions): pagination, errors, rate limits, dates and money. The [Reference](/reference) covers every endpoint. The specification itself is at [`/openapi.json`](/openapi.json). ## For AI agents Read [`/llms.txt`](/llms.txt) for an index of every page, [`/llms-full.txt`](/llms-full.txt) for the full text, and the [agent page](/agents) for a compact description of how to integrate. Instructions for agents: https://docs.fsaskaita.lt/agents/prompt.md ## Plan requirement API access and webhooks are included in the Premium plan. On other plans the token and webhook settings are not available in the app. --- # Integrating as an AI agent > Compact, agent-oriented description of the F-sąskaita API. Base URL, authentication, spec location, pagination, error handling and rules that prevent common mistakes. This page is written for LLM agents and coding assistants. It is intentionally dense. Humans may prefer the [guides](/guides/authentication). ## Facts - Base URL: `https://app.fsaskaita.lt/api` - OpenAPI 3.1 specification: `https://docs.fsaskaita.lt/openapi.json` - Full documentation as text: `https://docs.fsaskaita.lt/llms-full.txt` - Authentication: `Authorization: Bearer `. The token belongs to one business; there is no user-level or multi-business token. - Always send `Accept: application/json`. Without it, unauthenticated and rate-limited requests return an HTML redirect or page instead of JSON. - Content type for invoices and profile: `application/json`. Expenses use `multipart/form-data` because they carry a file. - Rate limit: 60 requests per minute per business, shared by all of its tokens. Read `X-RateLimit-Remaining`; on `429` wait for `Retry-After` seconds. - Pagination: `?page=N`, fixed 50 items per page, no filtering or sorting parameters. Response shape `{ "data": [...], "meta": { "current_page", "last_page", "per_page", "total", "from", "to", "path" } }`. - Single resources are wrapped: `{ "data": { ... } }`. - Identifiers are UUID strings. Dates are `YYYY-MM-DD`. `created_at` and `updated_at` are Unix timestamps in seconds. Money values are JSON numbers. Currency codes are uppercase ISO 4217 and must exist in `GET /currencies`. - Deleting returns `200` with an empty body. - Validation errors return `422` with `{ "message": "...", "errors": { "field.path": ["..."] } }`. Messages are in Lithuanian. - Resources that belong to another business return `404`. ## Rules that prevent mistakes 1. When updating an invoice with `PUT /invoices/{id}`, send the full invoice, including its current `invoice_number`. Omitting the number assigns a new one from the series counter. 2. For each invoice line send exactly one of `price`, `total` or `total_incl_vat`. The server derives the other two. 3. `type` values ending in `vat_invoice` are VAT invoices. They require `vat_percentage` on every line and a seller `vat_code` (yours from the profile when `use_default_seller_info` is `true`). 4. Prefer `use_default_seller_info: true` unless the caller explicitly wants to override seller details. 5. Draft invoices never appear in the API. Everything the API creates is a finalized, numbered invoice. 6. If the PDF is not ready yet, `GET /invoices/{id}/download` waits up to about 20 seconds for it, so call it after creation rather than expecting the file inside the create response. 7. Webhook payloads are `{ "event": "", "data": { ... } }`, signed with HMAC-SHA256 of the raw body in the `Signature` header. Verify with the subscription secret before trusting the payload. Deliveries are attempted up to 3 times (two retries, after 10 s and 100 s); treat them as at-least-once. 8. There is no API for managing tokens or webhook subscriptions. Both are created by a human in the app under Settings, Integrations. 9. There is no idempotency key. Do not retry a `POST` that returned a network error without first listing recent invoices. ## Instructions for your agent Paste this into your coding agent, or point it at `https://docs.fsaskaita.lt/agents/prompt.md`. ```text Implement invoicing in this project with the F-sąskaita API. Read first, in this order: 1. https://docs.fsaskaita.lt/llms.txt — the index of every documentation page. Fetch the Invoices and Conventions guides from it. 2. https://docs.fsaskaita.lt/openapi.json — the Spec: every endpoint, field and enum. Take field names and behaviour from the Spec. Where this prompt and the Spec disagree, the Spec wins. Facts - Base URL: https://app.fsaskaita.lt/api. JSON in, JSON out. - Authentication: a Business token, scoped to one business, sent as `Authorization: Bearer `. Read it from the FSASKAITA_TOKEN environment variable and keep it out of code, logs and version control. - Send `Accept: application/json` on every request; without it, 401 and 429 responses are HTML. - Rate limit: 60 requests per minute per business. On 429, wait `Retry-After` seconds, then retry. - Validation errors: 422 with `{ "message", "errors": { "field.path": ["..."] } }`. Messages are in Lithuanian; show them to the user unchanged. - Lists: `?page=N`, 50 per page, newest first, no filters. Single resources are wrapped in `{ "data": ... }`. - Identifiers are UUIDs, dates are `YYYY-MM-DD`, money values are JSON numbers, currency codes are uppercase ISO 4217 and must appear in `GET /currencies`. Build 1. One client module with a narrow interface: base URL, both headers, JSON encoding, and typed errors for 401, 404, 422, 429 and 500. Retry only on 429, and only GET, PUT and DELETE. 2. createInvoice(input): `POST /invoices`. Default `use_default_seller_info: true`. For each line in `products` send exactly one of `price`, `total` or `total_incl_vat`. Types ending in `vat_invoice` need `vat_percentage` on every line. Omit `invoice_number` so the series assigns the next one. Return `data` from the 201 response; it includes `share_link`, a public page where the buyer views and downloads the invoice. 3. downloadInvoicePdf(id): `GET /invoices/{id}/download`, called after create. Stream the body: there is no Content-Length, and the response can take up to about 20 seconds if the PDF is not ready yet. 4. updateInvoice(id, input): `PUT /invoices/{id}` replaces the whole invoice. Read it first, change what you need, and send it back including the current `invoice_number`; an update without it renumbers the invoice. 5. Webhooks, when the project needs them: an HTTPS endpoint that verifies the `Signature` header (hex HMAC-SHA256 of the raw body with the subscription secret) before parsing, and treats deliveries as at-least-once. Rules - There is no idempotency key. After a network error on POST, list recent invoices with `GET /invoices` and check before creating again. - Every invoice the API creates is final and numbered; drafts exist only in the app. - Tokens and webhook subscriptions have no API. A person creates them in the app under Settings, Integrations, and the integration reads them from configuration. Done when - Unit tests with recorded responses cover 201, 422 and 429. - A live check runs only when FSASKAITA_TOKEN is set. It creates a real, numbered invoice, so ask before running it and delete the invoice afterwards with `DELETE /invoices/{id}`. - Your report names what you built, which endpoints you used, and what in the Spec you left out. ``` ## Minimal request ```bash curl https://app.fsaskaita.lt/api/profile \ -H "Authorization: Bearer $FSASKAITA_TOKEN" \ -H "Accept: application/json" ``` ## Where to look next - Endpoint shapes and every field: the [OpenAPI specification](/openapi.json) or the [Reference](/reference). - Worked invoice payloads: [Invoices](/guides/invoices). - Signature verification code: [Webhooks](/guides/webhooks). - Behaviour changes over time: the [Changelog](/changelog), also available as RSS at `/changelog.xml`. --- # Changelog > Updates to the Public API and the details that matter to your integration. ## 2026-09-08 — New developer documentation at docs.fsaskaita.lt The F-sąskaita API documentation is now at docs.fsaskaita.lt, with integration guides, a full API reference and this changelog. --- # Authentication > Create a Business token in the app, send it as a bearer token, and understand its scope and lifetime. Every request to the F-sąskaita API is authenticated with a **Business token**. The token identifies one business in your account, and every invoice, expense or profile you touch belongs to that business. ## Create a token 1. Sign in to [app.fsaskaita.lt](https://app.fsaskaita.lt) as a user who can manage the business. 2. Open **Settings**, then **Integrations**, then **API**. 3. Give the token a name that tells you where it is used, such as `accounting-sync`, and create it. 4. Copy the token immediately. It is shown once. Afterwards only its name is listed. Tokens are only available on plans that include the API feature. If the section shows an upgrade notice instead of the form, the current plan does not include it. ## Use the token Send it in the `Authorization` header and always request JSON: ```bash tab="cURL" tab-group="request" curl https://app.fsaskaita.lt/api/profile \ -H "Authorization: Bearer $FSASKAITA_TOKEN" \ -H "Accept: application/json" ``` ```js tab="JavaScript" tab-group="request" const response = await fetch('https://app.fsaskaita.lt/api/profile', { headers: { Authorization: `Bearer ${process.env.FSASKAITA_TOKEN}`, Accept: 'application/json', }, }); console.log(response.status, await response.json()); ``` ```go tab="Go" tab-group="request" package main import ( "fmt" "io" "net/http" "os" ) func main() { req, _ := http.NewRequest("GET", "https://app.fsaskaita.lt/api/profile", nil) req.Header.Set("Authorization", "Bearer "+os.Getenv("FSASKAITA_TOKEN")) req.Header.Set("Accept", "application/json") res, err := http.DefaultClient.Do(req) if err != nil { panic(err) } defer res.Body.Close() body, _ := io.ReadAll(res.Body) fmt.Println(res.Status, string(body)) } ``` ```python tab="Python" tab-group="request" import os import requests response = requests.get( "https://app.fsaskaita.lt/api/profile", headers={ "Authorization": f"Bearer {os.environ['FSASKAITA_TOKEN']}", "Accept": "application/json", }, ) print(response.status_code, response.json()) ``` ```java tab="Java" tab-group="request" import java.net.URI; import java.net.http.HttpClient; import java.net.http.HttpRequest; import java.net.http.HttpResponse; public class GetProfile { public static void main(String[] args) throws Exception { HttpRequest request = HttpRequest.newBuilder() .uri(URI.create("https://app.fsaskaita.lt/api/profile")) .header("Authorization", "Bearer " + System.getenv("FSASKAITA_TOKEN")) .header("Accept", "application/json") .GET() .build(); HttpResponse response = HttpClient.newHttpClient() .send(request, HttpResponse.BodyHandlers.ofString()); System.out.println(response.statusCode() + " " + response.body()); } } ``` ```csharp tab="C#" tab-group="request" using System.Net.Http.Headers; using var client = new HttpClient(); client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue( "Bearer", Environment.GetEnvironmentVariable("FSASKAITA_TOKEN")); client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); var response = await client.GetAsync("https://app.fsaskaita.lt/api/profile"); Console.WriteLine($"{(int)response.StatusCode} {await response.Content.ReadAsStringAsync()}"); ``` A successful response describes the business behind the token: ```json { "data": { "business_id": "9c1f7b2e-3a6d-4d5e-9f0a-2b7c8d9e0f11", "business_title": "Pavyzdys, MB", "business_type": "small_partnership", "address": "Gedimino pr. 1, Vilnius", "vat_code": "LT100001234567", "company_name": "Pavyzdys, MB", "company_code": "305000001" } } ``` For a business registered as individual activity the profile carries `individual_activity_id`, `first_name` and `last_name` instead of `company_name` and `company_code`. ## Why the Accept header matters Application errors come back as JSON either way. Without `Accept: application/json`, however, a missing or revoked token answers with an HTML redirect to the login page, and a rate-limited request answers with an HTML error page. With the header you get `401 {"message":"Unauthenticated."}` and `429 {"message":"Too Many Attempts."}`. ## Scope and lifetime - A token grants full access to its business. There are no per-endpoint permissions. - Tokens do not expire. Revoke a token by deleting it in the same settings page; requests with a deleted token receive `401`. - If your account has several businesses, create a separate token for each one. - All tokens of one business share the same rate limit of 60 requests per minute. ## Keep it secret Treat the token like a password. Store it in a secret manager or environment variable, never in a repository or in a browser-side application. If a token leaks, delete it in the app and create a new one. --- # Conventions, errors and rate limits > Request and response formats, pagination, identifiers, dates and money, HTTP status codes, and the 60 requests per minute limit. ## Requests - Base URL `https://app.fsaskaita.lt/api`. - Headers on every request: `Authorization: Bearer ` and `Accept: application/json`. - Invoice endpoints take a JSON body (`Content-Type: application/json`). Expense endpoints take `multipart/form-data` because a file travels with them. - `PUT` and `PATCH` are equivalent on this API. Both replace the whole resource with the body you send, so always send every field. ## Responses A single resource is wrapped in `data`: ```json { "data": { "id": "…", "…": "…" } } ``` A list is wrapped in `data` with a `meta` block: ```json { "data": [ … ], "meta": { "current_page": 1, "from": 1, "last_page": 3, "path": "https://app.fsaskaita.lt/api/invoices", "per_page": 50, "to": 50, "total": 132 } } ``` Deletion returns `200` with an empty body. ## Pagination Lists return 50 items per page, newest first, and accept only `?page=N`. There are no filters, sort parameters or page-size options. To sync, walk the pages until `current_page` equals `last_page`. `GET /currencies` is not paginated. ## Identifiers, dates, money | Kind | Format | Example | |---|---|---| | Identifiers | UUID string | `"9c1f7b2e-3a6d-4d5e-9f0a-2b7c8d9e0f11"` | | Dates in requests and responses | `YYYY-MM-DD` | `"2026-09-08"` | | `created_at`, `updated_at` | Unix timestamp, seconds, integer | `1757318400` | | Money | JSON number | `60.5` | | Currency | uppercase ISO 4217 code accepted by `GET /currencies` | `"EUR"` | | Invoice numbers | string, zero-padded to three digits in responses | `"007"` | Enumerated values are lowercase snake_case strings, for example `vat_invoice` or `not_paid`. The reference lists the allowed values for every field. ## Errors | Status | Meaning | Body | |---|---|---| | `401` | Missing, invalid or deleted token | `{"message":"Unauthenticated."}` | | `404` | Unknown id, or the resource belongs to another business | `{"message":"…"}` | | `422` | Validation failed | see below | | `429` | Rate limit exceeded | `{"message":"Too Many Attempts."}` plus `Retry-After` | | `500` | Unexpected server error | `{"message":"Server Error"}` | Validation errors list every failing field. Nested fields use dot paths. Messages are in Lithuanian. ```json { "message": "Laukas type yra privalomas. (and 2 more errors)", "errors": { "type": ["Laukas type yra privalomas."], "buyer.company_name": ["…"], "products.0.quantity": ["…"] } } ``` There is no `403`. A token either works for its business or is rejected with `401`. ## Rate limits Each business may make 60 requests per minute across all of its tokens. Every response carries `X-RateLimit-Limit` and `X-RateLimit-Remaining`. When the limit is hit, the response is `429` with `Retry-After` in seconds and `X-RateLimit-Reset` as a Unix timestamp. Back off until then; retrying earlier only returns more `429`s. ## Idempotency and retries The API has no idempotency key. A `POST` that timed out on the network may still have created the resource. Before retrying, list the newest items and check whether yours is there. `PUT` and `DELETE` are safe to retry. ## Localisation Validation messages and the type label inside PDF file names are in Lithuanian unless the invoice `language` says otherwise. There is no `Accept-Language` negotiation. --- # Expenses > Record purchase documents with their file, update them, replace the file, and download the original. An expense is a purchase document you received: a supplier invoice, a receipt, a bill. The API stores its key figures and the original file. Because the file travels with the request, expense endpoints use `multipart/form-data` rather than JSON. ## Endpoints | Method | Path | Summary | |---|---|---| | `GET` | [`/expenses`](/reference/expenses/listExpenses/) | List expenses | | `POST` | [`/expenses`](/reference/expenses/createExpense/) | Create an expense | | `GET` | [`/expenses/{expense}`](/reference/expenses/getExpense/) | Get an expense | | `DELETE` | [`/expenses/{expense}`](/reference/expenses/deleteExpense/) | Delete an expense | | `PUT` | [`/expenses/{expense}`](/reference/expenses/updateExpense/) | Replace an expense | | `POST` | [`/expenses/{expense}/file`](/reference/expenses/replaceExpenseFile/) | Replace the expense file | | `GET` | [`/expenses/{expense}/download`](/reference/expenses/downloadExpenseFile/) | Download the expense file | ## Fields | Field | Required | Notes | |---|---|---| | `file` | on create | One file. Allowed extensions: `pdf`, `jpg`, `jpeg`, `png`, `gif`, `bmp`, `tiff`, `xls`, `xlsx`, `doc`, `docx`, `odf` | | `date` | yes | `YYYY-MM-DD`, the document date | | `total` | yes | Amount including VAT, number | | `currency` | yes | Code from `GET /currencies`, for example `EUR` | | `seller` | yes | Supplier name, up to 255 characters | | `vat` | no | VAT amount, number | | `invoice_number` | no | The supplier's document number | ## Create an expense ```bash tab="cURL" tab-group="request" curl -X POST https://app.fsaskaita.lt/api/expenses \ -H "Authorization: Bearer $FSASKAITA_TOKEN" \ -H "Accept: application/json" \ -F "file=@receipt.pdf" \ -F "date=2026-09-08" \ -F "total=60.50" \ -F "vat=10.50" \ -F "currency=EUR" \ -F "seller=Telia Lietuva, AB" \ -F "invoice_number=TL-2026-000123" ``` ```js tab="JavaScript" tab-group="request" import { openAsBlob } from 'node:fs'; const form = new FormData(); form.append('file', await openAsBlob('receipt.pdf', { type: 'application/pdf' }), 'receipt.pdf'); form.append('date', '2026-09-08'); form.append('total', '60.50'); form.append('vat', '10.50'); form.append('currency', 'EUR'); form.append('seller', 'Telia Lietuva, AB'); form.append('invoice_number', 'TL-2026-000123'); const response = await fetch('https://app.fsaskaita.lt/api/expenses', { method: 'POST', headers: { Authorization: `Bearer ${process.env.FSASKAITA_TOKEN}`, Accept: 'application/json', }, body: form, }); console.log(response.status, await response.json()); ``` ```go tab="Go" tab-group="request" package main import ( "bytes" "fmt" "io" "mime/multipart" "net/http" "os" ) func main() { var body bytes.Buffer form := multipart.NewWriter(&body) file, err := os.Open("receipt.pdf") if err != nil { panic(err) } defer file.Close() part, _ := form.CreateFormFile("file", "receipt.pdf") if _, err := io.Copy(part, file); err != nil { panic(err) } for name, value := range map[string]string{ "date": "2026-09-08", "total": "60.50", "vat": "10.50", "currency": "EUR", "seller": "Telia Lietuva, AB", "invoice_number": "TL-2026-000123", } { form.WriteField(name, value) } form.Close() req, _ := http.NewRequest("POST", "https://app.fsaskaita.lt/api/expenses", &body) req.Header.Set("Authorization", "Bearer "+os.Getenv("FSASKAITA_TOKEN")) req.Header.Set("Accept", "application/json") req.Header.Set("Content-Type", form.FormDataContentType()) res, err := http.DefaultClient.Do(req) if err != nil { panic(err) } defer res.Body.Close() response, _ := io.ReadAll(res.Body) fmt.Println(res.Status, string(response)) } ``` ```python tab="Python" tab-group="request" import os import requests with open("receipt.pdf", "rb") as file: response = requests.post( "https://app.fsaskaita.lt/api/expenses", headers={ "Authorization": f"Bearer {os.environ['FSASKAITA_TOKEN']}", "Accept": "application/json", }, data={ "date": "2026-09-08", "total": "60.50", "vat": "10.50", "currency": "EUR", "seller": "Telia Lietuva, AB", "invoice_number": "TL-2026-000123", }, files={"file": ("receipt.pdf", file, "application/pdf")}, ) print(response.status_code, response.json()) ``` ```java tab="Java" tab-group="request" import java.io.ByteArrayOutputStream; import java.net.URI; import java.net.http.HttpClient; import java.net.http.HttpRequest; import java.net.http.HttpResponse; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; import java.util.Map; import java.util.UUID; public class CreateExpense { public static void main(String[] args) throws Exception { String boundary = UUID.randomUUID().toString(); Map fields = Map.of( "date", "2026-09-08", "total", "60.50", "vat", "10.50", "currency", "EUR", "seller", "Telia Lietuva, AB", "invoice_number", "TL-2026-000123"); ByteArrayOutputStream body = new ByteArrayOutputStream(); for (Map.Entry field : fields.entrySet()) { body.write(("--" + boundary + "\r\n" + "Content-Disposition: form-data; name=\"" + field.getKey() + "\"\r\n\r\n" + field.getValue() + "\r\n").getBytes(StandardCharsets.UTF_8)); } body.write(("--" + boundary + "\r\n" + "Content-Disposition: form-data; name=\"file\"; filename=\"receipt.pdf\"\r\n" + "Content-Type: application/pdf\r\n\r\n").getBytes(StandardCharsets.UTF_8)); body.write(Files.readAllBytes(Path.of("receipt.pdf"))); body.write(("\r\n--" + boundary + "--\r\n").getBytes(StandardCharsets.UTF_8)); HttpRequest request = HttpRequest.newBuilder() .uri(URI.create("https://app.fsaskaita.lt/api/expenses")) .header("Authorization", "Bearer " + System.getenv("FSASKAITA_TOKEN")) .header("Accept", "application/json") .header("Content-Type", "multipart/form-data; boundary=" + boundary) .POST(HttpRequest.BodyPublishers.ofByteArray(body.toByteArray())) .build(); HttpResponse response = HttpClient.newHttpClient() .send(request, HttpResponse.BodyHandlers.ofString()); System.out.println(response.statusCode() + " " + response.body()); } } ``` ```csharp tab="C#" tab-group="request" using System.Net.Http.Headers; using var client = new HttpClient(); client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue( "Bearer", Environment.GetEnvironmentVariable("FSASKAITA_TOKEN")); client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); using var form = new MultipartFormDataContent(); var file = new StreamContent(File.OpenRead("receipt.pdf")); file.Headers.ContentType = new MediaTypeHeaderValue("application/pdf"); form.Add(file, "file", "receipt.pdf"); form.Add(new StringContent("2026-09-08"), "date"); form.Add(new StringContent("60.50"), "total"); form.Add(new StringContent("10.50"), "vat"); form.Add(new StringContent("EUR"), "currency"); form.Add(new StringContent("Telia Lietuva, AB"), "seller"); form.Add(new StringContent("TL-2026-000123"), "invoice_number"); var response = await client.PostAsync("https://app.fsaskaita.lt/api/expenses", form); Console.WriteLine($"{(int)response.StatusCode} {await response.Content.ReadAsStringAsync()}"); ``` Response: ```json { "data": { "id": "2a7d6c1b-8e9f-4a0b-9c1d-2e3f4a5b6c7d", "date": "2026-09-08", "total": 60.5, "currency": "EUR", "seller": "Telia Lietuva, AB", "created_at": 1757318400, "updated_at": 1757318400 } } ``` The response does not echo `vat`, `invoice_number` or file metadata. Keep them on your side if you need them; the file itself is always retrievable through the download endpoint. ## Update `PUT /expenses/{id}` accepts the same multipart fields. `file` is optional here; when present it replaces the stored file. Many HTTP clients cannot send multipart bodies with `PUT`. Use `PATCH`, which behaves identically, or send a `POST` with an extra form field `_method=PUT` (or the header `X-HTTP-Method-Override: PUT`), which the API treats as a `PUT`. If you only need to swap the file, use `POST /expenses/{id}/file`. ## Download the original ```bash tab="cURL" tab-group="request" curl -L https://app.fsaskaita.lt/api/expenses/$ID/download \ -H "Authorization: Bearer $FSASKAITA_TOKEN" \ -H "Accept: application/json" \ -o receipt.pdf ``` ```js tab="JavaScript" tab-group="request" import { createWriteStream } from 'node:fs'; import { Readable } from 'node:stream'; import { pipeline } from 'node:stream/promises'; const id = '2a7d6c1b-8e9f-4a0b-9c1d-2e3f4a5b6c7d'; const response = await fetch(`https://app.fsaskaita.lt/api/expenses/${id}/download`, { headers: { Authorization: `Bearer ${process.env.FSASKAITA_TOKEN}`, Accept: 'application/json', }, }); if (!response.ok) throw new Error(`${response.status} ${await response.text()}`); await pipeline(Readable.fromWeb(response.body), createWriteStream('receipt.pdf')); ``` ```go tab="Go" tab-group="request" package main import ( "io" "net/http" "os" ) func main() { id := "2a7d6c1b-8e9f-4a0b-9c1d-2e3f4a5b6c7d" req, _ := http.NewRequest("GET", "https://app.fsaskaita.lt/api/expenses/"+id+"/download", nil) req.Header.Set("Authorization", "Bearer "+os.Getenv("FSASKAITA_TOKEN")) req.Header.Set("Accept", "application/json") res, err := http.DefaultClient.Do(req) if err != nil { panic(err) } defer res.Body.Close() if res.StatusCode != http.StatusOK { body, _ := io.ReadAll(res.Body) panic(res.Status + " " + string(body)) } file, err := os.Create("receipt.pdf") if err != nil { panic(err) } defer file.Close() if _, err := io.Copy(file, res.Body); err != nil { panic(err) } } ``` ```python tab="Python" tab-group="request" import os import requests expense_id = "2a7d6c1b-8e9f-4a0b-9c1d-2e3f4a5b6c7d" with requests.get( f"https://app.fsaskaita.lt/api/expenses/{expense_id}/download", headers={ "Authorization": f"Bearer {os.environ['FSASKAITA_TOKEN']}", "Accept": "application/json", }, stream=True, ) as response: response.raise_for_status() with open("receipt.pdf", "wb") as file: for chunk in response.iter_content(chunk_size=65536): file.write(chunk) ``` ```java tab="Java" tab-group="request" import java.io.InputStream; import java.net.URI; import java.net.http.HttpClient; import java.net.http.HttpRequest; import java.net.http.HttpResponse; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.StandardCopyOption; public class DownloadExpense { public static void main(String[] args) throws Exception { String id = "2a7d6c1b-8e9f-4a0b-9c1d-2e3f4a5b6c7d"; HttpRequest request = HttpRequest.newBuilder() .uri(URI.create("https://app.fsaskaita.lt/api/expenses/" + id + "/download")) .header("Authorization", "Bearer " + System.getenv("FSASKAITA_TOKEN")) .header("Accept", "application/json") .GET() .build(); HttpResponse response = HttpClient.newHttpClient() .send(request, HttpResponse.BodyHandlers.ofInputStream()); try (InputStream body = response.body()) { if (response.statusCode() != 200) { throw new IllegalStateException(response.statusCode() + " " + new String(body.readAllBytes())); } Files.copy(body, Path.of("receipt.pdf"), StandardCopyOption.REPLACE_EXISTING); } } } ``` ```csharp tab="C#" tab-group="request" using System.Net.Http.Headers; var id = "2a7d6c1b-8e9f-4a0b-9c1d-2e3f4a5b6c7d"; using var client = new HttpClient(); client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue( "Bearer", Environment.GetEnvironmentVariable("FSASKAITA_TOKEN")); client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); using var response = await client.GetAsync( $"https://app.fsaskaita.lt/api/expenses/{id}/download", HttpCompletionOption.ResponseHeadersRead); response.EnsureSuccessStatusCode(); await using var file = File.Create("receipt.pdf"); await response.Content.CopyToAsync(file); ``` The response streams the stored file with the original file name in `Content-Disposition`. The content type follows the file. ## Side effects Creating fires the `expense.created` [webhook](/guides/webhooks); updating the figures or the file fires `expense.updated`. Deleting fires `expense.deleted` and removes the stored file. --- # Invoices > The invoice model, invoice types, numbering and series, the create and update requests, and downloading the PDF. An invoice in F-sąskaita is a finalized, numbered document issued by your business (the **seller**) to a **buyer**, with one or more **lines** (`products`) and optional **payment options**. The API only ever sees finalized invoices; drafts made in the app are invisible here. ## Endpoints | Method | Path | Summary | |---|---|---| | `GET` | [`/invoices`](/reference/invoices/listInvoices/) | List invoices | | `POST` | [`/invoices`](/reference/invoices/createInvoice/) | Create an invoice | | `GET` | [`/invoices/{invoice}`](/reference/invoices/getInvoice/) | Get an invoice | | `DELETE` | [`/invoices/{invoice}`](/reference/invoices/deleteInvoice/) | Delete an invoice | | `PUT` | [`/invoices/{invoice}`](/reference/invoices/updateInvoice/) | Replace an invoice | | `GET` | [`/invoices/{invoice}/download`](/reference/invoices/downloadInvoicePdf/) | Download the invoice PDF | ## Invoice types | `type` | VAT | Use | |---|---|---| | `regular_invoice` | no | Standard invoice for a non-VAT payer | | `vat_invoice` | yes | VAT invoice | | `preliminary_invoice` | no | Proforma | | `preliminary_vat_invoice` | yes | Proforma with VAT | | `credit_invoice` | no | Credit note | | `credit_vat_invoice` | yes | Credit note with VAT | VAT types require a `vat_percentage` on every line and a seller VAT code. When you use your own profile as the seller, the VAT code comes from the profile. ## Series and numbering Every invoice belongs to a **series**, a short code such as `SF`, and has a number unique within that series for your business. - Omit `invoice_number` on create and the API assigns the next number of the series. A series that does not exist yet starts at `1`. - Send `invoice_number` explicitly when you manage numbering yourself. It must be unique in the series. Padded (`"007"`) and unpadded (`"7"`) forms are compared exactly as sent, so use one form consistently within a series. - **On update, always send the current `invoice_number`.** An update without it assigns a fresh number from the series counter. - Responses return the number zero-padded to three digits (`"7"` is returned as `"007"`). ## Create an invoice The shortest useful request uses your own profile as the seller and prices per line: ```bash tab="cURL" tab-group="request" curl -X POST https://app.fsaskaita.lt/api/invoices \ -H "Authorization: Bearer $FSASKAITA_TOKEN" \ -H "Accept: application/json" \ -H "Content-Type: application/json" \ -d @- <<'JSON' { "type": "vat_invoice", "invoice_date": "2026-09-08", "pay_until_date": "2026-09-22", "series": "SF", "currency": "EUR", "language": "lt", "use_default_seller_info": true, "buyer": { "type": "company", "company_name": "Pirkėjas, UAB", "company_code": "300000001", "vat_code": "LT100000000011", "address": "Konstitucijos pr. 7, Vilnius", "email": "buhalterija@pirkejas.lt" }, "products": [ { "name": "Konsultacija", "units": "val.", "quantity": 2, "price": 50, "vat_percentage": 21 } ], "payment_options": [ { "type": "bank", "bank_name": "Swedbank", "bank_account": "LT12 7300 0100 0000 0001", "swift_bic_code": "HABALT22" } ] } JSON ``` ```js tab="JavaScript" tab-group="request" const response = await fetch('https://app.fsaskaita.lt/api/invoices', { method: 'POST', headers: { Authorization: `Bearer ${process.env.FSASKAITA_TOKEN}`, Accept: 'application/json', 'Content-Type': 'application/json', }, body: JSON.stringify({ type: 'vat_invoice', invoice_date: '2026-09-08', pay_until_date: '2026-09-22', series: 'SF', currency: 'EUR', language: 'lt', use_default_seller_info: true, buyer: { type: 'company', company_name: 'Pirkėjas, UAB', company_code: '300000001', vat_code: 'LT100000000011', address: 'Konstitucijos pr. 7, Vilnius', email: 'buhalterija@pirkejas.lt', }, products: [ { name: 'Konsultacija', units: 'val.', quantity: 2, price: 50, vat_percentage: 21 }, ], payment_options: [ { type: 'bank', bank_name: 'Swedbank', bank_account: 'LT12 7300 0100 0000 0001', swift_bic_code: 'HABALT22' }, ], }), }); console.log(response.status, await response.json()); ``` ```go tab="Go" tab-group="request" package main import ( "fmt" "io" "net/http" "os" "strings" ) const invoice = `{ "type": "vat_invoice", "invoice_date": "2026-09-08", "pay_until_date": "2026-09-22", "series": "SF", "currency": "EUR", "language": "lt", "use_default_seller_info": true, "buyer": { "type": "company", "company_name": "Pirkėjas, UAB", "company_code": "300000001", "vat_code": "LT100000000011", "address": "Konstitucijos pr. 7, Vilnius", "email": "buhalterija@pirkejas.lt" }, "products": [ { "name": "Konsultacija", "units": "val.", "quantity": 2, "price": 50, "vat_percentage": 21 } ], "payment_options": [ { "type": "bank", "bank_name": "Swedbank", "bank_account": "LT12 7300 0100 0000 0001", "swift_bic_code": "HABALT22" } ] }` func main() { req, _ := http.NewRequest("POST", "https://app.fsaskaita.lt/api/invoices", strings.NewReader(invoice)) req.Header.Set("Authorization", "Bearer "+os.Getenv("FSASKAITA_TOKEN")) req.Header.Set("Accept", "application/json") req.Header.Set("Content-Type", "application/json") res, err := http.DefaultClient.Do(req) if err != nil { panic(err) } defer res.Body.Close() body, _ := io.ReadAll(res.Body) fmt.Println(res.Status, string(body)) } ``` ```python tab="Python" tab-group="request" import os import requests response = requests.post( "https://app.fsaskaita.lt/api/invoices", headers={ "Authorization": f"Bearer {os.environ['FSASKAITA_TOKEN']}", "Accept": "application/json", }, json={ "type": "vat_invoice", "invoice_date": "2026-09-08", "pay_until_date": "2026-09-22", "series": "SF", "currency": "EUR", "language": "lt", "use_default_seller_info": True, "buyer": { "type": "company", "company_name": "Pirkėjas, UAB", "company_code": "300000001", "vat_code": "LT100000000011", "address": "Konstitucijos pr. 7, Vilnius", "email": "buhalterija@pirkejas.lt", }, "products": [ {"name": "Konsultacija", "units": "val.", "quantity": 2, "price": 50, "vat_percentage": 21}, ], "payment_options": [ {"type": "bank", "bank_name": "Swedbank", "bank_account": "LT12 7300 0100 0000 0001", "swift_bic_code": "HABALT22"}, ], }, ) print(response.status_code, response.json()) ``` ```java tab="Java" tab-group="request" import java.net.URI; import java.net.http.HttpClient; import java.net.http.HttpRequest; import java.net.http.HttpResponse; public class CreateInvoice { public static void main(String[] args) throws Exception { String invoice = """ { "type": "vat_invoice", "invoice_date": "2026-09-08", "pay_until_date": "2026-09-22", "series": "SF", "currency": "EUR", "language": "lt", "use_default_seller_info": true, "buyer": { "type": "company", "company_name": "Pirkėjas, UAB", "company_code": "300000001", "vat_code": "LT100000000011", "address": "Konstitucijos pr. 7, Vilnius", "email": "buhalterija@pirkejas.lt" }, "products": [ { "name": "Konsultacija", "units": "val.", "quantity": 2, "price": 50, "vat_percentage": 21 } ], "payment_options": [ { "type": "bank", "bank_name": "Swedbank", "bank_account": "LT12 7300 0100 0000 0001", "swift_bic_code": "HABALT22" } ] } """; HttpRequest request = HttpRequest.newBuilder() .uri(URI.create("https://app.fsaskaita.lt/api/invoices")) .header("Authorization", "Bearer " + System.getenv("FSASKAITA_TOKEN")) .header("Accept", "application/json") .header("Content-Type", "application/json") .POST(HttpRequest.BodyPublishers.ofString(invoice)) .build(); HttpResponse response = HttpClient.newHttpClient() .send(request, HttpResponse.BodyHandlers.ofString()); System.out.println(response.statusCode() + " " + response.body()); } } ``` ```csharp tab="C#" tab-group="request" using System.Net.Http.Headers; using System.Text; var invoice = """ { "type": "vat_invoice", "invoice_date": "2026-09-08", "pay_until_date": "2026-09-22", "series": "SF", "currency": "EUR", "language": "lt", "use_default_seller_info": true, "buyer": { "type": "company", "company_name": "Pirkėjas, UAB", "company_code": "300000001", "vat_code": "LT100000000011", "address": "Konstitucijos pr. 7, Vilnius", "email": "buhalterija@pirkejas.lt" }, "products": [ { "name": "Konsultacija", "units": "val.", "quantity": 2, "price": 50, "vat_percentage": 21 } ], "payment_options": [ { "type": "bank", "bank_name": "Swedbank", "bank_account": "LT12 7300 0100 0000 0001", "swift_bic_code": "HABALT22" } ] } """; using var client = new HttpClient(); client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue( "Bearer", Environment.GetEnvironmentVariable("FSASKAITA_TOKEN")); client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); var response = await client.PostAsync( "https://app.fsaskaita.lt/api/invoices", new StringContent(invoice, Encoding.UTF8, "application/json")); Console.WriteLine($"{(int)response.StatusCode} {await response.Content.ReadAsStringAsync()}"); ``` Key rules: - `buyer.type` is `company` or `individual`. Companies need `company_name`; individuals use `first_name` and `last_name`. Do not send company fields for an individual or personal names for a company. - Each line needs `name`, `units`, `quantity` and **exactly one** of `price` (unit price excluding VAT), `total` (line total excluding VAT) or `total_incl_vat`. The server computes the others. - `payment_options` entries are either `type: "bank"` with `bank_account` and `bank_name` (plus optional `routing_or_sort_number`, `swift_bic_code`) or `type: "other"` with a `fields` list of `{ "label", "value" }` pairs. - `payment_status` defaults to `not_paid` on create and is left unchanged when omitted on update. Set `"paid"` to mark the invoice paid. - `language` (`lt`, `en`, `es`, `de`, `fr`) decides the language of the PDF. Default `lt`. - `notes` is free text up to 255 characters printed on the invoice. ### Providing your own seller block Set `use_default_seller_info` to `false` (or omit it) and send `seller`. The required seller fields depend on how your business is registered: companies send `company_name` and `company_code`; individual activity sends `first_name`, `last_name` and `individual_activity_id`. VAT types additionally require `seller.vat_code`. `seller.custom_fields` accepts extra `{ "label", "value" }` pairs printed under the seller details. ## The response ```json { "data": { "id": "6f1e9d2a-0b3c-4e5f-8a9b-1c2d3e4f5a6b", "business_id": "9c1f7b2e-3a6d-4d5e-9f0a-2b7c8d9e0f11", "invoice_type": "vat_invoice", "series": "SF", "invoice_number": "007", "invoice_date": "2026-09-08", "pay_until_date": "2026-09-22", "language": "lt", "subtotal": 100, "vat": 21, "total_incl_vat": 121, "currency": "EUR", "payment_status": "not_paid", "notes": null, "share_link": "https://app.fsaskaita.lt/invoice/share/…", "seller": { "business_type": "small_partnership", "company_name": "Pavyzdys, MB", "…": "…", "custom_fields": [] }, "buyer": { "type": "company", "company_name": "Pirkėjas, UAB", "…": "…" }, "items": [ { "id": "…", "name": "Konsultacija", "price": 50, "vat_percentage": 21, "quantity": 2, "units": "val." } ], "payment_options": [ { "type": "bank", "bank_account": "LT12 7300 0100 0000 0001", "bank_name": "Swedbank", "routing_or_sort_number": null, "swift_bic_code": "HABALT22", "fields": [] } ], "created_at": 1757318400, "updated_at": 1757318400 } } ``` `share_link` is a public page where the buyer can view and download the invoice without signing in. `items[].price` is the unit price excluding VAT; line totals are not returned. ## Update an invoice `PUT /invoices/{id}` takes the same body as create and replaces every part of the invoice: lines, payment options and seller block included. Read the invoice first, modify the fields you need, and send the whole document back with its `invoice_number`. Changing `series` moves the invoice and re-synchronises both series counters. ## Download the PDF ```bash tab="cURL" tab-group="request" curl -L https://app.fsaskaita.lt/api/invoices/$ID/download \ -H "Authorization: Bearer $FSASKAITA_TOKEN" \ -H "Accept: application/json" \ -o invoice.pdf ``` ```js tab="JavaScript" tab-group="request" import { createWriteStream } from 'node:fs'; import { Readable } from 'node:stream'; import { pipeline } from 'node:stream/promises'; const id = '6f1e9d2a-0b3c-4e5f-8a9b-1c2d3e4f5a6b'; const response = await fetch(`https://app.fsaskaita.lt/api/invoices/${id}/download`, { headers: { Authorization: `Bearer ${process.env.FSASKAITA_TOKEN}`, Accept: 'application/json', }, }); if (!response.ok) throw new Error(`${response.status} ${await response.text()}`); await pipeline(Readable.fromWeb(response.body), createWriteStream('invoice.pdf')); ``` ```go tab="Go" tab-group="request" package main import ( "io" "net/http" "os" ) func main() { id := "6f1e9d2a-0b3c-4e5f-8a9b-1c2d3e4f5a6b" req, _ := http.NewRequest("GET", "https://app.fsaskaita.lt/api/invoices/"+id+"/download", nil) req.Header.Set("Authorization", "Bearer "+os.Getenv("FSASKAITA_TOKEN")) req.Header.Set("Accept", "application/json") res, err := http.DefaultClient.Do(req) if err != nil { panic(err) } defer res.Body.Close() if res.StatusCode != http.StatusOK { body, _ := io.ReadAll(res.Body) panic(res.Status + " " + string(body)) } file, err := os.Create("invoice.pdf") if err != nil { panic(err) } defer file.Close() if _, err := io.Copy(file, res.Body); err != nil { panic(err) } } ``` ```python tab="Python" tab-group="request" import os import requests invoice_id = "6f1e9d2a-0b3c-4e5f-8a9b-1c2d3e4f5a6b" with requests.get( f"https://app.fsaskaita.lt/api/invoices/{invoice_id}/download", headers={ "Authorization": f"Bearer {os.environ['FSASKAITA_TOKEN']}", "Accept": "application/json", }, stream=True, ) as response: response.raise_for_status() with open("invoice.pdf", "wb") as file: for chunk in response.iter_content(chunk_size=65536): file.write(chunk) ``` ```java tab="Java" tab-group="request" import java.io.InputStream; import java.net.URI; import java.net.http.HttpClient; import java.net.http.HttpRequest; import java.net.http.HttpResponse; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.StandardCopyOption; public class DownloadInvoice { public static void main(String[] args) throws Exception { String id = "6f1e9d2a-0b3c-4e5f-8a9b-1c2d3e4f5a6b"; HttpRequest request = HttpRequest.newBuilder() .uri(URI.create("https://app.fsaskaita.lt/api/invoices/" + id + "/download")) .header("Authorization", "Bearer " + System.getenv("FSASKAITA_TOKEN")) .header("Accept", "application/json") .GET() .build(); HttpResponse response = HttpClient.newHttpClient() .send(request, HttpResponse.BodyHandlers.ofInputStream()); try (InputStream body = response.body()) { if (response.statusCode() != 200) { throw new IllegalStateException(response.statusCode() + " " + new String(body.readAllBytes())); } Files.copy(body, Path.of("invoice.pdf"), StandardCopyOption.REPLACE_EXISTING); } } } ``` ```csharp tab="C#" tab-group="request" using System.Net.Http.Headers; var id = "6f1e9d2a-0b3c-4e5f-8a9b-1c2d3e4f5a6b"; using var client = new HttpClient(); client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue( "Bearer", Environment.GetEnvironmentVariable("FSASKAITA_TOKEN")); client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); using var response = await client.GetAsync( $"https://app.fsaskaita.lt/api/invoices/{id}/download", HttpCompletionOption.ResponseHeadersRead); response.EnsureSuccessStatusCode(); await using var file = File.Create("invoice.pdf"); await response.Content.CopyToAsync(file); ``` The response is `application/pdf` with a `Content-Disposition: attachment` file name built from the type label, series and number. If the PDF is not ready yet, the download waits up to about 20 seconds for it. There is no `Content-Length` header, so stream the body rather than preallocating. ## Side effects to expect - Creating or updating fires the `invoice.created` or `invoice.updated` [webhook](/guides/webhooks). Deleting fires `invoice.deleted`. - The buyer is saved to your client list in the app. - API access requires the Premium plan. --- # Webhooks > Subscribe an HTTPS endpoint to invoice and expense events, verify the HMAC-SHA256 signature, and handle retries. Webhooks push a JSON message to your HTTPS endpoint whenever an invoice or expense changes in your business, whether the change came from the API, the app, a recurring invoice or a payment. They are included in the same plan as the API. ## Subscribe There is no API for subscriptions. In the app open **Settings**, **Integrations**, **Webhooks**, add your endpoint URL and tick the events you want. The app generates a **signing secret** for the subscription, prefixed `whsec_`. Reveal it and store it with your endpoint's configuration. Endpoint rules: - Must be `https://`. - Up to 2048 characters. ## Events | Method | Path | Summary | |---|---|---| | `EVENT` | [`invoice.created`](/reference/invoices/webhookInvoiceCreated/) | invoice.created | | `EVENT` | [`invoice.updated`](/reference/invoices/webhookInvoiceUpdated/) | invoice.updated | | `EVENT` | [`invoice.deleted`](/reference/invoices/webhookInvoiceDeleted/) | invoice.deleted | | `EVENT` | [`expense.created`](/reference/expenses/webhookExpenseCreated/) | expense.created | | `EVENT` | [`expense.updated`](/reference/expenses/webhookExpenseUpdated/) | expense.updated | | `EVENT` | [`expense.deleted`](/reference/expenses/webhookExpenseDeleted/) | expense.deleted | What each event carries and when it is sent: | Event | `data` | When | |---|---|---| | `invoice.created` | full invoice, same shape as `GET /invoices/{id}` | a non-draft invoice is created | | `invoice.updated` | full invoice | any change, including payment status changes and payments received through the app | | `invoice.deleted` | `{ "id": "" }` | a non-draft invoice is deleted | | `expense.created` | full expense, same shape as `GET /expenses/{id}` | an expense is created | | `expense.updated` | full expense | figures or file changed | | `expense.deleted` | `{ "id": "" }` | an expense is deleted through the API or the app | Draft invoices never produce events. `invoice.created` is sent as soon as the invoice is saved, before its PDF is rendered; a download request made in the handler waits for the PDF. ## Delivery Each delivery is an HTTP `POST` with: ``` Content-Type: application/json Signature: ``` Body: ```json { "event": "invoice.updated", "data": { "id": "6f1e9d2a-0b3c-4e5f-8a9b-1c2d3e4f5a6b", "invoice_type": "vat_invoice", "series": "SF", "invoice_number": "007", "payment_status": "paid", "…": "…" } } ``` Your endpoint must answer with any `2xx` status within 10 seconds. Anything else, including a timeout, counts as a failure. ## Retries A failed delivery is retried twice more: after about 10 seconds, then after about 100 seconds. After three failures the message is dropped. Deliveries can therefore arrive more than once and, for a busy resource, out of order. Make your handler idempotent: use `data.id` plus `data.updated_at` to detect duplicates, and fetch the current state with `GET /invoices/{id}` when the order matters. There is no event identifier or timestamp header, and there is no delivery log in the app. ## Verify the signature Compute HMAC-SHA256 over the **raw request body** exactly as received, using the subscription secret, and compare it in constant time with the `Signature` header. ```php tab="PHP" tab-group="signature" $secret = getenv('FSASKAITA_WEBHOOK_SECRET'); // whsec_… $payload = file_get_contents('php://input'); $expected = hash_hmac('sha256', $payload, $secret); $signature = $_SERVER['HTTP_SIGNATURE'] ?? ''; if (! hash_equals($expected, $signature)) { http_response_code(401); exit; } $event = json_decode($payload, true); // handle $event['event'] and $event['data'] http_response_code(200); ``` ```js tab="JavaScript" tab-group="signature" import { createHmac, timingSafeEqual } from 'node:crypto'; export function verify(rawBody, signatureHeader, secret) { const expected = createHmac('sha256', secret).update(rawBody).digest('hex'); const a = Buffer.from(expected); const b = Buffer.from(signatureHeader ?? ''); return a.length === b.length && timingSafeEqual(a, b); } ``` ```go tab="Go" tab-group="signature" package webhooks import ( "crypto/hmac" "crypto/sha256" "encoding/hex" ) func Verify(rawBody []byte, signatureHeader, secret string) bool { mac := hmac.New(sha256.New, []byte(secret)) mac.Write(rawBody) expected := hex.EncodeToString(mac.Sum(nil)) return hmac.Equal([]byte(expected), []byte(signatureHeader)) } ``` ```python tab="Python" tab-group="signature" import hashlib import hmac def verify(raw_body: bytes, signature_header: str | None, secret: str) -> bool: expected = hmac.new(secret.encode(), raw_body, hashlib.sha256).hexdigest() return hmac.compare_digest(expected.encode(), (signature_header or "").encode()) ``` ```java tab="Java" tab-group="signature" import java.nio.charset.StandardCharsets; import java.security.MessageDigest; import java.util.HexFormat; import javax.crypto.Mac; import javax.crypto.spec.SecretKeySpec; public final class WebhookSignature { public static boolean verify(byte[] rawBody, String signatureHeader, String secret) throws Exception { Mac mac = Mac.getInstance("HmacSHA256"); mac.init(new SecretKeySpec(secret.getBytes(StandardCharsets.UTF_8), "HmacSHA256")); String expected = HexFormat.of().formatHex(mac.doFinal(rawBody)); return MessageDigest.isEqual( expected.getBytes(StandardCharsets.UTF_8), (signatureHeader == null ? "" : signatureHeader).getBytes(StandardCharsets.UTF_8)); } } ``` ```csharp tab="C#" tab-group="signature" using System.Security.Cryptography; using System.Text; public static class WebhookSignature { public static bool Verify(byte[] rawBody, string? signatureHeader, string secret) { var hash = HMACSHA256.HashData(Encoding.UTF8.GetBytes(secret), rawBody); var expected = Convert.ToHexString(hash).ToLowerInvariant(); return CryptographicOperations.FixedTimeEquals( Encoding.UTF8.GetBytes(expected), Encoding.UTF8.GetBytes(signatureHeader ?? "")); } } ``` Read the body as raw bytes before any JSON parsing; re-serialising the parsed object may change whitespace or key order and break the comparison. ## Respond fast Acknowledge with `2xx` first and process afterwards. Slow handlers hit the 10 second timeout, which triggers retries and duplicate work. ## Rotate a secret Delete the subscription and create a new one; the new subscription gets a new secret. Update your endpoint configuration before deleting the old subscription if you cannot tolerate a gap. --- # Reference > Every Public API operation, request and response, in one place. - [List currencies](/reference/currencies/listCurrencies/): Returns every accepted currency code. Not paginated. - [Create an expense](/reference/expenses/createExpense/): Creates an expense from a multipart/form-data body. file is required and must have one of the extensions jpeg, jpg, bmp, gif, pdf, png, tiff, xlsx, xls, doc, docx or odf. vat, invoice_number and the file are stored but not returned; fetch the file with the download endpoint. Fires the expense.created webhook. - [Delete an expense](/reference/expenses/deleteExpense/): Deletes the expense and its file. Fires the expense.deleted webhook. - [Download the expense file](/reference/expenses/downloadExpenseFile/): Streams the stored file under its original name. Content-Length is not sent. - [Get an expense](/reference/expenses/getExpense/): - [List expenses](/reference/expenses/listExpenses/): Returns the business's expenses, newest first, 50 per page. Use ?page= to paginate; the page size cannot be changed. - [Replace the expense file](/reference/expenses/replaceExpenseFile/): Replaces only the stored file; every other field is kept. Fires the expense.updated webhook. - [Replace an expense](/reference/expenses/updateExpense/): Replaces every field of the expense with the multipart/form-data body. file is optional here; when present it replaces the stored file. Fires the expense.updated webhook. - [expense.created](/reference/expenses/webhookExpenseCreated/): Sent when an expense is created through the API or the app. Each event is attempted up to 3 times: the first delivery, then retries after 10 s and 100 s; only a 2xx response counts as success. The request times out after 10 seconds. - [expense.deleted](/reference/expenses/webhookExpenseDeleted/): Sent when an expense is deleted through the API or the app. The payload contains only the id of the deleted expense. Each event is attempted up to 3 times: the first delivery, then retries after 10 s and 100 s; only a 2xx response counts as success. The request times out after 10 seconds. - [expense.updated](/reference/expenses/webhookExpenseUpdated/): Sent when an expense is replaced or its file is swapped. Each event is attempted up to 3 times: the first delivery, then retries after 10 s and 100 s; only a 2xx response counts as success. The request times out after 10 seconds. - [Create an invoice](/reference/invoices/createInvoice/): Creates a finalized invoice and queues its PDF. Fires the invoice.created webhook. - [Delete an invoice](/reference/invoices/deleteInvoice/): Deletes the invoice together with its PDF, items, payment options and e-mail logs, and recalculates the series counter. Fires the invoice.deleted webhook. - [Download the invoice PDF](/reference/invoices/downloadInvoicePdf/): Streams the invoice PDF. The PDF is rendered asynchronously after create and update; if it does not exist yet the request waits for it for up to 20 seconds and then fails with 500. Content-Length is not sent. - [Get an invoice](/reference/invoices/getInvoice/): - [List invoices](/reference/invoices/listInvoices/): Returns the business's finalized invoices, newest first, 50 per page. Use ?page= to paginate; the page size cannot be changed. Drafts made in the app are never included. - [Replace an invoice](/reference/invoices/updateInvoice/): Replaces every field of the invoice with the request body, under the same rules as create. Always resend the current invoice_number: when it is omitted the invoice is renumbered from the series counter. Items, payment options and custom fields are rewritten, totals recalculated and the PDF regenerated. Fires the invoice.updated webhook. - [invoice.created](/reference/invoices/webhookInvoiceCreated/): Sent when a finalized invoice is created, whether through the API, the app or a recurring invoice. The PDF is rendered asynchronously, so it may not exist yet when this event arrives; GET /invoices/{invoice}/download waits for it. Each event is attempted up to 3 times: the first delivery, then retries after 10 s and 100 s; only a 2xx response counts as success. The request times out after 10 seconds. - [invoice.deleted](/reference/invoices/webhookInvoiceDeleted/): Sent when a finalized invoice is deleted. The payload contains only the id of the deleted invoice. Each event is attempted up to 3 times: the first delivery, then retries after 10 s and 100 s; only a 2xx response counts as success. The request times out after 10 seconds. - [invoice.updated](/reference/invoices/webhookInvoiceUpdated/): Sent when an invoice is replaced, when its payment status changes (including a Stripe payment), or after any other save. Each event is attempted up to 3 times: the first delivery, then retries after 10 s and 100 s; only a 2xx response counts as success. The request times out after 10 seconds. - [Get the business profile](/reference/profile/getProfile/): Returns the business the token is scoped to. Companies include company_name and company_code; individual activities include first_name, last_name and individual_activity_id. --- # List currencies > Returns every accepted currency code. Not paginated. ## GET /currencies Returns every accepted currency code. Not paginated. ### Request and responses ```json { "servers": [ { "url": "https://app.fsaskaita.lt/api", "description": "Production" } ], "security": [ { "bearerAuth": [] } ], "operation": { "operationId": "listCurrencies", "description": "Returns every accepted currency code. Not paginated.", "summary": "List currencies", "tags": [ "Currencies" ], "responses": { "200": { "description": "Array of `Currency`", "content": { "application/json": { "schema": { "type": "object", "properties": { "data": { "type": "array", "items": { "$ref": "#/components/schemas/Currency" } } }, "required": [ "data" ] } } } }, "401": { "$ref": "#/components/responses/AuthenticationException" }, "429": { "description": "Rate limit exceeded. The limit is 60 requests per minute per business, shared across all of its tokens. Wait `Retry-After` seconds before retrying.", "content": { "application/json": { "schema": { "type": "object", "properties": { "message": { "type": "string" } }, "required": [ "message" ] } } }, "headers": { "Retry-After": { "description": "Seconds to wait before retrying.", "schema": { "type": "integer" } }, "X-RateLimit-Limit": { "description": "Requests allowed per minute.", "schema": { "type": "integer" } }, "X-RateLimit-Remaining": { "description": "Requests left in the current minute.", "schema": { "type": "integer" } }, "X-RateLimit-Reset": { "description": "Unix timestamp at which the window resets.", "schema": { "type": "integer" } } } } } }, "securitySchemes": { "bearerAuth": { "type": "http", "description": "Business token created in the app under Settings, Integrations, API. The token is scoped to exactly one business, has no expiry and is shown only once. Send it as `Authorization: Bearer ` together with `Accept: application/json`.", "scheme": "bearer" } } } ``` ### Referenced components ```json { "#/components/schemas/Currency": { "type": "object", "properties": { "code": { "type": "string", "description": "ISO 4217 code, e.g. `EUR`." }, "title": { "type": "string" } }, "required": [ "code", "title" ], "title": "Currency" }, "#/components/responses/AuthenticationException": { "description": "Unauthenticated", "content": { "application/json": { "schema": { "type": "object", "properties": { "message": { "type": "string", "description": "Error overview." } }, "required": [ "message" ] } } } } } ``` --- # Create an expense > Creates an expense from a multipart/form-data body. file is required and must have one of the extensions jpeg, jpg, bmp, gif, pdf, png, tiff, xlsx, xls, doc, docx or odf. vat, invoice_number and the file are stored but not returned; fetch the file with the download endpoint. Fires the expense.created webhook. ## POST /expenses Creates an expense from a `multipart/form-data` body. `file` is required and must have one of the extensions jpeg, jpg, bmp, gif, pdf, png, tiff, xlsx, xls, doc, docx or odf. `vat`, `invoice_number` and the file are stored but not returned; fetch the file with the download endpoint. Fires the `expense.created` webhook. ### Request and responses ```json { "servers": [ { "url": "https://app.fsaskaita.lt/api", "description": "Production" } ], "security": [ { "bearerAuth": [] } ], "operation": { "operationId": "createExpense", "description": "Creates an expense from a `multipart/form-data` body. `file` is required and must have one of the\nextensions jpeg, jpg, bmp, gif, pdf, png, tiff, xlsx, xls, doc, docx or odf. `vat`, `invoice_number` and the\nfile are stored but not returned; fetch the file with the download endpoint. Fires the `expense.created`\nwebhook.", "summary": "Create an expense", "tags": [ "Expenses" ], "requestBody": { "required": true, "content": { "multipart/form-data": { "schema": { "$ref": "#/components/schemas/ExpenseCreateInput" } } } }, "responses": { "201": { "description": "`Expense`", "content": { "application/json": { "schema": { "type": "object", "properties": { "data": { "$ref": "#/components/schemas/Expense" } }, "required": [ "data" ] } } } }, "401": { "$ref": "#/components/responses/AuthenticationException" }, "403": { "$ref": "#/components/responses/AuthorizationException" }, "422": { "$ref": "#/components/responses/ValidationException" }, "429": { "description": "Rate limit exceeded. The limit is 60 requests per minute per business, shared across all of its tokens. Wait `Retry-After` seconds before retrying.", "content": { "application/json": { "schema": { "type": "object", "properties": { "message": { "type": "string" } }, "required": [ "message" ] } } }, "headers": { "Retry-After": { "description": "Seconds to wait before retrying.", "schema": { "type": "integer" } }, "X-RateLimit-Limit": { "description": "Requests allowed per minute.", "schema": { "type": "integer" } }, "X-RateLimit-Remaining": { "description": "Requests left in the current minute.", "schema": { "type": "integer" } }, "X-RateLimit-Reset": { "description": "Unix timestamp at which the window resets.", "schema": { "type": "integer" } } } } } }, "securitySchemes": { "bearerAuth": { "type": "http", "description": "Business token created in the app under Settings, Integrations, API. The token is scoped to exactly one business, has no expiry and is shown only once. Send it as `Authorization: Bearer ` together with `Accept: application/json`.", "scheme": "bearer" } } } ``` ### Referenced components ```json { "#/components/schemas/ExpenseCreateInput": { "type": "object", "description": "Multipart body of `POST /expenses`: the same fields as `ExpenseInput`, but `file` is required.", "properties": { "currency": { "type": "string", "description": "One of the codes from `GET /currencies`.", "examples": [ "EUR" ] }, "total": { "type": "number", "description": "Amount including VAT.", "examples": [ 121 ] }, "vat": { "type": [ "number", "null" ], "description": "VAT amount contained in `total`. Stored but not returned.", "examples": [ 21 ] }, "seller": { "type": "string", "description": "Supplier name.", "examples": [ "Tiekėjas UAB" ], "maxLength": 255 }, "date": { "type": "string", "format": "date", "description": "Document date.", "examples": [ "2026-09-12" ] }, "invoice_number": { "type": [ "string", "null" ], "description": "Supplier's document number. Stored but not returned.", "examples": [ "TK-0042" ], "maxLength": 255 }, "file": { "type": "string", "format": "binary", "contentMediaType": "application/octet-stream", "description": "The document file: jpeg, jpg, bmp, gif, pdf, png, tiff, xlsx, xls, doc, docx or odf. Required when\ncreating an expense; optional on update, where it replaces the stored file." } }, "required": [ "currency", "total", "seller", "date", "file" ], "title": "ExpenseCreateInput" }, "#/components/schemas/Expense": { "type": "object", "properties": { "id": { "type": "string", "format": "uuid" }, "date": { "type": [ "string", "null" ], "format": "date", "description": "Document date, `Y-m-d`." }, "total": { "type": "number", "description": "Amount including VAT." }, "currency": { "type": "string" }, "seller": { "type": "string" }, "created_at": { "type": "integer", "description": "Unix timestamp, seconds." }, "updated_at": { "type": "integer", "description": "Unix timestamp, seconds." } }, "required": [ "id", "date", "total", "currency", "seller", "created_at", "updated_at" ], "title": "Expense" }, "#/components/responses/AuthenticationException": { "description": "Unauthenticated", "content": { "application/json": { "schema": { "type": "object", "properties": { "message": { "type": "string", "description": "Error overview." } }, "required": [ "message" ] } } } }, "#/components/responses/AuthorizationException": { "description": "Authorization error", "content": { "application/json": { "schema": { "type": "object", "properties": { "message": { "type": "string", "description": "Error overview." } }, "required": [ "message" ] } } } }, "#/components/responses/ValidationException": { "description": "Validation error", "content": { "application/json": { "schema": { "type": "object", "properties": { "message": { "type": "string", "description": "Errors overview." }, "errors": { "type": "object", "description": "A detailed description of each field that failed validation.", "additionalProperties": { "type": "array", "items": { "type": "string" } } } }, "required": [ "message", "errors" ] } } } } } ``` --- # Delete an expense > Deletes the expense and its file. Fires the expense.deleted webhook. ## DELETE /expenses/{expense} Deletes the expense and its file. Fires the `expense.deleted` webhook. ### Request and responses ```json { "servers": [ { "url": "https://app.fsaskaita.lt/api", "description": "Production" } ], "security": [ { "bearerAuth": [] } ], "operation": { "operationId": "deleteExpense", "description": "Deletes the expense and its file. Fires the `expense.deleted` webhook.", "summary": "Delete an expense", "tags": [ "Expenses" ], "parameters": [ { "name": "expense", "in": "path", "required": true, "description": "The expense ID.", "schema": { "type": "string" } } ], "responses": { "200": { "description": "Deleted. The body is empty." }, "401": { "$ref": "#/components/responses/AuthenticationException" }, "404": { "description": "The expense does not exist or belongs to another business.", "content": { "application/json": { "schema": { "type": "object", "properties": { "message": { "type": "string" } }, "required": [ "message" ] } } } }, "429": { "description": "Rate limit exceeded. The limit is 60 requests per minute per business, shared across all of its tokens. Wait `Retry-After` seconds before retrying.", "content": { "application/json": { "schema": { "type": "object", "properties": { "message": { "type": "string" } }, "required": [ "message" ] } } }, "headers": { "Retry-After": { "description": "Seconds to wait before retrying.", "schema": { "type": "integer" } }, "X-RateLimit-Limit": { "description": "Requests allowed per minute.", "schema": { "type": "integer" } }, "X-RateLimit-Remaining": { "description": "Requests left in the current minute.", "schema": { "type": "integer" } }, "X-RateLimit-Reset": { "description": "Unix timestamp at which the window resets.", "schema": { "type": "integer" } } } } } }, "securitySchemes": { "bearerAuth": { "type": "http", "description": "Business token created in the app under Settings, Integrations, API. The token is scoped to exactly one business, has no expiry and is shown only once. Send it as `Authorization: Bearer ` together with `Accept: application/json`.", "scheme": "bearer" } } } ``` ### Referenced components ```json { "#/components/responses/AuthenticationException": { "description": "Unauthenticated", "content": { "application/json": { "schema": { "type": "object", "properties": { "message": { "type": "string", "description": "Error overview." } }, "required": [ "message" ] } } } } } ``` --- # Download the expense file > Streams the stored file under its original name. Content-Length is not sent. ## GET /expenses/{expense}/download Streams the stored file under its original name. `Content-Length` is not sent. ### Request and responses ```json { "servers": [ { "url": "https://app.fsaskaita.lt/api", "description": "Production" } ], "security": [ { "bearerAuth": [] } ], "operation": { "operationId": "downloadExpenseFile", "description": "Streams the stored file under its original name. `Content-Length` is not sent.", "summary": "Download the expense file", "tags": [ "Expenses" ], "parameters": [ { "name": "expense", "in": "path", "required": true, "description": "The expense ID.", "schema": { "type": "string" } } ], "responses": { "200": { "description": "The stored file.", "content": { "application/octet-stream": { "schema": { "type": "string", "format": "binary" } }, "application/pdf": { "schema": { "type": "string", "format": "binary" } } }, "headers": { "Transfer-Encoding": { "required": true, "schema": { "type": "string", "enum": [ "chunked" ] } }, "Content-Disposition": { "description": "Attachment with the original file name.", "schema": { "type": "string" } } } }, "401": { "$ref": "#/components/responses/AuthenticationException" }, "404": { "description": "The expense does not exist or belongs to another business.", "content": { "application/json": { "schema": { "type": "object", "properties": { "message": { "type": "string" } }, "required": [ "message" ] } } } }, "429": { "description": "Rate limit exceeded. The limit is 60 requests per minute per business, shared across all of its tokens. Wait `Retry-After` seconds before retrying.", "content": { "application/json": { "schema": { "type": "object", "properties": { "message": { "type": "string" } }, "required": [ "message" ] } } }, "headers": { "Retry-After": { "description": "Seconds to wait before retrying.", "schema": { "type": "integer" } }, "X-RateLimit-Limit": { "description": "Requests allowed per minute.", "schema": { "type": "integer" } }, "X-RateLimit-Remaining": { "description": "Requests left in the current minute.", "schema": { "type": "integer" } }, "X-RateLimit-Reset": { "description": "Unix timestamp at which the window resets.", "schema": { "type": "integer" } } } } } }, "securitySchemes": { "bearerAuth": { "type": "http", "description": "Business token created in the app under Settings, Integrations, API. The token is scoped to exactly one business, has no expiry and is shown only once. Send it as `Authorization: Bearer ` together with `Accept: application/json`.", "scheme": "bearer" } } } ``` ### Referenced components ```json { "#/components/responses/AuthenticationException": { "description": "Unauthenticated", "content": { "application/json": { "schema": { "type": "object", "properties": { "message": { "type": "string", "description": "Error overview." } }, "required": [ "message" ] } } } } } ``` --- # Get an expense > ## GET /expenses/{expense} ### Request and responses ```json { "servers": [ { "url": "https://app.fsaskaita.lt/api", "description": "Production" } ], "security": [ { "bearerAuth": [] } ], "operation": { "operationId": "getExpense", "summary": "Get an expense", "tags": [ "Expenses" ], "parameters": [ { "name": "expense", "in": "path", "required": true, "description": "The expense ID.", "schema": { "type": "string" } } ], "responses": { "200": { "description": "`Expense`", "content": { "application/json": { "schema": { "type": "object", "properties": { "data": { "$ref": "#/components/schemas/Expense" } }, "required": [ "data" ] } } } }, "401": { "$ref": "#/components/responses/AuthenticationException" }, "404": { "description": "The expense does not exist or belongs to another business.", "content": { "application/json": { "schema": { "type": "object", "properties": { "message": { "type": "string" } }, "required": [ "message" ] } } } }, "429": { "description": "Rate limit exceeded. The limit is 60 requests per minute per business, shared across all of its tokens. Wait `Retry-After` seconds before retrying.", "content": { "application/json": { "schema": { "type": "object", "properties": { "message": { "type": "string" } }, "required": [ "message" ] } } }, "headers": { "Retry-After": { "description": "Seconds to wait before retrying.", "schema": { "type": "integer" } }, "X-RateLimit-Limit": { "description": "Requests allowed per minute.", "schema": { "type": "integer" } }, "X-RateLimit-Remaining": { "description": "Requests left in the current minute.", "schema": { "type": "integer" } }, "X-RateLimit-Reset": { "description": "Unix timestamp at which the window resets.", "schema": { "type": "integer" } } } } } }, "securitySchemes": { "bearerAuth": { "type": "http", "description": "Business token created in the app under Settings, Integrations, API. The token is scoped to exactly one business, has no expiry and is shown only once. Send it as `Authorization: Bearer ` together with `Accept: application/json`.", "scheme": "bearer" } } } ``` ### Referenced components ```json { "#/components/schemas/Expense": { "type": "object", "properties": { "id": { "type": "string", "format": "uuid" }, "date": { "type": [ "string", "null" ], "format": "date", "description": "Document date, `Y-m-d`." }, "total": { "type": "number", "description": "Amount including VAT." }, "currency": { "type": "string" }, "seller": { "type": "string" }, "created_at": { "type": "integer", "description": "Unix timestamp, seconds." }, "updated_at": { "type": "integer", "description": "Unix timestamp, seconds." } }, "required": [ "id", "date", "total", "currency", "seller", "created_at", "updated_at" ], "title": "Expense" }, "#/components/responses/AuthenticationException": { "description": "Unauthenticated", "content": { "application/json": { "schema": { "type": "object", "properties": { "message": { "type": "string", "description": "Error overview." } }, "required": [ "message" ] } } } } } ``` --- # List expenses > Returns the business's expenses, newest first, 50 per page. Use ?page= to paginate; the page size cannot be changed. ## GET /expenses Returns the business's expenses, newest first, 50 per page. Use `?page=` to paginate; the page size cannot be changed. ### Request and responses ```json { "servers": [ { "url": "https://app.fsaskaita.lt/api", "description": "Production" } ], "security": [ { "bearerAuth": [] } ], "operation": { "operationId": "listExpenses", "description": "Returns the business's expenses, newest first, 50 per page. Use `?page=` to paginate; the page size cannot\nbe changed.", "summary": "List expenses", "tags": [ "Expenses" ], "parameters": [ { "name": "page", "in": "query", "description": "Page number, starting at 1. The page size is fixed at 50.", "schema": { "type": "integer", "default": 1 } } ], "responses": { "200": { "description": "Paginated set of `Expense`", "content": { "application/json": { "schema": { "type": "object", "properties": { "data": { "type": "array", "items": { "$ref": "#/components/schemas/Expense" } }, "meta": { "type": "object", "properties": { "current_page": { "type": "integer", "minimum": 1 }, "from": { "type": [ "integer", "null" ], "minimum": 1 }, "last_page": { "type": "integer", "minimum": 1 }, "path": { "type": [ "string", "null" ], "description": "Base path for paginator generated URLs." }, "per_page": { "type": "integer", "description": "Number of items shown per page.", "minimum": 0 }, "to": { "type": [ "integer", "null" ], "description": "Number of the last item in the slice.", "minimum": 1 }, "total": { "type": "integer", "description": "Total number of items being paginated.", "minimum": 0 } }, "required": [ "current_page", "from", "last_page", "path", "per_page", "to", "total" ] } }, "required": [ "data", "meta" ] } } } }, "401": { "$ref": "#/components/responses/AuthenticationException" }, "429": { "description": "Rate limit exceeded. The limit is 60 requests per minute per business, shared across all of its tokens. Wait `Retry-After` seconds before retrying.", "content": { "application/json": { "schema": { "type": "object", "properties": { "message": { "type": "string" } }, "required": [ "message" ] } } }, "headers": { "Retry-After": { "description": "Seconds to wait before retrying.", "schema": { "type": "integer" } }, "X-RateLimit-Limit": { "description": "Requests allowed per minute.", "schema": { "type": "integer" } }, "X-RateLimit-Remaining": { "description": "Requests left in the current minute.", "schema": { "type": "integer" } }, "X-RateLimit-Reset": { "description": "Unix timestamp at which the window resets.", "schema": { "type": "integer" } } } } } }, "securitySchemes": { "bearerAuth": { "type": "http", "description": "Business token created in the app under Settings, Integrations, API. The token is scoped to exactly one business, has no expiry and is shown only once. Send it as `Authorization: Bearer ` together with `Accept: application/json`.", "scheme": "bearer" } } } ``` ### Referenced components ```json { "#/components/schemas/Expense": { "type": "object", "properties": { "id": { "type": "string", "format": "uuid" }, "date": { "type": [ "string", "null" ], "format": "date", "description": "Document date, `Y-m-d`." }, "total": { "type": "number", "description": "Amount including VAT." }, "currency": { "type": "string" }, "seller": { "type": "string" }, "created_at": { "type": "integer", "description": "Unix timestamp, seconds." }, "updated_at": { "type": "integer", "description": "Unix timestamp, seconds." } }, "required": [ "id", "date", "total", "currency", "seller", "created_at", "updated_at" ], "title": "Expense" }, "#/components/responses/AuthenticationException": { "description": "Unauthenticated", "content": { "application/json": { "schema": { "type": "object", "properties": { "message": { "type": "string", "description": "Error overview." } }, "required": [ "message" ] } } } } } ``` --- # Replace the expense file > Replaces only the stored file; every other field is kept. Fires the expense.updated webhook. ## POST /expenses/{expense}/file Replaces only the stored file; every other field is kept. Fires the `expense.updated` webhook. ### Request and responses ```json { "servers": [ { "url": "https://app.fsaskaita.lt/api", "description": "Production" } ], "security": [ { "bearerAuth": [] } ], "operation": { "operationId": "replaceExpenseFile", "description": "Replaces only the stored file; every other field is kept. Fires the `expense.updated` webhook.", "summary": "Replace the expense file", "tags": [ "Expenses" ], "parameters": [ { "name": "expense", "in": "path", "required": true, "description": "The expense ID.", "schema": { "type": "string" } } ], "requestBody": { "required": true, "content": { "multipart/form-data": { "schema": { "$ref": "#/components/schemas/ExpenseFileInput" } } } }, "responses": { "200": { "description": "`Expense`", "content": { "application/json": { "schema": { "type": "object", "properties": { "data": { "$ref": "#/components/schemas/Expense" } }, "required": [ "data" ] } } } }, "401": { "$ref": "#/components/responses/AuthenticationException" }, "403": { "$ref": "#/components/responses/AuthorizationException" }, "404": { "description": "The expense does not exist or belongs to another business.", "content": { "application/json": { "schema": { "type": "object", "properties": { "message": { "type": "string" } }, "required": [ "message" ] } } } }, "422": { "$ref": "#/components/responses/ValidationException" }, "429": { "description": "Rate limit exceeded. The limit is 60 requests per minute per business, shared across all of its tokens. Wait `Retry-After` seconds before retrying.", "content": { "application/json": { "schema": { "type": "object", "properties": { "message": { "type": "string" } }, "required": [ "message" ] } } }, "headers": { "Retry-After": { "description": "Seconds to wait before retrying.", "schema": { "type": "integer" } }, "X-RateLimit-Limit": { "description": "Requests allowed per minute.", "schema": { "type": "integer" } }, "X-RateLimit-Remaining": { "description": "Requests left in the current minute.", "schema": { "type": "integer" } }, "X-RateLimit-Reset": { "description": "Unix timestamp at which the window resets.", "schema": { "type": "integer" } } } } } }, "securitySchemes": { "bearerAuth": { "type": "http", "description": "Business token created in the app under Settings, Integrations, API. The token is scoped to exactly one business, has no expiry and is shown only once. Send it as `Authorization: Bearer ` together with `Accept: application/json`.", "scheme": "bearer" } } } ``` ### Referenced components ```json { "#/components/schemas/ExpenseFileInput": { "type": "object", "description": "Multipart body of `POST /expenses/{expense}/file`.", "properties": { "file": { "type": "string", "format": "binary", "contentMediaType": "application/octet-stream", "description": "The new document file: jpeg, jpg, bmp, gif, pdf, png, tiff, xlsx, xls, doc, docx or odf." } }, "required": [ "file" ], "title": "ExpenseFileInput" }, "#/components/schemas/Expense": { "type": "object", "properties": { "id": { "type": "string", "format": "uuid" }, "date": { "type": [ "string", "null" ], "format": "date", "description": "Document date, `Y-m-d`." }, "total": { "type": "number", "description": "Amount including VAT." }, "currency": { "type": "string" }, "seller": { "type": "string" }, "created_at": { "type": "integer", "description": "Unix timestamp, seconds." }, "updated_at": { "type": "integer", "description": "Unix timestamp, seconds." } }, "required": [ "id", "date", "total", "currency", "seller", "created_at", "updated_at" ], "title": "Expense" }, "#/components/responses/AuthenticationException": { "description": "Unauthenticated", "content": { "application/json": { "schema": { "type": "object", "properties": { "message": { "type": "string", "description": "Error overview." } }, "required": [ "message" ] } } } }, "#/components/responses/AuthorizationException": { "description": "Authorization error", "content": { "application/json": { "schema": { "type": "object", "properties": { "message": { "type": "string", "description": "Error overview." } }, "required": [ "message" ] } } } }, "#/components/responses/ValidationException": { "description": "Validation error", "content": { "application/json": { "schema": { "type": "object", "properties": { "message": { "type": "string", "description": "Errors overview." }, "errors": { "type": "object", "description": "A detailed description of each field that failed validation.", "additionalProperties": { "type": "array", "items": { "type": "string" } } } }, "required": [ "message", "errors" ] } } } } } ``` --- # Replace an expense > Replaces every field of the expense with the multipart/form-data body. file is optional here; when present it replaces the stored file. Fires the expense.updated webhook. ## PUT /expenses/{expense} Replaces every field of the expense with the `multipart/form-data` body. `file` is optional here; when present it replaces the stored file. Fires the `expense.updated` webhook. ### Request and responses ```json { "servers": [ { "url": "https://app.fsaskaita.lt/api", "description": "Production" } ], "security": [ { "bearerAuth": [] } ], "operation": { "operationId": "updateExpense", "description": "Replaces every field of the expense with the `multipart/form-data` body. `file` is optional here; when\npresent it replaces the stored file. Fires the `expense.updated` webhook.", "summary": "Replace an expense", "tags": [ "Expenses" ], "parameters": [ { "name": "expense", "in": "path", "required": true, "description": "The expense ID.", "schema": { "type": "string" } } ], "requestBody": { "required": true, "content": { "multipart/form-data": { "schema": { "$ref": "#/components/schemas/ExpenseInput" } } } }, "responses": { "200": { "description": "`Expense`", "content": { "application/json": { "schema": { "type": "object", "properties": { "data": { "$ref": "#/components/schemas/Expense" } }, "required": [ "data" ] } } } }, "401": { "$ref": "#/components/responses/AuthenticationException" }, "403": { "$ref": "#/components/responses/AuthorizationException" }, "404": { "description": "The expense does not exist or belongs to another business.", "content": { "application/json": { "schema": { "type": "object", "properties": { "message": { "type": "string" } }, "required": [ "message" ] } } } }, "422": { "$ref": "#/components/responses/ValidationException" }, "429": { "description": "Rate limit exceeded. The limit is 60 requests per minute per business, shared across all of its tokens. Wait `Retry-After` seconds before retrying.", "content": { "application/json": { "schema": { "type": "object", "properties": { "message": { "type": "string" } }, "required": [ "message" ] } } }, "headers": { "Retry-After": { "description": "Seconds to wait before retrying.", "schema": { "type": "integer" } }, "X-RateLimit-Limit": { "description": "Requests allowed per minute.", "schema": { "type": "integer" } }, "X-RateLimit-Remaining": { "description": "Requests left in the current minute.", "schema": { "type": "integer" } }, "X-RateLimit-Reset": { "description": "Unix timestamp at which the window resets.", "schema": { "type": "integer" } } } } } }, "securitySchemes": { "bearerAuth": { "type": "http", "description": "Business token created in the app under Settings, Integrations, API. The token is scoped to exactly one business, has no expiry and is shown only once. Send it as `Authorization: Bearer ` together with `Accept: application/json`.", "scheme": "bearer" } } } ``` ### Referenced components ```json { "#/components/schemas/ExpenseInput": { "type": "object", "description": "Multipart body of `PUT /expenses/{expense}`. `POST /expenses` uses `ExpenseCreateInput` (StoreExpenseRequest),\nwhich additionally requires `file`.", "properties": { "currency": { "type": "string", "description": "One of the codes from `GET /currencies`.", "examples": [ "EUR" ] }, "total": { "type": "number", "description": "Amount including VAT.", "examples": [ 121 ] }, "vat": { "type": [ "number", "null" ], "description": "VAT amount contained in `total`. Stored but not returned.", "examples": [ 21 ] }, "seller": { "type": "string", "description": "Supplier name.", "examples": [ "Tiekėjas UAB" ], "maxLength": 255 }, "date": { "type": "string", "format": "date", "description": "Document date.", "examples": [ "2026-09-12" ] }, "invoice_number": { "type": [ "string", "null" ], "description": "Supplier's document number. Stored but not returned.", "examples": [ "TK-0042" ], "maxLength": 255 }, "file": { "type": "string", "format": "binary", "contentMediaType": "application/octet-stream", "description": "The document file: jpeg, jpg, bmp, gif, pdf, png, tiff, xlsx, xls, doc, docx or odf. Required when\ncreating an expense; optional on update, where it replaces the stored file." } }, "required": [ "currency", "total", "seller", "date" ], "title": "ExpenseInput" }, "#/components/schemas/Expense": { "type": "object", "properties": { "id": { "type": "string", "format": "uuid" }, "date": { "type": [ "string", "null" ], "format": "date", "description": "Document date, `Y-m-d`." }, "total": { "type": "number", "description": "Amount including VAT." }, "currency": { "type": "string" }, "seller": { "type": "string" }, "created_at": { "type": "integer", "description": "Unix timestamp, seconds." }, "updated_at": { "type": "integer", "description": "Unix timestamp, seconds." } }, "required": [ "id", "date", "total", "currency", "seller", "created_at", "updated_at" ], "title": "Expense" }, "#/components/responses/AuthenticationException": { "description": "Unauthenticated", "content": { "application/json": { "schema": { "type": "object", "properties": { "message": { "type": "string", "description": "Error overview." } }, "required": [ "message" ] } } } }, "#/components/responses/AuthorizationException": { "description": "Authorization error", "content": { "application/json": { "schema": { "type": "object", "properties": { "message": { "type": "string", "description": "Error overview." } }, "required": [ "message" ] } } } }, "#/components/responses/ValidationException": { "description": "Validation error", "content": { "application/json": { "schema": { "type": "object", "properties": { "message": { "type": "string", "description": "Errors overview." }, "errors": { "type": "object", "description": "A detailed description of each field that failed validation.", "additionalProperties": { "type": "array", "items": { "type": "string" } } } }, "required": [ "message", "errors" ] } } } } } ``` --- # expense.created > Sent when an expense is created through the API or the app. Each event is attempted up to 3 times: the first delivery, then retries after 10 s and 100 s; only a 2xx response counts as success. The request times out after 10 seconds. ## Webhook event: POST expense.created Sent when an expense is created through the API or the app. Each event is attempted up to 3 times: the first delivery, then retries after 10 s and 100 s; only a 2xx response counts as success. The request times out after 10 seconds. ### Request and responses ```json { "servers": [ { "url": "https://app.fsaskaita.lt/api", "description": "Production" } ], "operation": { "tags": [ "Expenses" ], "operationId": "webhookExpenseCreated", "summary": "expense.created", "description": "Sent when an expense is created through the API or the app. Each event is attempted up to 3 times: the first delivery, then retries after 10 s and 100 s; only a 2xx response counts as success. The request times out after 10 seconds.", "parameters": [ { "$ref": "#/components/parameters/webhookSignature" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "required": [ "event", "data" ], "properties": { "event": { "const": "expense.created" }, "data": { "$ref": "#/components/schemas/Expense" } } } } } }, "responses": { "2XX": { "description": "Return any 2xx status to acknowledge the delivery. Any other status or a timeout schedules a retry." } } }, "securitySchemes": { "bearerAuth": { "type": "http", "description": "Business token created in the app under Settings, Integrations, API. The token is scoped to exactly one business, has no expiry and is shown only once. Send it as `Authorization: Bearer ` together with `Accept: application/json`.", "scheme": "bearer" } } } ``` ### Referenced components ```json { "#/components/parameters/webhookSignature": { "name": "Signature", "in": "header", "required": true, "description": "Lowercase hex HMAC-SHA256 of the raw request body, keyed with the webhook's signing secret (`whsec_…`). Recompute it over the exact bytes received and compare with a constant-time function before trusting the payload. No timestamp or event-id header is sent.", "schema": { "type": "string", "pattern": "^[0-9a-f]{64}$" }, "example": "5f1c0d8f9a7e4b2c6d3e1f0a9b8c7d6e5f4a3b2c1d0e9f8a7b6c5d4e3f2a1b0c" }, "#/components/schemas/Expense": { "type": "object", "properties": { "id": { "type": "string", "format": "uuid" }, "date": { "type": [ "string", "null" ], "format": "date", "description": "Document date, `Y-m-d`." }, "total": { "type": "number", "description": "Amount including VAT." }, "currency": { "type": "string" }, "seller": { "type": "string" }, "created_at": { "type": "integer", "description": "Unix timestamp, seconds." }, "updated_at": { "type": "integer", "description": "Unix timestamp, seconds." } }, "required": [ "id", "date", "total", "currency", "seller", "created_at", "updated_at" ], "title": "Expense" } } ``` --- # expense.deleted > Sent when an expense is deleted through the API or the app. The payload contains only the id of the deleted expense. Each event is attempted up to 3 times: the first delivery, then retries after 10 s and 100 s; only a 2xx response counts as success. The request times out after 10 seconds. ## Webhook event: POST expense.deleted Sent when an expense is deleted through the API or the app. The payload contains only the id of the deleted expense. Each event is attempted up to 3 times: the first delivery, then retries after 10 s and 100 s; only a 2xx response counts as success. The request times out after 10 seconds. ### Request and responses ```json { "servers": [ { "url": "https://app.fsaskaita.lt/api", "description": "Production" } ], "operation": { "tags": [ "Expenses" ], "operationId": "webhookExpenseDeleted", "summary": "expense.deleted", "description": "Sent when an expense is deleted through the API or the app. The payload contains only the id of the deleted expense. Each event is attempted up to 3 times: the first delivery, then retries after 10 s and 100 s; only a 2xx response counts as success. The request times out after 10 seconds.", "parameters": [ { "$ref": "#/components/parameters/webhookSignature" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "required": [ "event", "data" ], "properties": { "event": { "const": "expense.deleted" }, "data": { "$ref": "#/components/schemas/DeletedResource" } } } } } }, "responses": { "2XX": { "description": "Return any 2xx status to acknowledge the delivery. Any other status or a timeout schedules a retry." } } }, "securitySchemes": { "bearerAuth": { "type": "http", "description": "Business token created in the app under Settings, Integrations, API. The token is scoped to exactly one business, has no expiry and is shown only once. Send it as `Authorization: Bearer ` together with `Accept: application/json`.", "scheme": "bearer" } } } ``` ### Referenced components ```json { "#/components/parameters/webhookSignature": { "name": "Signature", "in": "header", "required": true, "description": "Lowercase hex HMAC-SHA256 of the raw request body, keyed with the webhook's signing secret (`whsec_…`). Recompute it over the exact bytes received and compare with a constant-time function before trusting the payload. No timestamp or event-id header is sent.", "schema": { "type": "string", "pattern": "^[0-9a-f]{64}$" }, "example": "5f1c0d8f9a7e4b2c6d3e1f0a9b8c7d6e5f4a3b2c1d0e9f8a7b6c5d4e3f2a1b0c" }, "#/components/schemas/DeletedResource": { "type": "object", "description": "Identifies a resource that no longer exists.", "required": [ "id" ], "properties": { "id": { "type": "string", "format": "uuid" } } } } ``` --- # expense.updated > Sent when an expense is replaced or its file is swapped. Each event is attempted up to 3 times: the first delivery, then retries after 10 s and 100 s; only a 2xx response counts as success. The request times out after 10 seconds. ## Webhook event: POST expense.updated Sent when an expense is replaced or its file is swapped. Each event is attempted up to 3 times: the first delivery, then retries after 10 s and 100 s; only a 2xx response counts as success. The request times out after 10 seconds. ### Request and responses ```json { "servers": [ { "url": "https://app.fsaskaita.lt/api", "description": "Production" } ], "operation": { "tags": [ "Expenses" ], "operationId": "webhookExpenseUpdated", "summary": "expense.updated", "description": "Sent when an expense is replaced or its file is swapped. Each event is attempted up to 3 times: the first delivery, then retries after 10 s and 100 s; only a 2xx response counts as success. The request times out after 10 seconds.", "parameters": [ { "$ref": "#/components/parameters/webhookSignature" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "required": [ "event", "data" ], "properties": { "event": { "const": "expense.updated" }, "data": { "$ref": "#/components/schemas/Expense" } } } } } }, "responses": { "2XX": { "description": "Return any 2xx status to acknowledge the delivery. Any other status or a timeout schedules a retry." } } }, "securitySchemes": { "bearerAuth": { "type": "http", "description": "Business token created in the app under Settings, Integrations, API. The token is scoped to exactly one business, has no expiry and is shown only once. Send it as `Authorization: Bearer ` together with `Accept: application/json`.", "scheme": "bearer" } } } ``` ### Referenced components ```json { "#/components/parameters/webhookSignature": { "name": "Signature", "in": "header", "required": true, "description": "Lowercase hex HMAC-SHA256 of the raw request body, keyed with the webhook's signing secret (`whsec_…`). Recompute it over the exact bytes received and compare with a constant-time function before trusting the payload. No timestamp or event-id header is sent.", "schema": { "type": "string", "pattern": "^[0-9a-f]{64}$" }, "example": "5f1c0d8f9a7e4b2c6d3e1f0a9b8c7d6e5f4a3b2c1d0e9f8a7b6c5d4e3f2a1b0c" }, "#/components/schemas/Expense": { "type": "object", "properties": { "id": { "type": "string", "format": "uuid" }, "date": { "type": [ "string", "null" ], "format": "date", "description": "Document date, `Y-m-d`." }, "total": { "type": "number", "description": "Amount including VAT." }, "currency": { "type": "string" }, "seller": { "type": "string" }, "created_at": { "type": "integer", "description": "Unix timestamp, seconds." }, "updated_at": { "type": "integer", "description": "Unix timestamp, seconds." } }, "required": [ "id", "date", "total", "currency", "seller", "created_at", "updated_at" ], "title": "Expense" } } ``` --- # Create an invoice > Creates a finalized invoice and queues its PDF. Fires the invoice.created webhook. ## POST /invoices Creates a finalized invoice and queues its PDF. Fires the `invoice.created` webhook. **Numbering.** Omit `invoice_number` to take the next number of the `series`: the series counter, otherwise the highest existing number in that series plus one, otherwise `1`. An explicit number must be unique within the series. Numbers are returned zero-padded to three digits. **Amounts.** Each product line carries exactly one of `price` (unit price excluding VAT), `total` (line total excluding VAT) or `total_incl_vat`; the other two are derived. `vat_percentage` is required on the VAT invoice types (`vat_invoice`, `preliminary_vat_invoice`, `credit_vat_invoice`) and whenever the seller has a `vat_code`; leave it out on non-VAT types. **Seller.** Send `use_default_seller_info: true` to copy the seller block from the business profile (plus the custom fields of the latest invoice); `seller` is then prohibited. Otherwise send `seller` with the fields that match the business type: companies use `company_name` and `company_code`, individual activities use `first_name`, `last_name` and `individual_activity_id` (`company_code` and `individual_activity_id` are optional). VAT invoice types require `seller.vat_code` when `seller` is sent; with the default seller info the profile's VAT code is copied as it is. ### Request and responses ```json { "servers": [ { "url": "https://app.fsaskaita.lt/api", "description": "Production" } ], "security": [ { "bearerAuth": [] } ], "operation": { "operationId": "createInvoice", "description": "Creates a finalized invoice and queues its PDF. Fires the `invoice.created` webhook.\n\n**Numbering.** Omit `invoice_number` to take the next number of the `series`: the series counter, otherwise\nthe highest existing number in that series plus one, otherwise `1`. An explicit number must be unique\nwithin the series. Numbers are returned zero-padded to three digits.\n\n**Amounts.** Each product line carries exactly one of `price` (unit price excluding VAT), `total` (line total\nexcluding VAT) or `total_incl_vat`; the other two are derived. `vat_percentage` is required on the VAT\ninvoice types (`vat_invoice`, `preliminary_vat_invoice`, `credit_vat_invoice`) and whenever the seller has a\n`vat_code`; leave it out on non-VAT types.\n\n**Seller.** Send `use_default_seller_info: true` to copy the seller block from the business profile (plus\nthe custom fields of the latest invoice); `seller` is then prohibited. Otherwise send `seller` with the fields\nthat match the business type: companies use `company_name` and `company_code`, individual activities use\n`first_name`, `last_name` and `individual_activity_id` (`company_code` and `individual_activity_id` are\noptional). VAT invoice types require `seller.vat_code` when `seller` is sent; with the default seller info the\nprofile's VAT code is copied as it is.", "summary": "Create an invoice", "tags": [ "Invoices" ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/InvoiceInput" } } } }, "responses": { "201": { "description": "`Invoice`", "content": { "application/json": { "schema": { "type": "object", "properties": { "data": { "$ref": "#/components/schemas/Invoice" } }, "required": [ "data" ] } } } }, "401": { "$ref": "#/components/responses/AuthenticationException" }, "403": { "$ref": "#/components/responses/AuthorizationException" }, "422": { "$ref": "#/components/responses/ValidationException" }, "429": { "description": "Rate limit exceeded. The limit is 60 requests per minute per business, shared across all of its tokens. Wait `Retry-After` seconds before retrying.", "content": { "application/json": { "schema": { "type": "object", "properties": { "message": { "type": "string" } }, "required": [ "message" ] } } }, "headers": { "Retry-After": { "description": "Seconds to wait before retrying.", "schema": { "type": "integer" } }, "X-RateLimit-Limit": { "description": "Requests allowed per minute.", "schema": { "type": "integer" } }, "X-RateLimit-Remaining": { "description": "Requests left in the current minute.", "schema": { "type": "integer" } }, "X-RateLimit-Reset": { "description": "Unix timestamp at which the window resets.", "schema": { "type": "integer" } } } } } }, "securitySchemes": { "bearerAuth": { "type": "http", "description": "Business token created in the app under Settings, Integrations, API. The token is scoped to exactly one business, has no expiry and is shown only once. Send it as `Authorization: Bearer ` together with `Accept: application/json`.", "scheme": "bearer" } } } ``` ### Referenced components ```json { "#/components/schemas/InvoiceInput": { "type": "object", "description": "Body of `POST /invoices` and `PUT /invoices/{invoice}`. On update every field is replaced with what you send;\nalways resend `invoice_number` or the invoice is renumbered.", "properties": { "type": { "type": "string", "description": "Invoice type. The `*vat_invoice` types require `seller.vat_code` and `vat_percentage` on every line.", "enum": [ "regular_invoice", "vat_invoice", "preliminary_invoice", "preliminary_vat_invoice", "credit_invoice", "credit_vat_invoice" ], "examples": [ "vat_invoice" ] }, "invoice_date": { "type": "string", "format": "date", "description": "Issue date.", "examples": [ "2026-09-12" ] }, "pay_until_date": { "type": [ "string", "null" ], "format": "date", "description": "Due date.", "examples": [ "2026-09-26" ] }, "series": { "type": "string", "description": "Series code the number belongs to. A new code starts its own counter.", "examples": [ "SF" ], "maxLength": 255 }, "notes": { "type": [ "string", "null" ], "description": "Free text printed under the lines.", "maxLength": 255 }, "currency": { "type": "string", "description": "One of the codes from `GET /currencies`.", "examples": [ "EUR" ] }, "payment_status": { "anyOf": [ { "description": "Defaults to `not_paid` on create; when omitted on update the current status is kept.", "$ref": "#/components/schemas/PaymentStatus" }, { "type": "null" } ] }, "language": { "type": [ "string", "null" ], "description": "Language of the PDF and the share page. Defaults to `lt`.", "enum": [ "en", "lt", "es", "de", "fr", null ] }, "invoice_number": { "type": [ "string", "null" ], "description": "Number within the series; must be unique there. Omit on create to auto-number. **On update always\nresend the current number**, otherwise the invoice is renumbered from the series counter. Accepts the\npadded (`\"007\"`) or unpadded (`\"7\"`) form; numbers are compared exactly as sent, so use one form\nconsistently within a series.", "pattern": "^(.*)+$", "examples": [ "7" ], "maxLength": 255 }, "buyer": { "type": "object", "properties": { "type": { "type": "string", "description": "`company` or `individual`. `person` is accepted as a legacy alias of `individual`; responses always\nreturn `individual`.", "enum": [ "company", "person", "individual" ], "examples": [ "company" ] }, "company_name": { "type": [ "string", "null" ], "description": "Required for companies, prohibited for individuals." }, "company_code": { "type": [ "string", "null" ], "description": "Prohibited for individuals.", "maxLength": 255 }, "first_name": { "type": [ "string", "null" ], "description": "Required for individuals, prohibited for companies.", "maxLength": 255 }, "last_name": { "type": [ "string", "null" ], "description": "Required for individuals, prohibited for companies.", "maxLength": 255 }, "individual_activity_id": { "type": [ "string", "null" ], "description": "Individual activity certificate number; prohibited for companies.", "maxLength": 255 }, "address": { "type": [ "string", "null" ], "maxLength": 255 }, "vat_code": { "type": [ "string", "null" ], "maxLength": 255 }, "email": { "type": [ "string", "null" ], "maxLength": 255 }, "phone": { "type": [ "string", "null" ], "maxLength": 255 } }, "required": [ "type" ] }, "use_default_seller_info": { "type": [ "boolean", "null" ], "description": "When `true` the seller block is copied from the business profile (plus the custom fields of the latest\ninvoice) and `seller` must be omitted.", "examples": [ true ] }, "seller": { "type": "object", "description": "Required unless `use_default_seller_info` is `true`. Which fields are required depends on the business\ntype: companies send `company_name` (required) and `company_code` (optional); individual activities send\n`first_name` and `last_name` (required) and `individual_activity_id` (optional). Fields of the other kind\nare rejected.", "properties": { "address": { "type": [ "string", "null" ], "maxLength": 255 }, "vat_code": { "type": [ "string", "null" ], "description": "Required for the `*vat_invoice` types when `seller` is sent.", "maxLength": 255 }, "email": { "type": [ "string", "null" ], "maxLength": 255 }, "phone": { "type": [ "string", "null" ], "maxLength": 255 }, "company_name": { "type": [ "string", "null" ], "description": "Companies only.", "maxLength": 255 }, "company_code": { "type": [ "string", "null" ], "description": "Companies only.", "maxLength": 255 }, "first_name": { "type": [ "string", "null" ], "description": "Individual activities only.", "maxLength": 255 }, "last_name": { "type": [ "string", "null" ], "description": "Individual activities only.", "maxLength": 255 }, "individual_activity_id": { "type": [ "string", "null" ], "description": "Individual activities only.", "maxLength": 255 }, "custom_fields": { "type": [ "array", "null" ], "description": "Extra label/value pairs printed in the seller block.", "items": { "type": "object", "properties": { "label": { "type": "string", "maxLength": 255 }, "value": { "type": "string", "maxLength": 255 } }, "required": [ "label", "value" ] } } } }, "products": { "type": "array", "description": "Invoice lines. Each line carries exactly one of `price`, `total` or `total_incl_vat`.", "items": { "type": "object", "properties": { "name": { "type": "string", "examples": [ "Consulting" ], "maxLength": 255 }, "units": { "type": "string", "examples": [ "h" ], "maxLength": 255 }, "quantity": { "type": "number", "examples": [ 2 ] }, "price": { "type": [ "number", "null" ], "description": "Unit price excluding VAT. Mutually exclusive with `total` and `total_incl_vat`.", "examples": [ 50 ] }, "total": { "type": [ "number", "null" ], "description": "Line total excluding VAT. Mutually exclusive with `price` and `total_incl_vat`." }, "total_incl_vat": { "type": [ "number", "null" ], "description": "Line total including VAT. Mutually exclusive with `price` and `total`." }, "vat_percentage": { "type": [ "number", "null" ], "description": "VAT rate, 0-100. Required whenever `seller.vat_code` is sent and, with `use_default_seller_info`, on the\n`*vat_invoice` types. On non-VAT types the value is ignored and stored as null.", "examples": [ 21 ], "minimum": 0, "maximum": 100 } }, "required": [ "name", "units", "quantity" ] }, "minItems": 1 }, "payment_options": { "type": [ "array", "null" ], "description": "Payment details printed on the invoice.", "items": { "type": "object", "properties": { "type": { "description": "`bank` takes the bank fields below; `other` takes free-form `fields`.", "$ref": "#/components/schemas/PaymentOptionType" }, "bank_account": { "type": "string", "description": "IBAN. Required for `bank`, prohibited otherwise.", "examples": [ "LT601010012345678901" ], "maxLength": 255 }, "bank_name": { "type": "string", "description": "Required for `bank`, prohibited otherwise.", "maxLength": 255 }, "routing_or_sort_number": { "type": [ "string", "null" ], "maxLength": 255 }, "swift_bic_code": { "type": [ "string", "null" ], "maxLength": 255 }, "fields": { "type": [ "array", "null" ], "description": "Required for `other`.", "items": { "type": "object", "properties": { "label": { "type": "string", "maxLength": 255 }, "value": { "type": "string", "maxLength": 255 } }, "required": [ "label", "value" ] } } }, "required": [ "type" ] } } }, "required": [ "type", "invoice_date", "series", "currency", "buyer", "seller", "products" ], "title": "InvoiceInput" }, "#/components/schemas/PaymentStatus": { "type": "string", "enum": [ "not_paid", "paid" ], "title": "PaymentStatus" }, "#/components/schemas/PaymentOptionType": { "type": "string", "description": "`bank` carries the bank account fields; `other` carries free-form label/value `fields`.\n", "enum": [ "bank", "other" ], "title": "PaymentOptionType" }, "#/components/schemas/Invoice": { "type": "object", "properties": { "id": { "type": "string", "format": "uuid" }, "business_id": { "type": "string", "format": "uuid" }, "invoice_type": { "$ref": "#/components/schemas/InvoiceType" }, "series": { "type": "string" }, "invoice_number": { "type": "string", "description": "Zero-padded to three digits, e.g. `\"007\"`. Send it back padded or unpadded on update; both are accepted." }, "invoice_date": { "type": "string", "format": "date", "description": "Issue date, `Y-m-d`." }, "pay_until_date": { "type": [ "string", "null" ], "format": "date", "description": "Due date, `Y-m-d`." }, "language": { "$ref": "#/components/schemas/InvoiceLanguage" }, "subtotal": { "type": "number", "description": "Sum of the lines excluding VAT." }, "vat": { "type": "number" }, "total_incl_vat": { "type": "number" }, "currency": { "type": "string" }, "payment_status": { "$ref": "#/components/schemas/PaymentStatus" }, "notes": { "type": [ "string", "null" ] }, "share_link": { "type": "string", "format": "uri", "description": "Public link to the invoice; anyone with the link can view it." }, "seller": { "type": "object", "properties": { "business_type": { "$ref": "#/components/schemas/BusinessType" }, "first_name": { "type": [ "string", "null" ] }, "last_name": { "type": [ "string", "null" ] }, "company_name": { "type": [ "string", "null" ] }, "company_code": { "type": [ "string", "null" ] }, "individual_activity_id": { "type": [ "string", "null" ] }, "vat_code": { "type": [ "string", "null" ] }, "address": { "type": [ "string", "null" ] }, "email": { "type": [ "string", "null" ] }, "phone": { "type": [ "string", "null" ] }, "custom_fields": { "type": "array", "items": { "type": "object", "properties": { "label": { "type": "string" }, "value": { "type": "string" } }, "required": [ "label", "value" ] } } }, "required": [ "business_type", "first_name", "last_name", "company_name", "company_code", "individual_activity_id", "vat_code", "address", "email", "phone", "custom_fields" ] }, "buyer": { "type": "object", "properties": { "type": { "type": "string", "description": "`person` sent on input is returned as `individual`.", "enum": [ "company", "individual" ] }, "first_name": { "type": [ "string", "null" ] }, "last_name": { "type": [ "string", "null" ] }, "company_name": { "type": [ "string", "null" ] }, "company_code": { "type": [ "string", "null" ] }, "individual_activity_id": { "type": [ "string", "null" ] }, "vat_code": { "type": [ "string", "null" ] }, "address": { "type": [ "string", "null" ] }, "email": { "type": [ "string", "null" ] }, "phone": { "type": [ "string", "null" ] } }, "required": [ "type", "first_name", "last_name", "company_name", "company_code", "individual_activity_id", "vat_code", "address", "email", "phone" ] }, "items": { "type": "array", "items": { "$ref": "#/components/schemas/InvoiceItem" } }, "payment_options": { "type": "array", "items": { "$ref": "#/components/schemas/PaymentOption" } }, "created_at": { "type": "integer", "description": "Unix timestamp, seconds." }, "updated_at": { "type": "integer", "description": "Unix timestamp, seconds." } }, "required": [ "id", "business_id", "invoice_type", "series", "invoice_number", "invoice_date", "pay_until_date", "language", "subtotal", "vat", "total_incl_vat", "currency", "payment_status", "notes", "share_link", "seller", "buyer", "items", "payment_options", "created_at", "updated_at" ], "title": "Invoice" }, "#/components/schemas/InvoiceType": { "type": "string", "description": "The three `*vat_invoice` types require `vat_percentage` on every line and, when `seller` is sent, `seller.vat_code`.\n", "enum": [ "regular_invoice", "vat_invoice", "preliminary_invoice", "preliminary_vat_invoice", "credit_invoice", "credit_vat_invoice" ], "title": "InvoiceType" }, "#/components/schemas/InvoiceLanguage": { "type": "string", "description": "Language of the PDF and the public share page.\n", "enum": [ "en", "lt", "es", "de", "fr" ], "title": "InvoiceLanguage" }, "#/components/schemas/BusinessType": { "type": "string", "description": "Every type except `individual_activity` is a company.\n", "enum": [ "small_partnership", "individual_activity", "private_limited_liability_company", "sole_proprietorship", "public_institution", "association", "joint_stock_company" ], "title": "BusinessType" }, "#/components/schemas/InvoiceItem": { "type": "object", "properties": { "id": { "type": "string", "format": "uuid" }, "name": { "type": "string" }, "price": { "type": "number" }, "vat_percentage": { "type": [ "number", "null" ] }, "quantity": { "type": "number" }, "units": { "type": "string" } }, "required": [ "id", "name", "price", "vat_percentage", "quantity", "units" ], "title": "InvoiceItem" }, "#/components/schemas/PaymentOption": { "type": "object", "properties": { "type": { "$ref": "#/components/schemas/PaymentOptionType" }, "bank_account": { "type": [ "string", "null" ] }, "bank_name": { "type": [ "string", "null" ] }, "routing_or_sort_number": { "type": [ "string", "null" ] }, "swift_bic_code": { "type": [ "string", "null" ] }, "fields": { "type": "array", "items": { "$ref": "#/components/schemas/LabelValue" } } }, "required": [ "type", "fields" ], "title": "PaymentOption" }, "#/components/schemas/LabelValue": { "type": "object", "properties": { "label": { "type": "string" }, "value": { "type": "string" } }, "required": [ "label", "value" ], "title": "LabelValue" }, "#/components/responses/AuthenticationException": { "description": "Unauthenticated", "content": { "application/json": { "schema": { "type": "object", "properties": { "message": { "type": "string", "description": "Error overview." } }, "required": [ "message" ] } } } }, "#/components/responses/AuthorizationException": { "description": "Authorization error", "content": { "application/json": { "schema": { "type": "object", "properties": { "message": { "type": "string", "description": "Error overview." } }, "required": [ "message" ] } } } }, "#/components/responses/ValidationException": { "description": "Validation error", "content": { "application/json": { "schema": { "type": "object", "properties": { "message": { "type": "string", "description": "Errors overview." }, "errors": { "type": "object", "description": "A detailed description of each field that failed validation.", "additionalProperties": { "type": "array", "items": { "type": "string" } } } }, "required": [ "message", "errors" ] } } } } } ``` --- # Delete an invoice > Deletes the invoice together with its PDF, items, payment options and e-mail logs, and recalculates the series counter. Fires the invoice.deleted webhook. ## DELETE /invoices/{invoice} Deletes the invoice together with its PDF, items, payment options and e-mail logs, and recalculates the series counter. Fires the `invoice.deleted` webhook. ### Request and responses ```json { "servers": [ { "url": "https://app.fsaskaita.lt/api", "description": "Production" } ], "security": [ { "bearerAuth": [] } ], "operation": { "operationId": "deleteInvoice", "description": "Deletes the invoice together with its PDF, items, payment options and e-mail logs, and recalculates the\nseries counter. Fires the `invoice.deleted` webhook.", "summary": "Delete an invoice", "tags": [ "Invoices" ], "parameters": [ { "name": "invoice", "in": "path", "required": true, "description": "The invoice ID.", "schema": { "type": "string" } } ], "responses": { "200": { "description": "Deleted. The body is empty." }, "401": { "$ref": "#/components/responses/AuthenticationException" }, "404": { "description": "The invoice does not exist or belongs to another business.", "content": { "application/json": { "schema": { "type": "object", "properties": { "message": { "type": "string" } }, "required": [ "message" ] } } } }, "429": { "description": "Rate limit exceeded. The limit is 60 requests per minute per business, shared across all of its tokens. Wait `Retry-After` seconds before retrying.", "content": { "application/json": { "schema": { "type": "object", "properties": { "message": { "type": "string" } }, "required": [ "message" ] } } }, "headers": { "Retry-After": { "description": "Seconds to wait before retrying.", "schema": { "type": "integer" } }, "X-RateLimit-Limit": { "description": "Requests allowed per minute.", "schema": { "type": "integer" } }, "X-RateLimit-Remaining": { "description": "Requests left in the current minute.", "schema": { "type": "integer" } }, "X-RateLimit-Reset": { "description": "Unix timestamp at which the window resets.", "schema": { "type": "integer" } } } } } }, "securitySchemes": { "bearerAuth": { "type": "http", "description": "Business token created in the app under Settings, Integrations, API. The token is scoped to exactly one business, has no expiry and is shown only once. Send it as `Authorization: Bearer ` together with `Accept: application/json`.", "scheme": "bearer" } } } ``` ### Referenced components ```json { "#/components/responses/AuthenticationException": { "description": "Unauthenticated", "content": { "application/json": { "schema": { "type": "object", "properties": { "message": { "type": "string", "description": "Error overview." } }, "required": [ "message" ] } } } } } ``` --- # Download the invoice PDF > Streams the invoice PDF. The PDF is rendered asynchronously after create and update; if it does not exist yet the request waits for it for up to 20 seconds and then fails with 500. Content-Length is not sent. ## GET /invoices/{invoice}/download Streams the invoice PDF. The PDF is rendered asynchronously after create and update; if it does not exist yet the request waits for it for up to 20 seconds and then fails with `500`. `Content-Length` is not sent. ### Request and responses ```json { "servers": [ { "url": "https://app.fsaskaita.lt/api", "description": "Production" } ], "security": [ { "bearerAuth": [] } ], "operation": { "operationId": "downloadInvoicePdf", "description": "Streams the invoice PDF. The PDF is rendered asynchronously after create and update; if it does not exist\nyet the request waits for it for up to 20 seconds and then fails with `500`. `Content-Length` is not sent.", "summary": "Download the invoice PDF", "tags": [ "Invoices" ], "parameters": [ { "name": "invoice", "in": "path", "required": true, "description": "The invoice ID.", "schema": { "type": "string" } } ], "responses": { "200": { "description": "The invoice PDF.", "content": { "application/pdf": { "schema": { "type": "string", "format": "binary" } } }, "headers": { "Content-Disposition": { "description": "Attachment with the file name ` .pdf`, e.g. `Sąskaita faktūra SF007.pdf`.", "schema": { "type": "string" } } } }, "401": { "$ref": "#/components/responses/AuthenticationException" }, "404": { "description": "The invoice does not exist or belongs to another business.", "content": { "application/json": { "schema": { "type": "object", "properties": { "message": { "type": "string" } }, "required": [ "message" ] } } } }, "429": { "description": "Rate limit exceeded. The limit is 60 requests per minute per business, shared across all of its tokens. Wait `Retry-After` seconds before retrying.", "content": { "application/json": { "schema": { "type": "object", "properties": { "message": { "type": "string" } }, "required": [ "message" ] } } }, "headers": { "Retry-After": { "description": "Seconds to wait before retrying.", "schema": { "type": "integer" } }, "X-RateLimit-Limit": { "description": "Requests allowed per minute.", "schema": { "type": "integer" } }, "X-RateLimit-Remaining": { "description": "Requests left in the current minute.", "schema": { "type": "integer" } }, "X-RateLimit-Reset": { "description": "Unix timestamp at which the window resets.", "schema": { "type": "integer" } } } }, "500": { "description": "The PDF was still not rendered after waiting 20 seconds.", "content": { "application/json": { "schema": { "type": "object", "properties": { "message": { "type": "string" } }, "required": [ "message" ] } } } } } }, "securitySchemes": { "bearerAuth": { "type": "http", "description": "Business token created in the app under Settings, Integrations, API. The token is scoped to exactly one business, has no expiry and is shown only once. Send it as `Authorization: Bearer ` together with `Accept: application/json`.", "scheme": "bearer" } } } ``` ### Referenced components ```json { "#/components/responses/AuthenticationException": { "description": "Unauthenticated", "content": { "application/json": { "schema": { "type": "object", "properties": { "message": { "type": "string", "description": "Error overview." } }, "required": [ "message" ] } } } } } ``` --- # Get an invoice > ## GET /invoices/{invoice} ### Request and responses ```json { "servers": [ { "url": "https://app.fsaskaita.lt/api", "description": "Production" } ], "security": [ { "bearerAuth": [] } ], "operation": { "operationId": "getInvoice", "summary": "Get an invoice", "tags": [ "Invoices" ], "parameters": [ { "name": "invoice", "in": "path", "required": true, "description": "The invoice ID.", "schema": { "type": "string" } } ], "responses": { "200": { "description": "`Invoice`", "content": { "application/json": { "schema": { "type": "object", "properties": { "data": { "$ref": "#/components/schemas/Invoice" } }, "required": [ "data" ] } } } }, "401": { "$ref": "#/components/responses/AuthenticationException" }, "404": { "description": "The invoice does not exist or belongs to another business.", "content": { "application/json": { "schema": { "type": "object", "properties": { "message": { "type": "string" } }, "required": [ "message" ] } } } }, "429": { "description": "Rate limit exceeded. The limit is 60 requests per minute per business, shared across all of its tokens. Wait `Retry-After` seconds before retrying.", "content": { "application/json": { "schema": { "type": "object", "properties": { "message": { "type": "string" } }, "required": [ "message" ] } } }, "headers": { "Retry-After": { "description": "Seconds to wait before retrying.", "schema": { "type": "integer" } }, "X-RateLimit-Limit": { "description": "Requests allowed per minute.", "schema": { "type": "integer" } }, "X-RateLimit-Remaining": { "description": "Requests left in the current minute.", "schema": { "type": "integer" } }, "X-RateLimit-Reset": { "description": "Unix timestamp at which the window resets.", "schema": { "type": "integer" } } } } } }, "securitySchemes": { "bearerAuth": { "type": "http", "description": "Business token created in the app under Settings, Integrations, API. The token is scoped to exactly one business, has no expiry and is shown only once. Send it as `Authorization: Bearer ` together with `Accept: application/json`.", "scheme": "bearer" } } } ``` ### Referenced components ```json { "#/components/schemas/Invoice": { "type": "object", "properties": { "id": { "type": "string", "format": "uuid" }, "business_id": { "type": "string", "format": "uuid" }, "invoice_type": { "$ref": "#/components/schemas/InvoiceType" }, "series": { "type": "string" }, "invoice_number": { "type": "string", "description": "Zero-padded to three digits, e.g. `\"007\"`. Send it back padded or unpadded on update; both are accepted." }, "invoice_date": { "type": "string", "format": "date", "description": "Issue date, `Y-m-d`." }, "pay_until_date": { "type": [ "string", "null" ], "format": "date", "description": "Due date, `Y-m-d`." }, "language": { "$ref": "#/components/schemas/InvoiceLanguage" }, "subtotal": { "type": "number", "description": "Sum of the lines excluding VAT." }, "vat": { "type": "number" }, "total_incl_vat": { "type": "number" }, "currency": { "type": "string" }, "payment_status": { "$ref": "#/components/schemas/PaymentStatus" }, "notes": { "type": [ "string", "null" ] }, "share_link": { "type": "string", "format": "uri", "description": "Public link to the invoice; anyone with the link can view it." }, "seller": { "type": "object", "properties": { "business_type": { "$ref": "#/components/schemas/BusinessType" }, "first_name": { "type": [ "string", "null" ] }, "last_name": { "type": [ "string", "null" ] }, "company_name": { "type": [ "string", "null" ] }, "company_code": { "type": [ "string", "null" ] }, "individual_activity_id": { "type": [ "string", "null" ] }, "vat_code": { "type": [ "string", "null" ] }, "address": { "type": [ "string", "null" ] }, "email": { "type": [ "string", "null" ] }, "phone": { "type": [ "string", "null" ] }, "custom_fields": { "type": "array", "items": { "type": "object", "properties": { "label": { "type": "string" }, "value": { "type": "string" } }, "required": [ "label", "value" ] } } }, "required": [ "business_type", "first_name", "last_name", "company_name", "company_code", "individual_activity_id", "vat_code", "address", "email", "phone", "custom_fields" ] }, "buyer": { "type": "object", "properties": { "type": { "type": "string", "description": "`person` sent on input is returned as `individual`.", "enum": [ "company", "individual" ] }, "first_name": { "type": [ "string", "null" ] }, "last_name": { "type": [ "string", "null" ] }, "company_name": { "type": [ "string", "null" ] }, "company_code": { "type": [ "string", "null" ] }, "individual_activity_id": { "type": [ "string", "null" ] }, "vat_code": { "type": [ "string", "null" ] }, "address": { "type": [ "string", "null" ] }, "email": { "type": [ "string", "null" ] }, "phone": { "type": [ "string", "null" ] } }, "required": [ "type", "first_name", "last_name", "company_name", "company_code", "individual_activity_id", "vat_code", "address", "email", "phone" ] }, "items": { "type": "array", "items": { "$ref": "#/components/schemas/InvoiceItem" } }, "payment_options": { "type": "array", "items": { "$ref": "#/components/schemas/PaymentOption" } }, "created_at": { "type": "integer", "description": "Unix timestamp, seconds." }, "updated_at": { "type": "integer", "description": "Unix timestamp, seconds." } }, "required": [ "id", "business_id", "invoice_type", "series", "invoice_number", "invoice_date", "pay_until_date", "language", "subtotal", "vat", "total_incl_vat", "currency", "payment_status", "notes", "share_link", "seller", "buyer", "items", "payment_options", "created_at", "updated_at" ], "title": "Invoice" }, "#/components/schemas/InvoiceType": { "type": "string", "description": "The three `*vat_invoice` types require `vat_percentage` on every line and, when `seller` is sent, `seller.vat_code`.\n", "enum": [ "regular_invoice", "vat_invoice", "preliminary_invoice", "preliminary_vat_invoice", "credit_invoice", "credit_vat_invoice" ], "title": "InvoiceType" }, "#/components/schemas/InvoiceLanguage": { "type": "string", "description": "Language of the PDF and the public share page.\n", "enum": [ "en", "lt", "es", "de", "fr" ], "title": "InvoiceLanguage" }, "#/components/schemas/PaymentStatus": { "type": "string", "enum": [ "not_paid", "paid" ], "title": "PaymentStatus" }, "#/components/schemas/BusinessType": { "type": "string", "description": "Every type except `individual_activity` is a company.\n", "enum": [ "small_partnership", "individual_activity", "private_limited_liability_company", "sole_proprietorship", "public_institution", "association", "joint_stock_company" ], "title": "BusinessType" }, "#/components/schemas/InvoiceItem": { "type": "object", "properties": { "id": { "type": "string", "format": "uuid" }, "name": { "type": "string" }, "price": { "type": "number" }, "vat_percentage": { "type": [ "number", "null" ] }, "quantity": { "type": "number" }, "units": { "type": "string" } }, "required": [ "id", "name", "price", "vat_percentage", "quantity", "units" ], "title": "InvoiceItem" }, "#/components/schemas/PaymentOption": { "type": "object", "properties": { "type": { "$ref": "#/components/schemas/PaymentOptionType" }, "bank_account": { "type": [ "string", "null" ] }, "bank_name": { "type": [ "string", "null" ] }, "routing_or_sort_number": { "type": [ "string", "null" ] }, "swift_bic_code": { "type": [ "string", "null" ] }, "fields": { "type": "array", "items": { "$ref": "#/components/schemas/LabelValue" } } }, "required": [ "type", "fields" ], "title": "PaymentOption" }, "#/components/schemas/PaymentOptionType": { "type": "string", "description": "`bank` carries the bank account fields; `other` carries free-form label/value `fields`.\n", "enum": [ "bank", "other" ], "title": "PaymentOptionType" }, "#/components/schemas/LabelValue": { "type": "object", "properties": { "label": { "type": "string" }, "value": { "type": "string" } }, "required": [ "label", "value" ], "title": "LabelValue" }, "#/components/responses/AuthenticationException": { "description": "Unauthenticated", "content": { "application/json": { "schema": { "type": "object", "properties": { "message": { "type": "string", "description": "Error overview." } }, "required": [ "message" ] } } } } } ``` --- # List invoices > Returns the business's finalized invoices, newest first, 50 per page. Use ?page= to paginate; the page size cannot be changed. Drafts made in the app are never included. ## GET /invoices Returns the business's finalized invoices, newest first, 50 per page. Use `?page=` to paginate; the page size cannot be changed. Drafts made in the app are never included. ### Request and responses ```json { "servers": [ { "url": "https://app.fsaskaita.lt/api", "description": "Production" } ], "security": [ { "bearerAuth": [] } ], "operation": { "operationId": "listInvoices", "description": "Returns the business's finalized invoices, newest first, 50 per page. Use `?page=` to paginate; the page\nsize cannot be changed. Drafts made in the app are never included.", "summary": "List invoices", "tags": [ "Invoices" ], "parameters": [ { "name": "page", "in": "query", "description": "Page number, starting at 1. The page size is fixed at 50.", "schema": { "type": "integer", "default": 1 } } ], "responses": { "200": { "description": "Paginated set of `Invoice`", "content": { "application/json": { "schema": { "type": "object", "properties": { "data": { "type": "array", "items": { "$ref": "#/components/schemas/Invoice" } }, "meta": { "type": "object", "properties": { "current_page": { "type": "integer", "minimum": 1 }, "from": { "type": [ "integer", "null" ], "minimum": 1 }, "last_page": { "type": "integer", "minimum": 1 }, "path": { "type": [ "string", "null" ], "description": "Base path for paginator generated URLs." }, "per_page": { "type": "integer", "description": "Number of items shown per page.", "minimum": 0 }, "to": { "type": [ "integer", "null" ], "description": "Number of the last item in the slice.", "minimum": 1 }, "total": { "type": "integer", "description": "Total number of items being paginated.", "minimum": 0 } }, "required": [ "current_page", "from", "last_page", "path", "per_page", "to", "total" ] } }, "required": [ "data", "meta" ] } } } }, "401": { "$ref": "#/components/responses/AuthenticationException" }, "429": { "description": "Rate limit exceeded. The limit is 60 requests per minute per business, shared across all of its tokens. Wait `Retry-After` seconds before retrying.", "content": { "application/json": { "schema": { "type": "object", "properties": { "message": { "type": "string" } }, "required": [ "message" ] } } }, "headers": { "Retry-After": { "description": "Seconds to wait before retrying.", "schema": { "type": "integer" } }, "X-RateLimit-Limit": { "description": "Requests allowed per minute.", "schema": { "type": "integer" } }, "X-RateLimit-Remaining": { "description": "Requests left in the current minute.", "schema": { "type": "integer" } }, "X-RateLimit-Reset": { "description": "Unix timestamp at which the window resets.", "schema": { "type": "integer" } } } } } }, "securitySchemes": { "bearerAuth": { "type": "http", "description": "Business token created in the app under Settings, Integrations, API. The token is scoped to exactly one business, has no expiry and is shown only once. Send it as `Authorization: Bearer ` together with `Accept: application/json`.", "scheme": "bearer" } } } ``` ### Referenced components ```json { "#/components/schemas/Invoice": { "type": "object", "properties": { "id": { "type": "string", "format": "uuid" }, "business_id": { "type": "string", "format": "uuid" }, "invoice_type": { "$ref": "#/components/schemas/InvoiceType" }, "series": { "type": "string" }, "invoice_number": { "type": "string", "description": "Zero-padded to three digits, e.g. `\"007\"`. Send it back padded or unpadded on update; both are accepted." }, "invoice_date": { "type": "string", "format": "date", "description": "Issue date, `Y-m-d`." }, "pay_until_date": { "type": [ "string", "null" ], "format": "date", "description": "Due date, `Y-m-d`." }, "language": { "$ref": "#/components/schemas/InvoiceLanguage" }, "subtotal": { "type": "number", "description": "Sum of the lines excluding VAT." }, "vat": { "type": "number" }, "total_incl_vat": { "type": "number" }, "currency": { "type": "string" }, "payment_status": { "$ref": "#/components/schemas/PaymentStatus" }, "notes": { "type": [ "string", "null" ] }, "share_link": { "type": "string", "format": "uri", "description": "Public link to the invoice; anyone with the link can view it." }, "seller": { "type": "object", "properties": { "business_type": { "$ref": "#/components/schemas/BusinessType" }, "first_name": { "type": [ "string", "null" ] }, "last_name": { "type": [ "string", "null" ] }, "company_name": { "type": [ "string", "null" ] }, "company_code": { "type": [ "string", "null" ] }, "individual_activity_id": { "type": [ "string", "null" ] }, "vat_code": { "type": [ "string", "null" ] }, "address": { "type": [ "string", "null" ] }, "email": { "type": [ "string", "null" ] }, "phone": { "type": [ "string", "null" ] }, "custom_fields": { "type": "array", "items": { "type": "object", "properties": { "label": { "type": "string" }, "value": { "type": "string" } }, "required": [ "label", "value" ] } } }, "required": [ "business_type", "first_name", "last_name", "company_name", "company_code", "individual_activity_id", "vat_code", "address", "email", "phone", "custom_fields" ] }, "buyer": { "type": "object", "properties": { "type": { "type": "string", "description": "`person` sent on input is returned as `individual`.", "enum": [ "company", "individual" ] }, "first_name": { "type": [ "string", "null" ] }, "last_name": { "type": [ "string", "null" ] }, "company_name": { "type": [ "string", "null" ] }, "company_code": { "type": [ "string", "null" ] }, "individual_activity_id": { "type": [ "string", "null" ] }, "vat_code": { "type": [ "string", "null" ] }, "address": { "type": [ "string", "null" ] }, "email": { "type": [ "string", "null" ] }, "phone": { "type": [ "string", "null" ] } }, "required": [ "type", "first_name", "last_name", "company_name", "company_code", "individual_activity_id", "vat_code", "address", "email", "phone" ] }, "items": { "type": "array", "items": { "$ref": "#/components/schemas/InvoiceItem" } }, "payment_options": { "type": "array", "items": { "$ref": "#/components/schemas/PaymentOption" } }, "created_at": { "type": "integer", "description": "Unix timestamp, seconds." }, "updated_at": { "type": "integer", "description": "Unix timestamp, seconds." } }, "required": [ "id", "business_id", "invoice_type", "series", "invoice_number", "invoice_date", "pay_until_date", "language", "subtotal", "vat", "total_incl_vat", "currency", "payment_status", "notes", "share_link", "seller", "buyer", "items", "payment_options", "created_at", "updated_at" ], "title": "Invoice" }, "#/components/schemas/InvoiceType": { "type": "string", "description": "The three `*vat_invoice` types require `vat_percentage` on every line and, when `seller` is sent, `seller.vat_code`.\n", "enum": [ "regular_invoice", "vat_invoice", "preliminary_invoice", "preliminary_vat_invoice", "credit_invoice", "credit_vat_invoice" ], "title": "InvoiceType" }, "#/components/schemas/InvoiceLanguage": { "type": "string", "description": "Language of the PDF and the public share page.\n", "enum": [ "en", "lt", "es", "de", "fr" ], "title": "InvoiceLanguage" }, "#/components/schemas/PaymentStatus": { "type": "string", "enum": [ "not_paid", "paid" ], "title": "PaymentStatus" }, "#/components/schemas/BusinessType": { "type": "string", "description": "Every type except `individual_activity` is a company.\n", "enum": [ "small_partnership", "individual_activity", "private_limited_liability_company", "sole_proprietorship", "public_institution", "association", "joint_stock_company" ], "title": "BusinessType" }, "#/components/schemas/InvoiceItem": { "type": "object", "properties": { "id": { "type": "string", "format": "uuid" }, "name": { "type": "string" }, "price": { "type": "number" }, "vat_percentage": { "type": [ "number", "null" ] }, "quantity": { "type": "number" }, "units": { "type": "string" } }, "required": [ "id", "name", "price", "vat_percentage", "quantity", "units" ], "title": "InvoiceItem" }, "#/components/schemas/PaymentOption": { "type": "object", "properties": { "type": { "$ref": "#/components/schemas/PaymentOptionType" }, "bank_account": { "type": [ "string", "null" ] }, "bank_name": { "type": [ "string", "null" ] }, "routing_or_sort_number": { "type": [ "string", "null" ] }, "swift_bic_code": { "type": [ "string", "null" ] }, "fields": { "type": "array", "items": { "$ref": "#/components/schemas/LabelValue" } } }, "required": [ "type", "fields" ], "title": "PaymentOption" }, "#/components/schemas/PaymentOptionType": { "type": "string", "description": "`bank` carries the bank account fields; `other` carries free-form label/value `fields`.\n", "enum": [ "bank", "other" ], "title": "PaymentOptionType" }, "#/components/schemas/LabelValue": { "type": "object", "properties": { "label": { "type": "string" }, "value": { "type": "string" } }, "required": [ "label", "value" ], "title": "LabelValue" }, "#/components/responses/AuthenticationException": { "description": "Unauthenticated", "content": { "application/json": { "schema": { "type": "object", "properties": { "message": { "type": "string", "description": "Error overview." } }, "required": [ "message" ] } } } } } ``` --- # Replace an invoice > Replaces every field of the invoice with the request body, under the same rules as create. Always resend the current invoice_number: when it is omitted the invoice is renumbered from the series counter. Items, payment options and custom fields are rewritten, totals recalculated and the PDF regenerated. Fires the invoice.updated webhook. ## PUT /invoices/{invoice} Replaces every field of the invoice with the request body, under the same rules as create. **Always resend the current `invoice_number`**: when it is omitted the invoice is renumbered from the series counter. Items, payment options and custom fields are rewritten, totals recalculated and the PDF regenerated. Fires the `invoice.updated` webhook. ### Request and responses ```json { "servers": [ { "url": "https://app.fsaskaita.lt/api", "description": "Production" } ], "security": [ { "bearerAuth": [] } ], "operation": { "operationId": "updateInvoice", "description": "Replaces every field of the invoice with the request body, under the same rules as create. **Always resend\nthe current `invoice_number`**: when it is omitted the invoice is renumbered from the series counter. Items,\npayment options and custom fields are rewritten, totals recalculated and the PDF regenerated. Fires the\n`invoice.updated` webhook.", "summary": "Replace an invoice", "tags": [ "Invoices" ], "parameters": [ { "name": "invoice", "in": "path", "required": true, "description": "The invoice ID.", "schema": { "type": "string" } } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/InvoiceInput" } } } }, "responses": { "200": { "description": "`Invoice`", "content": { "application/json": { "schema": { "type": "object", "properties": { "data": { "$ref": "#/components/schemas/Invoice" } }, "required": [ "data" ] } } } }, "401": { "$ref": "#/components/responses/AuthenticationException" }, "403": { "$ref": "#/components/responses/AuthorizationException" }, "404": { "description": "The invoice does not exist or belongs to another business.", "content": { "application/json": { "schema": { "type": "object", "properties": { "message": { "type": "string" } }, "required": [ "message" ] } } } }, "422": { "$ref": "#/components/responses/ValidationException" }, "429": { "description": "Rate limit exceeded. The limit is 60 requests per minute per business, shared across all of its tokens. Wait `Retry-After` seconds before retrying.", "content": { "application/json": { "schema": { "type": "object", "properties": { "message": { "type": "string" } }, "required": [ "message" ] } } }, "headers": { "Retry-After": { "description": "Seconds to wait before retrying.", "schema": { "type": "integer" } }, "X-RateLimit-Limit": { "description": "Requests allowed per minute.", "schema": { "type": "integer" } }, "X-RateLimit-Remaining": { "description": "Requests left in the current minute.", "schema": { "type": "integer" } }, "X-RateLimit-Reset": { "description": "Unix timestamp at which the window resets.", "schema": { "type": "integer" } } } } } }, "securitySchemes": { "bearerAuth": { "type": "http", "description": "Business token created in the app under Settings, Integrations, API. The token is scoped to exactly one business, has no expiry and is shown only once. Send it as `Authorization: Bearer ` together with `Accept: application/json`.", "scheme": "bearer" } } } ``` ### Referenced components ```json { "#/components/schemas/InvoiceInput": { "type": "object", "description": "Body of `POST /invoices` and `PUT /invoices/{invoice}`. On update every field is replaced with what you send;\nalways resend `invoice_number` or the invoice is renumbered.", "properties": { "type": { "type": "string", "description": "Invoice type. The `*vat_invoice` types require `seller.vat_code` and `vat_percentage` on every line.", "enum": [ "regular_invoice", "vat_invoice", "preliminary_invoice", "preliminary_vat_invoice", "credit_invoice", "credit_vat_invoice" ], "examples": [ "vat_invoice" ] }, "invoice_date": { "type": "string", "format": "date", "description": "Issue date.", "examples": [ "2026-09-12" ] }, "pay_until_date": { "type": [ "string", "null" ], "format": "date", "description": "Due date.", "examples": [ "2026-09-26" ] }, "series": { "type": "string", "description": "Series code the number belongs to. A new code starts its own counter.", "examples": [ "SF" ], "maxLength": 255 }, "notes": { "type": [ "string", "null" ], "description": "Free text printed under the lines.", "maxLength": 255 }, "currency": { "type": "string", "description": "One of the codes from `GET /currencies`.", "examples": [ "EUR" ] }, "payment_status": { "anyOf": [ { "description": "Defaults to `not_paid` on create; when omitted on update the current status is kept.", "$ref": "#/components/schemas/PaymentStatus" }, { "type": "null" } ] }, "language": { "type": [ "string", "null" ], "description": "Language of the PDF and the share page. Defaults to `lt`.", "enum": [ "en", "lt", "es", "de", "fr", null ] }, "invoice_number": { "type": [ "string", "null" ], "description": "Number within the series; must be unique there. Omit on create to auto-number. **On update always\nresend the current number**, otherwise the invoice is renumbered from the series counter. Accepts the\npadded (`\"007\"`) or unpadded (`\"7\"`) form; numbers are compared exactly as sent, so use one form\nconsistently within a series.", "pattern": "^(.*)+$", "examples": [ "7" ], "maxLength": 255 }, "buyer": { "type": "object", "properties": { "type": { "type": "string", "description": "`company` or `individual`. `person` is accepted as a legacy alias of `individual`; responses always\nreturn `individual`.", "enum": [ "company", "person", "individual" ], "examples": [ "company" ] }, "company_name": { "type": [ "string", "null" ], "description": "Required for companies, prohibited for individuals." }, "company_code": { "type": [ "string", "null" ], "description": "Prohibited for individuals.", "maxLength": 255 }, "first_name": { "type": [ "string", "null" ], "description": "Required for individuals, prohibited for companies.", "maxLength": 255 }, "last_name": { "type": [ "string", "null" ], "description": "Required for individuals, prohibited for companies.", "maxLength": 255 }, "individual_activity_id": { "type": [ "string", "null" ], "description": "Individual activity certificate number; prohibited for companies.", "maxLength": 255 }, "address": { "type": [ "string", "null" ], "maxLength": 255 }, "vat_code": { "type": [ "string", "null" ], "maxLength": 255 }, "email": { "type": [ "string", "null" ], "maxLength": 255 }, "phone": { "type": [ "string", "null" ], "maxLength": 255 } }, "required": [ "type" ] }, "use_default_seller_info": { "type": [ "boolean", "null" ], "description": "When `true` the seller block is copied from the business profile (plus the custom fields of the latest\ninvoice) and `seller` must be omitted.", "examples": [ true ] }, "seller": { "type": "object", "description": "Required unless `use_default_seller_info` is `true`. Which fields are required depends on the business\ntype: companies send `company_name` (required) and `company_code` (optional); individual activities send\n`first_name` and `last_name` (required) and `individual_activity_id` (optional). Fields of the other kind\nare rejected.", "properties": { "address": { "type": [ "string", "null" ], "maxLength": 255 }, "vat_code": { "type": [ "string", "null" ], "description": "Required for the `*vat_invoice` types when `seller` is sent.", "maxLength": 255 }, "email": { "type": [ "string", "null" ], "maxLength": 255 }, "phone": { "type": [ "string", "null" ], "maxLength": 255 }, "company_name": { "type": [ "string", "null" ], "description": "Companies only.", "maxLength": 255 }, "company_code": { "type": [ "string", "null" ], "description": "Companies only.", "maxLength": 255 }, "first_name": { "type": [ "string", "null" ], "description": "Individual activities only.", "maxLength": 255 }, "last_name": { "type": [ "string", "null" ], "description": "Individual activities only.", "maxLength": 255 }, "individual_activity_id": { "type": [ "string", "null" ], "description": "Individual activities only.", "maxLength": 255 }, "custom_fields": { "type": [ "array", "null" ], "description": "Extra label/value pairs printed in the seller block.", "items": { "type": "object", "properties": { "label": { "type": "string", "maxLength": 255 }, "value": { "type": "string", "maxLength": 255 } }, "required": [ "label", "value" ] } } } }, "products": { "type": "array", "description": "Invoice lines. Each line carries exactly one of `price`, `total` or `total_incl_vat`.", "items": { "type": "object", "properties": { "name": { "type": "string", "examples": [ "Consulting" ], "maxLength": 255 }, "units": { "type": "string", "examples": [ "h" ], "maxLength": 255 }, "quantity": { "type": "number", "examples": [ 2 ] }, "price": { "type": [ "number", "null" ], "description": "Unit price excluding VAT. Mutually exclusive with `total` and `total_incl_vat`.", "examples": [ 50 ] }, "total": { "type": [ "number", "null" ], "description": "Line total excluding VAT. Mutually exclusive with `price` and `total_incl_vat`." }, "total_incl_vat": { "type": [ "number", "null" ], "description": "Line total including VAT. Mutually exclusive with `price` and `total`." }, "vat_percentage": { "type": [ "number", "null" ], "description": "VAT rate, 0-100. Required whenever `seller.vat_code` is sent and, with `use_default_seller_info`, on the\n`*vat_invoice` types. On non-VAT types the value is ignored and stored as null.", "examples": [ 21 ], "minimum": 0, "maximum": 100 } }, "required": [ "name", "units", "quantity" ] }, "minItems": 1 }, "payment_options": { "type": [ "array", "null" ], "description": "Payment details printed on the invoice.", "items": { "type": "object", "properties": { "type": { "description": "`bank` takes the bank fields below; `other` takes free-form `fields`.", "$ref": "#/components/schemas/PaymentOptionType" }, "bank_account": { "type": "string", "description": "IBAN. Required for `bank`, prohibited otherwise.", "examples": [ "LT601010012345678901" ], "maxLength": 255 }, "bank_name": { "type": "string", "description": "Required for `bank`, prohibited otherwise.", "maxLength": 255 }, "routing_or_sort_number": { "type": [ "string", "null" ], "maxLength": 255 }, "swift_bic_code": { "type": [ "string", "null" ], "maxLength": 255 }, "fields": { "type": [ "array", "null" ], "description": "Required for `other`.", "items": { "type": "object", "properties": { "label": { "type": "string", "maxLength": 255 }, "value": { "type": "string", "maxLength": 255 } }, "required": [ "label", "value" ] } } }, "required": [ "type" ] } } }, "required": [ "type", "invoice_date", "series", "currency", "buyer", "seller", "products" ], "title": "InvoiceInput" }, "#/components/schemas/PaymentStatus": { "type": "string", "enum": [ "not_paid", "paid" ], "title": "PaymentStatus" }, "#/components/schemas/PaymentOptionType": { "type": "string", "description": "`bank` carries the bank account fields; `other` carries free-form label/value `fields`.\n", "enum": [ "bank", "other" ], "title": "PaymentOptionType" }, "#/components/schemas/Invoice": { "type": "object", "properties": { "id": { "type": "string", "format": "uuid" }, "business_id": { "type": "string", "format": "uuid" }, "invoice_type": { "$ref": "#/components/schemas/InvoiceType" }, "series": { "type": "string" }, "invoice_number": { "type": "string", "description": "Zero-padded to three digits, e.g. `\"007\"`. Send it back padded or unpadded on update; both are accepted." }, "invoice_date": { "type": "string", "format": "date", "description": "Issue date, `Y-m-d`." }, "pay_until_date": { "type": [ "string", "null" ], "format": "date", "description": "Due date, `Y-m-d`." }, "language": { "$ref": "#/components/schemas/InvoiceLanguage" }, "subtotal": { "type": "number", "description": "Sum of the lines excluding VAT." }, "vat": { "type": "number" }, "total_incl_vat": { "type": "number" }, "currency": { "type": "string" }, "payment_status": { "$ref": "#/components/schemas/PaymentStatus" }, "notes": { "type": [ "string", "null" ] }, "share_link": { "type": "string", "format": "uri", "description": "Public link to the invoice; anyone with the link can view it." }, "seller": { "type": "object", "properties": { "business_type": { "$ref": "#/components/schemas/BusinessType" }, "first_name": { "type": [ "string", "null" ] }, "last_name": { "type": [ "string", "null" ] }, "company_name": { "type": [ "string", "null" ] }, "company_code": { "type": [ "string", "null" ] }, "individual_activity_id": { "type": [ "string", "null" ] }, "vat_code": { "type": [ "string", "null" ] }, "address": { "type": [ "string", "null" ] }, "email": { "type": [ "string", "null" ] }, "phone": { "type": [ "string", "null" ] }, "custom_fields": { "type": "array", "items": { "type": "object", "properties": { "label": { "type": "string" }, "value": { "type": "string" } }, "required": [ "label", "value" ] } } }, "required": [ "business_type", "first_name", "last_name", "company_name", "company_code", "individual_activity_id", "vat_code", "address", "email", "phone", "custom_fields" ] }, "buyer": { "type": "object", "properties": { "type": { "type": "string", "description": "`person` sent on input is returned as `individual`.", "enum": [ "company", "individual" ] }, "first_name": { "type": [ "string", "null" ] }, "last_name": { "type": [ "string", "null" ] }, "company_name": { "type": [ "string", "null" ] }, "company_code": { "type": [ "string", "null" ] }, "individual_activity_id": { "type": [ "string", "null" ] }, "vat_code": { "type": [ "string", "null" ] }, "address": { "type": [ "string", "null" ] }, "email": { "type": [ "string", "null" ] }, "phone": { "type": [ "string", "null" ] } }, "required": [ "type", "first_name", "last_name", "company_name", "company_code", "individual_activity_id", "vat_code", "address", "email", "phone" ] }, "items": { "type": "array", "items": { "$ref": "#/components/schemas/InvoiceItem" } }, "payment_options": { "type": "array", "items": { "$ref": "#/components/schemas/PaymentOption" } }, "created_at": { "type": "integer", "description": "Unix timestamp, seconds." }, "updated_at": { "type": "integer", "description": "Unix timestamp, seconds." } }, "required": [ "id", "business_id", "invoice_type", "series", "invoice_number", "invoice_date", "pay_until_date", "language", "subtotal", "vat", "total_incl_vat", "currency", "payment_status", "notes", "share_link", "seller", "buyer", "items", "payment_options", "created_at", "updated_at" ], "title": "Invoice" }, "#/components/schemas/InvoiceType": { "type": "string", "description": "The three `*vat_invoice` types require `vat_percentage` on every line and, when `seller` is sent, `seller.vat_code`.\n", "enum": [ "regular_invoice", "vat_invoice", "preliminary_invoice", "preliminary_vat_invoice", "credit_invoice", "credit_vat_invoice" ], "title": "InvoiceType" }, "#/components/schemas/InvoiceLanguage": { "type": "string", "description": "Language of the PDF and the public share page.\n", "enum": [ "en", "lt", "es", "de", "fr" ], "title": "InvoiceLanguage" }, "#/components/schemas/BusinessType": { "type": "string", "description": "Every type except `individual_activity` is a company.\n", "enum": [ "small_partnership", "individual_activity", "private_limited_liability_company", "sole_proprietorship", "public_institution", "association", "joint_stock_company" ], "title": "BusinessType" }, "#/components/schemas/InvoiceItem": { "type": "object", "properties": { "id": { "type": "string", "format": "uuid" }, "name": { "type": "string" }, "price": { "type": "number" }, "vat_percentage": { "type": [ "number", "null" ] }, "quantity": { "type": "number" }, "units": { "type": "string" } }, "required": [ "id", "name", "price", "vat_percentage", "quantity", "units" ], "title": "InvoiceItem" }, "#/components/schemas/PaymentOption": { "type": "object", "properties": { "type": { "$ref": "#/components/schemas/PaymentOptionType" }, "bank_account": { "type": [ "string", "null" ] }, "bank_name": { "type": [ "string", "null" ] }, "routing_or_sort_number": { "type": [ "string", "null" ] }, "swift_bic_code": { "type": [ "string", "null" ] }, "fields": { "type": "array", "items": { "$ref": "#/components/schemas/LabelValue" } } }, "required": [ "type", "fields" ], "title": "PaymentOption" }, "#/components/schemas/LabelValue": { "type": "object", "properties": { "label": { "type": "string" }, "value": { "type": "string" } }, "required": [ "label", "value" ], "title": "LabelValue" }, "#/components/responses/AuthenticationException": { "description": "Unauthenticated", "content": { "application/json": { "schema": { "type": "object", "properties": { "message": { "type": "string", "description": "Error overview." } }, "required": [ "message" ] } } } }, "#/components/responses/AuthorizationException": { "description": "Authorization error", "content": { "application/json": { "schema": { "type": "object", "properties": { "message": { "type": "string", "description": "Error overview." } }, "required": [ "message" ] } } } }, "#/components/responses/ValidationException": { "description": "Validation error", "content": { "application/json": { "schema": { "type": "object", "properties": { "message": { "type": "string", "description": "Errors overview." }, "errors": { "type": "object", "description": "A detailed description of each field that failed validation.", "additionalProperties": { "type": "array", "items": { "type": "string" } } } }, "required": [ "message", "errors" ] } } } } } ``` --- # invoice.created > Sent when a finalized invoice is created, whether through the API, the app or a recurring invoice. The PDF is rendered asynchronously, so it may not exist yet when this event arrives; GET /invoices/{invoice}/download waits for it. Each event is attempted up to 3 times: the first delivery, then retries after 10 s and 100 s; only a 2xx response counts as success. The request times out after 10 seconds. ## Webhook event: POST invoice.created Sent when a finalized invoice is created, whether through the API, the app or a recurring invoice. The PDF is rendered asynchronously, so it may not exist yet when this event arrives; `GET /invoices/{invoice}/download` waits for it. Each event is attempted up to 3 times: the first delivery, then retries after 10 s and 100 s; only a 2xx response counts as success. The request times out after 10 seconds. ### Request and responses ```json { "servers": [ { "url": "https://app.fsaskaita.lt/api", "description": "Production" } ], "operation": { "tags": [ "Invoices" ], "operationId": "webhookInvoiceCreated", "summary": "invoice.created", "description": "Sent when a finalized invoice is created, whether through the API, the app or a recurring invoice. The PDF is rendered asynchronously, so it may not exist yet when this event arrives; `GET /invoices/{invoice}/download` waits for it. Each event is attempted up to 3 times: the first delivery, then retries after 10 s and 100 s; only a 2xx response counts as success. The request times out after 10 seconds.", "parameters": [ { "$ref": "#/components/parameters/webhookSignature" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "required": [ "event", "data" ], "properties": { "event": { "const": "invoice.created" }, "data": { "$ref": "#/components/schemas/Invoice" } } } } } }, "responses": { "2XX": { "description": "Return any 2xx status to acknowledge the delivery. Any other status or a timeout schedules a retry." } } }, "securitySchemes": { "bearerAuth": { "type": "http", "description": "Business token created in the app under Settings, Integrations, API. The token is scoped to exactly one business, has no expiry and is shown only once. Send it as `Authorization: Bearer ` together with `Accept: application/json`.", "scheme": "bearer" } } } ``` ### Referenced components ```json { "#/components/parameters/webhookSignature": { "name": "Signature", "in": "header", "required": true, "description": "Lowercase hex HMAC-SHA256 of the raw request body, keyed with the webhook's signing secret (`whsec_…`). Recompute it over the exact bytes received and compare with a constant-time function before trusting the payload. No timestamp or event-id header is sent.", "schema": { "type": "string", "pattern": "^[0-9a-f]{64}$" }, "example": "5f1c0d8f9a7e4b2c6d3e1f0a9b8c7d6e5f4a3b2c1d0e9f8a7b6c5d4e3f2a1b0c" }, "#/components/schemas/Invoice": { "type": "object", "properties": { "id": { "type": "string", "format": "uuid" }, "business_id": { "type": "string", "format": "uuid" }, "invoice_type": { "$ref": "#/components/schemas/InvoiceType" }, "series": { "type": "string" }, "invoice_number": { "type": "string", "description": "Zero-padded to three digits, e.g. `\"007\"`. Send it back padded or unpadded on update; both are accepted." }, "invoice_date": { "type": "string", "format": "date", "description": "Issue date, `Y-m-d`." }, "pay_until_date": { "type": [ "string", "null" ], "format": "date", "description": "Due date, `Y-m-d`." }, "language": { "$ref": "#/components/schemas/InvoiceLanguage" }, "subtotal": { "type": "number", "description": "Sum of the lines excluding VAT." }, "vat": { "type": "number" }, "total_incl_vat": { "type": "number" }, "currency": { "type": "string" }, "payment_status": { "$ref": "#/components/schemas/PaymentStatus" }, "notes": { "type": [ "string", "null" ] }, "share_link": { "type": "string", "format": "uri", "description": "Public link to the invoice; anyone with the link can view it." }, "seller": { "type": "object", "properties": { "business_type": { "$ref": "#/components/schemas/BusinessType" }, "first_name": { "type": [ "string", "null" ] }, "last_name": { "type": [ "string", "null" ] }, "company_name": { "type": [ "string", "null" ] }, "company_code": { "type": [ "string", "null" ] }, "individual_activity_id": { "type": [ "string", "null" ] }, "vat_code": { "type": [ "string", "null" ] }, "address": { "type": [ "string", "null" ] }, "email": { "type": [ "string", "null" ] }, "phone": { "type": [ "string", "null" ] }, "custom_fields": { "type": "array", "items": { "type": "object", "properties": { "label": { "type": "string" }, "value": { "type": "string" } }, "required": [ "label", "value" ] } } }, "required": [ "business_type", "first_name", "last_name", "company_name", "company_code", "individual_activity_id", "vat_code", "address", "email", "phone", "custom_fields" ] }, "buyer": { "type": "object", "properties": { "type": { "type": "string", "description": "`person` sent on input is returned as `individual`.", "enum": [ "company", "individual" ] }, "first_name": { "type": [ "string", "null" ] }, "last_name": { "type": [ "string", "null" ] }, "company_name": { "type": [ "string", "null" ] }, "company_code": { "type": [ "string", "null" ] }, "individual_activity_id": { "type": [ "string", "null" ] }, "vat_code": { "type": [ "string", "null" ] }, "address": { "type": [ "string", "null" ] }, "email": { "type": [ "string", "null" ] }, "phone": { "type": [ "string", "null" ] } }, "required": [ "type", "first_name", "last_name", "company_name", "company_code", "individual_activity_id", "vat_code", "address", "email", "phone" ] }, "items": { "type": "array", "items": { "$ref": "#/components/schemas/InvoiceItem" } }, "payment_options": { "type": "array", "items": { "$ref": "#/components/schemas/PaymentOption" } }, "created_at": { "type": "integer", "description": "Unix timestamp, seconds." }, "updated_at": { "type": "integer", "description": "Unix timestamp, seconds." } }, "required": [ "id", "business_id", "invoice_type", "series", "invoice_number", "invoice_date", "pay_until_date", "language", "subtotal", "vat", "total_incl_vat", "currency", "payment_status", "notes", "share_link", "seller", "buyer", "items", "payment_options", "created_at", "updated_at" ], "title": "Invoice" }, "#/components/schemas/InvoiceType": { "type": "string", "description": "The three `*vat_invoice` types require `vat_percentage` on every line and, when `seller` is sent, `seller.vat_code`.\n", "enum": [ "regular_invoice", "vat_invoice", "preliminary_invoice", "preliminary_vat_invoice", "credit_invoice", "credit_vat_invoice" ], "title": "InvoiceType" }, "#/components/schemas/InvoiceLanguage": { "type": "string", "description": "Language of the PDF and the public share page.\n", "enum": [ "en", "lt", "es", "de", "fr" ], "title": "InvoiceLanguage" }, "#/components/schemas/PaymentStatus": { "type": "string", "enum": [ "not_paid", "paid" ], "title": "PaymentStatus" }, "#/components/schemas/BusinessType": { "type": "string", "description": "Every type except `individual_activity` is a company.\n", "enum": [ "small_partnership", "individual_activity", "private_limited_liability_company", "sole_proprietorship", "public_institution", "association", "joint_stock_company" ], "title": "BusinessType" }, "#/components/schemas/InvoiceItem": { "type": "object", "properties": { "id": { "type": "string", "format": "uuid" }, "name": { "type": "string" }, "price": { "type": "number" }, "vat_percentage": { "type": [ "number", "null" ] }, "quantity": { "type": "number" }, "units": { "type": "string" } }, "required": [ "id", "name", "price", "vat_percentage", "quantity", "units" ], "title": "InvoiceItem" }, "#/components/schemas/PaymentOption": { "type": "object", "properties": { "type": { "$ref": "#/components/schemas/PaymentOptionType" }, "bank_account": { "type": [ "string", "null" ] }, "bank_name": { "type": [ "string", "null" ] }, "routing_or_sort_number": { "type": [ "string", "null" ] }, "swift_bic_code": { "type": [ "string", "null" ] }, "fields": { "type": "array", "items": { "$ref": "#/components/schemas/LabelValue" } } }, "required": [ "type", "fields" ], "title": "PaymentOption" }, "#/components/schemas/PaymentOptionType": { "type": "string", "description": "`bank` carries the bank account fields; `other` carries free-form label/value `fields`.\n", "enum": [ "bank", "other" ], "title": "PaymentOptionType" }, "#/components/schemas/LabelValue": { "type": "object", "properties": { "label": { "type": "string" }, "value": { "type": "string" } }, "required": [ "label", "value" ], "title": "LabelValue" } } ``` --- # invoice.deleted > Sent when a finalized invoice is deleted. The payload contains only the id of the deleted invoice. Each event is attempted up to 3 times: the first delivery, then retries after 10 s and 100 s; only a 2xx response counts as success. The request times out after 10 seconds. ## Webhook event: POST invoice.deleted Sent when a finalized invoice is deleted. The payload contains only the id of the deleted invoice. Each event is attempted up to 3 times: the first delivery, then retries after 10 s and 100 s; only a 2xx response counts as success. The request times out after 10 seconds. ### Request and responses ```json { "servers": [ { "url": "https://app.fsaskaita.lt/api", "description": "Production" } ], "operation": { "tags": [ "Invoices" ], "operationId": "webhookInvoiceDeleted", "summary": "invoice.deleted", "description": "Sent when a finalized invoice is deleted. The payload contains only the id of the deleted invoice. Each event is attempted up to 3 times: the first delivery, then retries after 10 s and 100 s; only a 2xx response counts as success. The request times out after 10 seconds.", "parameters": [ { "$ref": "#/components/parameters/webhookSignature" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "required": [ "event", "data" ], "properties": { "event": { "const": "invoice.deleted" }, "data": { "$ref": "#/components/schemas/DeletedResource" } } } } } }, "responses": { "2XX": { "description": "Return any 2xx status to acknowledge the delivery. Any other status or a timeout schedules a retry." } } }, "securitySchemes": { "bearerAuth": { "type": "http", "description": "Business token created in the app under Settings, Integrations, API. The token is scoped to exactly one business, has no expiry and is shown only once. Send it as `Authorization: Bearer ` together with `Accept: application/json`.", "scheme": "bearer" } } } ``` ### Referenced components ```json { "#/components/parameters/webhookSignature": { "name": "Signature", "in": "header", "required": true, "description": "Lowercase hex HMAC-SHA256 of the raw request body, keyed with the webhook's signing secret (`whsec_…`). Recompute it over the exact bytes received and compare with a constant-time function before trusting the payload. No timestamp or event-id header is sent.", "schema": { "type": "string", "pattern": "^[0-9a-f]{64}$" }, "example": "5f1c0d8f9a7e4b2c6d3e1f0a9b8c7d6e5f4a3b2c1d0e9f8a7b6c5d4e3f2a1b0c" }, "#/components/schemas/DeletedResource": { "type": "object", "description": "Identifies a resource that no longer exists.", "required": [ "id" ], "properties": { "id": { "type": "string", "format": "uuid" } } } } ``` --- # invoice.updated > Sent when an invoice is replaced, when its payment status changes (including a Stripe payment), or after any other save. Each event is attempted up to 3 times: the first delivery, then retries after 10 s and 100 s; only a 2xx response counts as success. The request times out after 10 seconds. ## Webhook event: POST invoice.updated Sent when an invoice is replaced, when its payment status changes (including a Stripe payment), or after any other save. Each event is attempted up to 3 times: the first delivery, then retries after 10 s and 100 s; only a 2xx response counts as success. The request times out after 10 seconds. ### Request and responses ```json { "servers": [ { "url": "https://app.fsaskaita.lt/api", "description": "Production" } ], "operation": { "tags": [ "Invoices" ], "operationId": "webhookInvoiceUpdated", "summary": "invoice.updated", "description": "Sent when an invoice is replaced, when its payment status changes (including a Stripe payment), or after any other save. Each event is attempted up to 3 times: the first delivery, then retries after 10 s and 100 s; only a 2xx response counts as success. The request times out after 10 seconds.", "parameters": [ { "$ref": "#/components/parameters/webhookSignature" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "required": [ "event", "data" ], "properties": { "event": { "const": "invoice.updated" }, "data": { "$ref": "#/components/schemas/Invoice" } } } } } }, "responses": { "2XX": { "description": "Return any 2xx status to acknowledge the delivery. Any other status or a timeout schedules a retry." } } }, "securitySchemes": { "bearerAuth": { "type": "http", "description": "Business token created in the app under Settings, Integrations, API. The token is scoped to exactly one business, has no expiry and is shown only once. Send it as `Authorization: Bearer ` together with `Accept: application/json`.", "scheme": "bearer" } } } ``` ### Referenced components ```json { "#/components/parameters/webhookSignature": { "name": "Signature", "in": "header", "required": true, "description": "Lowercase hex HMAC-SHA256 of the raw request body, keyed with the webhook's signing secret (`whsec_…`). Recompute it over the exact bytes received and compare with a constant-time function before trusting the payload. No timestamp or event-id header is sent.", "schema": { "type": "string", "pattern": "^[0-9a-f]{64}$" }, "example": "5f1c0d8f9a7e4b2c6d3e1f0a9b8c7d6e5f4a3b2c1d0e9f8a7b6c5d4e3f2a1b0c" }, "#/components/schemas/Invoice": { "type": "object", "properties": { "id": { "type": "string", "format": "uuid" }, "business_id": { "type": "string", "format": "uuid" }, "invoice_type": { "$ref": "#/components/schemas/InvoiceType" }, "series": { "type": "string" }, "invoice_number": { "type": "string", "description": "Zero-padded to three digits, e.g. `\"007\"`. Send it back padded or unpadded on update; both are accepted." }, "invoice_date": { "type": "string", "format": "date", "description": "Issue date, `Y-m-d`." }, "pay_until_date": { "type": [ "string", "null" ], "format": "date", "description": "Due date, `Y-m-d`." }, "language": { "$ref": "#/components/schemas/InvoiceLanguage" }, "subtotal": { "type": "number", "description": "Sum of the lines excluding VAT." }, "vat": { "type": "number" }, "total_incl_vat": { "type": "number" }, "currency": { "type": "string" }, "payment_status": { "$ref": "#/components/schemas/PaymentStatus" }, "notes": { "type": [ "string", "null" ] }, "share_link": { "type": "string", "format": "uri", "description": "Public link to the invoice; anyone with the link can view it." }, "seller": { "type": "object", "properties": { "business_type": { "$ref": "#/components/schemas/BusinessType" }, "first_name": { "type": [ "string", "null" ] }, "last_name": { "type": [ "string", "null" ] }, "company_name": { "type": [ "string", "null" ] }, "company_code": { "type": [ "string", "null" ] }, "individual_activity_id": { "type": [ "string", "null" ] }, "vat_code": { "type": [ "string", "null" ] }, "address": { "type": [ "string", "null" ] }, "email": { "type": [ "string", "null" ] }, "phone": { "type": [ "string", "null" ] }, "custom_fields": { "type": "array", "items": { "type": "object", "properties": { "label": { "type": "string" }, "value": { "type": "string" } }, "required": [ "label", "value" ] } } }, "required": [ "business_type", "first_name", "last_name", "company_name", "company_code", "individual_activity_id", "vat_code", "address", "email", "phone", "custom_fields" ] }, "buyer": { "type": "object", "properties": { "type": { "type": "string", "description": "`person` sent on input is returned as `individual`.", "enum": [ "company", "individual" ] }, "first_name": { "type": [ "string", "null" ] }, "last_name": { "type": [ "string", "null" ] }, "company_name": { "type": [ "string", "null" ] }, "company_code": { "type": [ "string", "null" ] }, "individual_activity_id": { "type": [ "string", "null" ] }, "vat_code": { "type": [ "string", "null" ] }, "address": { "type": [ "string", "null" ] }, "email": { "type": [ "string", "null" ] }, "phone": { "type": [ "string", "null" ] } }, "required": [ "type", "first_name", "last_name", "company_name", "company_code", "individual_activity_id", "vat_code", "address", "email", "phone" ] }, "items": { "type": "array", "items": { "$ref": "#/components/schemas/InvoiceItem" } }, "payment_options": { "type": "array", "items": { "$ref": "#/components/schemas/PaymentOption" } }, "created_at": { "type": "integer", "description": "Unix timestamp, seconds." }, "updated_at": { "type": "integer", "description": "Unix timestamp, seconds." } }, "required": [ "id", "business_id", "invoice_type", "series", "invoice_number", "invoice_date", "pay_until_date", "language", "subtotal", "vat", "total_incl_vat", "currency", "payment_status", "notes", "share_link", "seller", "buyer", "items", "payment_options", "created_at", "updated_at" ], "title": "Invoice" }, "#/components/schemas/InvoiceType": { "type": "string", "description": "The three `*vat_invoice` types require `vat_percentage` on every line and, when `seller` is sent, `seller.vat_code`.\n", "enum": [ "regular_invoice", "vat_invoice", "preliminary_invoice", "preliminary_vat_invoice", "credit_invoice", "credit_vat_invoice" ], "title": "InvoiceType" }, "#/components/schemas/InvoiceLanguage": { "type": "string", "description": "Language of the PDF and the public share page.\n", "enum": [ "en", "lt", "es", "de", "fr" ], "title": "InvoiceLanguage" }, "#/components/schemas/PaymentStatus": { "type": "string", "enum": [ "not_paid", "paid" ], "title": "PaymentStatus" }, "#/components/schemas/BusinessType": { "type": "string", "description": "Every type except `individual_activity` is a company.\n", "enum": [ "small_partnership", "individual_activity", "private_limited_liability_company", "sole_proprietorship", "public_institution", "association", "joint_stock_company" ], "title": "BusinessType" }, "#/components/schemas/InvoiceItem": { "type": "object", "properties": { "id": { "type": "string", "format": "uuid" }, "name": { "type": "string" }, "price": { "type": "number" }, "vat_percentage": { "type": [ "number", "null" ] }, "quantity": { "type": "number" }, "units": { "type": "string" } }, "required": [ "id", "name", "price", "vat_percentage", "quantity", "units" ], "title": "InvoiceItem" }, "#/components/schemas/PaymentOption": { "type": "object", "properties": { "type": { "$ref": "#/components/schemas/PaymentOptionType" }, "bank_account": { "type": [ "string", "null" ] }, "bank_name": { "type": [ "string", "null" ] }, "routing_or_sort_number": { "type": [ "string", "null" ] }, "swift_bic_code": { "type": [ "string", "null" ] }, "fields": { "type": "array", "items": { "$ref": "#/components/schemas/LabelValue" } } }, "required": [ "type", "fields" ], "title": "PaymentOption" }, "#/components/schemas/PaymentOptionType": { "type": "string", "description": "`bank` carries the bank account fields; `other` carries free-form label/value `fields`.\n", "enum": [ "bank", "other" ], "title": "PaymentOptionType" }, "#/components/schemas/LabelValue": { "type": "object", "properties": { "label": { "type": "string" }, "value": { "type": "string" } }, "required": [ "label", "value" ], "title": "LabelValue" } } ``` --- # Get the business profile > Returns the business the token is scoped to. Companies include company_name and company_code; individual activities include first_name, last_name and individual_activity_id. ## GET /profile Returns the business the token is scoped to. Companies include `company_name` and `company_code`; individual activities include `first_name`, `last_name` and `individual_activity_id`. ### Request and responses ```json { "servers": [ { "url": "https://app.fsaskaita.lt/api", "description": "Production" } ], "security": [ { "bearerAuth": [] } ], "operation": { "operationId": "getProfile", "description": "Returns the business the token is scoped to. Companies include `company_name` and `company_code`;\nindividual activities include `first_name`, `last_name` and `individual_activity_id`.", "summary": "Get the business profile", "tags": [ "Profile" ], "responses": { "200": { "description": "`Profile`", "content": { "application/json": { "schema": { "type": "object", "properties": { "data": { "$ref": "#/components/schemas/Profile" } }, "required": [ "data" ] } } } }, "401": { "$ref": "#/components/responses/AuthenticationException" }, "429": { "description": "Rate limit exceeded. The limit is 60 requests per minute per business, shared across all of its tokens. Wait `Retry-After` seconds before retrying.", "content": { "application/json": { "schema": { "type": "object", "properties": { "message": { "type": "string" } }, "required": [ "message" ] } } }, "headers": { "Retry-After": { "description": "Seconds to wait before retrying.", "schema": { "type": "integer" } }, "X-RateLimit-Limit": { "description": "Requests allowed per minute.", "schema": { "type": "integer" } }, "X-RateLimit-Remaining": { "description": "Requests left in the current minute.", "schema": { "type": "integer" } }, "X-RateLimit-Reset": { "description": "Unix timestamp at which the window resets.", "schema": { "type": "integer" } } } } } }, "securitySchemes": { "bearerAuth": { "type": "http", "description": "Business token created in the app under Settings, Integrations, API. The token is scoped to exactly one business, has no expiry and is shown only once. Send it as `Authorization: Bearer ` together with `Accept: application/json`.", "scheme": "bearer" } } } ``` ### Referenced components ```json { "#/components/schemas/Profile": { "type": "object", "properties": { "business_id": { "type": "string", "format": "uuid" }, "business_title": { "type": "string" }, "business_type": { "$ref": "#/components/schemas/BusinessType" }, "address": { "type": [ "string", "null" ] }, "vat_code": { "type": [ "string", "null" ] }, "company_name": { "type": [ "string", "null" ], "description": "Present when the business is a company." }, "company_code": { "type": [ "string", "null" ], "description": "Present when the business is a company." }, "individual_activity_id": { "type": [ "string", "null" ], "description": "Present when `business_type` is `individual_activity`." }, "first_name": { "type": [ "string", "null" ], "description": "Present when `business_type` is `individual_activity`." }, "last_name": { "type": [ "string", "null" ], "description": "Present when `business_type` is `individual_activity`." } }, "required": [ "business_id", "business_title", "business_type", "address", "vat_code" ], "title": "Profile" }, "#/components/schemas/BusinessType": { "type": "string", "description": "Every type except `individual_activity` is a company.\n", "enum": [ "small_partnership", "individual_activity", "private_limited_liability_company", "sole_proprietorship", "public_institution", "association", "joint_stock_company" ], "title": "BusinessType" }, "#/components/responses/AuthenticationException": { "description": "Unauthenticated", "content": { "application/json": { "schema": { "type": "object", "properties": { "message": { "type": "string", "description": "Error overview." } }, "required": [ "message" ] } } } } } ```