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.
Calling the API
Section titled “Calling the API”Send your key in the X-API-Key header:
GET /api/transactions HTTP/1.1Host: api.moneylights.appX-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 machine-readable reference
Section titled “The machine-readable reference”The complete, always-current list of what your key can reach is the public OpenAPI document:
GET https://api.moneylights.app/api/public/openapi.jsonIt 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 ever disagree, the document is right. You can
feed it to a client generator or import it into an API tool.
What is reachable — and what is not
Section titled “What is reachable — and what is not”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, project or person 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.
Rate limits
Section titled “Rate limits”Three limits apply, and a request must satisfy all of them:
| Plan | Reads/min per key | Writes/min per key | Requests/min per organization | Per day, per organization |
|---|---|---|---|---|
| Team | 120 | 30 | 120 | 10 000 |
| Enterprise | 600 | 150 | 600 | 100 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 run several integrations, pace them.
Every response carries X-RateLimit-Limit and X-RateLimit-Remaining. A
429 carries Retry-After in seconds — honour it; retrying immediately is
how a rate limit becomes an outage.
Errors
Section titled “Errors”Refusals carry a stable code you can switch on. The ones you will actually
meet:
| Code | Meaning |
|---|---|
api_key_invalid | Malformed, unknown, or wrong secret |
api_key_expired | Past its expiry date — create a new key |
api_key_revoked | The key was cut, or a rotated secret lapsed |
api_key_scope_missing | The key lacks the scope this endpoint needs |
api_key_endpoint_not_published | The endpoint is not part of the public API |
api_key_rate_limited | Over a limit — honour Retry-After |
A request with no key at all gets a plain 401 with no code — treat a
bodyless 401 as “I forgot the header”.
Good to know
Section titled “Good to know”- Your key reaches exactly one organization — the one it was issued for. It cannot be pointed anywhere else.
- Usage figures are indicative. “Last used” and the request count answer “is this still in use?”, not billing questions.
- Prefer the API for data flows, and the MCP Server when the caller is an AI assistant — same credential, same scopes.