Skip to content

Invoices

An invoice is the most direct way to request a specific amount from a customer. Creating one returns a unique web address (url) — direct your customer there, and Byl handles everything: choosing a payment method, paying, and receiving a receipt.

As soon as an invoice is paid, an invoice.paid event is sent via webhook, so your system knows without delay.

Invoice vs Checkout

To collect a specific amount, use an invoice. For a purchase involving products, quantities, coupon codes, or shipping addresses, Checkout is a better fit.

Statuses

StatusDescription
draftCreated but not finalized. Does not accept payment.
openFinalized and awaiting payment. Can be shown to the customer.
paidPaid. The invoice.paid webhook has been sent.
voidVoided. Can no longer be paid.

A newly created invoice moves straight to open because of the auto_advance setting (default true). Pass auto_advance: false to create it in the draft status.

The invoice object

FieldTypeDescription
idNumberThe invoice ID.
statusStringStatus: draft, open, paid, void.
amountNumberAmount (in tugrik).
descriptionStringDescription.
numberStringUnique invoice number.
urlStringThe invoice web page to show the customer.
customer_idNumberID of the associated customer.
project_idNumberThe Byl project ID.
due_dateDatePayment due date.
created_atDateCreation date.
updated_atDateLast updated date.

Create an invoice

POST /v1/projects/:project_id/invoices
ParameterTypeRequiredDescription
amountNumbertrueAmount. Minimum 10, up to 2 decimal places.
descriptionStringfalseDescription. Up to 255 characters.
due_dateDatefalsePayment due date. Must be a future date. Default: 1 day from now.
auto_advanceBooleanfalseIf true (default), the invoice moves straight to open. If false, it stays in draft.
customer_idNumberfalseA customer ID. Must belong to the project.

Example request

shell
BYL_PROJECT_ID="your project ID"
BYL_TOKEN="your API token"

curl -X POST https://byl.mn/api/v1/projects/$BYL_PROJECT_ID/invoices \
    -H "Authorization: Bearer $BYL_TOKEN" \
    -H 'Accept: application/json' \
    -H 'Content-Type: application/json' \
    -d '{
          "amount": 500,
          "description": "Test invoice",
          "auto_advance": true
      }'

Example response

json
{
  "data": {
    "id": 5708,
    "status": "open",
    "amount": 500,
    "description": "Test invoice",
    "number": "DEMO-0011",
    "customer_id": null,
    "project_id": 1,
    "url": "https://byl.mn/h/invoice/5708/XN3GbRBxTslkMCeDj10CJtqlHiPfcmZ8",
    "due_date": "2026-08-06T13:13:07.000000Z",
    "created_at": "2026-08-05T13:13:07.000000Z",
    "updated_at": "2026-08-05T13:13:07.000000Z"
  }
}

Direct your customer to the url in the response. The address contains a secret, making it impossible to guess, but we still recommend sharing it only with that customer.

Retrieve an invoice

GET /v1/projects/:project_id/invoices/:invoice_id

Use this to check whether an invoice has been paid, or to re-read its amount and number.

TIP

There is no need to poll this endpoint to find out when a payment lands — set up a webhook and the invoice.paid event will reach you immediately.

Example request

shell
curl -X GET https://byl.mn/api/v1/projects/$BYL_PROJECT_ID/invoices/5708 \
    -H "Authorization: Bearer $BYL_TOKEN" \
    -H 'Accept: application/json'

Example response

json
{
  "data": {
    "id": 5708,
    "status": "paid",
    "amount": 500,
    "description": "Test invoice",
    "number": "DEMO-0011",
    "customer_id": null,
    "project_id": 1,
    "url": "https://byl.mn/h/invoice/5708/XN3GbRBxTslkMCeDj10CJtqlHiPfcmZ8",
    "due_date": "2026-08-06T13:13:07.000000Z",
    "created_at": "2026-08-05T13:13:07.000000Z",
    "updated_at": "2026-08-05T13:13:20.000000Z"
  }
}

Void an invoice

POST /v1/projects/:project_id/invoices/:invoice_id/void

Voids the invoice — it will no longer accept payment. Voided invoices remain in your history and reports, so we recommend voiding a mistakenly created invoice rather than deleting it.

draft status only

Currently, voiding via the API only works on invoices in the draft status. Calling it on an invoice in the open, paid, or void status returns 403.

Note that because auto_advance defaults to true, invoices created via the API move straight to open — if you may need to void an invoice later, create it with auto_advance: false. An invoice that is already open can be voided from the dashboard.

Example request

shell
curl -X POST https://byl.mn/api/v1/projects/$BYL_PROJECT_ID/invoices/5711/void \
    -H "Authorization: Bearer $BYL_TOKEN" \
    -H 'Accept: application/json'

Example response

json
{
  "data": {
    "id": 5711,
    "status": "void",
    "amount": 500,
    "description": "Test invoice",
    "number": "DEMO-0011",
    "customer_id": null,
    "project_id": 1,
    "url": "https://byl.mn/h/invoice/5711/XN3GbRBxTslkMCeDj10CJtqlHiPfcmZ8",
    "due_date": "2026-09-08T16:33:41.000000Z",
    "created_at": "2026-09-07T16:33:41.000000Z",
    "updated_at": "2026-09-07T16:33:50.000000Z"
  }
}

Delete an invoice

DELETE /v1/projects/:project_id/invoices/:invoice_id

Hides the invoice from your list. The response returns a deleted_at timestamp.

draft status only

Deleting likewise only works on invoices in the draft status — other statuses return 403. Finalized invoices are never deleted, to preserve the integrity of your reports and history.

Example request

shell
curl -X DELETE https://byl.mn/api/v1/projects/$BYL_PROJECT_ID/invoices/5711 \
    -H "Authorization: Bearer $BYL_TOKEN" \
    -H 'Accept: application/json'

Example response

json
{
  "data": {
    "id": 5711,
    "deleted_at": "2026-09-07T16:30:35.000000Z"
  }
}

Next steps

  • Webhook — receive the invoice.paid event in your own system
  • Checkout — purchases with products