The Expenses API is in Beta. Additive changes are normal, and breaking changes may be made with notice while the resource incorporates customer feedback. See Versioning and compatibility.
These endpoints read the corporate expenses of the business linked to your API Access Token. They all require the expenses:read scope.
The Expenses API provides a read-only view of corporate card expenses. Reimbursements use their own API resource and are not returned by these endpoints. Each expense includes its approval state, policy compliance, tags, and receipt attachments.
GET /api/v1/expenses returns expenses for the authenticated business in every approval state. Use the same filters and sorting options for every request in a paginated result set.
curl "https://rhoapi.rho.co/api/v1/expenses?approval_status=needs_approval&page_size=20" \
-H "Authorization: Bearer $RHO_API_TOKEN"| Parameter | Description |
|---|---|
approval_status | Filter by approval state. Repeat the key to pass several states (not_ready, automatically_approved, needs_approval, approved, rejected, archived). |
user_id | Filter by expense owner. Repeat the key to pass several user IDs. |
transaction_date_after | Earliest spend date, inclusive, at midnight UTC (YYYY-MM-DD). |
transaction_date_before | Latest spend date, exclusive, at midnight UTC (YYYY-MM-DD). |
created_after | Earliest creation timestamp, inclusive (date-time). |
created_before | Latest creation timestamp, exclusive (date-time). |
has_attachments | true selects expenses with attachments; false selects those without. |
sort_by | Field to sort on (created_at, transaction_date, amount). Defaults to created_at. |
order | Sort direction (asc, desc). Defaults to desc. |
page_size | Number of expenses per page (1-100). Defaults to 20. |
page_token | Opaque cursor from the previous response. |
{
"expenses": [
{
"id": "0198ba3c-0000-7000-8000-000000000201",
"amount": {"amount": 12500, "currency": "USD"},
"transaction_date": "2026-09-08T14:30:00Z",
"created_at": "2026-09-08T14:31:00Z",
"updated_at": "2026-09-08T15:00:00Z",
"user_id": "0198ba3c-0000-7000-8000-000000000101",
"approval_status": "needs_approval",
"merchant_name": "Delta Airlines",
"merchant_category": "Airlines",
"source_details": {
"card_transaction": {
"card_id": "0198ba3c-0000-7000-8000-000000000302",
"transaction_type": "capture"
}
},
"policy": {
"requirements_status": "needs_details",
"out_of_policy_status": "automatic_ok",
"missing_requirements": [{"kind": "receipt"}]
},
"tags": [
{"field_id": "0198ba3c-0000-7000-8000-000000000401", "field_name": "Department", "value": "Engineering"}
],
"attachments": [
{"file_id": "00000000-0000-0000-0000-0000000000f1", "file_name": "boarding_pass.pdf", "attached_at": "2026-09-08T14:35:00Z"}
]
}
],
"page": {"next_page_token": "opaque-cursor"}
}page.next_page_token is null when there are no further pages. Page tokens belong to the API version that created them, so restart pagination when migrating from v0 to v1.
policy.requirements_status is either needs_details or requirements_met. policy.missing_requirements can be empty when requirement details are not available, including when the status is needs_details.
policy.out_of_policy_status preserves how the policy status was determined:
| Value | Meaning |
|---|---|
automatic_ok | Automatically marked in policy. |
automatic_not_ok | Automatically marked out of policy. |
manual_ok | Manually marked in policy. |
manual_not_ok | Manually marked out of policy. |
GET /api/v1/expenses/{expense_id} returns a single expense owned by the authenticated business. Missing and foreign-business expenses both return 404 Not Found without distinguishing between them.
curl "https://rhoapi.rho.co/api/v1/expenses/0198ba3c-0000-7000-8000-000000000201" \
-H "Authorization: Bearer $RHO_API_TOKEN"GET /api/v1/expenses/{expense_id}/activity returns an expense's audit history, including approval changes and field edits. Entries are ordered most recent first and use cursor pagination.
curl "https://rhoapi.rho.co/api/v1/expenses/0198ba3c-0000-7000-8000-000000000201/activity?page_size=50" \
-H "Authorization: Bearer $RHO_API_TOKEN"{
"entries": [
{
"occurred_at": "2026-09-08T15:00:00Z",
"actor_user_id": "0198ba3c-0000-7000-8000-000000000102",
"automated": false,
"changes": [
{"field": "approval_status", "old_value": "NOT_READY", "new_value": "AUTOMATICALLY_APPROVED"}
],
"message": "Expense approved"
}
],
"page": {"next_page_token": null}
}old_value and new_value are display strings recorded by the activity feed. Their format depends on the changed field and is not normalized to the corresponding API enum. Treat them as descriptive values rather than enum identifiers.
GET /api/v1/expenses/{expense_id}/files/{file_id} returns metadata and a fresh, short-lived signed download URL for a file attached to the expense. Fetch a new URL when needed instead of storing it. A file attached to another expense returns 404 Not Found.
curl "https://rhoapi.rho.co/api/v1/expenses/0198ba3c-0000-7000-8000-000000000201/files/00000000-0000-0000-0000-0000000000f1" \
-H "Authorization: Bearer $RHO_API_TOKEN"{
"file_id": "00000000-0000-0000-0000-0000000000f1",
"file_name": "boarding_pass.pdf",
"download_url": "https://..."
}Full endpoint catalogue - paths, parameters, response shapes, and required scopes - lives in the API Reference.