Everything an AI agent can do with the Expensify API.

A reference guide for building AI agents: every method, how to authenticate, and the permissions each one needs.

Endpoints16
API version2026-06-09
Last updated23 June 2026
Orientation

How the Expensify API works.

The Expensify API is how an app or AI agent works with an Expensify account: exporting report and card data, creating expenses and reports, reading and updating policies, and marking reports reimbursed. Access is granted through a partner credential, a paired ID and secret generated per account, and the credential carries the account holder's own reach rather than a set of per-job scopes. Each request names a job type, and an export job can run on a schedule rather than the account pushing events back to an app.

16Endpoints
4Capability groups
6Read
10Write
0Permissions
Authentication
Every request authenticates with a partner credential, a partnerUserID paired with a partnerUserSecret, generated for the account at the Integration Server tools page. The pair is sent inside the request body, not as a header. Expensify warns never to share the secret and to rotate the pair immediately if it leaks.
Permissions
Expensify does not offer per-job scopes. One credential carries the full reach of the account it belongs to, so what a call can do is bounded by that account's role, like being a domain and policy admin, not by a permission attached to the credential. Bollard adds the per-job, per-agent boundary the API itself does not.
Versioning
There is no dated API version. The Integration Server is a single endpoint, updated in place, so an integration always calls the current behaviour. Notable capabilities ship through Expensify product releases rather than a versioned path.
Data model
Every call goes to one endpoint and names a job type in a JSON requestJobDescription: file and reconciliation export data, download retrieves a generated file, create makes expenses, reports, or policies, get reads policy and card data, and update changes policies, employees, and report status. Export jobs format their output with a Freemarker template.
Connect & authenticate

Connection & authentication methods.

How an app or AI agent connects to Expensify determines what it can reach. There is the Integration Server, which runs jobs against an account with a partner credential, and a hosted server that exposes Expensify search to AI agents, and each is governed by the credential behind it.

Ways to connect

Integration Server API

The Integration Server exposes one HTTP endpoint, ExpensifyIntegrations, that takes a form-encoded body with a requestJobDescription JSON object naming a job type (file, reconciliation, download, create, get, or update) plus a partner credential, input settings, and, for exports, a Freemarker template. It returns JSON with a responseCode and, on failure, a responseMessage. This is the route for creating, reading, updating, and exporting account data.

Best forConnecting an app or AI agent to Expensify for create, read, update, and export jobs.
Governed byThe partner credential and the reach of the account it belongs to.
Docs ↗

MCP server

A first-party hosted Model Context Protocol server, launched June 2026 at expensify.com/mcp, connects AI assistants like Claude, ChatGPT, and Cursor over OAuth 2.1 with PKCE. It exposes a single Search tool that retrieves and analyses expenses, reports, reimbursements, invoices, merchants, categories, receipts, approvals, and spend trends. It is read-only and cannot create, edit, or delete data.

Best forConnecting an AI agent to Expensify for read-only search and analysis through MCP.
Governed byThe OAuth 2.1 grant tied to the member's Expensify account.
Docs ↗
Authentication

Partner credential

The Integration Server authenticates with a paired partnerUserID and partnerUserSecret, generated for the account at the tools page and sent inside the request body. There are no per-job scopes: the credential carries the full reach of the account it belongs to, so an admin credential can act across a domain while a member credential is limited to its own account. The secret is shown so it can be stored, and Expensify advises rotating it if it leaks.

TokenpartnerUserID + partnerUserSecret (in the request body)
Best forServer-side jobs against the Integration Server.
Docs ↗

OAuth 2.1 (MCP)

The hosted MCP server authenticates with OAuth 2.1 with PKCE, where a member signs in with their existing Expensify account and grants the AI client access. The resulting access is read-only and tied to that member, separate from the partner credential used by the Integration Server.

TokenOAuth 2.1 access token tied to a member account
Best forConnecting an AI assistant to Expensify search over MCP.
Docs ↗
Endpoint reference

Every Expensify Integration Server job.

Filter by method, access, or permission, or search any path. Select a row for version detail, rate limits, the related webhook event, and the source.

MethodEndpointWhat it doesAccessPermissionVersion

Export & download

Jobs that export report and card data and retrieve generated files.3

No per-job scope; bounded by the account's reach. A template parameter is required to format the output. An onReceive setting controls whether the file is returned immediately or generated for later download.

Acts onreport export
Permission (capability)None required
VersionAvailable since the API’s base version
Webhook eventNone
Rate limitStandard limits apply

No per-job scope. Uses its own reconciliation template format, distinct from the report export template.

Acts oncard reconciliation
Permission (capability)None required
VersionAvailable since the API’s base version
Webhook eventNone
Rate limitStandard limits apply

