Reimbursement
Learn how a reimbursement works for eligible expenses, and how its status changes from creation to completion.
A reimbursement pays a user back from their own HSA or FSA for expenses Sail has already classified as eligible. This page explains what a reimbursement needs before Sail creates one, how its status changes from creation to a successful payout, and the two distinct ways it can fail.
What a reimbursement is
A reimbursement is a request to pay a user back from their own benefit account for a set of expenses, not a payment from Sail or from your own funds. It draws from a benefit_account connection, the same connection type covered in Account Connections, and it only ever returns money the user already has in that account.
Scope requiredCreating, getting, or listing reimbursements needs the
benefit_accountkey scope. Creating one also needs thebenefit_accountproduct on the funding account's connection.
Preconditions
Two things must be true before Sail accepts a request to create a reimbursement:
- Every included expense must carry an
eligibleSection 213(d) classification. An expense that'sineligible, stillitemization_required, orlmn_requiredcan't be reimbursed until it resolves toeligible. See the Expense Classification article to understand each outcome. - The funding account's cash balance must cover the sum of the included expenses. Sail checks that total against the account's available balance, not against each expense individually.
An expense can only belong to one reimbursement at a time. Including an expense that isn't eligible, or one that's already part of an in-flight reimbursement, returns a 409 conflict error instead of creating a new reimbursement.
Create a reimbursement
A reimbursement request names the expenses to pay back and the account to pay them from: an array of expense IDs plus the funding account_id, matching the ReimbursementCreateRequest shape. Sail responds with a Reimbursement object, identified by an ID like reimb_8c1f, whose amount field reports the sum of the included expenses as a decimal USD value (for example, 1050.50 for $1,050.50).
The reimbursement status lifecycle
A reimbursement moves through four statuses on its way to a successful payout:
pending: Sail has created the reimbursement and is about to contact the funding account's administrator.submitted: Sail has submitted the included expenses to the administrator.processing: the administrator is processing the submitted reimbursement claim. A reimbursement claim is the request the administrator reviews. Once the administrator approves it and the money reaches the user, the reimbursement iscompleted.completed: the administrator has finished processing the reimbursement claim, and the money has moved out of the account back to the user.completedreflects money actually moving, not just the administrator approving the reimbursement claim.
Once a reimbursement reaches completed, its expenses move to a reimbursed status, and a receipt document becomes available through Get Reimbursement's receipt_url field, which stays empty until then.
Why a reimbursement fails
A failed status covers two distinct causes, both surfaced the same way today:
-
Failed to submit: something went wrong on Sail's side before the reimbursement claim reached the administrator. Sail doesn't automatically retry, but you can resubmit the same expenses and account as a new reimbursement request.
-
Failed after submission: the administrator denied the reimbursement claim. Sail returns a reason alongside the failure. Denial reasons aren't a fixed set, since administrators' review processes vary and are still evolving. For example, an administrator can ask for a Letter of Medical Necessity (LMN) on an expense Sail classified as
eligible, since each administrator applies its own documentation standards when it reviews a reimbursement claim. Afailedreason is context on that decision, not a fixed, retryable error code.
How you find out the result
Sail sends a reimbursement.status_changed webhook on every status transition, naming the reimbursement_id, the previous_status, the new status, and a failure_reason when the new status is failed. See Receiving New Data for how to verify and deduplicate any webhook delivery, reimbursements included.
The current status is also available any time from Get Reimbursement or List Reimbursements, so polling either endpoint on any cadence stays a valid alternative to only listening for the webhook.
Next steps
- To confirm eligibility and balance, create a reimbursement, and track it to completion, see Create and Track a Reimbursement.
- To see the three ways Sail connects to an account, including the
benefit_accountconnections a reimbursement draws from, see Account Connections. - To see how an expense reaches
eligiblein the first place, see Expense Classification.
Updated 14 days ago