Pular para o conteúdo

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ódulodespesas
Escoposexpenses:read para leitura, expenses:write para escrita
Operaçõesleitura 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.

MétodoEndpointEscopoDescrição
GET/v1/expensesexpenses:readLista despesas, com paginação por cursor
GET/v1/expenses/{id}expenses:readBusca uma despesa pelo id, com ?include=recurring opcional
POST/v1/expensesexpenses:writeCria uma despesa e responde 201
PATCH/v1/expenses/{id}expenses:writeAtualização parcial: envie só os campos que mudam
DELETE/v1/expenses/{id}expenses:writeDesativa a despesa e responde 204
CampoTipoDescrição
iduuidIdentificador da despesa
expense_numberstringNúmero da despesa. Se omitido no POST, é gerado como API-<timestamp>-<sufixo>
expense_typestringTipo da despesa. Obrigatório na criação
descriptionstringDescrição da despesa. Obrigatório na criação
original_amountnumberValor original, maior ou igual a zero. Obrigatório na criação
discount_amountnumber | nullDesconto aplicado, maior ou igual a zero
final_amountnumberValor final, maior ou igual a zero. Obrigatório na criação
category_iduuid | nullCategoria da despesa
subcategory_iduuid | nullSubcategoria da despesa
cost_center_iduuid | nullCentro de custo
supplier_iduuid | nullFornecedor vinculado
payment_methodstring | nullForma de pagamento, por exemplo pix, bank_slip ou credit_card
bank_account_iduuid | nullConta bancária usada no pagamento
credit_card_iduuid | nullCartão de crédito usado no pagamento
check_numberstring | nullNúmero do cheque, quando aplicável
installmentsinteger | nullQuantidade de parcelas, maior ou igual a 1
statusstring | nullStatus da despesa, por exemplo pending ou paid
payment_datedate (YYYY-MM-DD) | nullData do pagamento
due_datedate (YYYY-MM-DD) | nullData de vencimento
notesstring | nullObservações livres
tagsstring[] | nullTags livres para organização
is_recurringboolean | nullIndica se a despesa veio de uma recorrência
is_activeboolean | nullfalse quando a despesa foi desativada
payment_referencestring | nullReferência externa do pagamento
recurring_expense_iduuid | nullRecorrência que gerou esta despesa
installment_numberinteger | nullNúmero desta parcela. Somente leitura
total_installmentsinteger | nullTotal de parcelas da série. Somente leitura
created_attimestampData de criação, em ISO 8601
updated_attimestamp | nullÚltima atualização, em ISO 8601
recurringobject | nullRecorrê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.

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.

CampoExemplo
expense_numberfilter[expense_number][eq]=DESP-2026-0142
expense_typefilter[expense_type][eq]=fixed
descriptionfilter[description][ilike]=%aluguel%
category_idfilter[category_id][eq]=3f2a7b1c-8d9e-4f0a-b1c2-d3e4f5a6b7c8
subcategory_idfilter[subcategory_id][eq]=1c2b3a4d-5e6f-4a7b-8c9d-0e1f2a3b4c5d
cost_center_idfilter[cost_center_id][eq]=5d4e3c2b-1a0f-4e9d-8c7b-6a5f4e3d2c1b
supplier_idfilter[supplier_id][eq]=9a0f8e7d-6c5b-4a3f-2e1d-0c9b8a7f6e5d
payment_methodfilter[payment_method][in]=pix,bank_slip
bank_account_idfilter[bank_account_id][eq]=0d4f2c9a-1b7e-4c3d-9a52-8e6f1b2c3d4e
credit_card_idfilter[credit_card_id][is_null]=true
statusfilter[status][eq]=pending
payment_datefilter[payment_date][gte]=2026-07-01
due_datefilter[due_date][lte]=2026-07-31
is_recurringfilter[is_recurring][eq]=true
is_activefilter[is_active][eq]=true
created_atfilter[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:

Terminal window
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"

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 recurringTipo
iduuid
expense_template_iduuid
recurrence_frequencystring, por exemplo monthly
recurrence_intervalinteger
start_datedate
end_datedate | null
next_generation_datedate
last_generated_expense_iduuid | null
is_activeboolean | null
created_attimestamp

Os exemplos abaixo supõem as duas variáveis de ambiente do Início rápido:

Terminal window
export LIGGA_API_KEY='ligga_live_…'
export LIGGA_BASE='https://api.ligga.app/functions/v1/api'
Terminal window
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.

Terminal window
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.

Terminal window
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" }
}

O PATCH é parcial: os campos que você não enviar continuam como estão. Para marcar a despesa como paga, bastam dois:

Terminal window
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.

Terminal window
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.

HTTPtypeQuando acontece
401invalid_tokenCabeçalho Authorization ausente ou chave inexistente
401token_revokedA chave foi revogada
401token_expiredA chave passou da data de expiração
403module_not_enabledMódulo despesas fora do contrato
403insufficient_scopeChave sem expenses:read na leitura ou expenses:write na escrita
404not_foundid inexistente ou pertencente a outra conta
409idempotency_conflictMesma Idempotency-Key reaproveitada com corpo diferente
422validationCorpo inválido, como final_amount negativo ou data fora do formato YYYY-MM-DD; filtro, operador ou cursor não aceito
429rate-limit-exceededLimite de requisições do plano excedido

O corpo do erro traz type, title, status e request_id. O formato completo está em Erros.