Despesas (expenses)
O recurso expenses expõe as despesas do seu financeiro. Cada despesa traz os
valores (original, desconto e final), os vínculos com categoria, fornecedor,
centro de custo, conta bancária e cartão, as datas de vencimento e pagamento,
tags livres e as informações de recorrência e parcelas. É um recurso de leitura
e escrita.
| Módulo | despesas |
| Escopos | expenses:read para leitura, expenses:write para escrita |
| Operações | leitura e escrita |
Sem o módulo no contrato, a resposta é 403 module_not_enabled. Sem o escopo na
chave, é 403 insufficient_scope. expenses:write concede também a leitura.
Endpoints
Seção intitulada “Endpoints”| Método | Endpoint | Escopo | Descrição |
|---|---|---|---|
GET | /v1/expenses | expenses:read | Lista despesas, com paginação por cursor |
GET | /v1/expenses/{id} | expenses:read | Busca uma despesa pelo id, com ?include=recurring opcional |
POST | /v1/expenses | expenses:write | Cria uma despesa e responde 201 |
PATCH | /v1/expenses/{id} | expenses:write | Atualização parcial: envie só os campos que mudam |
DELETE | /v1/expenses/{id} | expenses:write | Desativa a despesa e responde 204 |
| Campo | Tipo | Descrição |
|---|---|---|
id | uuid | Identificador da despesa |
expense_number | string | Número da despesa. Se omitido no POST, é gerado como API-<timestamp>-<sufixo> |
expense_type | string | Tipo da despesa. Obrigatório na criação |
description | string | Descrição da despesa. Obrigatório na criação |
original_amount | number | Valor original, maior ou igual a zero. Obrigatório na criação |
discount_amount | number | null | Desconto aplicado, maior ou igual a zero |
final_amount | number | Valor final, maior ou igual a zero. Obrigatório na criação |
category_id | uuid | null | Categoria da despesa |
subcategory_id | uuid | null | Subcategoria da despesa |
cost_center_id | uuid | null | Centro de custo |
supplier_id | uuid | null | Fornecedor vinculado |
payment_method | string | null | Forma de pagamento, por exemplo pix, bank_slip ou credit_card |
bank_account_id | uuid | null | Conta bancária usada no pagamento |
credit_card_id | uuid | null | Cartão de crédito usado no pagamento |
check_number | string | null | Número do cheque, quando aplicável |
installments | integer | null | Quantidade de parcelas, maior ou igual a 1 |
status | string | null | Status da despesa, por exemplo pending ou paid |
payment_date | date (YYYY-MM-DD) | null | Data do pagamento |
due_date | date (YYYY-MM-DD) | null | Data de vencimento |
notes | string | null | Observações livres |
tags | string[] | null | Tags livres para organização |
is_recurring | boolean | null | Indica se a despesa veio de uma recorrência |
is_active | boolean | null | false quando a despesa foi desativada |
payment_reference | string | null | Referência externa do pagamento |
recurring_expense_id | uuid | null | Recorrência que gerou esta despesa |
installment_number | integer | null | Número desta parcela. Somente leitura |
total_installments | integer | null | Total de parcelas da série. Somente leitura |
created_at | timestamp | Data de criação, em ISO 8601 |
updated_at | timestamp | null | Última atualização, em ISO 8601 |
recurring | object | null | Recorrência embutida. Só aparece com ?include=recurring |
No POST, os campos obrigatórios são expense_type, description,
original_amount e final_amount. No PATCH, todos os campos aceitos no POST
são opcionais: envie apenas o que quer alterar. installment_number e
total_installments não são aceitos na escrita.
Nos GET, o parâmetro fields devolve campos parciais:
?fields=id,description,final_amount,due_date,status.
Filtros e ordenação
Seção intitulada “Filtros e ordenação”A sintaxe do filtro é filter[campo][operador]=valor, com os operadores eq,
neq, gt, gte, lt, lte, in, nin, ilike e is_null. Os detalhes
estão em Paginação, filtros e ordenação.
| Campo | Exemplo |
|---|---|
expense_number | filter[expense_number][eq]=DESP-2026-0142 |
expense_type | filter[expense_type][eq]=fixed |
description | filter[description][ilike]=%aluguel% |
category_id | filter[category_id][eq]=3f2a7b1c-8d9e-4f0a-b1c2-d3e4f5a6b7c8 |
subcategory_id | filter[subcategory_id][eq]=1c2b3a4d-5e6f-4a7b-8c9d-0e1f2a3b4c5d |
cost_center_id | filter[cost_center_id][eq]=5d4e3c2b-1a0f-4e9d-8c7b-6a5f4e3d2c1b |
supplier_id | filter[supplier_id][eq]=9a0f8e7d-6c5b-4a3f-2e1d-0c9b8a7f6e5d |
payment_method | filter[payment_method][in]=pix,bank_slip |
bank_account_id | filter[bank_account_id][eq]=0d4f2c9a-1b7e-4c3d-9a52-8e6f1b2c3d4e |
credit_card_id | filter[credit_card_id][is_null]=true |
status | filter[status][eq]=pending |
payment_date | filter[payment_date][gte]=2026-07-01 |
due_date | filter[due_date][lte]=2026-07-31 |
is_recurring | filter[is_recurring][eq]=true |
is_active | filter[is_active][eq]=true |
created_at | filter[created_at][gte]=2026-01-01 |
A ordenação padrão é -created_at, da mais recente para a mais antiga. Os campos
aceitos em sort são created_at, updated_at, payment_date e due_date.
Um exemplo de combinação, para as despesas pendentes e ativas que vencem em julho de 2026:
curl -G "$LIGGA_BASE/v1/expenses" \ -H "Authorization: Bearer $LIGGA_API_KEY" \ --data-urlencode "filter[status][eq]=pending" \ --data-urlencode "filter[is_active][eq]=true" \ --data-urlencode "filter[due_date][gte]=2026-07-01" \ --data-urlencode "filter[due_date][lte]=2026-07-31" \ --data-urlencode "sort=due_date"Relações incluídas
Seção intitulada “Relações incluídas”GET /v1/expenses/{id} aceita ?include=recurring. Quando a despesa veio de uma
recorrência, ou seja, quando recurring_expense_id está preenchido, a resposta
embute o objeto recurring com os dados da série. Caso contrário, recurring
vem como null.
Campo de recurring | Tipo |
|---|---|
id | uuid |
expense_template_id | uuid |
recurrence_frequency | string, por exemplo monthly |
recurrence_interval | integer |
start_date | date |
end_date | date | null |
next_generation_date | date |
last_generated_expense_id | uuid | null |
is_active | boolean | null |
created_at | timestamp |
Exemplos
Seção intitulada “Exemplos”Os exemplos abaixo supõem as duas variáveis de ambiente do Início rápido:
export LIGGA_API_KEY='ligga_live_…'export LIGGA_BASE='https://api.ligga.app/functions/v1/api'curl -G "$LIGGA_BASE/v1/expenses" \ -H "Authorization: Bearer $LIGGA_API_KEY" \ --data-urlencode "limit=2" \ --data-urlencode "sort=-due_date" \ --data-urlencode "filter[is_active][eq]=true"{ "data": [ { "id": "2e6c1a9b-4d7f-4b3a-9c25-8f0e1d2c3b4a", "expense_number": "DESP-2026-0142", "expense_type": "fixed", "description": "Aluguel da loja, julho de 2026", "original_amount": 3500, "discount_amount": null, "final_amount": 3500, "category_id": "3f2a7b1c-8d9e-4f0a-b1c2-d3e4f5a6b7c8", "subcategory_id": null, "cost_center_id": "5d4e3c2b-1a0f-4e9d-8c7b-6a5f4e3d2c1b", "supplier_id": "9a0f8e7d-6c5b-4a3f-2e1d-0c9b8a7f6e5d", "payment_method": "pix", "bank_account_id": "0d4f2c9a-1b7e-4c3d-9a52-8e6f1b2c3d4e", "credit_card_id": null, "check_number": null, "installments": null, "status": "pending", "payment_date": null, "due_date": "2026-07-10", "notes": "Reajuste anual previsto para agosto.", "tags": ["aluguel", "loja-centro"], "is_recurring": true, "is_active": true, "payment_reference": null, "recurring_expense_id": "b8c7d6e5-f4a3-4b2c-9d1e-0f9a8b7c6d5e", "installment_number": null, "total_installments": null, "created_at": "2026-07-01T08:00:12.334Z", "updated_at": null }, { "id": "7f1e2d3c-4b5a-4968-8776-655443322110", "expense_number": "API-1751925600000-a1b2c3", "expense_type": "variable", "description": "Ração premium, reposição de estoque", "original_amount": 1280.5, "discount_amount": 80.5, "final_amount": 1200, "category_id": "3f2a7b1c-8d9e-4f0a-b1c2-d3e4f5a6b7c8", "subcategory_id": "1c2b3a4d-5e6f-4a7b-8c9d-0e1f2a3b4c5d", "cost_center_id": null, "supplier_id": "9a0f8e7d-6c5b-4a3f-2e1d-0c9b8a7f6e5d", "payment_method": "bank_slip", "bank_account_id": null, "credit_card_id": null, "check_number": null, "installments": 2, "status": "paid", "payment_date": "2026-07-03", "due_date": "2026-07-05", "notes": null, "tags": ["estoque"], "is_recurring": false, "is_active": true, "payment_reference": "NF-e 12345", "recurring_expense_id": null, "installment_number": 1, "total_installments": 2, "created_at": "2026-06-30T15:42:51.902Z", "updated_at": "2026-07-03T10:11:23.556Z" } ], "pagination": { "next_cursor": "eyJpZCI6IjdmMWUyZDNjLS4uLiIsInYiOiIyMDI2LTA3LTA1In0", "has_more": true, "limit": 2 }, "meta": { "request_id": "req_01JZXQ8V2K5M7N9P0R1S2T3U4V" }}O cursor da próxima página está em pagination.next_cursor. Repasse-o em
?cursor= enquanto has_more for true.
Buscar por id
Seção intitulada “Buscar por id”curl "$LIGGA_BASE/v1/expenses/2e6c1a9b-4d7f-4b3a-9c25-8f0e1d2c3b4a?include=recurring" \ -H "Authorization: Bearer $LIGGA_API_KEY"{ "data": { "id": "2e6c1a9b-4d7f-4b3a-9c25-8f0e1d2c3b4a", "expense_number": "DESP-2026-0142", "description": "Aluguel da loja, julho de 2026", "final_amount": 3500, "status": "pending", "due_date": "2026-07-10", "is_recurring": true, "is_active": true, "recurring_expense_id": "b8c7d6e5-f4a3-4b2c-9d1e-0f9a8b7c6d5e", "recurring": { "id": "b8c7d6e5-f4a3-4b2c-9d1e-0f9a8b7c6d5e", "expense_template_id": "a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d", "recurrence_frequency": "monthly", "recurrence_interval": 1, "start_date": "2026-01-10", "end_date": null, "next_generation_date": "2026-08-10", "last_generated_expense_id": "2e6c1a9b-4d7f-4b3a-9c25-8f0e1d2c3b4a", "is_active": true, "created_at": "2026-01-05T09:12:00.000Z" } }, "meta": { "request_id": "req_01JZY7B2C3D4E5F6G7H8J9K0L1" }}O objeto acima está resumido para caber na página. A resposta real traz todos os campos da tabela de Campos.
POST é uma operação de escrita. Envie o cabeçalho
Idempotency-Key para poder fazer uma nova tentativa
sem duplicar o lançamento.
curl -X POST "$LIGGA_BASE/v1/expenses" \ -H "Authorization: Bearer $LIGGA_API_KEY" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{ "expense_type": "variable", "description": "Manutenção do ar-condicionado", "original_amount": 450, "discount_amount": 50, "final_amount": 400, "supplier_id": "9a0f8e7d-6c5b-4a3f-2e1d-0c9b8a7f6e5d", "payment_method": "pix", "due_date": "2026-07-20", "status": "pending", "tags": ["manutencao"] }'A resposta é 201 Created. Como expense_number não foi enviado, a API gerou um:
{ "data": { "id": "c4d5e6f7-a8b9-4c0d-9e1f-2a3b4c5d6e7f", "expense_number": "API-1752148800000-f3e2d1", "expense_type": "variable", "description": "Manutenção do ar-condicionado", "original_amount": 450, "discount_amount": 50, "final_amount": 400, "category_id": null, "subcategory_id": null, "cost_center_id": null, "supplier_id": "9a0f8e7d-6c5b-4a3f-2e1d-0c9b8a7f6e5d", "payment_method": "pix", "bank_account_id": null, "credit_card_id": null, "check_number": null, "installments": null, "status": "pending", "payment_date": null, "due_date": "2026-07-20", "notes": null, "tags": ["manutencao"], "is_recurring": null, "is_active": true, "payment_reference": null, "recurring_expense_id": null, "installment_number": null, "total_installments": null, "created_at": "2026-07-10T12:00:03.118Z", "updated_at": null }, "meta": { "request_id": "req_01JZY0A1B2C3D4E5F6G7H8J9K0" }}Atualizar
Seção intitulada “Atualizar”O PATCH é parcial: os campos que você não enviar continuam como estão. Para
marcar a despesa como paga, bastam dois:
curl -X PATCH "$LIGGA_BASE/v1/expenses/2e6c1a9b-4d7f-4b3a-9c25-8f0e1d2c3b4a" \ -H "Authorization: Bearer $LIGGA_API_KEY" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{ "status": "paid", "payment_date": "2026-07-08" }'A resposta é 200 OK com a despesa já atualizada, no envelope de item.
Desativar
Seção intitulada “Desativar”curl -X DELETE "$LIGGA_BASE/v1/expenses/2e6c1a9b-4d7f-4b3a-9c25-8f0e1d2c3b4a" \ -H "Authorization: Bearer $LIGGA_API_KEY"A resposta é 204 No Content, sem corpo. A despesa passa a ter
is_active: false.
Erros comuns
Seção intitulada “Erros comuns”| HTTP | type | Quando acontece |
|---|---|---|
| 401 | invalid_token | Cabeçalho Authorization ausente ou chave inexistente |
| 401 | token_revoked | A chave foi revogada |
| 401 | token_expired | A chave passou da data de expiração |
| 403 | module_not_enabled | Módulo despesas fora do contrato |
| 403 | insufficient_scope | Chave sem expenses:read na leitura ou expenses:write na escrita |
| 404 | not_found | id inexistente ou pertencente a outra conta |
| 409 | idempotency_conflict | Mesma Idempotency-Key reaproveitada com corpo diferente |
| 422 | validation | Corpo inválido, como final_amount negativo ou data fora do formato YYYY-MM-DD; filtro, operador ou cursor não aceito |
| 429 | rate-limit-exceeded | Limite de requisições do plano excedido |
O corpo do erro traz type, title, status e request_id. O formato completo
está em Erros.
Veja também
Seção intitulada “Veja também”- Fornecedores (suppliers) — o destino de
supplier_id - Paginação, filtros e ordenação — cursor,
filter,sortefields - Idempotência — como repetir uma escrita com segurança
- Erros — catálogo completo e formato da resposta