Skip to content

Using the REST API

The MoneyLights REST API lets your own systems read and maintain your organization’s data: transactions, vendors, clients, projects, categories and cashflow. You authenticate with an API key.

Send your key in the X-API-Key header:

GET /api/transactions HTTP/1.1
Host: api.moneylights.app
X-API-Key: ml_sk_<key-id>_<secret>

Authorization: ApiKey <key> also works. Authorization: Bearer <key> does not — Bearer belongs to the browser session. Never put the key in the URL: such requests are refused before they reach anything.

The complete, always-current list of what your key can reach is the public OpenAPI document:

GET https://api.moneylights.app/api/public/openapi.json

It is generated from the running application and lists exactly the published endpoints, each annotated with the scope it requires (x-required-scope). If this guide and that document say different things, trust the document. You can feed it to a client generator or import it into an API tool.

Only endpoints that were explicitly published are part of the public API. The guiding rule is enrich and maintain, never destroy:

  • You can list and filter transactions, assign them a category, vendor, client or project, split them across people (allocations), and create or update vendors, clients, projects and categories.
  • You cannot delete a vendor, client, project or category through the API. Removing a record other records point at is a decision a script should not make unattended — those actions live in the app.

Bank connections, billing, team management and API-key management are never reachable with a key, whatever scopes it holds.

Three limits apply, and a request must satisfy all of them:

PlanReads/min per keyWrites/min per keyRequests/min per organizationPer day, per organization
Team1203012010 000
Enterprise600150600100 000

The organization-wide per-minute limit is the one to design around. It is the same number as the per-key limit, so one key running flat out can consume the whole organization’s minute — adding keys does not buy throughput. If you have several integrations, spread their requests out over time.

Every response carries X-RateLimit-Limit and X-RateLimit-Remaining. A 429 carries Retry-After in seconds — honour it; retrying immediately can turn a short rate limit into an outage.

Refusals carry a stable code that your integration can act on. The ones you will actually meet:

CodeMeaning
api_key_invalidThe key is malformed or unknown, or its secret is wrong
api_key_expiredPast its expiry date — create a new key
api_key_revokedThe key was revoked, or the old secret was used after its rotation window closed
api_key_scope_missingThe key lacks the scope this endpoint needs
api_key_endpoint_not_publishedThe endpoint is not part of the public API
api_key_rate_limitedOver a limit — honour Retry-After

A request that sends no key gets a plain 401 with an empty body and no error code. If you see that, the key header was not sent.

GET /api/cashflow/overview takes an optional dateFrom and dateTo. If omitted, dateFrom defaults to 1 January of the current year and dateTo to today (both UTC). It returns 400, not an empty overview, when:

  • a date cannot be parsed (for example 2026-13-01);
  • dateFrom is after dateTo;
  • only dateTo is sent and it is earlier than the default start (1 January of the current UTC year) — send a dateFrom too;
  • only dateFrom is sent and it is later than today — send a dateTo too.
  • Your key reaches exactly one organization — the one it was issued for. It cannot be pointed anywhere else.
  • Usage figures are approximate. Use “Last used” and the request count to check whether a key is still in use, not for billing.
  • Prefer the API for data flows, and the MCP Server when an AI assistant makes the requests — same credential, same scopes.