# Creates a vendor bill.

`POST /accounting/vendor-bills`

Group: Accounting › Vendor Bills · Operation ID: `createVendorBill`

The response contains only the new bill's id. Read the record with GET accounting/vendor-bills/:id if you need its stored state, where vendorBillNumber appears once assigned. The bill is always created pendingApproval, so a status cannot be supplied here. currency governs every line amount and vatAmount, which are decimals with no currency of their own. vatPercentage is a percentage, so 19 means 19%, not 0.19. A bill with more lines than your tenant runs in one call is refused with TOO_MANY_LINES, so split it or load it through the integration platform.

[Open in the interactive reference](https://docs.api.lensing.ai/?op=createVendorBill)

## Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `Api-Version` | header | `"v1"` | yes | The API version this request targets, named by its public identifier. Required on every request; omitting it, or naming a version this company does not have, is answered with 400. This document describes version `v1`. |

## Request body

Required, `application/json`: createVendorBillInput.

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `vendorId` | string | yes | The vendor the bill is from. See id on GET accounting/vendors/:id. |
| `entityId` | string | yes | The legal entity the bill is posted under. See id on GET base/entities. |
| `billNumber` | string | yes | The vendor-issued invoice number, as printed on the bill. It is not unique across vendors. |
| `billDate` | string (date) | yes | The date printed on the vendor's invoice. Use format YYYY-MM-DD. |
| `dueDate` | string (date) | yes | The date payment is due. Use format YYYY-MM-DD. |
| `currency` | string | yes | The currency of the bill. Format ISO 4217, for example 'USD'. Governs every line amount and vatAmount, which are decimals. |
| `serviceDate` | string (date) | no | The date the goods or services were delivered. Use format YYYY-MM-DD. Omit to leave it unset. For an entity whose country requires a service date it then defaults to billDate. |
| `paymentTerms` | string | no | The payment-terms key, for example 'net30', 'net60' or 'dueOnReceipt'. The API does not check it against a list. Omit to inherit 'custom'. |
| `externalVendorBillId` | string | no | The identifier this bill has in the upstream system that produced it. It is not unique. |
| `markAsPaid` | boolean | no | Whether to mark the bill paid on creation. Defaults to false. |
| `origin` | string | no | The source system this record came from, as free-form text, for example 'Ramp'. Omit it and it stays unset. The server does not set a value. |
| `lines` | array of object | yes | The line items of the bill, in the order they should appear. At least one is expected. A bill with no lines asks for no expense. |
| `lines[].amount` | string (decimal) | yes | The total line amount, gross, including VAT where applicable, as a decimal in the bill currency. |
| `lines[].description` | string | no | A description of the line item, typically copied from the vendor's invoice. |
| `lines[].accountId` | string | no | The GL expense account this line posts to. See id on GET accounting/accounts/:id. |
| `lines[].departmentId` | string | no | The department this line is charged to. See id on GET departments/:id. |
| `lines[].businessUnitId` | string | no | The business unit this line is charged to. There is no endpoint for it. |
| `lines[].customerId` | string | no | The customer this expense is rebilled to. See id on GET accounting/customers/:id. It is only meaningful alongside billableExpense. |
| `lines[].vatPercentage` | string (decimal) | no | The VAT rate applied, as a percentage. 19 means 19%, not 0.19. |
| `lines[].vatAccountId` | string | no | The GL account the VAT posts to. See id on GET accounting/accounts/:id. |
| `lines[].reverseVatAccountId` | string | no | The GL account reverse-charge VAT posts to. See id on GET accounting/accounts/:id. |
| `lines[].vatAmount` | string (decimal) | no | The explicit VAT amount, as a decimal in the bill currency. Omit to derive it from vatPercentage. |
| `lines[].valueAllocationId` | string | no | The value-allocation rule distributing this line across dimensions. There is no endpoint for it. |
| `lines[].purchaseOrderLineId` | string | no | The purchase-order line this line is matched against. There is no endpoint for it. |
| `lines[].billableExpense` | string | no | The billable-expense status for this line. Values include 'yes', 'no' and 'skipped'. |
| `lines[].lineType` | string | no | The kind of line. Values include 'expense' (a one-time cost) and 'prepaidExpense' (an upfront cost spread over several periods). Defaults to 'expense'. |
| `attachments` | array of object | no | Files to attach to the bill. Each names an already-uploaded file by its id. |
| `attachments[].fileName` | string | yes | The display name of the attached file. |
| `attachments[].fileId` | string | yes | The identifier of the already-uploaded file. There is no endpoint for it. |

Example:

```json
{
  "vendorId": "3b7d5e9c-1a24-4f80-9c6d-2e8f70b13a45",
  "entityId": "8f2c1d40-5a6b-4c7d-9e80-1f2a3b4c5d6e",
  "billNumber": "INV-88213",
  "billDate": "2026-08-01",
  "dueDate": "2026-08-31",
  "currency": "EUR",
  "serviceDate": "2026-01-15",
  "paymentTerms": "<paymentTerms>",
  "externalVendorBillId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "markAsPaid": true,
  "origin": "<origin>",
  "lines": [
    {
      "amount": "1200.00",
      "description": "Consulting, August",
      "vatPercentage": "19.00"
    }
  ],
  "attachments": [
    {
      "fileName": "<fileName>",
      "fileId": "3fa85f64-5717-4562-b3fc-2c963f66afa6"
    }
  ]
}
```

## Response

`200` Success

Under `data` (createVendorBillOutput):

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `id` | string | yes | The unique identifier for the created vendor bill. |

## Errors

| Code | Status |
| --- | --- |
| `REFERENCE_NOT_FOUND` | 400 |
| `ACCOUNT_ENTITY_MISMATCH` | 400 |
| `TOO_MANY_LINES` | 400 |
| `IDEMPOTENCY_NOT_SUPPORTED` | 400 |

## Statuses

- `400` — Invalid request or business failure. Codes: REFERENCE_NOT_FOUND, ACCOUNT_ENTITY_MISMATCH, TOO_MANY_LINES. Sending an Idempotency-Key is answered with `IDEMPOTENCY_NOT_SUPPORTED`: this action does not run in its own transaction, so the replay guarantee cannot be offered and the header is refused rather than ignored.
- `401` — Missing or invalid access token
- `403` — Not authorized
- `404` — Not found
- `429` — Too many requests
- `500` — Internal server error
