Using the APIRequests and responses

Using the API

Requests and responses

How to shape requests to the API, which headers to send, and what successful responses look like for single resources, lists, creates, deletes and jobs.

Every endpoint follows the same rules for URLs, bodies, headers and responses. Learn them once and every page in this reference reads the same way. This page covers the request side, the success envelopes and the headers you will see. Errors have their own page, Errors.

URLs and methods

All paths start at the base URL https://api.freeinvoiceautomation.com/v1.

  • Resources are plural nouns: /documents, /clients, /items, /payments.
  • Actions that are not a plain create or update are sub-resources named after the action: POST /documents/{id}/send, POST /documents/{id}/void, POST /documents/{id}/credit-notes.
  • Business-owned resources use flat paths with a business_id field (proposed): in the body for writes and in the query for reads. If you can reach exactly one business, you may leave business_id out.
MethodUse
GETRead a resource or a list. Never changes anything.
POSTCreate a resource, or run an action such as send or void. POST /clients and POST /items with an existing id update that record (upsert).
PATCHPartial update. Send only the fields you want to change (JSON merge).
PUTReplace a whole sub-resource, such as a business's accepted payment methods.
DELETESoft delete. Returns 204 with no body.

Request bodies

  • JSON only, UTF-8. Send Content-Type: application/json. A body that is not valid JSON returns invalid_json (400).
  • Field names are snake_case.
  • Ids are uuid v7 strings.
  • Dates are YYYY-MM-DD; timestamps are RFC 3339 in UTC, such as 2027-01-04T10:15:00Z.
  • Money is a string of integer minor units plus a currency field. "unit_price_minor": "45000" with "currency": "USD" is 450.00 USD. Numbers with decimals are rejected. See Money and currencies.
  • File uploads (such as a CSV import or a logo) use multipart/form-data, as shown on the endpoint page.

Every input is validated before anything is saved. When a field is wrong you get validation_failed (422) with the list of problems in details.issues:

Validation error
{
  "error": {
    "code": "validation_failed",
    "message": "Some fields are not valid.",
    "details": {
      "issues": [
        { "path": ["lines", 0, "quantity"], "message": "Must be greater than 0" }
      ]
    },
    "request_id": "req_0193f2a2c0e0"
  }
}

A partial update

PATCH changes only the fields you send. Fields you leave out keep their values.

cURL
curl -X PATCH "https://api.freeinvoiceautomation.com/v1/documents/0193f2b4-5a6b-7c8d-9e0f-1a2b3c4d5e6f" \
  -H "Authorization: Bearer $FIA_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: 9a41c0de-update-due" \
  -d '{ "due_date": "2027-02-15" }'

A sent document is never edited in place. Updating it creates a new revision, so what your client received stays on record. See Revisions.

Request headers

HeaderWhenNotes
AuthorizationEvery authenticated callBearer <api key or MCP token>. See Authentication.
Content-TypeCalls with a bodyapplication/json, or multipart/form-data for uploads
Idempotency-KeyEvery write; required on creates, sends, payments, voids and credit notes from API keys and MCP clientsUp to 255 characters. See Idempotency.
FIA-Account-IdWeb app sessions only (proposed)Chooses the account when a person belongs to several. API keys never need it.

Success responses

A single resource

A single resource is wrapped in data:

Get an item (200)
{
  "data": {
    "id": "0193f2a1-7c4e-7b9a-9f10-3c2d1e0a4b51",
    "business_id": "0193f29e-11aa-7c3b-8d2e-5a6b7c8d9e0f",
    "name": "Logo design",
    "unit_price_minor": "45000",
    "currency": "USD",
    "created_at": "2027-01-04T09:12:44Z",
    "updated_at": "2027-01-04T09:12:44Z"
  }
}

A list

Lists return the page in data, plus next_cursor and has_more (proposed envelope). See Pagination and filters.

List items (200)
{
  "data": [ { "id": "0193f2a1-7c4e-7b9a-9f10-3c2d1e0a4b51", "name": "Logo design" } ],
  "next_cursor": null,
  "has_more": false
}

Status codes for success

StatusWhen
200 OKA read, an update, or an action that finished
201 CreatedA new resource; the Location header holds its URL
202 AcceptedWork that runs in the background: account exports, accounting backfills, bank statement imports, agent runs. The body carries the id of a job or resource that you poll.
204 No ContentA delete. There is no body.

Documents carry their totals

Documents always come back with the totals the server computed: subtotal_minor, discount_minor, tax_minor, total_minor, amount_paid_minor, amount_credited_minor and balance_minor, plus status and number. They also include links to related documents (credit notes, the estimate an invoice came from, a contract), the payment_schedule when there is one, and pay_url when a share link exists. Do not calculate totals yourself; read them from the response.

Response headers

HeaderMeaning
X-Request-IdThe id of this request (proposed name). The same value appears as request_id in errors. Quote it when you contact support.
Idempotent-Replayed: trueThe response is a stored copy of an earlier request with the same Idempotency-Key.
RateLimit-Limit, RateLimit-Remaining, RateLimit-ResetYour rate-limit budget (proposed names). See Rate limits.
Retry-AfterSent with 429 rate_limited: how many seconds to wait.
LocationSent with 201: the URL of the new resource.
DeprecationSent when an endpoint or field is scheduled for removal in a later major version (proposed).

Async jobs

Some work takes longer than a request should. These endpoints answer 202 Accepted at once with an id, and you fetch the result later:

Start an account export
curl -X POST "https://api.freeinvoiceautomation.com/v1/account/exports" \
  -H "Authorization: Bearer $FIA_API_KEY" \
  -H "Idempotency-Key: 4d2e8b10-export-jan"

Then poll GET /v1/account/exports/{id} until it is ready. For agent runs, poll Get an agent run, or subscribe to the agent_run.completed and agent_run.failed webhook events instead of polling.

What the API never returns

  • Secrets. Connection secrets, SMTP passwords, AI keys and webhook signing secrets are write-only. You can set or replace them, but no response contains them; at most you see the last four characters.
  • Other accounts' data. Records you cannot reach answer 404 not_found, the same as records that do not exist.
  • Card numbers. Card data never reaches our servers. Payments are taken on hosted checkout pages.