> For the complete documentation index, see [llms.txt](https://help.alternativepayments.io/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://help.alternativepayments.io/getting-started/accounts-payable-api/bills.md).

# Bills

Bills represent payable obligations to vendors. They are the Accounts Payable equivalent of Invoices in the Accounts Receivable API.

## Endpoints

| Method | Path                   | Description                           |
| ------ | ---------------------- | ------------------------------------- |
| POST   | `/bills`               | Create a bill                         |
| GET    | `/bills`               | List bills (paginated, filterable)    |
| GET    | `/bills/{id}`          | Get bill by ID                        |
| PATCH  | `/bills/{id}`          | Update bill fields                    |
| DELETE | `/bills/{id}`          | Soft-delete a bill                    |
| POST   | `/bills/{id}/submit`   | Submit bill for approval              |
| POST   | `/bills/{id}/reject`   | Reject a bill                         |
| POST   | `/bills/{id}/pay-date` | Set or update scheduled pay date      |
| GET    | `/bills/{id}/document` | Get bill attachment download URL      |
| POST   | `/bills/upload`        | Upload document with OCR, create bill |
| POST   | `/bills/bulk-submit`   | Submit multiple bills for approval    |
| POST   | `/bills/bulk-delete`   | Soft-delete multiple bills            |

***

## Bill Lifecycle

```
draft -> needs_approval -> processing -> paid
                        -> failed
         needs_approval -> draft (rejected)
```

Bills start in `draft` status. They must be submitted for approval (`needs_approval`) before payment can be initiated. Once a payment is created, the bill transitions to `processing`, and eventually to `paid` or `failed`.

***

## Create Bill

```
POST /bills
```

### Request Body

```json
{
  "vendor_id": "550e8400-e29b-41d4-a716-446655440000",
  "number": "INV-2026-001",
  "issue_date": "2026-04-01",
  "due_date": "2026-05-01",
  "amount": "1500.00",
  "description": "Monthly hosting services",
  "status": "draft",
  "line_items": [
    {
      "name": "Cloud Hosting",
      "description": "AWS monthly fee",
      "unit_type": "service",
      "quantity": 1,
      "unit_price": 1500.00
    }
  ]
}
```

| Field         | Type          | Required | Description                               |
| ------------- | ------------- | -------- | ----------------------------------------- |
| `vendor_id`   | string (UUID) | Yes      | Vendor to associate the bill with         |
| `number`      | string        | No       | Bill/invoice number                       |
| `issue_date`  | string        | Yes      | Date the bill was issued (YYYY-MM-DD)     |
| `due_date`    | string        | Yes      | Payment due date (YYYY-MM-DD)             |
| `amount`      | number        | Yes      | Total bill amount (e.g. `1500.00`)        |
| `description` | string        | No       | Bill description                          |
| `status`      | string        | No       | `"draft"` (default) or `"needs_approval"` |
| `line_items`  | array         | No       | Bill line items                           |

**Direct-to-approval:** Set `status` to `"needs_approval"` to skip the draft stage and submit the bill directly for approval in a single API call.

### Response (201 Created)

```json
{
  "id": "660e8400-e29b-41d4-a716-446655440000",
  "vendor_id": "550e8400-e29b-41d4-a716-446655440000",
  "number": "INV-2026-001",
  "issue_date": "2026-04-01",
  "due_date": "2026-05-01",
  "amount": 1500.00,
  "description": "Monthly hosting services",
  "status": "draft",
  "source": "manual",
  "pay_date": null,
  "line_items": [
    {
      "sequence": 1,
      "name": "Cloud Hosting",
      "description": "AWS monthly fee",
      "unit_type": "service",
      "quantity": 1,
      "unit_price": 1500.00,
      "total": 1500.00,
      "tax": 0.00,
      "expense_account_id": ""
    }
  ],
  "vendor_payments": [],
  "last_status": {
    "status": "draft",
    "reason": null,
    "created_at": "2026-04-01T00:00:00Z",
    "user_id": "770e8400-e29b-41d4-a716-446655440000"
  },
  "created_at": "2026-04-01T00:00:00Z",
  "updated_at": "2026-04-01T00:00:00Z"
}
```

***

## List Bills

```
GET /bills
```

### Query Parameters

| Parameter         | Type    | Description                                                                            |
| ----------------- | ------- | -------------------------------------------------------------------------------------- |
| `limit`           | integer | Items per page (default 100)                                                           |
| `after`           | string  | Forward pagination cursor                                                              |
| `before`          | string  | Backward pagination cursor                                                             |
| `vendor_id`       | string  | Filter by vendor ID                                                                    |
| `status`          | string  | Filter by status: `draft`, `needs_approval`, `processing`, `paid`, `deleted`, `failed` |
| `bill_number`     | string  | Filter by bill number                                                                  |
| `source`          | string  | Filter by source: `manual`, `quickbooks`, `ocr`                                        |
| `include_deleted` | boolean | Include soft-deleted bills (default false)                                             |

***

## Submit Bill for Approval

```
POST /bills/{id}/submit
```

Transitions a bill from `draft` to `needs_approval`. No request body required.

***

## Reject Bill

```
POST /bills/{id}/reject
```

Rejects a bill that is in `needs_approval` status, moving it back to `draft`.

### Request Body

```json
{
  "reason": "Amount does not match PO"
}
```

***

## Set Pay Date

```
POST /bills/{id}/pay-date
```

Sets or updates the scheduled payment date for a bill. **This is a prerequisite for initiating a vendor payment.** If `pay_date` is null when you try to create a vendor payment, the request will return 422.

### Request Body

```json
{
  "pay_date": "2026-04-15"
}
```

`pay_date` must be in `YYYY-MM-DD` format.

***

## Upload Bill Document (OCR)

```
POST /bills/upload
```

Upload a document (PDF, PNG, JPEG) as base64-encoded content. The system extracts bill data via OCR and creates a bill automatically.

### Request Body

```json
{
  "content": "<base64-encoded-file-content>",
  "filename": "invoice.pdf",
  "content_type": "application/pdf"
}
```

| Field          | Type   | Required | Description                                              |
| -------------- | ------ | -------- | -------------------------------------------------------- |
| `content`      | string | Yes      | Base64-encoded file content                              |
| `filename`     | string | Yes      | Original filename                                        |
| `content_type` | string | Yes      | MIME type (`application/pdf`, `image/png`, `image/jpeg`) |

### Response (201 Created)

```json
{
  "bill_id": "660e8400-e29b-41d4-a716-446655440000",
  "bill_number": "INV-OCR-001",
  "extracted_data": {
    "vendor_name": "Acme Corp",
    "vendor_email": "billing@acme.com",
    "invoice_number": "INV-OCR-001",
    "total": 1500.00,
    "issue_date": "2026-04-01",
    "due_date": "2026-05-01",
    "description": "Monthly services",
    "line_items": [
      {
        "name": "Cloud Hosting",
        "description": "AWS monthly fee",
        "quantity": 1,
        "unit_price": 1500.00,
        "total": 1500.00
      }
    ]
  },
  "document_path": "/uploads/invoice.pdf",
  "warnings": []
}
```

***

## Bulk Submit Bills

```
POST /bills/bulk-submit
```

Submit multiple bills for approval in a single request.

### Request Body

```json
{
  "bill_ids": [
    "660e8400-e29b-41d4-a716-446655440001",
    "660e8400-e29b-41d4-a716-446655440002"
  ]
}
```

### Response (200 OK)

```json
{
  "results": [
    { "bill_id": "660e8400-...-440001", "success": true },
    { "bill_id": "660e8400-...-440002", "success": true }
  ]
}
```

***

## Bulk Delete Bills

```
POST /bills/bulk-delete
```

Soft-delete multiple bills in a single request. Same request/response shape as bulk submit.

***

## Bill Statuses

| Status           | Description             |
| ---------------- | ----------------------- |
| `draft`          | Initial state, editable |
| `needs_approval` | Submitted for review    |
| `processing`     | Payment in progress     |
| `paid`           | Payment completed       |
| `failed`         | Payment failed          |
| `deleted`        | Soft-deleted            |

## Bill Sources

| Source       | Description                                      |
| ------------ | ------------------------------------------------ |
| `manual`     | Created via API or UI                            |
| `quickbooks` | Synced from QuickBooks                           |
| `ocr`        | Created from document upload with OCR extraction |


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://help.alternativepayments.io/getting-started/accounts-payable-api/bills.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
