# Quickstart

The entire happy path against the sandbox, in order. Every step is a runnable curl. Completing steps 1–13 makes `GET /partner/v1/sandbox/verification` return `"readyForProduction": true` for all 12 required checks.

Base URL for everything on this page: `https://sandbox.bilnex.io`. Auth header on every call except step 1: `Authorization: Bearer <YOUR_API_KEY>`. A call without `X-Company-Id` acts for the sender company.

## 1. Provision a key

```bash
curl -s -X POST https://sandbox.bilnex.io/partner/v1/sandbox \
  -H "Content-Type: application/json" \
  -d '{"email":"dev@erp.example","erpName":"AwesomeERP","ref":"agent"}'
```

Response `201 Created`:

```json
{
  "apiKey": "blx_sbx_<YOUR_API_KEY>",
  "keyId": "cd9e4507-92ab-421e-b8d3-c746b0ecb352",
  "keyPrefix": "blx_sbx_",
  "expiresAt": "2026-10-14T10:58:31.230669582",
  "companies": {
    "sender": {
      "companyId": "f2fe5e72-0792-41f4-88b7-a9ce5fda82be",
      "name": "AwesomeERP Sandbox Sender OÜ",
      "regCode": "95000040",
      "role": "sender",
      "peppolId": "0191:95000040"
    },
    "receiver": {
      "companyId": "2cc86222-3717-4f26-b9f9-378dc89e9384",
      "name": "AwesomeERP Sandbox Receiver OÜ",
      "regCode": "95000041",
      "role": "receiver",
      "peppolId": "0191:95000041"
    }
  },
  "fixtures": [
    {
      "name": "Sandbox Capable OÜ",
      "regCode": "95999901",
      "behavior": "accepts_einvoice",
      "description": "Accepts operator-channel e-invoices and Peppol documents."
    },
    {
      "name": "Sandbox Paper OÜ",
      "regCode": "95999902",
      "behavior": "not_einvoice_capable",
      "description": "Is not registered to receive e-invoices — send this one a PDF by email instead."
    },
    {
      "name": "Sandbox Rejector OÜ",
      "regCode": "95999903",
      "behavior": "rejects_einvoice",
      "description": "Always refuses e-invoices at the operator, so you can exercise the failure path."
    }
  ],
  "limits": {
    "requestsPerMinute": 60,
    "requestsPerDay": 5000,
    "sendsPerDay": 200,
    "maxInvoices": 500,
    "maxEmails": 200
  },
  "urls": {
    "docs": "https://sandbox.bilnex.io/agents.md",
    "verification": "https://sandbox.bilnex.io/partner/v1/sandbox/verification",
    "openapi": "https://sandbox.bilnex.io/partner/v1/openapi.json",
    "claim": "https://sandbox.bilnex.io/partner/v1/sandbox/claim"
  },
  "companyKeys": {
    "sender": {
      "companyId": "f2fe5e72-0792-41f4-88b7-a9ce5fda82be",
      "apiKey": "blx_sbx_<COMPANY_KEY>",
      "keyId": "5ea3816d-45b0-4a11-ab80-1fe246edd789",
      "keyPrefix": "blx_sbx_",
      "last4": "C9Sv"
    },
    "receiver": {
      "companyId": "2cc86222-3717-4f26-b9f9-378dc89e9384",
      "apiKey": "blx_sbx_<COMPANY_KEY>",
      "keyId": "1f06a99c-1ff3-41fc-a862-b92148a8453f",
      "keyPrefix": "blx_sbx_",
      "last4": "4y4z"
    }
  }
}
```

- `apiKey` is shown once. Store it in server-side configuration only. It acts for both sandbox companies.
- The steps below use the values from this response; substitute your own. `<RECEIVER_COMPANY_ID>` = `companies.receiver.companyId`.
- `companyKeys` holds one key per sandbox company. Each acts for its own company only, as the key each customer generates in production does. Use them to test your software's Bilnex URL + API key settings screen (see [sandbox](https://sandbox.bilnex.io/docs/sandbox.md)).
- The sandbox lasts 2 days. `POST /partner/v1/sandbox/claim` extends it once, to 30 days from the claim. Nothing reminds you before it expires.
- `limits.maxInvoices` and `limits.maxEmails` are reported but not enforced.

