# Import a bill from an unlinked account

Use Bill Imports when the customer has a bill document but has not connected that biller account. BillerAPI creates a normalized Bill after review. If the biller is supported, prompt the customer to connect so future bills arrive automatically.

> **Note — No account connection is required**
> The customer can import this bill before linking an account. After extraction, show the resolved biller and whether Connect is available.

1. Create an import and receive a short-lived upload target
2. PUT the original document directly to the upload target
3. Complete the upload and wait for NEEDS_REVIEW or READY_TO_COMMIT
4. Review candidates and evidence; patch corrections when needed
5. Confirm with the expected draft and lifecycle versions
6. Store committed_bill_id and consume bill.created

## Create and upload

**Node**

```javascript
import { createHash } from 'node:crypto';
import { readFile } from 'node:fs/promises';

const bytes = await readFile('utility-bill.pdf');
const sha256 = createHash('sha256').update(bytes).digest('hex');
const billImport = await billerapi.billImports.create({
  client_user_id: 'user_123',
  file_name: 'utility-bill.pdf',
  media_type: 'application/pdf',
  declared_bytes: bytes.length,
  sha256,
});

await fetch(billImport.upload_target!.url, {
  method: 'PUT', headers: billImport.upload_target!.headers, body: bytes,
});
```

> **Note — Review is a product boundary, not an error state**
> Extraction confidence and source evidence are exposed so your UI can ask a human to verify uncertain values. Confirmation uses optimistic versions to prevent committing a stale draft.

## Confirm, then choose the honest next action

Branch on the committed Bill's payment route. The durable goal is to connect a supported account for future sync, not merely to unlock payment.

**Node**

```javascript
const result = await billerapi.billImports.confirm(importId, review);
const { bill } = result;

switch (bill.payment_route?.type) {
  case 'ONBOARDED_LINKED':
    return showConnectedBill(bill);
  case 'ONBOARDED_CONNECTION_REQUIRED':
    return showConnectAccount({
      billerId: bill.biller?.biller_id ?? bill.payee?.canonical_biller_id,
      billId: bill.id,
    });
  default:
    return showExternalOnlyBill(bill);
}
```

| API state | Primary action | What happens next |
| --- | --- | --- |
| `ONBOARDED_LINKED` | View bill; schedule payment if eligible | Future bills continue to sync. |
| `ONBOARDED_CONNECTION_REQUIRED` | Connect account | Future bills and eligible biller messages flow through the connection. |
| `EXTERNAL_ONLY` | Track bill or mark paid externally | The biller cannot be connected yet; never imply automated payment. |
