Kiipu · invoicing v1 current
kiipu. invoice_ proposed
Prepares an invoice as a DRAFT for a client named by name, with its lines and taxes. Does NOT issue it, does NOT number it and does NOT count as debt: a person reviews and issues it in Kiipu. Does not create the client if it does not exist.
Last updated
POST /api/v1/actions/kiipu.invoice_proposed- Key scope
kiipu.invoice_proposed@1- Workspace permission
api.kiipu.invoice_proposedoff by default
Two permissions, not one
Both are needed: a key with that scope, and the workspace owner having switched the permission on. Holding the key is not enough — they are two decisions made by different people.
Request
| field | type | rules | |
|---|---|---|---|
client | string | required | min 1 · max 200 |
lines | object[] | required | |
dueAt | string (date-time) | optional | |
series | string | optional | ^[A-Za-z0-9-]{1,12}$ |
lines[]
| field | type | rules | |
|---|---|---|---|
concept | string | required | min 1 · max 500 |
quantity | string | required | ^(?:0*[1-9]\d*(?:\.\d{1,3})?|0+\.(?:[1-9]\d{0,2}|0[1-9]\d?|00[1-9]))$ |
unitPriceUsd | string | required | ^\d+(\.\d{1,2})?$ |
tax | "exempt" | "itbms_7" | "itbms_10" | "itbms_15" | optional | = "exempt" |
Response — output when status is done
| field | type | rules | |
|---|---|---|---|
invoiceId | string | required | |
clientId | string | required | |
clientName | string | required | |
status | "draft" | required | |
subtotalUsd | string | required | |
taxUsd | string | required | |
totalUsd | string | required | |
dueAt | string | required | |
series | string | required | |
issueAt | "/kiipu/facturas" | required |
Example
# One request, one idempotency key: retrying with the same key never runs twice.
curl -X POST https://niiko.org/api/v1/actions/kiipu.invoice_proposed \
-H "Authorization: Bearer nk_…" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{
"client": "…",
"lines": [
{
"concept": "…",
"quantity": "1",
"unitPriceUsd": "1"
}
]
}'
# 200 → done · 202 → pending_approval (a person signs later) · 4xx → refused, with a named reasonWhy it may refuse
Each reason names who can fix it and how. With reason stale, detail.message says what to do.
cliente_no_encontradocliente_ambiguodemasiados_clientessin_permiso
In the clients
| @vorluno/niiko-sdk | niiko.proposedInvoice() |
| niiko (Python) | niiko.proposed_invoice() |
| niiko-cli | niiko run kiipu.invoice_proposed |
| n8n-nodes-niiko | kiipuInvoiceProposed |
| niiko-mcp-server | kiipu_invoice_proposed |