## 2. Auth check — `AUTH_OK`

```bash
curl -s https://sandbox.bilnex.io/partner/v1/me \
  -H "Authorization: Bearer <YOUR_API_KEY>"
```

```json
{
  "environment": "sandbox",
  "keyId": "cd9e4507-92ab-421e-b8d3-c746b0ecb352",
  "keyExpiresAt": "2026-10-14T10:58:31.23067",
  "actingCompany": {
    "companyId": "f2fe5e72-0792-41f4-88b7-a9ce5fda82be",
    "name": "AwesomeERP Sandbox Sender OÜ",
    "regCode": "95000040",
    "role": "sender",
    "peppolId": "0191:95000040"
  },
  "companies": [
    {
      "companyId": "2cc86222-3717-4f26-b9f9-378dc89e9384",
      "name": "AwesomeERP Sandbox Receiver OÜ",
      "regCode": "95000041",
      "role": "receiver",
      "peppolId": "0191:95000041"
    },
    {
      "companyId": "f2fe5e72-0792-41f4-88b7-a9ce5fda82be",
      "name": "AwesomeERP Sandbox Sender OÜ",
      "regCode": "95000040",
      "role": "sender",
      "peppolId": "0191:95000040"
    }
  ],
  "limits": {
    "requestsPerMinute": 60,
    "requestsPerDay": 5000,
    "sendsPerDay": 200,
    "maxInvoices": 500,
    "maxEmails": 200
  },
  "usage": {
    "requestsToday": 1,
    "sendsToday": 0,
    "emailsCaptured": 0
  }
}
```

`usage` holds the key's live counters.

## 3. Capability check, capable — `CAPABILITY_CHECKED_CAPABLE`

```bash
curl -s https://sandbox.bilnex.io/partner/v1/customers/95000041/e-invoice-capability \
  -H "Authorization: Bearer <YOUR_API_KEY>"
```

```json
{
  "regCode": "95000041",
  "name": "AwesomeERP Sandbox Receiver OÜ",
  "eInvoiceCapable": true,
  "operator": "BILNEX",
  "peppolCapable": true,
  "peppolId": "0191:95000041",
  "recommendedChannel": "E_INVOICE",
  "checkedAt": "2026-10-12T10:58:32.43101703"
}
```

## 4. Capability check, not capable — `CAPABILITY_CHECKED_NOT_CAPABLE`

```bash
curl -s https://sandbox.bilnex.io/partner/v1/customers/95999902/e-invoice-capability \
  -H "Authorization: Bearer <YOUR_API_KEY>"
```

```json
{
  "regCode": "95999902",
  "name": "Sandbox Paper OÜ",
  "eInvoiceCapable": false,
  "operator": null,
  "peppolCapable": false,
  "peppolId": null,
  "recommendedChannel": "EMAIL",
  "checkedAt": "2026-10-12T10:58:32.637562205"
}
```

Branch on `eInvoiceCapable`: `false` → send via `EMAIL` (step 10).

## 5. Create an invoice — `INVOICE_CREATED`

```bash
curl -s -X POST https://sandbox.bilnex.io/partner/v1/invoices \
  -H "Authorization: Bearer <YOUR_API_KEY>" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: 19dffedd-56dd-442a-b0e7-6420afe40544" \
  -d '{
    "customer": {
      "name": "AwesomeERP Sandbox Receiver OÜ",
      "regCode": "95000041",
      "email": "arved@receiver.example"
    },
    "date": "2026-10-12",
    "dueDate": "2026-10-26",
    "currency": "EUR",
    "language": "ET",
    "items": [
      {
        "description": "Consulting services, September 2026",
        "quantity": 10.00,
        "unit": "HR",
        "price": 95.00,
        "vatRate": 24
      }
    ]
  }'
```

Response `201 Created`:

