---
title: "Pay by invoice"
method: POST
path: "/api/billing/invoice-billing"
tags: ["internal"]
---

# Pay by invoice

`POST /api/billing/invoice-billing`

## Request

- Base URL: `https://app.scanopy.net`
- URL: `https://app.scanopy.net/api/billing/invoice-billing`
- Auth: one of:
  - API key in header `Authorization`
  - API key in cookie `session_id`

Records the billing entity on the organization's billing account, then
either issues the first invoice now or opens a quote for the buyer's
procurement to raise a purchase order against. Self-hosted plans only.

## Request body

- InvoiceBillingRequest: Switch the organization to paying by invoice.
  - `details` InvoiceBillingDetails, required: Who an invoice is addressed to and what the buyer's finance team matches it against.
    - `address` InvoiceBillingAddress, required: Postal address of the billing entity, as Stripe's Address Element returns it.
      - `city` string, required: City, town or locality.
      - `country` string, required: Two-letter ISO country code.
      - `line1` string, required: Street address, including number.
      - `line2` string, nullable: Suite, unit or floor, when the address has one.
      - `postal_code` string, required: Postal or ZIP code.
      - `state` string, nullable: State, province or region. Absent where the country has no such level.
    - `billing_email` string, email, required: Where Stripe emails invoices.
    - `entity_name` string, required: Legal name of the organization being invoiced.
    - `po_number` string, nullable: Purchase order number printed on every invoice.
    - `tax_id` InvoiceBillingTaxId: Tax ID of the billing entity, as Stripe's Tax ID Element returns it.
      - `tax_id_type` string, required: Stripe tax ID type, e.g. `eu_vat` or `us_ein`.
      - `value` string, required: The registration number itself, in the format its type expects.
  - `mode` 'send_invoice' | 'quote', required: What to do once the billing entity is recorded.
  - `plan` union
    - object
      - `base_cents` integer, required: Fixed charge per billing period, in cents.
      - `host_cents` integer, nullable: Charge per host beyond `included_hosts`, in cents.
      - `included_hosts` integer, nullable: Hosts included before per-host charges apply.
      - `included_orgs` integer, nullable: Organizations allowed on one self-hosted server instance. `None` = unlimited. Only enforced for self-hosted deployments (see `provision_user`); cloud stays multi-tenant regardless. Defaulted so existing stored plan JSON deserializes unchanged.
      - `included_seats` integer, nullable: Seats included before per-seat charges apply.
      - `included_sites` integer, nullable: Sites included before per-site charges apply.
      - `rate` 'Month' | 'Year', required
      - `seat_cents` integer, nullable: Charge per seat beyond `included_seats`, in cents.
      - `site_cents` integer, nullable: Charge per site beyond `included_sites`, in cents. Plans stored before the site rename (org rows, Stripe subscription metadata) say `network_cents`.
      - `trial_days` integer, required: Length of the free trial, in days. Zero when the plan has no trial.
      - `type` 'Community', required
    - object
      - `base_cents` integer, required: Fixed charge per billing period, in cents.
      - `host_cents` integer, nullable: Charge per host beyond `included_hosts`, in cents.
      - `included_hosts` integer, nullable: Hosts included before per-host charges apply.
      - `included_orgs` integer, nullable: Organizations allowed on one self-hosted server instance. `None` = unlimited. Only enforced for self-hosted deployments (see `provision_user`); cloud stays multi-tenant regardless. Defaulted so existing stored plan JSON deserializes unchanged.
      - `included_seats` integer, nullable: Seats included before per-seat charges apply.
      - `included_sites` integer, nullable: Sites included before per-site charges apply.
      - `rate` 'Month' | 'Year', required
      - `seat_cents` integer, nullable: Charge per seat beyond `included_seats`, in cents.
      - `site_cents` integer, nullable: Charge per site beyond `included_sites`, in cents. Plans stored before the site rename (org rows, Stripe subscription metadata) say `network_cents`.
      - `trial_days` integer, required: Length of the free trial, in days. Zero when the plan has no trial.
      - `type` 'Free', required
    - object
      - `base_cents` integer, required: Fixed charge per billing period, in cents.
      - `host_cents` integer, nullable: Charge per host beyond `included_hosts`, in cents.
      - `included_hosts` integer, nullable: Hosts included before per-host charges apply.
      - `included_orgs` integer, nullable: Organizations allowed on one self-hosted server instance. `None` = unlimited. Only enforced for self-hosted deployments (see `provision_user`); cloud stays multi-tenant regardless. Defaulted so existing stored plan JSON deserializes unchanged.
      - `included_seats` integer, nullable: Seats included before per-seat charges apply.
      - `included_sites` integer, nullable: Sites included before per-site charges apply.
      - `rate` 'Month' | 'Year', required
      - `seat_cents` integer, nullable: Charge per seat beyond `included_seats`, in cents.
      - `site_cents` integer, nullable: Charge per site beyond `included_sites`, in cents. Plans stored before the site rename (org rows, Stripe subscription metadata) say `network_cents`.
      - `trial_days` integer, required: Length of the free trial, in days. Zero when the plan has no trial.
      - `type` 'Starter', required
    - object
      - `base_cents` integer, required: Fixed charge per billing period, in cents.
      - `host_cents` integer, nullable: Charge per host beyond `included_hosts`, in cents.
      - `included_hosts` integer, nullable: Hosts included before per-host charges apply.
      - `included_orgs` integer, nullable: Organizations allowed on one self-hosted server instance. `None` = unlimited. Only enforced for self-hosted deployments (see `provision_user`); cloud stays multi-tenant regardless. Defaulted so existing stored plan JSON deserializes unchanged.
      - `included_seats` integer, nullable: Seats included before per-seat charges apply.
      - `included_sites` integer, nullable: Sites included before per-site charges apply.
      - `rate` 'Month' | 'Year', required
      - `seat_cents` integer, nullable: Charge per seat beyond `included_seats`, in cents.
      - `site_cents` integer, nullable: Charge per site beyond `included_sites`, in cents. Plans stored before the site rename (org rows, Stripe subscription metadata) say `network_cents`.
      - `trial_days` integer, required: Length of the free trial, in days. Zero when the plan has no trial.
      - `type` 'Pro', required
    - object
      - `base_cents` integer, required: Fixed charge per billing period, in cents.
      - `host_cents` integer, nullable: Charge per host beyond `included_hosts`, in cents.
      - `included_hosts` integer, nullable: Hosts included before per-host charges apply.
      - `included_orgs` integer, nullable: Organizations allowed on one self-hosted server instance. `None` = unlimited. Only enforced for self-hosted deployments (see `provision_user`); cloud stays multi-tenant regardless. Defaulted so existing stored plan JSON deserializes unchanged.
      - `included_seats` integer, nullable: Seats included before per-seat charges apply.
      - `included_sites` integer, nullable: Sites included before per-site charges apply.
      - `rate` 'Month' | 'Year', required
      - `seat_cents` integer, nullable: Charge per seat beyond `included_seats`, in cents.
      - `site_cents` integer, nullable: Charge per site beyond `included_sites`, in cents. Plans stored before the site rename (org rows, Stripe subscription metadata) say `network_cents`.
      - `trial_days` integer, required: Length of the free trial, in days. Zero when the plan has no trial.
      - `type` 'Team', required
    - object
      - `base_cents` integer, required: Fixed charge per billing period, in cents.
      - `host_cents` integer, nullable: Charge per host beyond `included_hosts`, in cents.
      - `included_hosts` integer, nullable: Hosts included before per-host charges apply.
      - `included_orgs` integer, nullable: Organizations allowed on one self-hosted server instance. `None` = unlimited. Only enforced for self-hosted deployments (see `provision_user`); cloud stays multi-tenant regardless. Defaulted so existing stored plan JSON deserializes unchanged.
      - `included_seats` integer, nullable: Seats included before per-seat charges apply.
      - `included_sites` integer, nullable: Sites included before per-site charges apply.
      - `rate` 'Month' | 'Year', required
      - `seat_cents` integer, nullable: Charge per seat beyond `included_seats`, in cents.
      - `site_cents` integer, nullable: Charge per site beyond `included_sites`, in cents. Plans stored before the site rename (org rows, Stripe subscription metadata) say `network_cents`.
      - `trial_days` integer, required: Length of the free trial, in days. Zero when the plan has no trial.
      - `type` 'Business', required
    - object
      - `base_cents` integer, required: Fixed charge per billing period, in cents.
      - `host_cents` integer, nullable: Charge per host beyond `included_hosts`, in cents.
      - `included_hosts` integer, nullable: Hosts included before per-host charges apply.
      - `included_orgs` integer, nullable: Organizations allowed on one self-hosted server instance. `None` = unlimited. Only enforced for self-hosted deployments (see `provision_user`); cloud stays multi-tenant regardless. Defaulted so existing stored plan JSON deserializes unchanged.
      - `included_seats` integer, nullable: Seats included before per-seat charges apply.
      - `included_sites` integer, nullable: Sites included before per-site charges apply.
      - `rate` 'Month' | 'Year', required
      - `seat_cents` integer, nullable: Charge per seat beyond `included_seats`, in cents.
      - `site_cents` integer, nullable: Charge per site beyond `included_sites`, in cents. Plans stored before the site rename (org rows, Stripe subscription metadata) say `network_cents`.
      - `trial_days` integer, required: Length of the free trial, in days. Zero when the plan has no trial.
      - `type` 'Enterprise', required
    - object
      - `base_cents` integer, required: Fixed charge per billing period, in cents.
      - `host_cents` integer, nullable: Charge per host beyond `included_hosts`, in cents.
      - `included_hosts` integer, nullable: Hosts included before per-host charges apply.
      - `included_orgs` integer, nullable: Organizations allowed on one self-hosted server instance. `None` = unlimited. Only enforced for self-hosted deployments (see `provision_user`); cloud stays multi-tenant regardless. Defaulted so existing stored plan JSON deserializes unchanged.
      - `included_seats` integer, nullable: Seats included before per-seat charges apply.
      - `included_sites` integer, nullable: Sites included before per-site charges apply.
      - `rate` 'Month' | 'Year', required
      - `seat_cents` integer, nullable: Charge per seat beyond `included_seats`, in cents.
      - `site_cents` integer, nullable: Charge per site beyond `included_sites`, in cents. Plans stored before the site rename (org rows, Stripe subscription metadata) say `network_cents`.
      - `trial_days` integer, required: Length of the free trial, in days. Zero when the plan has no trial.
      - `type` 'Demo', required
    - object
      - `base_cents` integer, required: Fixed charge per billing period, in cents.
      - `host_cents` integer, nullable: Charge per host beyond `included_hosts`, in cents.
      - `included_hosts` integer, nullable: Hosts included before per-host charges apply.
      - `included_orgs` integer, nullable: Organizations allowed on one self-hosted server instance. `None` = unlimited. Only enforced for self-hosted deployments (see `provision_user`); cloud stays multi-tenant regardless. Defaulted so existing stored plan JSON deserializes unchanged.
      - `included_seats` integer, nullable: Seats included before per-seat charges apply.
      - `included_sites` integer, nullable: Sites included before per-site charges apply.
      - `rate` 'Month' | 'Year', required
      - `seat_cents` integer, nullable: Charge per seat beyond `included_seats`, in cents.
      - `site_cents` integer, nullable: Charge per site beyond `included_sites`, in cents. Plans stored before the site rename (org rows, Stripe subscription metadata) say `network_cents`.
      - `trial_days` integer, required: Length of the free trial, in days. Zero when the plan has no trial.
      - `type` 'CommercialSelfHosted', required
    - object
      - `base_cents` integer, required: Fixed charge per billing period, in cents.
      - `host_cents` integer, nullable: Charge per host beyond `included_hosts`, in cents.
      - `included_hosts` integer, nullable: Hosts included before per-host charges apply.
      - `included_orgs` integer, nullable: Organizations allowed on one self-hosted server instance. `None` = unlimited. Only enforced for self-hosted deployments (see `provision_user`); cloud stays multi-tenant regardless. Defaulted so existing stored plan JSON deserializes unchanged.
      - `included_seats` integer, nullable: Seats included before per-seat charges apply.
      - `included_sites` integer, nullable: Sites included before per-site charges apply.
      - `rate` 'Month' | 'Year', required
      - `seat_cents` integer, nullable: Charge per seat beyond `included_seats`, in cents.
      - `site_cents` integer, nullable: Charge per site beyond `included_sites`, in cents. Plans stored before the site rename (org rows, Stripe subscription metadata) say `network_cents`.
      - `trial_days` integer, required: Length of the free trial, in days. Zero when the plan has no trial.
      - `type` 'SelfHostedStandard', required
    - object
      - `base_cents` integer, required: Fixed charge per billing period, in cents.
      - `host_cents` integer, nullable: Charge per host beyond `included_hosts`, in cents.
      - `included_hosts` integer, nullable: Hosts included before per-host charges apply.
      - `included_orgs` integer, nullable: Organizations allowed on one self-hosted server instance. `None` = unlimited. Only enforced for self-hosted deployments (see `provision_user`); cloud stays multi-tenant regardless. Defaulted so existing stored plan JSON deserializes unchanged.
      - `included_seats` integer, nullable: Seats included before per-seat charges apply.
      - `included_sites` integer, nullable: Sites included before per-site charges apply.
      - `rate` 'Month' | 'Year', required
      - `seat_cents` integer, nullable: Charge per seat beyond `included_seats`, in cents.
      - `site_cents` integer, nullable: Charge per site beyond `included_sites`, in cents. Plans stored before the site rename (org rows, Stripe subscription metadata) say `network_cents`.
      - `trial_days` integer, required: Length of the free trial, in days. Zero when the plan has no trial.
      - `type` 'SelfHostedPlus', required

