ExpenseBot

Developer reference

Zapier REST API

The ExpenseBot Zapier integration uses this production API to read approved expense data, create reviewed entries, upload receipts, start Gmail scans, and create reports.

Base URL
https://mcp.expensebot.ai
Content type
application/json

Authentication

ExpenseBot uses OAuth 2.0 Authorization Code with PKCE. Native Zapier connections obtain and refresh tokens through the ExpenseBot consent flow; users do not create API keys or copy client secrets.

Authorization: Bearer <OAuth access token>
Accept: application/json
Content-Type: application/json
ScopePermits
expenses.readRead expenses, categories, tags, and receipt results.
expenses.writeCreate expenses, mileage, income, and receipt submissions.
gmail.scanStart Gmail receipt scans and read their status.
reports.readList and find reports.
reports.writeCreate reports.

Dates and safe retries

Calendar dates use strict, valid YYYY-MM-DD values. Date ranges are inclusive and must provide both boundaries, with the end on or after the start. Timestamps use timezone-bearing ISO 8601 instants. Invalid, ambiguous, incomplete, or reversed dates are rejected.

Every financial write requires source_event_id: the stable unique ID from the source trigger. Reusing it for the same operation makes a retry idempotent and returns idempotent_replay: true instead of creating a duplicate. Reusing it with conflicting data returns 409.

Receipt upload flow

  1. Call POST /api/zapier/receipts/upload-urls with file metadata.
  2. Upload each file's raw bytes to its short-lived signedUrl using PUT and exactly the returned requiredHeaders.
  3. Call POST /api/zapier/receipts with the returned upload references, then poll the exact submission ID until processing completes.

Endpoints

GET/api/zapier/me

Return the ExpenseBot account connected to the OAuth token.

Scope
Authenticated connection
Request
No query parameters.
Response
An object containing id and email for the connected account.
GET/api/zapier/reports

List reports for polling triggers and exact report searches.

Scope
reports.read
Request
Optional query parameters: page (1 or greater), limit (1-100), and status.
Response
An array of report objects with a stable report_id, title, status, created_at timestamp, expense_count, total, currency, and report_url.
GET/api/zapier/expenses

List or search expenses using exact filters.

Scope
expenses.read
Request
Optional query parameters: query, merchant, category, tag, start, end, limit (1-100), and cursor. start and end are inclusive ISO calendar dates.
Response
An array of expense objects. Each object includes expense_id, date, merchant, amount, currency, category, tag, notes, and review_url when available.
GET/api/zapier/categories

List configured expense categories for Zapier dynamic fields.

Scope
expenses.read
Request
No query parameters.
Response
An array of objects containing id and name.
GET/api/zapier/tags

List configured client, project, and trip groups for Zapier dynamic fields.

Scope
expenses.read
Request
No query parameters.
Response
An array of objects containing id and name.
POST/api/zapier/expenses

Create a reviewed cash or card expense.

Scope
expenses.write
Request
JSON body. Required: source_event_id, merchant, total, date, category. Optional: currency, subtotal, tax, tip, city, notes, tag. date is YYYY-MM-DD.
Response
A write result with success, message, record_id, row_number, spreadsheet_url, review_expenses_url, and idempotent_replay.
POST/api/zapier/mileage

Create a reviewed business mileage entry.

Scope
expenses.write
Request
JSON body. Required: source_event_id, distance, purpose. Optional: date, round_trip, destination, city, category, tag, notes. date is YYYY-MM-DD when supplied.
Response
A write result with success, message, record_id, review_expenses_url, and idempotent_replay.
POST/api/zapier/income

Create a reviewed income entry.

Scope
expenses.write
Request
JSON body. Required: source_event_id, amount, source, payment_method. Optional: date, currency, description, category, reference, fees, tax_collected, tag, notes. date is YYYY-MM-DD when supplied.
Response
A write result with success, message, record_id, review_income_url, and idempotent_replay.
POST/api/zapier/gmail/scans

Start a Gmail receipt scan for a recent lookback or an exact date range.

Scope
gmail.scan
Request
JSON body. Required: source_event_id and either lookback_days or both start_date and end_date. Optional: account_email. Date ranges are inclusive YYYY-MM-DD values and end_date cannot precede start_date.
Response
A write result with submission_id, status, message, and idempotent_replay.
GET/api/zapier/gmail/status

Return the current or latest Gmail scan status.

Scope
gmail.scan
Request
No query parameters.
Response
A status object with scan_in_progress, completed_at, result counts, action_needed_count, and available review links.
POST/api/zapier/receipts/upload-urls

Create short-lived signed upload URLs for receipt files.

Scope
expenses.write
Request
JSON body with files, an array of objects containing id, filename, and mimeType. Supported receipt sources include images, HEIC files, and PDFs.
Response
Upload metadata for each file, including signedUrl, uploadRef, requiredHeaders, and the expiration window. Upload raw file bytes to signedUrl with PUT and exactly the returned headers.
POST/api/zapier/receipts

Submit uploaded receipt references for extraction.

Scope
expenses.write
Request
JSON body. Required: source_event_id and upload_refs. Each upload_refs item contains the same id used in the upload request and its uploadRef. Optional: note and tag.
Response
A write result with submission_id, status, spreadsheet_url, review_expenses_url, and idempotent_replay.
GET/api/zapier/receipts/{submissionId}

Get the processing result for one exact receipt submission.

Scope
expenses.read
Request
Path parameter: submissionId returned by POST /api/zapier/receipts.
Response
A processing result with found, state, verdict, completed_at, aggregate counts, per-file outcomes when available, and review links.
POST/api/zapier/reports

Create an expense report for an exact date range.

Scope
reports.write
Request
JSON body. Required: source_event_id, title, and date_range with inclusive YYYY-MM-DD start and end values. Optional: categories, tags, exclude_personal, excluded_categories, and excluded_tags.
Response
A write result with report_id, report_url, bill_client_url, message, and idempotent_replay.

Error responses

StatusMeaning
400Invalid input, missing source event ID, or failed validation.
401Missing, invalid, expired, or revoked OAuth token. Reconnect the Zapier account.
403The OAuth connection does not include the required scope.
409A source event is already processing or conflicts with an earlier write.
502The underlying ExpenseBot operation could not return a usable result.

Google permissions and data use

ExpenseBot's production Google OAuth application is verified for the Google permissions it requests. Gmail access is optional and is used only after the user connects Gmail and starts or schedules a scan. ExpenseBot does not send or delete email.