```json
{
  "id": "9e0a9088-a4b3-4d80-9d17-4917667a95f7",
  "number": "2026-0001",
  "status": "SAVED",
  "category": "PDF",
  "customerName": "AwesomeERP Sandbox Receiver OÜ",
  "customerRegCode": "95000041",
  "date": "2026-10-12",
  "dueDate": "2026-10-26",
  "totalAmount": 1178.0
}
```

The server computes the totals; `totalAmount` is the gross total (10 × 95.00 plus 24 % VAT). The response carries no lines or VAT breakdown: keep your own, and store Bilnex's `id`, `number` and `totalAmount`. `unit` takes codes such as `HR` and `PCS` — see [sending-invoices](https://sandbox.bilnex.io/docs/sending-invoices.md).

Read it back at any time:

```bash
curl -s https://sandbox.bilnex.io/partner/v1/invoices/9e0a9088-a4b3-4d80-9d17-4917667a95f7 \
  -H "Authorization: Bearer <YOUR_API_KEY>"
```

The answer is the same invoice object as above.

## 6. Fetch the PDF — `PDF_FETCHED`

```bash
curl -s https://sandbox.bilnex.io/partner/v1/invoices/9e0a9088-a4b3-4d80-9d17-4917667a95f7/pdf \
  -H "Authorization: Bearer <YOUR_API_KEY>"
```

```json
{
  "expiresAt": "2026-10-12T11:13:44.9724759",
  "pdfUrl": "https://s3.eu-north-1.amazonaws.com/<presigned URL, valid 15 minutes>"
}
```

Download the file within 15 minutes. Store the bytes, not the URL.

## 7. Send as e-invoice — `EINVOICE_SENT`

```bash
curl -s -X POST https://sandbox.bilnex.io/partner/v1/invoices/9e0a9088-a4b3-4d80-9d17-4917667a95f7/send \
  -H "Authorization: Bearer <YOUR_API_KEY>" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: 0b3c8e5d-2f7a-4c19-8a6b-d4e1f9a0c752" \
  -d '{"channel":"E_INVOICE"}'
```

```json
{
  "id": "9e0a9088-a4b3-4d80-9d17-4917667a95f7",
  "status": "SENT",
  "category": "E_INVOICE",
  "channel": "E_INVOICE",
  "sentAt": "2026-10-12T10:58:46.100115571"
}
```

`SENT` is final for `E_INVOICE` — nothing further to poll. Send each invoice once: Bilnex does not stop a second send, and it sends the invoice again.

## 8. List purchase invoices at the receiver — `EINVOICE_RECEIVED_AT_RECEIVER`, `PURCHASE_LISTED`

```bash
curl -s "https://sandbox.bilnex.io/partner/v1/purchase-invoices?since=2026-10-12T00:00:00Z" \
  -H "Authorization: Bearer <YOUR_API_KEY>" \
  -H "X-Company-Id: <RECEIVER_COMPANY_ID>"
```

```json
{
  "items": [
    {
      "id": "aa360bdf-c873-4a6c-ac80-0a758c3411f6",
      "status": "NEW",
      "source": "E_INVOICE",
      "senderName": "AwesomeERP Sandbox Sender OÜ",
      "invoiceNumber": "2026-0001",
      "date": "2026-10-12T00:00:00",
      "dueDate": "2026-10-26T00:00:00",
      "currency": "EUR",
      "totalAmount": 1178.0,
      "receivedAt": "2026-10-12T10:58:46.701667"
    }
  ],
  "page": 1,
  "pageSize": 50,
  "total": 1,
  "hasMore": false,
  "nextSince": "2026-10-12T10:58:46.701667"
}
```

The e-invoice from step 7 arrives here a moment after the send; `EINVOICE_RECEIVED_AT_RECEIVER` passes when it does. If the list is empty, poll again. Persist `nextSince` and send it as `since` on the next poll. Dedupe by `id`.

Read one document. The answer has the same fields as the list, and reading it does not change its status:

```bash
curl -s https://sandbox.bilnex.io/partner/v1/purchase-invoices/aa360bdf-c873-4a6c-ac80-0a758c3411f6 \
  -H "Authorization: Bearer <YOUR_API_KEY>" \
  -H "X-Company-Id: <RECEIVER_COMPANY_ID>"
```