No per-job scope. Distinguishes between the reconciliation and integration-server file systems when locating the file.

Acts ongenerated file
Permission (capability)None required
VersionAvailable since the API’s base version
Webhook eventNone
Rate limitStandard limits apply

Create

Jobs that create expenses, reports, and policies.4

No per-job scope; bounded by the credential's account. Supports assigning each expense a category, tag, and report.

Acts onexpense
Permission (capability)None required
VersionAvailable since the API’s base version
Webhook eventNone
Rate limitStandard limits apply

Requires the credential to be a domain and policy admin, and the capability enabled by contacting Concierge.

Acts onreport
Permission (capability)None required
VersionAvailable since the API’s base version
Webhook eventNone
Rate limitStandard limits apply

No per-job scope; bounded by the account's reach.

Acts onpolicy
Permission (capability)None required
VersionAvailable since the API’s base version
Webhook eventNone
Rate limitStandard limits apply

No per-job scope; bounded by the account's reach.

Acts onexpense rule
Permission (capability)None required
VersionAvailable since the API’s base version
Webhook eventNone
Rate limitStandard limits apply

Read

Jobs that read policy details, the policy list, and domain cards.3

No per-job scope. Returns the full policy detail in one response.

Acts onpolicy
Permission (capability)None required
VersionAvailable since the API’s base version
Webhook eventNone
Rate limitStandard limits apply

No per-job scope. Supports an admin-only filter to limit results to policies the account administers.

Acts onpolicy list
Permission (capability)None required
VersionAvailable since the API’s base version
Webhook eventNone
Rate limitStandard limits apply

No per-job scope; requires a domain-admin credential to see domain cards.

Acts ondomain card list
Permission (capability)None required
VersionAvailable since the API’s base version
Webhook eventNone
Rate limitStandard limits apply

Update

Jobs that change policies, employees, expense rules, and report status.6

No per-job scope. A merge action adds to existing values; a replace action overwrites them.

Acts onpolicy
Permission (capability)None required
VersionAvailable since the API’s base version
Webhook eventNone
Rate limitStandard limits apply

The current way to provision employees; replaces the deprecated CSV employee updater. Automates policy assignment and manager invitations.

Acts onemployee
Permission (capability)None required
VersionAvailable since the API’s base version
Webhook eventNone
Rate limitStandard limits apply

Deprecated. Expensify directs integrators to the Advanced Employee Updater for adding, updating, or removing employees.

Acts onemployee
Permission (capability)None required
VersionAvailable since the API’s base version
Webhook eventNone
Rate limitStandard limits apply

No per-job scope; bounded by the account's reach.

Acts onexpense rule
Permission (capability)None required
VersionAvailable since the API’s base version
Webhook eventNone
Rate limitStandard limits apply

No per-job scope. Can return a 207 partial success with failed and skipped report lists.

Acts onreport status
Permission (capability)None required
VersionAvailable since the API’s base version
Webhook eventNone
Rate limitStandard limits apply

No per-job scope; bounded by the account's reach.

Acts ontag approver
Permission (capability)None required
VersionAvailable since the API’s base version
Webhook eventNone
Rate limitStandard limits apply
No endpoints match those filters.
Webhooks

Webhook events.

Expensify does not push events to an app. Instead, an export job can run on a schedule set in the account and deliver its file by email or to an SFTP destination when it finishes.

EventWhat it signalsTriggered by
No events match that search.
Rate limits & pagination

Rate limits, pagination & request size.

Expensify caps how fast an app can start jobs, counted over two windows, a short one and a longer one.

Request rate

Expensify caps how fast an app can start jobs, counted over two windows: up to 5 requests every 10 seconds and up to 20 requests every 60 seconds. Going over returns HTTP 429, and the app should slow down and retry. The limits apply to job starts, not to the number of records a single job touches, so one create or export job can process many expenses or reports within a single request.

Pagination

The Integration Server does not paginate with a cursor. A read job, like getting the policy list or a policy's details, returns the full result set in one response, and an export job filters by date range and report state rather than walking pages. To bound a large export, narrow the input filters.

Request size

An export or create job can carry many records in a single request, so the practical limit is the rate window rather than a fixed page size. A generated export file is held for later retrieval by the download job, named by the filename the export job returned.

Errors

Status codes & error handling.

The status codes an agent should handle, and what to do about each.

