API & AI Agent Access
SimplyQuote exposes a REST API so your AI agents, scripts, and integrations can work with your quotes and invoices on your behalf. Access is controlled with scoped, revocable personal access tokens.
1. Enable API access
- Open your Settings page and log in
- Scroll to the "API & AI Agent Access" section.
- Name your token, choose scopes, and click "Create Token".
- Copy the token immediately — for security, it is only shown once.
2. Make a request
Send the token as a Bearer token in the Authorization header:
curl https://simplyquote.net/api/v1/quotes \ -H "Authorization: Bearer sq_your_token_here"
3. Create and update documents
Creating and updating quotes and invoices uses the same token with a write scope. Totals are always computed server-side from the items you send:
curl -X POST https://simplyquote.net/api/v1/quotes \
-H "Authorization: Bearer sq_your_token_here" \
-H "Content-Type: application/json" \
-d '{
"client_name": "Acme Ltd",
"client_email": "billing@acme.example",
"items": [
{ "description": "Consulting", "quantity": 4, "unit_price": 120 },
{ "description": "Hosting (1 month)", "quantity": 1, "unit_price": 30 }
],
"currency": "USD",
"tax_rate": 10,
"expiry_date": "2026-10-01"
}'Success response (lists look the same, with quotes/invoices + total/page/limit/has_more):
// Wrapped envelope (POST/PATCH/lists): { success:true, data:{ quote } }
{
"success": true,
"data": {
"quote": { "id": "uuid", "quote_number": "Q-1001", "total": 528.0 }
}
}curl -X PATCH https://simplyquote.net/api/v1/invoices/{id} \
-H "Authorization: Bearer sq_your_token_here" \
-H "Content-Type: application/json" \
-d '{ "status": "paid" }'Listing & pagination
List endpoints accept updated_since (ISO 8601), page (default 1), limit (default 20, max 100), and status (case-insensitive; unknown values are ignored). Responses include total, page, limit, and has_more.
GET /api/v1/quotes?status=sent&page=1&limit=20&updated_since=2026-01-01T00:00:00Z
Field rules for create & update
items is required on POST: non-empty array, each with a non-empty description, quantity > 0 (default 1), unit_price >= 0 (default 0). tax_rate is a percent (0–100); on create, tax_rate > 0 implies tax_enabled. currency is uppercased. issue_date accepts any parseable date (stored YYYY-MM-DD). Quotes use expiry_date, invoices use due_date (either alias is accepted, null clears). Status: quotes draft|sent, invoices draft|sent|viewed|paid|cancelled — setting paid stamps paid_at. Totals are always recomputed server-side.
4. Use with an AI agent
Give your agent the base URL, your token, and the endpoint list below. Example instructions for any tool-calling agent (Claude, GPT, LangChain, etc.):
You can access my SimplyQuote account.
Base URL: https://simplyquote.net
For every request, send header: Authorization: Bearer sq_your_token_here
Available endpoints: GET/POST /api/v1/quotes, GET/PATCH /api/v1/quotes/{id},
GET/POST /api/v1/invoices, GET/PATCH /api/v1/invoices/{id}, POST /api/mcp
Lists support ?page, ?limit (max 100), ?status, ?updated_since and return { success:true, data:{ quotes|invoices, total, page, limit, has_more } }.
Single GETs return the bare object. {id} is the UUID, not the document number.
Use POST to create documents — always send items with description, quantity, unit_price.5. Connect via MCP (recommended for agents)
SimplyQuote ships a built-in Model Context Protocol (MCP) server at /api/mcp (stateless streamable HTTP, JSON-RPC 2.0). Agents that support remote MCP servers (Claude, ChatGPT, Cursor, VS Code, etc.) can connect directly with your token — no prompt engineering required. Available tools:
list_quotesget_quotecreate_quotelist_invoicesget_invoicecreate_invoice
{
"mcpServers": {
"simplyquote": {
"type": "http",
"url": "https://simplyquote.net/api/mcp",
"headers": {
"Authorization": "Bearer sq_your_token_here"
}
}
}
}Example tool call (JSON-RPC 2.0 — batch requests are rejected, notifications return 202, GET returns 405):
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": { "name": "list_quotes", "arguments": { "limit": 5 } }
}Each tool call is enforced against your token's scopes — a read-only token can list and fetch, while creating quotes or invoices requires the matching write scope.
Endpoints
| Method | Path | Required scope | Description |
|---|---|---|---|
| GET | /api/v1/quotes | quotes:read | List quotes |
| GET | /api/v1/quotes/{id} | quotes:read | Get a single quote |
| POST | /api/v1/quotes | quotes:write | Create a quote (totals computed server-side) |
| PATCH | /api/v1/quotes/{id} | quotes:write | Update a quote (status: draft | sent) |
| GET | /api/v1/invoices | invoices:read | List invoices |
| GET | /api/v1/invoices/{id} | invoices:read | Get a single invoice |
| POST | /api/v1/invoices | invoices:write | Create an invoice (totals computed server-side) |
| PATCH | /api/v1/invoices/{id} | invoices:write | Update an invoice (status: draft | sent | viewed | paid | cancelled) |
| GET | /api/v1/webhooks | any valid token | List webhook subscriptions |
| POST | /api/v1/webhooks | any valid token | Create a webhook (secret returned once) |
| PATCH | /api/v1/webhooks | any valid token | Update a webhook |
| DELETE | /api/v1/webhooks?id= | any valid token | Delete a webhook (?id=) |
| GET | /api/v1/openapi.json | none | Machine-readable OpenAPI spec |
| POST | /api/mcp | per-tool | MCP server (JSON-RPC 2.0) for AI agents |
Scopes
quotes:read— Read your quotesinvoices:read— Read your invoicesclients:read— Reserved — no separate clients endpoint yet (client info is on quotes/invoices)quotes:write— Create and update quotesinvoices:write— Create and update invoicesclients:write— Reserved — no separate clients endpoint yet (client info is created/updated implicitly when you save quotes/invoices)
Response format & errors
REST endpoints use two shapes — check which one applies:
{
"success": true,
"data": { ... },
"error": { "code": "...", "message": "...", "details": { ... } }
}Single-document GETs return the bare object above (no wrapper), with flat { error, message } errors — e.g. 404 when the id is unknown. Lists and POST/PATCH always use the wrapped envelope.
// Flat envelope (single GET): bare object, no success/data wrapper
{
"id": "uuid",
"quote_number": "Q-1001",
"status": "sent",
"total": 528.0
}
// unknown id:
{ "error": "not_found", "message": "Quote not found" }success— true on success, false on failuredata— the payload on successerror— the error code, message, and optional details on failure
The most common error codes:
UNAUTHORIZED— Missing, invalid, or expired token (HTTP 401)FORBIDDEN— Token does not have the required scope (HTTP 403)VALIDATION_ERROR— Request body failed validation (HTTP 400)NOT_FOUND— The requested document does not exist (HTTP 404)DATABASE_ERROR— Storage error while handling the request (HTTP 500)RATE_LIMIT— Too many requests — retry later (HTTP 429)
Webhooks, OAuth & full reference
Webhooks: manage subscriptions at GET/POST/PATCH/DELETE /api/v1/webhooks (any valid token, no specific scope). The url must be a public HTTPS endpoint. The secret is returned only on creation — verify deliveries via the X-SimplyQuote-Signature HMAC-SHA256 header.
Partner apps use OAuth 2.0 (/api/oauth/authorize, /api/oauth/token, /api/oauth/revoke) instead of personal tokens. Full details in docs/API.md and the machine-readable spec at /api/v1/openapi.json.
Security notes
- Tokens are stored hashed — SimplyQuote never keeps the raw token.
- Grant only the scopes your agent needs; read-only scopes are usually enough.
- Revoke a token at any time from Settings to immediately cut off access.
- A machine-readable spec for agents is available at
/api/v1/openapi.json