```json
{
  "id": "aa360bdf-c873-4a6c-ac80-0a758c3411f6",
  "status": "NEW",
  "source": "E_INVOICE",
  "senderName": "AwesomeERP Sandbox Sender OÜ",
  "invoiceNumber": "2026-0001",
  "date": "2026-10-12T00:00:00",
  "dueDate": "2026-10-26T00:00:00",
  "currency": "EUR",
  "totalAmount": 1178.0,
  "receivedAt": "2026-10-12T10:58:46.701667"
}
```

Fetch the received document's PDF for your ERP:

```bash
curl -s https://sandbox.bilnex.io/partner/v1/purchase-invoices/aa360bdf-c873-4a6c-ac80-0a758c3411f6/original \
  -H "Authorization: Bearer <YOUR_API_KEY>" \
  -H "X-Company-Id: <RECEIVER_COMPANY_ID>"
```

```json
{
  "expiresAt": "2026-10-12T11:13:56.39728849",
  "url": "https://s3.eu-north-1.amazonaws.com/<presigned URL, valid 15 minutes>"
}
```

The link is valid for 15 minutes. Fetching it moves the document from `NEW` to `SEEN`.

## 9. Mark exported — `MARKED_EXPORTED`

```bash
curl -s -X POST https://sandbox.bilnex.io/partner/v1/purchase-invoices/aa360bdf-c873-4a6c-ac80-0a758c3411f6/mark-exported \
  -H "Authorization: Bearer <YOUR_API_KEY>" \
  -H "X-Company-Id: <RECEIVER_COMPANY_ID>"
```

```json
{
  "id": "aa360bdf-c873-4a6c-ac80-0a758c3411f6",
  "status": "EXPORTED",
  "source": "E_INVOICE",
  "senderName": "AwesomeERP Sandbox Sender OÜ",
  "invoiceNumber": "2026-0001",
  "date": "2026-10-12T00:00:00",
  "dueDate": "2026-10-26T00:00:00",
  "currency": "EUR",
  "totalAmount": 1178.0,
  "receivedAt": "2026-10-12T10:58:46.701667"
}
```

Mandatory after every ERP import. Calling it again changes nothing.

## 10. Create + send an EMAIL invoice to the not-capable customer — `EMAIL_SENT`, `NOT_CAPABLE_FALLBACK`

Back as the sender (no `X-Company-Id`):

```bash
curl -s -X POST https://sandbox.bilnex.io/partner/v1/invoices \
  -H "Authorization: Bearer <YOUR_API_KEY>" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: b62ed1da-9e8a-496e-b357-40ea8e832b2d" \
  -d '{
    "customer": {
      "name": "Sandbox Paper OÜ",
      "regCode": "95999902",
      "email": "billing@sandbox-paper.example"
    },
    "date": "2026-10-12",
    "dueDate": "2026-10-26",
    "currency": "EUR",
    "language": "ET",
    "items": [
      {
        "description": "Consulting services, September 2026",
        "quantity": 10.00,
        "unit": "HR",
        "price": 95.00,
        "vatRate": 24
      }
    ]
  }'
```

```json
{
  "id": "1d6c2176-2fc2-462f-a76b-c10f1eeb26c6",
  "number": "2026-0002",
  "status": "SAVED",
  "category": "PDF",
  "customerName": "Sandbox Paper OÜ",
  "customerRegCode": "95999902",
  "date": "2026-10-12",
  "dueDate": "2026-10-26",
  "totalAmount": 1178.0
}
```

```bash
curl -s -X POST https://sandbox.bilnex.io/partner/v1/invoices/1d6c2176-2fc2-462f-a76b-c10f1eeb26c6/send \
  -H "Authorization: Bearer <YOUR_API_KEY>" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: c5a9b0d3-7e21-4f6f-8e6d-1b4a2c4d0e97" \
  -d '{"channel":"EMAIL","to":"billing@sandbox-paper.example","message":"Invoice attached."}'
```

