API Documentation
A small, read-only REST API for your contracts. Everything is scoped to your account.
Base URL
https://expiro.io/api/v1
Authentication
The API uses bearer tokens. In Expiro, an account admin creates a token under Settings → API . The full token is shown once on creation, so copy it then.
Send it in the Authorization header on every request:
curl -H "Authorization: Bearer YOUR_TOKEN" \ https://expiro.io/api/v1/contracts
A token can be given an expiry (30, 90 or 365 days, or never) and revoked at any time. A revoked or expired token stops working immediately.
Tokens are read-only by default. When creating a token you can tick
write access
to also allow creating contracts (the POST /contracts
endpoint below). Reading is always allowed.
Rate limit
Each account may make 60 requests per minute. Over that, the API returns 429 Too Many Requests; wait a moment and retry.
List contracts
GET /api/v1/contracts
returns every contract on your account.
curl -H "Authorization: Bearer YOUR_TOKEN" \ https://expiro.io/api/v1/contracts
Response:
{
"data": [
{
"id": "5f9b2c1a-8e3d-4a7b-9c10-2b6e1f0a4d22",
"name": "Annual retainer",
"client_name": "Acme Corp",
"client_email": "ops@acme.com",
"value": "24000.00",
"currency": "GBP",
"start_date": "2026-01-01",
"end_date": "2026-12-31",
"status": "active",
"pipeline_status": "upcoming",
"auto_renewal": false,
"renewal_notice_days": 90,
"custom_fields": { "po_number": "PO-1188" },
"inserted_at": "2026-01-02T09:14:00.000000Z",
"updated_at": "2026-03-10T11:00:00.000000Z"
}
]
}
Contracts expiring soon
GET /api/v1/contracts/expiring
returns active contracts ending within a window, newest first - handy as a trigger.
Pass ?days=N
(1 to 365, default 30). Each record adds a days_until_expiry
field.
curl -H "Authorization: Bearer YOUR_TOKEN" \ "https://expiro.io/api/v1/contracts/expiring?days=60"
Create a contract
POST /api/v1/contracts
creates a contract. Requires a token with write access.
curl -X POST -H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{"name":"Annual retainer","client_name":"Acme Corp","value":"24000","currency":"GBP","end_date":"2026-12-31"}' \
https://expiro.io/api/v1/contracts
Returns 201 Created
with the new contract. A token without write access returns 403; a plan over its contract limit returns 403; invalid fields return
422
with an errors
object.
Verify a token
GET /api/v1/me
returns the account behind the token. Useful for confirming a connection works.
curl -H "Authorization: Bearer YOUR_TOKEN" \ https://expiro.io/api/v1/me
Get one contract
GET /api/v1/contracts/:id
returns a single contract by its id.
curl -H "Authorization: Bearer YOUR_TOKEN" \ https://expiro.io/api/v1/contracts/5f9b2c1a-8e3d-4a7b-9c10-2b6e1f0a4d22
Response:
{
"data": {
"id": "5f9b2c1a-8e3d-4a7b-9c10-2b6e1f0a4d22",
"name": "Annual retainer",
"client_name": "Acme Corp",
"status": "active",
"end_date": "2026-12-31"
}
}
An id that does not belong to your account returns 404 Not Found.
Errors
Errors come back as JSON with an error message:
{ "error": "Invalid or missing API token." }
| Status | Meaning |
|---|---|
| 401 | The token is missing, invalid, expired or revoked. |
| 403 | The token lacks write access, or your plan is over its contract limit. |
| 404 | No contract with that id on your account. |
| 422 | The contract could not be created; see the errors object. |
| 429 | Rate limit exceeded (60 requests per minute). Retry shortly. |
| 5xx | Something went wrong on our side. Retry later. |
Need a token? Head to Settings → API in your account. Questions? Email support@expiro.io.