Public API Reference
Introduction
The Recite Public API lets you programmatically scan receipts, extract structured financial data, manage transactions and projects, run batch operations, and automate bookkeeping workflows. It is designed for AI agents, automation platforms (Zapier, Make, n8n), and custom integrations.
https://recite.rivra.dev/apiV1/api/v1Authentication
All requests require a Bearer token in the Authorization header. Create and manage API keys in Settings β API Access.
Authorization: Bearer sk_live_YOUR_API_KEY| Key State | Behavior |
|---|---|
| active | Requests proceed normally |
| revoked | Immediately returns 401 INVALID_API_KEY |
| expired | Returns 401 INVALID_API_KEY once expiry passes |
Security: Never expose your API keys in client-side code, public repositories, or logs. If a key is compromised, rotate it immediately from the settings page.
Response Format
All API responses use a standard envelope. Choose the format via the ?format= query parameter or the Accept header.
// Success
{
"success": true,
"data": { ... },
"meta": {
"request_id": "550e8400-e29b-41d4-a716-446655440000",
"api_version": "v1",
"processing_time_ms": 1234,
"quota_limit": 200,
"quota_remaining": 157
}
}
// Error
{
"success": false,
"error": {
"code": "INVALID_REQUEST",
"message": "Field 'amount' must be a positive number",
"details": { "field": "amount" }
},
"meta": { "request_id": "...", "api_version": "v1", "processing_time_ms": 12 }
}Supported formats: json (default) Β· csv Β· text
Rate Limits
Rate limits are enforced per API key using sliding window counters. When exceeded, the API returns 429 RATE_LIMITED with a Retry-After header.
| Window | Limit | Retry-After |
|---|---|---|
| Per minute | 100 requests | 60s window |
| Per hour | 500 requests | 3,600s window |
| Per day | 5,000 requests | Contact support for higher limits |
Response Headers
For better client-side throttling management, we include the following headers in every response:
| X-RateLimit-Limit | The maximum number of requests you're permitted to make per window. |
| X-RateLimit-Remaining | The number of requests remaining in the current window. |
| X-RateLimit-Reset | The UTC epoch time (in seconds) at which the current rate limit window resets. |
RATE_LIMITED vs QUOTA_EXCEEDED: Rate limits reset within minutes. Monthly scan quota (QUOTA_EXCEEDED) resets on your billing cycle date. Both return HTTP 429 but with different error codes.
Scopes & Permissions
Each API key can be restricted to specific scopes. If an endpoint requires a scope your key lacks, you'll receive a 403 INSUFFICIENT_SCOPE error. New keys include a set of default scopes; additional scopes must be explicitly granted at creation.
| Scope | Grants Access To | Default |
|---|---|---|
| scan:create | POST /scan, POST /batch/scans | β |
| scan:read | GET /scan/:id, GET /batch/scans/:id/results | β |
| transactions:create | POST /transactions, POST /import/transactions | β |
| transactions:read | GET /transactions, GET /transactions/:id, GET /summary | β |
| transactions:update | PATCH /transactions/:id | β |
| transactions:delete | DELETE /transactions/:id | β |
| batch:create | POST /batch/scans | β |
| batch:read | GET /batch/scans/:id, GET /batch/scans/:id/results | β |
| bank_statements:create | POST /bank-statements | β |
| bank_statements:read | GET /bank-statements, GET /bank-statements/:id | β |
| bank_statements:delete | DELETE /bank-statements/:id | β |
| bank_transactions:read | GET /bank-transactions, GET /bank-transactions/:id | β |
| bank_transactions:update | PATCH /bank-transactions/:id | β |
| bank_transactions:delete | DELETE /bank-transactions/:id | β |
| reconciliation:read | GET /reconciliation/links, GET /reconciliation/summary | β |
| reconciliation:write | POST /reconciliation/links, POST /reconciliation/auto-match | β |
| projects:read | GET /projects | β |
| projects:write | POST /projects, PATCH /projects/:id, DELETE /projects/:id | β |
| usage:read | GET /usage | β |
| export:create | POST /export | β |
| webhooks:manage | POST /webhooks, GET /webhooks, DELETE /webhooks/:id | β |
| rules:read | GET /rules | β |
| rules:write | POST /rules, PATCH /rules/:id, DELETE /rules/:id | β |
| preferences:read | GET /categories, GET /vendors | β |
| preferences:write | POST /categories, DELETE /categories/:name, POST /vendors, DELETE /vendors/:name | β |
Error Codes
We use standard HTTP status codes along with a machine-readable code field in the error response body.
| Status | Code | Meaning |
|---|---|---|
| 400 | INVALID_REQUEST | Missing or invalid fields in request body or params |
| 400 | INVALID_IMAGE | Image cannot be decoded or is unsupported format |
| 401 | INVALID_API_KEY | Missing, malformed, revoked, or expired Bearer token |
| 403 | INSUFFICIENT_SCOPE | Key lacks the scope required by this endpoint |
| 404 | NOT_FOUND | Resource does not exist or belongs to a different user |
| 409 | DUPLICATE | Idempotency key matched an existing request (cached response returned) |
| 413 | FILE_TOO_LARGE | Image or payload exceeds size limit |
| 422 | EXTRACTION_FAILED | LLM could not extract structured data β try a clearer image |
| 429 | RATE_LIMITED | Too many requests in the current window β see Retry-After header |
| 429 | QUOTA_EXCEEDED | Monthly scan limit exhausted β resets on billing cycle date |
| 500 | INTERNAL_ERROR | Server-side error |
Scanning
Extract structured data from receipts using AI vision. Supports image URLs, base64 data, and raw text. Optionally auto-create a transaction when confidence meets your threshold.
Transactions
Import
Bulk-create up to 500 transactions from a JSON array or CSV file in a single request. No image processing occurs β you supply field values directly.
Batch Scanning
Process up to 20 receipt images asynchronously in a single job. Items are processed concurrently. Poll the status endpoint or use a webhook to receive completion notification.
Bank Statements
Upload, list, and manage CSV bank statements.
Bank Transactions
Manage individual bank transactions parsed from bank statements.
Reconciliation
Match receipt transactions with bank transactions.
Projects
Projects are named buckets that organize transactions. Assign transactions to a project via project_id in any create or update call.
Summary
Aggregate financial statistics for dashboards and reports. Returns totals and an optional breakdown by category, vendor, payment method, or month.
Webhooks
Register HTTPS endpoints to receive real-time event notifications. Recite sends a signed POST request to your URL when an event fires.
| Event | Fired When |
|---|---|
| transaction.created | A transaction is created (manual or auto-saved from scan) |
| transaction.updated | A transaction field is updated via PATCH |
| transaction.deleted | A transaction is deleted via DELETE |
| scan.completed | A single receipt scan finishes processing (via /scan) |
| batch.completed | A batch scan job finishes processing |
Signature Verification
Every webhook request includes an X-Recite-Signature header. Verify it using HMAC-SHA256 over the raw request body with the secret from your webhook registration.
const crypto = require('crypto');
function verifyWebhook(rawBody, signatureHeader, secret) {
if (!signatureHeader) return false;
const [algorithm, signature] = signatureHeader.split('=');
if (algorithm !== 'sha256') return false;
const expectedSignature = crypto
.createHmac('sha256', secret)
.update(rawBody)
.digest('hex');
try {
return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(expectedSignature)
);
} catch (err) {
return false;
}
}
// Express handler:
app.post('/webhook', express.raw({ type: 'application/json' }), (req, res) => {
const sig = req.headers['x-recite-signature'];
if (!verifyWebhook(req.body, sig, process.env.WEBHOOK_SECRET)) {
return res.status(401).send('Invalid signature');
}
const event = JSON.parse(req.body);
// Handle event.event, event.data, event.timestamp
res.sendStatus(200);
});Rules
Automation rules override extracted fields during scanning. Rules are shared between the web UI and the API β creating a rule here makes it available in Settings, and vice versa. Rules execute in ascending priority order; the first matching rule wins.
| rule_type | Format | Use case |
|---|---|---|
| transaction_rule | Rich conditions[] + actions[] arrays with AND/OR | Advanced multi-condition rules (same as web UI) |
| vendor_category | Simple condition + action objects | Map a vendor to a category |
| default_project | Simple objects | Auto-assign vendor/category to a project |
| processing_preference | Simple objects | Set payment method or category for a vendor |
{
"rule_type": "transaction_rule",
"conditions": [
{ "type": "vendor_contains", "value": "Starbucks" }
],
"condition_operator": "AND",
"actions": [
{ "type": "set_category", "value": "Coffee & Beverages" },
{ "type": "set_type", "value": "Expense" }
],
"priority": 1
}{
"rule_type": "vendor_category",
"condition": { "vendor": "Starbucks" },
"action": { "set_category": "Coffee & Beverages" },
"priority": 1
}Categories & Vendors
Discover and manage categories and vendors. Recite ships with a set of default categories that cannot be deleted. You can add custom categories and vendors that are shared between the web UI and the API.
Advertising & Marketing, Office Supplies, Rent & Lease, Utilities, Telecommunications, Insurance, Legal & Professional Services, Software & Subscriptions, Travel, Meals & Entertainment, Salaries & Wages, Payroll Taxes, Contractors & Freelancers, Bank Charges & Fees, Interest Paid, Depreciation, Other
Export
Usage Metrics
Try It Now
Ready to test? Use our interactive playground to send real requests to the Recite API.
Interactive Playground
Test the API directly from your browser. Your API key is sent directly to the API and never stored on our servers.