```json
{
  "id": "1d6c2176-2fc2-462f-a76b-c10f1eeb26c6",
  "status": "SENT",
  "category": "PDF",
  "channel": "EMAIL",
  "sentAt": "2026-10-12T10:58:58.585549903"
}
```

`NOT_CAPABLE_FALLBACK` passes because an invoice to the not-capable fixture `95999902` was sent with `EMAIL`. Pass `to` on every EMAIL send, and keep within the [e-mail limits](https://sandbox.bilnex.io/docs/email-invoices.md): a company that keeps reaching them is suspended.

## 11. Fetch the intercepted email — `EMAIL_FETCHED_FROM_INTERCEPT`

Sandbox email is never delivered; read it here. The answer is a JSON array, newest first:

```bash
curl -s https://sandbox.bilnex.io/partner/v1/sandbox/emails \
  -H "Authorization: Bearer <YOUR_API_KEY>"
```

```json
[
  {
    "id": "49acbee7-9fd7-45fc-ab13-9e9d4d18d946",
    "to": "billing@sandbox-paper.example",
    "cc": "",
    "from": null,
    "subject": "Arve #2026-0002 AwesomeERP Sandbox Sender OÜ",
    "body": "<!DOCTYPE html>\n<html>\n<head>\n    <meta charset=\"UTF-8\">\n    <title>Arve #2026-0002 AwesomeERP Sandbox Sender OÜ</title> …",
    "attachmentName": "Arve#20260002.pdf",
    "sentAt": "2026-10-12T10:58:59.873864"
  }
]
```

`body` is the HTML of the e-mail, shortened here. The e-mail is captured a moment after the send; if the array is empty, read it again.

## 12. Triggers: SEEN and incoming documents — `INVOICE_SEEN_HANDLED`, `PEPPOL_RECEIVED` (optional)

Mark the e-mailed invoice as opened:

```bash
curl -s -X POST https://sandbox.bilnex.io/partner/v1/sandbox/trigger \
  -H "Authorization: Bearer <YOUR_API_KEY>" \
  -H "Content-Type: application/json" \
  -d '{"event":"invoice_seen","invoiceId":"1d6c2176-2fc2-462f-a76b-c10f1eeb26c6"}'
```

```json
{
  "event": "invoice_seen",
  "applied": true,
  "invoiceId": "1d6c2176-2fc2-462f-a76b-c10f1eeb26c6",
  "hint": "The invoice moves to SEEN shortly; re-read it with GET /partner/v1/invoices/1d6c2176-2fc2-462f-a76b-c10f1eeb26c6."
}
```

`INVOICE_SEEN_HANDLED` passes now. A moment later, reading the invoice shows `"status": "SEEN"`:

```bash
curl -s https://sandbox.bilnex.io/partner/v1/invoices/1d6c2176-2fc2-462f-a76b-c10f1eeb26c6 \
  -H "Authorization: Bearer <YOUR_API_KEY>"
```

```json
{
  "id": "1d6c2176-2fc2-462f-a76b-c10f1eeb26c6",
  "number": "2026-0002",
  "status": "SEEN",
  "category": "PDF",
  "customerName": "Sandbox Paper OÜ",
  "customerRegCode": "95999902",
  "date": "2026-10-12",
  "dueDate": "2026-10-26",
  "totalAmount": 1178.0
}
```

Make a supplier send your receiver company an e-invoice, then a Peppol document:

```bash
curl -s -X POST https://sandbox.bilnex.io/partner/v1/sandbox/trigger \
  -H "Authorization: Bearer <YOUR_API_KEY>" \
  -H "Content-Type: application/json" \
  -d '{"event":"inbound_einvoice"}'
```

```json
{
  "event": "inbound_einvoice",
  "applied": true,
  "deliveredTo": {
    "companyId": "2cc86222-3717-4f26-b9f9-378dc89e9384",
    "regCode": "95000041"
  },
  "hint": "Poll GET /partner/v1/purchase-invoices with X-Company-Id: 2cc86222-3717-4f26-b9f9-378dc89e9384 to pick it up."
}
```

```bash
curl -s -X POST https://sandbox.bilnex.io/partner/v1/sandbox/trigger \
  -H "Authorization: Bearer <YOUR_API_KEY>" \
  -H "Content-Type: application/json" \
  -d '{"event":"inbound_peppol"}'
```

```json
{
  "event": "inbound_peppol",
  "applied": true,
  "deliveredTo": {
    "companyId": "2cc86222-3717-4f26-b9f9-378dc89e9384",
    "peppolId": "0191:95000041"
  },
  "hint": "Delivered to the receiver; this passes PEPPOL_RECEIVED. Peppol documents are not yet listed by GET /partner/v1/purchase-invoices."
}
```

Both land at the receiver company, whatever `X-Company-Id` you send. `PEPPOL_RECEIVED` passes when the Peppol document arrives. The API does not return incoming Peppol documents yet (see [peppol](https://sandbox.bilnex.io/docs/peppol.md)), so a poll with the `nextSince` from step 8 finds only the e-invoice:

```bash
curl -s "https://sandbox.bilnex.io/partner/v1/purchase-invoices?since=2026-10-12T10:58:46.701667" \
  -H "Authorization: Bearer <YOUR_API_KEY>" \
  -H "X-Company-Id: <RECEIVER_COMPANY_ID>"
```

```json
{
  "items": [
    {
      "id": "2e8f0ea5-a3d2-4afd-b156-a0855064c893",
      "status": "NEW",
      "source": "E_INVOICE",
      "senderName": "Sandbox Capable OÜ",
      "invoiceNumber": "SBX-2026-448BEC",
      "date": "2026-10-12T00:00:00",
      "dueDate": "2026-10-26T00:00:00",
      "currency": "EUR",
      "totalAmount": 148.8,
      "receivedAt": "2026-10-12T10:59:02.408861"
    }
  ],
  "page": 1,
  "pageSize": 50,
  "total": 1,
  "hasMore": false,
  "nextSince": "2026-10-12T10:59:02.408861"
}
```

## 13. Verification — the stopping condition

```bash
curl -s https://sandbox.bilnex.io/partner/v1/sandbox/verification \
  -H "Authorization: Bearer <YOUR_API_KEY>"
```

```json
{
  "checks": [
    { "id": "AUTH_OK", "required": true, "status": "pass", "detail": "GET /partner/v1/me succeeded with this key.", "fixHint": null, "docsUrl": "https://sandbox.bilnex.io/docs/authentication.md" },
    { "id": "CAPABILITY_CHECKED_CAPABLE", "required": true, "status": "pass", "detail": "Capability checked for 95000041 (capable).", "fixHint": null, "docsUrl": "https://sandbox.bilnex.io/docs/sending-invoices.md" },
    { "id": "CAPABILITY_CHECKED_NOT_CAPABLE", "required": true, "status": "pass", "detail": "Capability checked for 95999902 (not capable).", "fixHint": null, "docsUrl": "https://sandbox.bilnex.io/docs/sending-invoices.md" },
    { "id": "INVOICE_CREATED", "required": true, "status": "pass", "detail": "Invoice 2026-0001 created.", "fixHint": null, "docsUrl": "https://sandbox.bilnex.io/docs/sending-invoices.md" },
    { "id": "PDF_FETCHED", "required": true, "status": "pass", "detail": "PDF fetched for invoice 9e0a9088-a4b3-4d80-9d17-4917667a95f7.", "fixHint": null, "docsUrl": "https://sandbox.bilnex.io/docs/sending-invoices.md" },
    { "id": "EINVOICE_SENT", "required": true, "status": "pass", "detail": "Invoice 2026-0001 sent via E_INVOICE.", "fixHint": null, "docsUrl": "https://sandbox.bilnex.io/docs/sending-invoices.md" },
    { "id": "EINVOICE_RECEIVED_AT_RECEIVER", "required": true, "status": "pass", "detail": "E-invoice 9e0a9088-a4b3-4d80-9 was delivered to 95000041.", "fixHint": null, "docsUrl": "https://sandbox.bilnex.io/docs/receiving-invoices.md" },
    { "id": "PURCHASE_LISTED", "required": true, "status": "pass", "detail": "Listed incoming documents (1 total).", "fixHint": null, "docsUrl": "https://sandbox.bilnex.io/docs/receiving-invoices.md" },
    { "id": "MARKED_EXPORTED", "required": true, "status": "pass", "detail": "Document aa360bdf-c873-4a6c-ac80-0a758c3411f6 confirmed as imported.", "fixHint": null, "docsUrl": "https://sandbox.bilnex.io/docs/receiving-invoices.md" },
    { "id": "EMAIL_SENT", "required": true, "status": "pass", "detail": "Invoice 2026-0002 emailed.", "fixHint": null, "docsUrl": "https://sandbox.bilnex.io/docs/email-invoices.md" },
    { "id": "EMAIL_FETCHED_FROM_INTERCEPT", "required": true, "status": "pass", "detail": "Read 1 intercepted email(s).", "fixHint": null, "docsUrl": "https://sandbox.bilnex.io/docs/email-invoices.md" },
    { "id": "NOT_CAPABLE_FALLBACK", "required": true, "status": "pass", "detail": "Fell back to email for 95999902, which cannot receive e-invoices.", "fixHint": null, "docsUrl": "https://sandbox.bilnex.io/docs/sending-invoices.md" },
    { "id": "PEPPOL_SENT", "required": false, "status": "pending", "detail": null, "fixHint": "Optional, and not available yet: sending with channel PEPPOL answers 501 peppol_send_unavailable. Nothing to do.", "docsUrl": "https://sandbox.bilnex.io/docs/peppol.md" },
    { "id": "PEPPOL_RECEIVED", "required": false, "status": "pass", "detail": "A Peppol document arrived at the receiver company.", "fixHint": null, "docsUrl": "https://sandbox.bilnex.io/docs/peppol.md" },
    { "id": "INVOICE_SEEN_HANDLED", "required": false, "status": "pass", "detail": "Invoice 2026-0002 was marked as opened by the recipient.", "fixHint": null, "docsUrl": "https://sandbox.bilnex.io/docs/email-invoices.md" }
  ],
  "readyForProduction": true,
  "nextSteps": []
}
```

There are 15 checks: 12 required, 3 optional. Each one is `pass` or `pending`. `readyForProduction` is `true` when all 12 required checks pass; while one is pending, `nextSteps` names up to three of them with their `fixHint`. `PEPPOL_SENT` stays pending, because Peppol sending is not available yet.

Do not report the integration complete until this returns `"readyForProduction": true`. If a check is pending, read its `fixHint` and `docsUrl`, fix the integration code, and run it again. Then continue below.

## Going to production

Your integration code does not change for production: point it at `https://api.app.bilnex.io/partner/v1` and use the key each customer generates. Switching it on is not self-serve yet — Bilnex opens the Partner API per integration. Nothing is sent to you automatically when verification passes; the first step is yours:

1. Email partners@bilnex.io the verification response and your ERP's name.
2. Open a Bilnex account for your own company at https://app.bilnex.io, activate e-invoice sending and add a bank account.
3. Bilnex switches the Partner API on for that company. You generate its key under Settings → ERP integration and run the production smoke test ([go-live](https://sandbox.bilnex.io/docs/go-live.md)).
4. When you confirm it works, Bilnex switches it on for your customers. Each of them generates its own key under Settings → ERP integration and enters it in your ERP together with the URL.

Until the Partner API is switched on for a company, every production call for it answers 503 `feature_disabled` — not retryable.

API version 2026-08-01. /partner/v1 changes are additive-only; see [versioning-policy](https://sandbox.bilnex.io/docs/versioning-policy.md).

---
**Building with a coding agent?** Start from [agents.md](https://sandbox.bilnex.io/agents.md) or install the skill: `npx skills add https://sandbox.bilnex.io`. Machine-readable index: [llms.txt](https://sandbox.bilnex.io/llms.txt). Every page on this site is also plain markdown — append `.md`.
