Reimbursements

Spend & Expense API reimbursements

In this section, we walk through understanding reimbursements in BILL Spend & Expense.

What is a reimbursement?

A reimbursement is a request to be repaid from budget funds for an out-of-pocket expense. Reimbursements enable business transactions without a charge card (physical or virtual card) to be included in the Spend & Expense platform.

Spend & Expense users with the ADMIN user role can approve or deny reimbursement requests.

See the /v3/spend/reimbursements API for the complete list of available operations.

Upload a receipt for a reimbursement

Uploading receipt images for a reimbursement is a two-step process.

Generate an upload URL

Generate an upload URL with POST /v3/spend/reimbursements/upload-image-url.

curl --request POST \
--url 'https://gateway.stage.bill.com/connect/v3/spend/reimbursements/upload-image-url' \
--header 'apiToken: {api_token}' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json'

In the response, an upload url is available. Use this value to upload an image for a receipt in the next step.

👍

Use the upload url in your reimbursement

Use the same upload url value when you create a reimbursement with POST /v3/spend/reimbursements.

Upload an image

Upload an image by sending a PUT request with the upload url value.

In this example, an image is uploaded to the provided url location. To upload a PNG image, set the content type as image/png in the request. When you get an HTTP 200 response, the image is successfully uploaded.

👍

Upload JPG or PNG images

BILL supports JPG and PNG file formats for transaction images.

curl '{upload_url}'
--Content-Type: image/jpeg
--upload-file {file_name_with_extension}
import requests

url = "{upload_url}"

# Open the file in binary mode
with open("{file_name_with_extension}", "rb") as file:
    response = requests.put(url, data=file)

# Check the response status
if response.status_code == 200:
    print("File uploaded successfully!")
else:
    print(f"Failed to upload. Status code: {response.status_code}")
    print(response.text)

Create a reimbursement

In your POST /v3/spend/reimbursements request, set the required fields.

Field

Description

budgetUuid

BILL-generated UUID of the budget for the reimbursement. Funds for the reimbursement are taken from this budget.

userUuid

BILL-generated ID of the user to be reimbursed.

Note: This user must be assigned to the budget specified by the budgetUuid.

amount

Out-of-pocket expense amount

note

Reimbursement note. Use this field to provide more information about the expense.

merchantName

Merchant name for the out-of-pocket expense

occurredDate

Date when the user made the out-of-pocket expense. This value is in the yyyy-MM-dd format.

receipts

Receipts information. In the receipts array, set the url and filename values for each receipt.

See the POST /v3/spend/reimbursements API for information about the complete list of reimbursements fields you can set.

Sample request

In this cURL example, a reimbursement transaction of $50 is created for the provided budget (budgetUuid). The request is submitted by the budget user (userUuid). In addition, the receipt image url and filename is added to the request.

curl --request POST \
--url 'https://gateway.stage.bill.com/connect/v3/spend/reimbursements' \
--header 'apiToken: {api_token}' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--data '{
  "budgetUuid": "{budget_uuid}",
  "userUuid": "\{user_uuid}",
  "occurredDate": "2026-12-25",
  "note": "Team lunch",
  "merchantName": "Jasmine Thai",
  "amount": 50,
  "receipts": [
    {
        "url": "{receipt_url}",
        "filename": "{file_name_with_extension}"
    }
  ]
}'

Response

In the response, a BILL-generated reimbursement transaction uuid is available. The statusHistory information provides details about the different stages of the reimbursement transaction. When the reimbursement is approved, the statusHistory information is updated.

{
    "uuid": "{reimbursement_uuid}",
    "id": "{reimbursement_id}",
    "amount": 50.00,
    "fundRequestAmount": 0.00,
    "fundRequestBudgetAmount": 0.00,
    "merchantName": "Jasmine Thai",
    "note": "Team lunch",
    "submittedTime": "2026-12-26T23:12:04Z",
    "occurredTime": "2026-12-25T00:00:00Z",
    "retired": false,
    "status": "AWAITING_APPROVAL",
    "type": "PURCHASE",
    "statusHistory": [
        {
            "actorUuid": "\{user_uuid}",
            "actorId": "\{user_id}",
            "actorRole": "SUBMITTER",
            "occurredTime": "2026-12-26T23:12:04Z",
            "note": "Team lunch",
            "status": "AWAITING_APPROVAL"
        }
    ],
    "budgetUuid": "{budget_uuid}",
    "budgetId": "{budget_id}",
    "userUuid": "\{user_uuid}",
    "userId": "\{user_id}",
    "receipts": [
        {
            "url": "{receipt_url}",
            "filename": "{file_name_with_extension}"
        }
    ],
    "customFields": [
        {
            // custom_fields_details
        }
    ]
}

Approve a reimbursement

In your POST /v3/spend/reimbursements/{reimbursementUuid}/action request, set the required fields.

FieldDescription
reimbursementUuidBILL-generated UUID of the reimbursement transaction
actionReimbursement approval decision (APPROVE or DENY)

Sample request

In this cURL example, a reimbursement request is marked as approved. An approval note is added to the approval. Spend & Expense users with the ADMIN user role can approve or deny reimbursement requests.

curl --request POST \
--url 'https://gateway.stage.bill.com/connect/v3/spend/reimbursements/{reimbursement_uuid}/action' \
--header 'apiToken: {api_token}' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--data '{
    "action": "APPROVE",
    "note": "Team lunch expense approved"
}'

Response

In the response, the statusHistory information is updated in the reimbursement transaction. The status is set as APPROVED.

{
    "uuid": "{reimbursement_uuid}",
    "id": "{reimbursement_id}",
    "amount": 50.00,
    "fundRequestAmount": 0.00,
    "fundRequestBudgetAmount": 0.00,
    "merchantName": "Jasmine Thai",
    "note": "Team lunch",
    "submittedTime": "2026-12-26T23:12:04Z",
    "occurredTime": "2026-12-25T00:00:00Z",
    "retired": false,
    "status": "APPROVED",
    "type": "PURCHASE",
    "statusHistory": [
        {
            "actorUuid": "{admin_user_uuid}",
            "actorId": "{admin_user_id}",
            "actorRole": "ADMIN",
            "occurredTime": "2026-01-02T23:12:04Z",
            "note": "Team lunch expense approved",
            "status": "APPROVED"
        },
        {
            "actorUuid": "{user_uuid}",
            "actorId": "{user_id}",
            "actorRole": "SUBMITTER",
            "occurredTime": "2026-12-26T23:12:04Z",
            "note": "Team lunch",
            "status": "AWAITING_APPROVAL"
        }
    ],
    "budgetUuid": "{budget_uuid}",
    "budgetId": "{budget_id}",
    "userUuid": "\{user_uuid}",
    "userId": "\{user_id}",
    "receipts": [
        {
            "url": "{receipt_url}",
            "filename": "{file_name_with_extension}"
        }
    ],
    "customFields": [
        {
            // custom_fields_details
        }
    ]
}

See the /v3/spend/reimbursements API for the complete list of available operations.