EnemoAi Data API
Send your business's own figures to EnemoAi, and its answers, its 13-week cash forecast and its early warnings work from your books, not only from the public record. Machine-readable reference: openapi.json (OpenAPI 3.1).
Read-only for EnemoAi. EnemoAi never moves money or acts on an account: it can't pay, transfer, post to your ledger or change anything in your systems. Your data stays inside your business's account, is never used for another business and never used to train AI models. It's kept while your account is open and deleted when you delete it or close the account.
Keys
The account owner or an admin creates a key in EnemoAi: Account → Your business data → Data API keys (EnemoAi asks them to confirm with WorkPair first). Each key:
- is shown once: EnemoAi keeps only a fingerprint (SHA-256) of it;
- may send only the data types ticked when it was made (its scopes):
accounts,transactions,ledger(gl_entries and chart_of_accounts),invoices,bills,payroll,sales,inventory,counterparties,kpis,documents; - has a rate limit (120 requests a minute by default, at most 600; 50,000 a day), answered with
429when exceeded; - can be revoked at any time, and every use is written to your business's security log (which key, what it did, how many records; never the data).
Authorization: Bearer eai_live_…
Sending data
Every type works the same way: POST /v1/data/{type} with up to 1,000 records, each carrying your own external_id. A record with an ID EnemoAi already has replaces it. The whole batch is checked first; if any record has a problem nothing is stored, and the response lists every problem by position, ID and field.
curl https://api.enemo.ai/v1/data/invoices \
-H "Authorization: Bearer $ENEMOAI_KEY" \
-H "Idempotency-Key: ar-sync-2026-11-01" \
-H "Content-Type: application/json" \
-d '{"schema_version": 1, "records": [
{"external_id": "INV-1042", "number": "1042", "customer": "Acme Builders Inc",
"issue_date": "2026-10-01", "due_date": "2026-10-31",
"amount": 12000.00, "balance_due": 12000.00, "status": "open"}]}'
{"type": "invoices", "schema_version": 1, "received": 1, "created": 1, "updated": 0}
- Idempotency-Key (optional): a retry with the same key and the same body returns the first result without storing anything twice (remembered for 7 days); the same key with a different body is refused with
409. - Amounts are U.S. dollars as numbers or strings (
1234.56,"1,234.56"), stored to the cent. Transactions are signed: money in is positive, money out negative. - Dates are
YYYY-MM-DD. - Read back:
GET /v1/data/{type}?limit=100&cursor=…&updated_since=YYYY-MM-DD. - Delete:
DELETE /v1/data/{type}/{external_id}, orDELETE /v1/data/{type}(orPOST /v1/data/{type}/delete) with{"external_ids": [...]}. - Schema versions: every request may say
"schema_version": 1. New versions will be added alongside, never changed underneath you.GET /v1/data/schemasreturns the live field list.
Data types (schema version 1)
Required fields in bold. Unknown fields are refused, so typos never go unnoticed.
| Type | Fields |
|---|---|
accounts | Bank, card, loan, credit line or investment accounts. external_id, name, type (bank, card, loan, credit_line, investment, other), balance, balance_as_of, institution, last4 (last 4 digits only), currency, available, credit_limit, interest_rate_pct, rate_type (fixed or floating), maturity_date, payment_amount, payment_due_date, payment_frequency, covenants: a list of {name, metric, threshold, test_date, current_value}; metric is min_cash, min_liquidity, max_utilization, max_leverage, min_dscr, min_current_ratio, min_ebitda or other. |
transactions | external_id, date, amount (+ in, − out), account_external_id, description, counterparty, category, status (posted, pending), currency. |
gl_entries | external_id, date, account_code, account_name, debit, credit (one of them), memo, journal_id, currency. |
chart_of_accounts | external_id, code, name, type (asset, liability, equity, income, cogs, expense, other), parent_code. |
invoices | Receivables. external_id, customer, issue_date, due_date, amount, balance_due, number, status (draft, open, partial, paid, void, written_off), paid_date, currency. |
bills | Payables. external_id, supplier, issue_date, due_date, amount, balance_due, number, status, paid_date, category, currency. |
payroll | Totals by pay period only. external_id, period_start, period_end, pay_date, gross_wages, employer_taxes, benefits, net_pay_total, headcount, contractors_total, department, currency. |
sales | external_id, date, amount, channel, category, product, quantity, customer (businesses only), status (completed, refunded, pending), currency. |
inventory | Snapshots. external_id, sku, as_of, quantity, name, unit_cost, value, location, reorder_point. |
counterparties | Customers, suppliers, lenders, landlords, partners: businesses only. external_id, name, role (customer, supplier, lender, landlord, partner, other), entity_type (business, government, nonprofit), state, country, website. |
kpis | Named time series. external_id, series, date, value, unit. |
documents | Contracts, board decks, loan agreements, financial statements, policies: POST /v1/data/documents as multipart/form-data with file, external_id, doc_type, title, date. PDF (up to 100 pages), Word, Excel, text or CSV, up to 20 MB. Kept until you delete them. |
What EnemoAi refuses
- People's payroll data. Payroll is accepted as totals by period. Any field about a person or their pay (names, employee IDs, Social Security numbers, addresses, bank details, emails, phone numbers, pay rates) is refused, and so is any value that looks like a Social Security number. A department's totals need a headcount of at least 3, so no one's pay can be worked out.
- Individuals as customers or suppliers. Counterparties, invoice customers and bill suppliers must be businesses, government bodies or nonprofits; names that read like a person, a family trust or an estate are refused. Put consumer sales in
saleswithout names. - Full account or card numbers. Only the last 4 digits (
last4).
Errors
422 {"detail": "1 of 2 records have problems; nothing was stored.",
"errors": [{"index": 1, "external_id": "p2", "field": "employee_name",
"message": "Payroll is accepted as totals by period only; …"}]}
401 missing, invalid or revoked key · 403 the key lacks that type's scope, or the account is closed · 409 Idempotency-Key reused with a different body · 413 more than 1,000 records or too large a file · 422 validation · 429 over the key's rate limit.
No code needed
In Account → Your business data, the owner or an admin can import OFX or QFX bank and card statements (the Quicken or QuickBooks download every major U.S. bank offers) or any CSV, matching columns to fields. PDF statements aren't imported: their layouts differ by bank and can't be read reliably, so download the OFX, QFX or CSV version instead. Direct QuickBooks, Xero and bank connections are coming next.
What EnemoAi does with it
- Answers draw on your records next to the public record, cite them as "Your data" with their source (the key's name or the import file), and always say which figures are yours and which come from other companies.
- Live monitoring (part of Monitoring, first month free): a 13-week cash forecast every day with its method and assumptions shown, runway, covenant countdowns, warnings when cash may fall below your floor, overdue receivables or customer and supplier concentration, and checks of your customers, suppliers, banks and lenders against bankruptcy courts, FDIC failures, OFAC sanctions, FDA and CPSC recalls and Justice Department releases.
Questions: hello@enemo.ai. Security: enemo.ai/security. Legal: enemo.ai/legal.