StatusCodeMeaningWhat to do
200SuccessThe job ran successfully. The response carries a responseCode of 200 and the job's result, like a reportID for a created report or a policyList for a list read.Read the result fields from the response body.
207Partial successSome records in a batch succeeded and others failed, for example a report-status update where some reports were skipped. The response lists the failed and skipped records.Inspect the failedReports or skipped arrays in the response, fix those records, and resubmit only them.
404Policy not foundA policy named in the request, by policyID, does not exist or is not visible to the credential.Confirm the policyID, which appears in the workspace URL, and that the credential's account can see that policy.
410Validation errorThe request was rejected for a validation problem, like a missing required field or a malformed value. The responseMessage names the issue.Read the responseMessage, correct the request, and resend. The request is not retryable as-is.
429Rate limit exceededToo many jobs were started too quickly, over the limit of 5 every 10 seconds or 20 every 60 seconds.Slow the rate of job starts and retry with backoff.
500Generic errorAn error on Expensify's side prevented the job from completing. The responseMessage may carry detail.Retry after a short wait, and contact Expensify support if it persists.
Versioning & freshness

Version history.

The Integration Server is a single, continuously updated endpoint with no dated version in the path. Notable changes ship through Expensify product releases, like the hosted server for AI agents added in June 2026.

Version history

What changed, and when

Latest version2026-06-09
2026-06-09Current version
Hosted MCP server for AI agents

Expensify launched a first-party hosted Model Context Protocol server so AI assistants like Claude and ChatGPT can connect over OAuth 2.1 with PKCE and search Expensify data through a read-only Search tool. The Integration Server itself remains a single, unversioned endpoint updated in place.

What changed
  • First-party MCP server launched at expensify.com/mcp.
  • OAuth 2.1 with PKCE for AI-client connections.
  • Read-only Search tool over expenses, reports, reimbursements, and related data.
  • Supported clients include Claude, ChatGPT, and Cursor.
Earlier
Integration Server

The Integration Server has long exposed a single endpoint that runs export, create, read, and update jobs against an account, authenticated with a partner credential. Employee provisioning moved from the CSV employee updater to the Advanced Employee Updater, and the older updater is no longer maintained.

What changed
  • Single ExpensifyIntegrations endpoint with job types selected in requestJobDescription.
  • Advanced Employee Updater added; CSV employee updater deprecated.
  • Export jobs formatted with Freemarker templates.

There is no version to pin; the Integration Server is updated in place.

Expensify Integration Server manual ↗
Questions

Expensify API, answered.

How do I get a partnerUserID and partnerUserSecret?+
Both are generated for the account at the Integration Server tools page (expensify.com/tools/integrations). They form one credential: the ID identifies the partner and the secret authenticates it. Expensify warns never to share the secret, and to rotate the pair immediately if it is ever exposed.
Why is everything one endpoint?+
The Integration Server exposes a single URL, ExpensifyIntegrations, and the work is selected by the job type named inside the requestJobDescription JSON sent in the request body. So create, get, update, file, reconciliation, and download all go to the same place, distinguished by the type field rather than by separate paths.
How do I read errors from a job?+
Every response includes a responseCode and, on failure, a responseMessage describing what went wrong. A 410 signals a validation problem in the request, a 404 a policy that was not found, a 500 a generic server error, and a 207 a partial success where some records in a batch succeeded and others, listed in the response, did not.
Can I create reports or expenses in another employee's account?+
Yes, but only with the right role. Creating a report with transactions in a user's account requires being a domain admin and a policy admin, and Expensify asks integrators to have the capability enabled by contacting Concierge. Without that, a create job is limited to the credential holder's own account.
Does Expensify send webhooks?+
No. There is no event push. Instead, an export job can be scheduled in the account and deliver its file by email or to an SFTP destination when it finishes, and a generated file can be pulled later with the download job. An app that needs to learn about changes polls with a read or export job.
Is there an official MCP server for AI agents?+
Yes. In June 2026 Expensify launched a hosted Model Context Protocol server at expensify.com/mcp that connects AI assistants like Claude and ChatGPT over OAuth 2.1 with PKCE. It is read-only: a single Search tool retrieves and analyses expenses, reports, reimbursements, and related data, but cannot create, edit, or delete anything.
Related

More finance API guides for agents

What is Bollard AI?

Control what every AI agent can do in Expensify.

Bollard AI sits between a team's AI agents and Expensify. Grant each agent exactly the access it needs, read or write, job by job, and every call is checked and logged.

  • Set read, write, or full access per agent, never a shared Expensify partner credential.
  • Denied by default, so an agent reaches only what has been explicitly allowed.
  • Every call recorded in plain English: who, what, where, and the decision.
Expensify
Expense Agent
Export reports ActionOffReadFull use
Create expenses ActionOffReadFull use
Policies ResourceOffReadFull use
Per-agent access, set in Bollard AI, not in Expensify