Sail

List Expenses

GET/users/{user_id}/expenses

Expenses adjudicated for Section 213(d) eligibility across the user’s connections. Requires the expenses product.

Path Parameters

user_idstringrequired

The Sail user id.

Query Parameters

statusstring

Filter to expenses in this status.

connection_idstring

Restrict to expenses sourced from one connection.

source_typestring

Filter to expenses from one source type.

sincestring

Expenses created or updated after this timestamp (ISO 8601).

limitinteger

Max results per page.

offsetinteger

Pagination offset.

Response

Expenses.

dataobject[]
Show data properties
idstring

The Sail expense id.

connection_idstring

The connection this expense was sourced from.

external_transaction_idstring

Echo of the customer-supplied id for expenses ingested through an external connection; null for Sail-sourced expenses. Join key back to the customer’s own transaction store.

namestring

The expense’s display name.

descriptionstring

Human-readable description of the expense.

datestring<date>

The transaction date.

amountnumber<float>

USD.

status"eligible" | "needs_review" | "ineligible" | "reimbursed" | "archived"

The expense’s current workflow status.

source_type"card" | "store" | "receipt_upload" | "external"

How this expense entered Sail; pairs with the source_type list filter.

originobject

What the expense was derived from.

Show origin properties
type"transaction" | "product"

transaction — derived from a bank/credit-card transaction (one expense per transaction, split via parent_expense_id after itemization). product — derived from an individual product line (store order data or an itemized receipt).

detailstring

The raw descriptor (transactions) or product title (products) the expense was derived from.

merchantobject

The merchant this expense was incurred at, as resolved by enrichment. supported_merchant_id references the /merchants directory only when the merchant is one Sail can connect to for store data; it is null for the long tail of merchants that are recognized but not scrape-supported.

Show merchant properties
namestring

The merchant’s display name.

logo_urlstring

URL of the merchant’s logo. Null if unavailable.

supported_merchant_idstring

The /merchants directory id, when Sail can connect to this merchant for store data. Null otherwise.

enrichmentobject

General transaction enrichment, independent of Section 213(d) adjudication.

Show enrichment properties
categorystring

General spend category.

subcategorystring

More granular spend subcategory, when available.

mccstring

Merchant category code, when derived from a card transaction or supplied at ingest.

parent_expense_idstring

Set when this expense is a line item split from another expense (e.g. itemization of a mixed-basket transaction after receipt review); null for top-level expenses.

section_213d_classificationobject

Section 213(d) eligibility adjudication. The review states pair with origin.type: lmn_required applies to product-origin expenses (a dual-purpose item that becomes eligible with a Letter of Medical Necessity); itemization_required applies to transaction-origin expenses (a mixed basket that needs an itemized receipt before line items can be adjudicated). Both surface as needs_review in the top-level workflow status.

Show section_213d_classification properties
status"eligible" | "lmn_required" | "itemization_required" | "ineligible"

The Section 213(d) review outcome.

categorystring

Section 213(d) category.

reasoningstring

Human-readable explanation for the classification. Null if not available.

created_atstring<date-time>

When the expense was created.

updated_atstring<date-time>

When the expense was last updated.

paginationobject

Pagination metadata for this page.

Show pagination properties
totalinteger

Total number of matching records, across all pages.

limitinteger

The limit used for this page.

offsetinteger

The offset used for this page.

has_moreboolean

Whether additional pages remain after this one.

Standard error envelope covering 400, 401, 403, 404, 429, and 500.

errorobject

The error detail.

Show error properties
codestring

Machine-readable code, e.g. not_found, token_scope_mismatch, product_not_enabled, insufficient_key_scope, insufficient_token_scope, user_token_required, user_token_expired, invalid_user_token, invalid_key_configuration, connection_not_reconnectable, rate_limited.

messagestring

Human-readable error message. May change, so match on error.code instead.

paramstring

The request field that caused the error, when applicable. Null otherwise.

Request
curl -X GET "https://live.savewithsail.com/api/v1/users/<user_id>/expenses?status=<status>&connection_id=<connection_id>&source_type=<source_type>&since=<since>&limit=<limit>&offset=<offset>" \
  -H "Authorization: Bearer <token>"
Response
{
  "data": [
    {
      "id": "string",
      "connection_id": "string",
      "external_transaction_id": "string",
      "name": "string",
      "description": "string",
      "date": "2024-01-01",
      "amount": 0,
      "status": "eligible",
      "source_type": "card",
      "origin": {
        "type": "transaction",
        "detail": "string"
      },
      "merchant": {
        "name": "Costco",
        "logo_url": "string",
        "supported_merchant_id": "mer_costco"
      },
      "enrichment": {
        "category": "Pharmacies",
        "subcategory": "Drug Stores",
        "mcc": "string"
      },
      "parent_expense_id": "string",
      "section_213d_classification": {
        "status": "eligible",
        "category": "Health Monitoring Devices",
        "reasoning": "string"
      },
      "created_at": "1970-01-01T00:00:00.000Z",
      "updated_at": "1970-01-01T00:00:00.000Z"
    }
  ],
  "pagination": {
    "total": 0,
    "limit": 0,
    "offset": 0,
    "has_more": true
  }
}