## Response `200`

Invoice sent or quote opened

- ApiResponseString: Envelope for a successful response. Failures are sent with a non-2xx status and an `ApiErrorResponse` body instead.
  - `data` string: The result payload. Omitted on failure.
  - `error` string, nullable: Not sent on a successful response. Failure messages arrive in an `ApiErrorResponse`.
  - `meta` ApiMeta, required: API metadata included in all responses
    - `api_version` integer, required: API version (integer, increments on breaking changes)
    - `server_version` string, required: Server version (semver)
  - `success` boolean, required: Always `true` on a successful response.

## Other responses

- `400`: Not a self-hosted plan, invalid details, or billing not enabled

## Changes

- **2026-10-26** `c9d9d46d1ae8`: 1 info
  - api tag `billing` removed
- **2026-10-11** `a6ea2ab6fbb9`: 22 warning, 22 info
  - removed the request property `plan/oneOf[#/components/schemas/BillingPlan]/oneOf[subschema #10: SelfHostedStandard]/allOf[#/components/schemas/PlanConfig]/included_networks`
  - removed the request property `plan/oneOf[#/components/schemas/BillingPlan]/oneOf[subschema #10: SelfHostedStandard]/allOf[#/components/schemas/PlanConfig]/network_cents`
  - removed the request property `plan/oneOf[#/components/schemas/BillingPlan]/oneOf[subschema #11: SelfHostedPlus]/allOf[#/components/schemas/PlanConfig]/included_networks`
  - removed the request property `plan/oneOf[#/components/schemas/BillingPlan]/oneOf[subschema #11: SelfHostedPlus]/allOf[#/components/schemas/PlanConfig]/network_cents`
  - …40 more
- **2026-09-24** `7a30dff58ddd`: 1 info
  - endpoint added

[Operation history](https://skmtc.dev/scanopy/apis/scanopy-api/changes/api/billing/invoice-billing/post.md)

---

[API](https://skmtc.dev/scanopy/apis/scanopy-api.md) - [All operations](https://skmtc.dev/scanopy/apis/scanopy-api/llms.txt) - [OpenAPI document](https://skmtc.dev/scanopy/apis/scanopy-api/revisions/966ba786bdb5?raw)
