# Bills via API

Create, list, retrieve, update, and mark bills as paid programmatically using the Spend API.

The Bills API lets you create and manage invoices received from vendors for goods or services. You can also update the sync status of your bills and mark them as paid outside Airwallex.

## Before you begin

- [Obtain your access token](/api/authentication/api_access_token) by authenticating to Airwallex using your unique Client ID and [API key](https://www.airwallex.com/docs/developer-tools/api/manage-api-keys.md). You can [create scoped API keys](https://www.airwallex.com/docs/developer-tools/api/manage-api-keys#scoped-api-keys.md) in **Settings** > **Developer** > **API keys** in the Airwallex web app. Spend resources require Organization-level permissions.
- [Set up custom accounting data](https://www.airwallex.com/docs/spend/get-started/set-up-custom-accounting-data.md) if you plan to code bill line items with accounting field selections. See [Accounting field selections](https://www.airwallex.com/docs/spend/how-airwallex-spend-works#accounting-field-selections.md).

## Create a bill

To create a new bill, call the [Create bill](/api/spend/bills/create) endpoint.

1. Send the create request with all required fields:

   ```shell
   curl -X POST \
     'https://api.sandbox.airwallex.com/api/v1/spend/bills/create' \
     -H 'Authorization: Bearer {{ACCESS_TOKEN}}' \
     -H 'Content-Type: application/json' \
     -d '{
       "billing_currency": "USD",
       "due_date": "2025-01-10",
       "external_id": "BILL-EXT-001",
       "invoice_number": "INV-0001",
       "issued_date": "2025-01-10",
       "legal_entity_id": "le_U3jlHqQRNHWn2zAKeeT8sg",
       "line_items": [
         {
           "quantity": "1",
           "unit_price": "500.0",
           "accounting_field_selections": [
             {
               "type": "GENERAL_LEDGER_ACCOUNT",
               "source_id": "ba46f0ff-8081-4db6-8333-4e011fe9561d"
             }
           ]
         }
       ],
       "request_id": "985461d5-016f-4e1f-a387-5f1380b42d92",
       "sync_status": "SYNCED",
       "tax_status": "TAX_EXCLUSIVE",
       "vendor_id": "ba46f0ff-8081-4db6-8333-4e011fe9561d"
     }'
   ```

2. The response returns the created bill with its unique ID:

   ```json
   {
     "id": "985461d5-016f-4e1f-a387-5f1380b42d92",
     "external_id": "BILL-EXT-001",
     "invoice_number": "INV-0001",
     "billing_currency": "USD",
     "billing_amount": "551.0",
     "vendor_id": "ba46f0ff-8081-4db6-8333-4e011fe9561d",
     "status": "AWAITING_PAYMENT",
     "sync_status": "SYNCED",
     "created_at": "2025-01-01T00:00:00Z"
   }
   ```

## List bills

To retrieve a list of bills, call the [List bills](/api/spend/bills/list) endpoint. You can filter by status and sync status.

1. Send the request with optional filters:

   ```shell
   curl -G \
     'https://api.sandbox.airwallex.com/api/v1/spend/bills' \
     --data-urlencode 'sync_status=NOT_SYNCED' \
     -H 'Authorization: Bearer {{ACCESS_TOKEN}}'
   ```

2. The response returns a list of bills:

   ```json
   {
     "items": [
       {
         "id": "985461d5-016f-4e1f-a387-5f1380b42d92",
         "vendor_id": "ba46f0ff-8081-4db6-8333-4e011fe9561d",
         "billing_amount": "4500.00",
         "billing_currency": "USD",
         "status": "AWAITING_PAYMENT",
         "sync_status": "NOT_SYNCED",
         "due_date": "2026-03-01"
       }
     ],
     "page_after": "eyJwYWdlX2JlZm9yZSI6IjIwMjUtMDctMDFUMDA6MDA6MDBaIn0=",
     "page_before": "eyJwYWdlX2JlZm9yZSI6IjIwMjUtMDctMDFUMDA6MDA6MDBaIn0="
   }
   ```

Key query parameters include:

| Parameter           | Description                                                                                                                                                                                |
| ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `status`            | Filter by bill status. Possible values are `DRAFT`, `AWAITING_APPROVAL`, `AWAITING_PAYMENT`, `PAYMENT_IN_PROGRESS`, `PAID`, `REJECTED`, `SCHEDULED`.                                       |
| `sync_status`       | Filter by sync status (`NOT_SYNCED`, `SYNCED`, `SYNC_FAILED`).                                                                                                                             |
| `from_created_at`   | Filter bills created on or after this timestamp (ISO 8601).                                                                                                                                |
| `to_created_at`     | Filter bills created on or before this timestamp (ISO 8601).                                                                                                                               |
| `legal_entity_id`   | Filter bills by legal entity ID.                                                                                                                                                           |
| `purchase_order_id` | Filter bills by associated purchase order ID.                                                                                                                                              |
| `page`              | A bookmark for use in pagination to retrieve either the next page or the previous page of results. You can fetch the value for this identifier from the response of the previous API call. |

## Get bill details

To retrieve the full details of a specific bill, including line items and accounting fields, call the [Get bill](/api/spend/bills/retrieve) endpoint.

1. Use the `id` from the list response:

   ```shell
   curl -G \
     'https://api.sandbox.airwallex.com/api/v1/spend/bills/{{BILL_ID}}' \
     -H 'Authorization: Bearer {{ACCESS_TOKEN}}'
   ```

2. The response includes complete bill details:

   ```json
   {
     "approvers": [
       "approver1@airwallex.com",
       "approver2@airwallex.com"
     ],
     "attachments": [
       {
         "content_type": "image/jpeg",
         "created_at": "2025-02-02T00:00:00Z",
         "file_name": "flight_receipt.jpg",
         "file_url": "https://www.airwallex.com/flight_receipt.jpg",
         "id": "985461d5-016f-4e1f-a387-5f1380b42d92"
       }
     ],
     "bill_payments": [
       {
         "amount": "500.00",
         "card_transaction": {
           "account_id": "acct_a2y0pxz3m4k5hoZldn97hjzp",
           "card_funding_type": "CREDIT",
           "card_id": "985461d5-016f-4e1f-a387-5f1380b42d92",
           "card_transaction_id": "ba46f0ff-8081-4db6-8333-4e011fe9561d",
           "source_amount": "500.00",
           "source_currency": "USD",
           "transacted_at": "2025-01-02T00:00:00Z"
         },
         "created_at": "2025-01-02T00:00:00Z",
         "currency": "USD",
         "id": "ba46f0ff-8081-4db6-8333-4e011fe9561d",
         "type": "CARD_TRANSACTION"
       },
       {
         "amount": "4000.00",
         "created_at": "2025-01-01T00:00:00Z",
         "currency": "USD",
         "id": "985461d5-016f-4e1f-a387-5f1380b42d92",
         "transfer": {
           "account_id": "acct_a2y0pxz3m4k5hoZldn97hjzp",
           "multi_bill": false,
           "source_amount": "400.00",
           "source_currency": "USD",
           "status": "PAID",
           "transfer_date": "2025-01-01",
           "transfer_id": "985461d5-016f-4e1f-a387-5f1380b42d92"
         },
         "type": "TRANSFER"
       }
     ],
     "billing_amount": "4500.0",
     "billing_currency": "USD",
     "created_at": "2025-01-01T00:00:00Z",
     "description": "This is a description of the bill.",
     "due_date": "2025-01-10",
     "external_id": "BILL-EXT-001",
     "id": "985461d5-016f-4e1f-a387-5f1380b42d92",
     "invoice_number": "INV-0001",
     "issued_date": "2025-01-10",
     "legal_entity_id": "le_U3jlHqQRNHWn2zAKeeT8sg",
     "line_items": [
       {
         "accounting_field_selections": [
           {
             "source_id": "ba46f0ff-8081-4db6-8333-4e011fe9561d",
             "name": "Cost Center",
             "type": "OTHER",
             "value": "Office Expense",
             "external_id": "1036f6f7-87e4-4508-b865-f670b1926022",
             "value_label": "Office Expense"
           }
         ],
         "description": "Office supplies",
         "id": "985461d5-016f-4e1f-a387-5f1380b42d92",
         "purchase_order_line_item_id": "ba46f0ff-8081-4db6-8333-4e011fe9561d",
         "quantity": "5",
         "tax_amount": "0.0",
         "total_amount": "4500.0",
         "unit_price": "500.0"
       }
     ],
     "purchase_order_id": "ca56f0ff-8081-4db6-8333-4e011fe9561e",
     "status": "AWAITING_PAYMENT",
     "sync_status": "NOT_SYNCED",
     "tax_status": "TAX_EXCLUSIVE",
     "updated_at": "2025-02-02T00:00:00Z",
     "vendor_id": "ba46f0ff-8081-4db6-8333-4e011fe9561d"
   }
   ```

## Update a bill

To update a bill with a new sync status, call the [Update bill sync status](/api/spend/bills/sync) endpoint.

### Update sync status

After you persist a bill to your system, mark it as synced:

1. Send the update request with the sync status:

   ```shell
   curl -X POST \
     'https://api.sandbox.airwallex.com/api/v1/spend/bills/{{BILL_ID}}/sync' \
     -H 'Authorization: Bearer {{ACCESS_TOKEN}}' \
     -H 'Content-Type: application/json' \
     -d '{
       "sync_status": "SYNCED"
     }'
   ```

2. The response confirms the updated status:

   ```json
   {
     "id": "uuid",
     "sync_status": "SYNCED"
   }
   ```

## Mark a bill as paid externally

When a bill is paid outside Airwallex (for example, from your ERP or an external bank account), call [Mark bill as paid](/api/spend/bills/mark_as_paid) so bill status is updated in Airwallex.

1. Send the mark-as-paid request with the bill ID in the path:

   ```shell
   curl -X POST \
     'https://api.sandbox.airwallex.com/api/v1/spend/bills/{{BILL_ID}}/mark_as_paid' \
     -H 'Authorization: Bearer {{ACCESS_TOKEN}}'
   ```

2. The response returns the updated bill details with status set to `PAID`.

If an error occurs:

1. Send the update request with the sync status:

   ```shell
   curl -X POST \
     'https://api.sandbox.airwallex.com/api/v1/spend/bills/{{BILL_ID}}/sync' \
     -H 'Authorization: Bearer {{ACCESS_TOKEN}}' \
     -H 'Content-Type: application/json' \
     -d '{
       "sync_error_message": "Failed to sync bill: found a mismatch between the bill payment and bill currency.",
       "sync_status": "SYNC_FAILED"
     }'
   ```

2. The response confirms the updated status:

   ```json
   {
     "id": "uuid",
     "sync_error_message": "Failed to sync bill: found a mismatch between the bill payment and bill currency.",
     "sync_status": "SYNC_FAILED"
   }
   ```

## Next steps

Now that you can manage bills via the API, explore these related guides:

- [Vendors via API](https://www.airwallex.com/docs/spend/accounts-payable/vendors-via-api.md)
- [Purchase orders via API](https://www.airwallex.com/docs/spend/accounts-payable/purchase-orders-via-api.md)
- [Set up Spend webhooks](https://www.airwallex.com/docs/spend/get-started/set-up-spend-webhooks.md)
- [Set up custom accounting data](https://www.airwallex.com/docs/spend/get-started/set-up-custom-accounting-data.md)
- [Error codes](https://www.airwallex.com/docs/spend/troubleshooting/error-codes.md)