# 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<String, String> 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<String, String> 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<String> 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<InputStream> 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.
