The Peil API is a REST API. Every endpoint requires authentication via an API key with the right scopes. Use it to export data, log hours, create draft invoices, or connect Peil to your own scripts and AI assistants (MCP).
Authentication
Every API request must carry a valid API key as a bearer token in the
Authorization header:
Authorization: Bearer peil_xxxxxxxxxxxxxxxxxxxxxxxx
Requests without a valid key get a 401 Unauthorized response. API keys are
personal and tied to your account — don't share them.
Create an API key
Create an API key via Settings → Developer settings in the Peil app (Pro). Give your key a recognizable name (e.g. "My accountant" or "Claude") so you can identify and revoke it later, and optionally set an expiry date — a short lifetime is wise for keys you hand to an AI assistant.
A key is shown in full only once, right after creation — save it afterwards in a password manager or a secured environment variable.
Scopes
Every key has its own set of scopes. Read access is always included; write scopes are chosen explicitly at creation. That way a script or assistant never gets more access than it needs.
| Scope | What it allows |
|---|---|
read | Read clients, projects, hours, invoices and the orientation snapshot (always active) |
timesheet:write | Create, edit and delete time entries |
invoices:write | Create, edit, delete and archive invoices, and write reminder copy — never sends |
clients:write | Create, edit and delete clients |
invoices:send | All client-facing email: send invoices, schedule sends and manual reminders — irreversible, deliberately a separate scope |
Missing a scope, and the API responds with 403 and
{"code": "INSUFFICIENT_SCOPE"}, naming the missing scope.
Draft-first: without invoices:send a key can only create
drafts — never send anything to your clients. Every write action by a key is logged; you'll
find the per-key activity log in Developer settings.
Base URL
https://api.peil.app/api/v1 Example
A request with curl:
curl -H "Authorization: Bearer peil_xxxxxx" \
https://api.peil.app/api/v1/export/clients?format=csv
The format parameter accepts csv or json for most
export endpoints. Archive exports always return a ZIP file.
Core endpoints
Beyond the exports below, a key with the right scopes reaches these endpoints. Full parameters and response schemas are in the interactive reference at the bottom of this page.
| Endpoint | Scope | What it does |
|---|---|---|
GET /clients | read | Client list (name → id) |
GET /projects | read | Project list |
GET·POST·PUT·DELETE /time_entries | read · timesheet:write | Read, log, edit and delete hours |
POST·PUT·DELETE /clients | read · clients:write | Read and manage clients |
GET /invoices · GET /invoices/unbilled-entries | read | Invoices and unbilled hours |
POST·PUT·DELETE /invoices · /archive | invoices:write | Create, edit, change status, delete, archive invoices (draft-first without invoices:send) |
POST /invoices/from-hours | invoices:write | Draft invoice from unbilled hours (see below) |
PUT /invoices/reminder-settings | invoices:write | Write reminder copy and schedule |
POST /invoices/{id}/send-email · /schedule-send · /send-reminder | invoices:send | Send an invoice, schedule it, or email a reminder |
GET /orientation/snapshot | read | Compact financial snapshot (see below) |
Draft invoice from hours
POST /invoices/from-hours is the API's compound verb: it gathers a client's
unbilled billable hours over a period, builds the invoice lines and creates a
draft — numbering happens only on send. grouping controls the
line layout: summary (one line per description, blended rate),
by_project or per_day.
curl -X POST https://api.peil.app/api/v1/invoices/from-hours \
-H "Authorization: Bearer peil_xxxxxx" \
-H "Content-Type: application/json" \
-d '{
"client_id": 12,
"period_start": "2026-06-01",
"period_end": "2026-06-30",
"grouping": "summary"
}'
The response contains the full draft invoice plus entry_count and
total_hours; the hours used are linked to the draft. If there's nothing to
invoice, you get 422 with {"code": "NO_UNBILLED_ENTRIES"}.
Orientation snapshot
GET /orientation/snapshot answers "where do I stand?" in a single request:
outstanding, overdue (derived from the due date), drafts, invoiced this year, and unbilled
hours.
{
"outstanding": { "count": 2, "total": 2420.0 },
"overdue": { "count": 1, "total": 1210.0 },
"drafts": { "count": 1, "total": 500.0 },
"invoiced_ytd": 24000.0,
"uninvoiced": { "hours": 12.5, "value": 1125.0 },
"billable_hours_ytd": 800.0,
"as_of": "2026-07-14"
} Limits
Write endpoints are rate-limited per minute: logging hours 60/min, creating invoices 20/min,
sending 10/min. Beyond that the API responds 429. Maximum 10 keys per account.
Export formats
The Peil API offers the following export endpoints. All endpoints are GET
requests and require authentication.
| Endpoint | Format | Content |
|---|---|---|
/export/clients | CSV / JSON | Client name, contact details, created date |
/export/time-entries | CSV / JSON | Date, hours, rate, client, project |
/export/invoices | CSV / JSON | Invoice number, amount, status, client |
/export/invoices/archive | ZIP | All PDF invoices |
/export/full | ZIP | All exports above, combined |
The full interactive endpoint reference is below. All routes, parameters and response schemas are generated automatically from the live OpenAPI specification.