docspack v1.2.0
Endpoints

Invoice Service

A worked example, rendered by docspack from the OpenAPI document served at /api/example.json.

It describes a small billing API: invoices are drafted, sent, paid and voided, and every request carries a bearer token. None of it is real — api.example.com resolves to nothing — so this is a document to read and to generate from, not an API to call.

The same document is served as LAPIS at /api/example.lapis, which is what an agent would read.

A fictional API

api.example.com does not exist, so pressing Send below reports a failed request. Point the server field at something real and it will send there instead — the console builds the request from this document, not from a hard-coded target.

Base URL
https://api.example.com/v2
Authentication
A bearer token, on every route but GET /status. The console reads the field when you press Send and keeps it nowhere — not in storage, not in a cookie.
Operations
9

The same document for an agent: /api/example.lapis — every operation and every type in about 900 tokens, against 5,700 for the JSON beside it. The document itself: /api/example.json.

Invoices

Drafting, sending and settling invoices.


GET/invoices

Lists invoices, newest first.

Paginated with an opaque cursor. Pass the next_cursor from the previous page; a response with has_more: false is the last one.

Authentication

  • bearerAuthBearer token in the Authorization header

    An API key from the dashboard. It travels as an Authorization header: Bearer sk_live_… in production, sk_test_… in the sandbox.

Query parameters

  • statusdraft | open | paid | void

    Return only invoices in this state.

  • customer_idstr

    Return only invoices addressed to this customer.

  • limitint

    How many to return. Between 1 and 100.

  • cursorstr

    The next_cursor of the previous page.

Response

200A page of invoices.
  • data[Invoice]required
    • idstrrequired
    • customer_idstrrequired
    • statusdraft | open | paid | voidrequired

      Where the invoice is in its life: drafted, sent, settled or cancelled.

    • lines[LineItem]required
      • descriptionstrrequired
      • quantityintrequired
      • unit_priceMoneyrequired
      • tax_ratefloat

        Percentage, as a number: 19 is 19%.

    • totalMoneyrequired
      • amountintrequired
      • currencyEUR | USD | GBPrequired
    • due_datedate
    • created_atdatetimerequired
    • pdf_urlstr?

      A link to the rendered invoice, valid for an hour.

    • notesstr?
    • metadata{str:str}

      Your own keys, returned unchanged.

  • has_moreboolrequired
  • next_cursorstr?

    Pass as cursor for the next page. Null on the last one.

json
{
  "data": [
    {
      "id": "inv_3PkQ2m",
      "customer_id": "cus_8ZQd41",
      "status": "open",
      "lines": [
        {
          "description": "Seat licence, October",
          "quantity": 12,
          "unit_price": {
            "amount": 2900,
            "currency": "EUR"
          }
        }
      ],
      "total": {
        "amount": 2900,
        "currency": "EUR"
      },
      "created_at": "2026-09-01T09:12:44Z"
    }
  ],
  "has_more": false
}

Errors

401The token is missing, expired or invalid.
  • error{type: invalid_request | authentication_failed | not_found | conflict | rate_limited, message: str, param?: str?}required
    • typeinvalid_request | authentication_failed | not_found | conflict | rate_limitedrequired
    • messagestrrequired

      One sentence, written for a developer reading a log.

    • paramstr?

      The field at fault, when one field is.

json
{
  "error": {
    "type": "invalid_request",
    "message": "lines must contain at least one item."
  }
}

Request

cURL

bash
curl -X GET 'https://api.example.com/v2/invoices' \
  -H "Authorization: Bearer $API_TOKEN"

JavaScript

js
const token = process.env.API_TOKEN;

const response = await fetch("https://api.example.com/v2/invoices", {
  method: "GET",
  headers: {
    "Authorization": `Bearer ${token}`,
  },
});

if (!response.ok) throw new Error(`HTTP ${response.status}`);
const data = await response.json();

Python

python
import os
import requests

token = os.environ["API_TOKEN"]

response = requests.get(
    "https://api.example.com/v2/invoices",
    headers={"Authorization": f"Bearer {token}"},
)
response.raise_for_status()
data = response.json()

Go

go
req, err := http.NewRequest("GET", "https://api.example.com/v2/invoices", nil)
if err != nil {
	return err
}
req.Header.Set("Authorization", "Bearer "+os.Getenv("API_TOKEN"))

resp, err := http.DefaultClient.Do(req)
if err != nil {
	return err
}
defer resp.Body.Close()

Try it

The document's servers, or one of your own.

Sent with this request only. It is not saved anywhere.

Return only invoices in this state.

Return only invoices addressed to this customer.

How many to return. Between 1 and 100.

The next_cursor of the previous page.


POST/invoices

Creates a draft invoice.

The invoice is created in draft and sends nothing. POST /invoices/{invoice_id}/send is what puts it in front of the customer.

Totals are computed from the line items; sending one is an error rather than an override.

Authentication

  • bearerAuthBearer token in the Authorization header

    An API key from the dashboard. It travels as an Authorization header: Bearer sk_live_… in production, sk_test_… in the sandbox.

Headers

  • Idempotency-Keystr

    Repeat a key to retry safely: the first invoice created under it is returned again rather than a second one being drafted.

Request body application/json · required

  • customer_idstrrequired
  • lines[LineItem]required

    At least one. The total is the sum of these.

    • descriptionstrrequired
    • quantityintrequired
    • unit_priceMoneyrequired
      • amountintrequired
      • currencyEUR | USD | GBPrequired
    • tax_ratefloat

      Percentage, as a number: 19 is 19%.

  • due_datedate

    Defaults to 30 days out.

  • notesstr
  • metadata{str:str}

Response

201The created invoice.
  • idstrrequired
  • customer_idstrrequired
  • statusdraft | open | paid | voidrequired

    Where the invoice is in its life: drafted, sent, settled or cancelled.

  • lines[LineItem]required
    • descriptionstrrequired
    • quantityintrequired
    • unit_priceMoneyrequired
      • amountintrequired
      • currencyEUR | USD | GBPrequired
    • tax_ratefloat

      Percentage, as a number: 19 is 19%.

  • totalMoneyrequired
    • amountintrequired
    • currencyEUR | USD | GBPrequired
  • due_datedate
  • created_atdatetimerequired
  • pdf_urlstr?

    A link to the rendered invoice, valid for an hour.

  • notesstr?
  • metadata{str:str}

    Your own keys, returned unchanged.

json
{
  "id": "inv_3PkQ2m",
  "customer_id": "cus_8ZQd41",
  "status": "open",
  "lines": [
    {
      "description": "Seat licence, October",
      "quantity": 12,
      "unit_price": {
        "amount": 2900,
        "currency": "EUR"
      }
    }
  ],
  "total": {
    "amount": 2900,
    "currency": "EUR"
  },
  "created_at": "2026-09-01T09:12:44Z"
}

Errors

422The line items did not validate.
  • error{type: invalid_request | authentication_failed | not_found | conflict | rate_limited, message: str, param?: str?}required
    • typeinvalid_request | authentication_failed | not_found | conflict | rate_limitedrequired
    • messagestrrequired

      One sentence, written for a developer reading a log.

    • paramstr?

      The field at fault, when one field is.

json
{
  "error": {
    "type": "invalid_request",
    "message": "lines must contain at least one item."
  }
}

Request

cURL

bash
curl -X POST 'https://api.example.com/v2/invoices' \
  -H 'Content-Type: application/json' \
  -H "Authorization: Bearer $API_TOKEN" \
  -d '{
  "customer_id": "cus_8ZQd41",
  "due_date": "2026-10-01",
  "lines": [
    {
      "description": "Seat licence, October",
      "quantity": 12,
      "unit_price": {
        "amount": 2900,
        "currency": "EUR"
      }
    }
  ],
  "notes": "Net 30."
}'

JavaScript

js
const token = process.env.API_TOKEN;

const response = await fetch("https://api.example.com/v2/invoices", {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
    "Authorization": `Bearer ${token}`,
  },
  body: JSON.stringify({
    "customer_id": "cus_8ZQd41",
    "due_date": "2026-10-01",
    "lines": [
      {
        "description": "Seat licence, October",
        "quantity": 12,
        "unit_price": {
          "amount": 2900,
          "currency": "EUR"
        }
      }
    ],
    "notes": "Net 30."
  }),
});

if (!response.ok) throw new Error(`HTTP ${response.status}`);
const data = await response.json();

Python

python
import os
import requests

token = os.environ["API_TOKEN"]

response = requests.post(
    "https://api.example.com/v2/invoices",
    headers={"Authorization": f"Bearer {token}"},
    json={
      "customer_id": "cus_8ZQd41",
      "due_date": "2026-10-01",
      "lines": [
        {
          "description": "Seat licence, October",
          "quantity": 12,
          "unit_price": {
            "amount": 2900,
            "currency": "EUR"
          }
        }
      ],
      "notes": "Net 30."
    },
)
response.raise_for_status()
data = response.json()

Go

go
body := strings.NewReader(`{
  "customer_id": "cus_8ZQd41",
  "due_date": "2026-10-01",
  "lines": [
    {
      "description": "Seat licence, October",
      "quantity": 12,
      "unit_price": {
        "amount": 2900,
        "currency": "EUR"
      }
    }
  ],
  "notes": "Net 30."
}`)
req, err := http.NewRequest("POST", "https://api.example.com/v2/invoices", body)
if err != nil {
	return err
}
req.Header.Set("Content-Type", "application/json")
req.Header.Set("Authorization", "Bearer "+os.Getenv("API_TOKEN"))

resp, err := http.DefaultClient.Do(req)
if err != nil {
	return err
}
defer resp.Body.Close()

Try it

The document's servers, or one of your own.

Sent with this request only. It is not saved anywhere.

Repeat a key to retry safely: the first invoice created under it is returned again rather than a second one being drafted.


GET/invoices/{invoice_id}

Retrieves one invoice.

Authentication

  • bearerAuthBearer token in the Authorization header

    An API key from the dashboard. It travels as an Authorization header: Bearer sk_live_… in production, sk_test_… in the sandbox.

Path parameters

  • invoice_idstrrequired

    The invoice's id, as returned when it was created.

Response

200The invoice.
  • idstrrequired
  • customer_idstrrequired
  • statusdraft | open | paid | voidrequired

    Where the invoice is in its life: drafted, sent, settled or cancelled.

  • lines[LineItem]required
    • descriptionstrrequired
    • quantityintrequired
    • unit_priceMoneyrequired
      • amountintrequired
      • currencyEUR | USD | GBPrequired
    • tax_ratefloat

      Percentage, as a number: 19 is 19%.

  • totalMoneyrequired
    • amountintrequired
    • currencyEUR | USD | GBPrequired
  • due_datedate
  • created_atdatetimerequired
  • pdf_urlstr?

    A link to the rendered invoice, valid for an hour.

  • notesstr?
  • metadata{str:str}

    Your own keys, returned unchanged.

json
{
  "id": "inv_3PkQ2m",
  "customer_id": "cus_8ZQd41",
  "status": "open",
  "lines": [
    {
      "description": "Seat licence, October",
      "quantity": 12,
      "unit_price": {
        "amount": 2900,
        "currency": "EUR"
      }
    }
  ],
  "total": {
    "amount": 2900,
    "currency": "EUR"
  },
  "created_at": "2026-09-01T09:12:44Z"
}

Errors

404No such record, or the token cannot see it.
  • error{type: invalid_request | authentication_failed | not_found | conflict | rate_limited, message: str, param?: str?}required
    • typeinvalid_request | authentication_failed | not_found | conflict | rate_limitedrequired
    • messagestrrequired

      One sentence, written for a developer reading a log.

    • paramstr?

      The field at fault, when one field is.

json
{
  "error": {
    "type": "invalid_request",
    "message": "lines must contain at least one item."
  }
}

Request

cURL

bash
curl -X GET 'https://api.example.com/v2/invoices/inv_3PkQ2m' \
  -H "Authorization: Bearer $API_TOKEN"

JavaScript

js
const token = process.env.API_TOKEN;

const response = await fetch("https://api.example.com/v2/invoices/inv_3PkQ2m", {
  method: "GET",
  headers: {
    "Authorization": `Bearer ${token}`,
  },
});

if (!response.ok) throw new Error(`HTTP ${response.status}`);
const data = await response.json();

Python

python
import os
import requests

token = os.environ["API_TOKEN"]

response = requests.get(
    "https://api.example.com/v2/invoices/inv_3PkQ2m",
    headers={"Authorization": f"Bearer {token}"},
)
response.raise_for_status()
data = response.json()

Go

go
req, err := http.NewRequest("GET", "https://api.example.com/v2/invoices/inv_3PkQ2m", nil)
if err != nil {
	return err
}
req.Header.Set("Authorization", "Bearer "+os.Getenv("API_TOKEN"))

resp, err := http.DefaultClient.Do(req)
if err != nil {
	return err
}
defer resp.Body.Close()

Try it

The document's servers, or one of your own.

Sent with this request only. It is not saved anywhere.

The invoice's id, as returned when it was created.


PATCH/invoices/{invoice_id}

Changes a draft invoice.

Only a draft invoice can be changed. Once it has been sent, the way to correct it is a credit note.

Authentication

  • bearerAuthBearer token in the Authorization header

    An API key from the dashboard. It travels as an Authorization header: Bearer sk_live_… in production, sk_test_… in the sandbox.

Path parameters

  • invoice_idstrrequired

    The invoice's id, as returned when it was created.

Request body application/json · required

  • due_datedate
  • lines[LineItem]
    • descriptionstrrequired
    • quantityintrequired
    • unit_priceMoneyrequired
      • amountintrequired
      • currencyEUR | USD | GBPrequired
    • tax_ratefloat

      Percentage, as a number: 19 is 19%.

  • notesstr?
  • metadata{str:str}

Response

200The updated invoice.
  • idstrrequired
  • customer_idstrrequired
  • statusdraft | open | paid | voidrequired

    Where the invoice is in its life: drafted, sent, settled or cancelled.

  • lines[LineItem]required
    • descriptionstrrequired
    • quantityintrequired
    • unit_priceMoneyrequired
      • amountintrequired
      • currencyEUR | USD | GBPrequired
    • tax_ratefloat

      Percentage, as a number: 19 is 19%.

  • totalMoneyrequired
    • amountintrequired
    • currencyEUR | USD | GBPrequired
  • due_datedate
  • created_atdatetimerequired
  • pdf_urlstr?

    A link to the rendered invoice, valid for an hour.

  • notesstr?
  • metadata{str:str}

    Your own keys, returned unchanged.

json
{
  "id": "inv_3PkQ2m",
  "customer_id": "cus_8ZQd41",
  "status": "open",
  "lines": [
    {
      "description": "Seat licence, October",
      "quantity": 12,
      "unit_price": {
        "amount": 2900,
        "currency": "EUR"
      }
    }
  ],
  "total": {
    "amount": 2900,
    "currency": "EUR"
  },
  "created_at": "2026-09-01T09:12:44Z"
}

Errors

404No such record, or the token cannot see it.
  • error{type: invalid_request | authentication_failed | not_found | conflict | rate_limited, message: str, param?: str?}required
    • typeinvalid_request | authentication_failed | not_found | conflict | rate_limitedrequired
    • messagestrrequired

      One sentence, written for a developer reading a log.

    • paramstr?

      The field at fault, when one field is.

json
{
  "error": {
    "type": "invalid_request",
    "message": "lines must contain at least one item."
  }
}
409The invoice is no longer a draft.
  • error{type: invalid_request | authentication_failed | not_found | conflict | rate_limited, message: str, param?: str?}required
    • typeinvalid_request | authentication_failed | not_found | conflict | rate_limitedrequired
    • messagestrrequired

      One sentence, written for a developer reading a log.

    • paramstr?

      The field at fault, when one field is.

json
{
  "error": {
    "type": "invalid_request",
    "message": "lines must contain at least one item."
  }
}

Request

cURL

bash
curl -X PATCH 'https://api.example.com/v2/invoices/inv_3PkQ2m' \
  -H 'Content-Type: application/json' \
  -H "Authorization: Bearer $API_TOKEN" \
  -d '{
  "due_date": "2026-10-15",
  "notes": "Net 45, agreed by email."
}'

JavaScript

js
const token = process.env.API_TOKEN;

const response = await fetch("https://api.example.com/v2/invoices/inv_3PkQ2m", {
  method: "PATCH",
  headers: {
    "Content-Type": "application/json",
    "Authorization": `Bearer ${token}`,
  },
  body: JSON.stringify({
    "due_date": "2026-10-15",
    "notes": "Net 45, agreed by email."
  }),
});

if (!response.ok) throw new Error(`HTTP ${response.status}`);
const data = await response.json();

Python

python
import os
import requests

token = os.environ["API_TOKEN"]

response = requests.patch(
    "https://api.example.com/v2/invoices/inv_3PkQ2m",
    headers={"Authorization": f"Bearer {token}"},
    json={
      "due_date": "2026-10-15",
      "notes": "Net 45, agreed by email."
    },
)
response.raise_for_status()
data = response.json()

Go

go
body := strings.NewReader(`{
  "due_date": "2026-10-15",
  "notes": "Net 45, agreed by email."
}`)
req, err := http.NewRequest("PATCH", "https://api.example.com/v2/invoices/inv_3PkQ2m", body)
if err != nil {
	return err
}
req.Header.Set("Content-Type", "application/json")
req.Header.Set("Authorization", "Bearer "+os.Getenv("API_TOKEN"))

resp, err := http.DefaultClient.Do(req)
if err != nil {
	return err
}
defer resp.Body.Close()

Try it

The document's servers, or one of your own.

Sent with this request only. It is not saved anywhere.

The invoice's id, as returned when it was created.


DELETE/invoices/{invoice_id}

Voids an invoice.

A voided invoice stays readable and stops being owed. Nothing is deleted: an invoice that was sent is a record.

Authentication

  • bearerAuthBearer token in the Authorization header

    An API key from the dashboard. It travels as an Authorization header: Bearer sk_live_… in production, sk_test_… in the sandbox.

Path parameters

  • invoice_idstrrequired

    The invoice's id, as returned when it was created.

Response

204Voided. No body.

Errors

404No such record, or the token cannot see it.
  • error{type: invalid_request | authentication_failed | not_found | conflict | rate_limited, message: str, param?: str?}required
    • typeinvalid_request | authentication_failed | not_found | conflict | rate_limitedrequired
    • messagestrrequired

      One sentence, written for a developer reading a log.

    • paramstr?

      The field at fault, when one field is.

json
{
  "error": {
    "type": "invalid_request",
    "message": "lines must contain at least one item."
  }
}
409The invoice is already paid.
  • error{type: invalid_request | authentication_failed | not_found | conflict | rate_limited, message: str, param?: str?}required
    • typeinvalid_request | authentication_failed | not_found | conflict | rate_limitedrequired
    • messagestrrequired

      One sentence, written for a developer reading a log.

    • paramstr?

      The field at fault, when one field is.

json
{
  "error": {
    "type": "invalid_request",
    "message": "lines must contain at least one item."
  }
}

Request

cURL

bash
curl -X DELETE 'https://api.example.com/v2/invoices/inv_3PkQ2m' \
  -H "Authorization: Bearer $API_TOKEN"

JavaScript

js
const token = process.env.API_TOKEN;

const response = await fetch("https://api.example.com/v2/invoices/inv_3PkQ2m", {
  method: "DELETE",
  headers: {
    "Authorization": `Bearer ${token}`,
  },
});

if (!response.ok) throw new Error(`HTTP ${response.status}`);
const data = await response.json();

Python

python
import os
import requests

token = os.environ["API_TOKEN"]

response = requests.delete(
    "https://api.example.com/v2/invoices/inv_3PkQ2m",
    headers={"Authorization": f"Bearer {token}"},
)
response.raise_for_status()
data = response.json()

Go

go
req, err := http.NewRequest("DELETE", "https://api.example.com/v2/invoices/inv_3PkQ2m", nil)
if err != nil {
	return err
}
req.Header.Set("Authorization", "Bearer "+os.Getenv("API_TOKEN"))

resp, err := http.DefaultClient.Do(req)
if err != nil {
	return err
}
defer resp.Body.Close()

Try it

The document's servers, or one of your own.

Sent with this request only. It is not saved anywhere.

The invoice's id, as returned when it was created.


POST/invoices/{invoice_id}/send

Sends a draft invoice to the customer.

Moves the invoice from draft to open and emails it. With no to, it goes to the customer’s own address.

Authentication

  • bearerAuthBearer token in the Authorization header

    An API key from the dashboard. It travels as an Authorization header: Bearer sk_live_… in production, sk_test_… in the sandbox.

Path parameters

  • invoice_idstrrequired

    The invoice's id, as returned when it was created.

Request body application/json

  • to[str]

    Defaults to the customer's own address.

  • cc[str]
  • messagestr

    A line above the invoice in the email.

Response

202Queued for delivery. The invoice is now open.
  • idstrrequired
  • customer_idstrrequired
  • statusdraft | open | paid | voidrequired

    Where the invoice is in its life: drafted, sent, settled or cancelled.

  • lines[LineItem]required
    • descriptionstrrequired
    • quantityintrequired
    • unit_priceMoneyrequired
      • amountintrequired
      • currencyEUR | USD | GBPrequired
    • tax_ratefloat

      Percentage, as a number: 19 is 19%.

  • totalMoneyrequired
    • amountintrequired
    • currencyEUR | USD | GBPrequired
  • due_datedate
  • created_atdatetimerequired
  • pdf_urlstr?

    A link to the rendered invoice, valid for an hour.

  • notesstr?
  • metadata{str:str}

    Your own keys, returned unchanged.

json
{
  "id": "inv_3PkQ2m",
  "customer_id": "cus_8ZQd41",
  "status": "open",
  "lines": [
    {
      "description": "Seat licence, October",
      "quantity": 12,
      "unit_price": {
        "amount": 2900,
        "currency": "EUR"
      }
    }
  ],
  "total": {
    "amount": 2900,
    "currency": "EUR"
  },
  "created_at": "2026-09-01T09:12:44Z"
}

Errors

404No such record, or the token cannot see it.
  • error{type: invalid_request | authentication_failed | not_found | conflict | rate_limited, message: str, param?: str?}required
    • typeinvalid_request | authentication_failed | not_found | conflict | rate_limitedrequired
    • messagestrrequired

      One sentence, written for a developer reading a log.

    • paramstr?

      The field at fault, when one field is.

json
{
  "error": {
    "type": "invalid_request",
    "message": "lines must contain at least one item."
  }
}
409The invoice was not a draft.
  • error{type: invalid_request | authentication_failed | not_found | conflict | rate_limited, message: str, param?: str?}required
    • typeinvalid_request | authentication_failed | not_found | conflict | rate_limitedrequired
    • messagestrrequired

      One sentence, written for a developer reading a log.

    • paramstr?

      The field at fault, when one field is.

json
{
  "error": {
    "type": "invalid_request",
    "message": "lines must contain at least one item."
  }
}

Request

cURL

bash
curl -X POST 'https://api.example.com/v2/invoices/inv_3PkQ2m/send' \
  -H 'Content-Type: application/json' \
  -H "Authorization: Bearer $API_TOKEN" \
  -d '{
  "cc": [
    "ap@northwind.example"
  ],
  "message": "October seats, as discussed."
}'

JavaScript

js
const token = process.env.API_TOKEN;

const response = await fetch("https://api.example.com/v2/invoices/inv_3PkQ2m/send", {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
    "Authorization": `Bearer ${token}`,
  },
  body: JSON.stringify({
    "cc": [
      "ap@northwind.example"
    ],
    "message": "October seats, as discussed."
  }),
});

if (!response.ok) throw new Error(`HTTP ${response.status}`);
const data = await response.json();

Python

python
import os
import requests

token = os.environ["API_TOKEN"]

response = requests.post(
    "https://api.example.com/v2/invoices/inv_3PkQ2m/send",
    headers={"Authorization": f"Bearer {token}"},
    json={
      "cc": [
        "ap@northwind.example"
      ],
      "message": "October seats, as discussed."
    },
)
response.raise_for_status()
data = response.json()

Go

go
body := strings.NewReader(`{
  "cc": [
    "ap@northwind.example"
  ],
  "message": "October seats, as discussed."
}`)
req, err := http.NewRequest("POST", "https://api.example.com/v2/invoices/inv_3PkQ2m/send", body)
if err != nil {
	return err
}
req.Header.Set("Content-Type", "application/json")
req.Header.Set("Authorization", "Bearer "+os.Getenv("API_TOKEN"))

resp, err := http.DefaultClient.Do(req)
if err != nil {
	return err
}
defer resp.Body.Close()

Try it

The document's servers, or one of your own.

Sent with this request only. It is not saved anywhere.

The invoice's id, as returned when it was created.


GET/invoices/{invoice_id}/pdfDeprecated

Downloads the rendered invoice.

Deprecated. Every invoice now carries a pdf_url that is valid for an hour; fetch that instead.

Authentication

  • bearerAuthBearer token in the Authorization header

    An API key from the dashboard. It travels as an Authorization header: Bearer sk_live_… in production, sk_test_… in the sandbox.

Path parameters

  • invoice_idstrrequired

    The invoice's id, as returned when it was created.

Response

200The PDF.

Errors

404No such record, or the token cannot see it.
  • error{type: invalid_request | authentication_failed | not_found | conflict | rate_limited, message: str, param?: str?}required
    • typeinvalid_request | authentication_failed | not_found | conflict | rate_limitedrequired
    • messagestrrequired

      One sentence, written for a developer reading a log.

    • paramstr?

      The field at fault, when one field is.

json
{
  "error": {
    "type": "invalid_request",
    "message": "lines must contain at least one item."
  }
}

Request

cURL

bash
curl -X GET 'https://api.example.com/v2/invoices/inv_3PkQ2m/pdf' \
  -H "Authorization: Bearer $API_TOKEN"

JavaScript

js
const token = process.env.API_TOKEN;

const response = await fetch("https://api.example.com/v2/invoices/inv_3PkQ2m/pdf", {
  method: "GET",
  headers: {
    "Authorization": `Bearer ${token}`,
  },
});

if (!response.ok) throw new Error(`HTTP ${response.status}`);
const data = await response.json();

Python

python
import os
import requests

token = os.environ["API_TOKEN"]

response = requests.get(
    "https://api.example.com/v2/invoices/inv_3PkQ2m/pdf",
    headers={"Authorization": f"Bearer {token}"},
)
response.raise_for_status()
data = response.json()

Go

go
req, err := http.NewRequest("GET", "https://api.example.com/v2/invoices/inv_3PkQ2m/pdf", nil)
if err != nil {
	return err
}
req.Header.Set("Authorization", "Bearer "+os.Getenv("API_TOKEN"))

resp, err := http.DefaultClient.Do(req)
if err != nil {
	return err
}
defer resp.Body.Close()

Try it

The document's servers, or one of your own.

Sent with this request only. It is not saved anywhere.

The invoice's id, as returned when it was created.

Customers

The party an invoice is addressed to.


GET/customers/{customer_id}

Retrieves a customer.

Authentication

  • bearerAuthBearer token in the Authorization header

    An API key from the dashboard. It travels as an Authorization header: Bearer sk_live_… in production, sk_test_… in the sandbox.

Path parameters

  • customer_idstrrequired

Response

200The customer, with the address invoices are billed to.
  • idstrrequired
  • namestrrequired
  • emailstrrequired
  • addressAddressrequired
    • line1strrequired
    • line2str?
    • citystrrequired
    • postal_codestrrequired
    • countrystrrequired

      ISO 3166-1 alpha-2.

  • tax_idstr?
json
{
  "id": "cus_8ZQd41",
  "name": "Northwind GmbH",
  "email": "ap@northwind.example",
  "address": {
    "line1": "Kastanienallee 12",
    "city": "Berlin",
    "postal_code": 10435,
    "country": "DE"
  }
}

Errors

404No such record, or the token cannot see it.
  • error{type: invalid_request | authentication_failed | not_found | conflict | rate_limited, message: str, param?: str?}required
    • typeinvalid_request | authentication_failed | not_found | conflict | rate_limitedrequired
    • messagestrrequired

      One sentence, written for a developer reading a log.

    • paramstr?

      The field at fault, when one field is.

json
{
  "error": {
    "type": "invalid_request",
    "message": "lines must contain at least one item."
  }
}

Request

cURL

bash
curl -X GET 'https://api.example.com/v2/customers/cus_8ZQd41' \
  -H "Authorization: Bearer $API_TOKEN"

JavaScript

js
const token = process.env.API_TOKEN;

const response = await fetch("https://api.example.com/v2/customers/cus_8ZQd41", {
  method: "GET",
  headers: {
    "Authorization": `Bearer ${token}`,
  },
});

if (!response.ok) throw new Error(`HTTP ${response.status}`);
const data = await response.json();

Python

python
import os
import requests

token = os.environ["API_TOKEN"]

response = requests.get(
    "https://api.example.com/v2/customers/cus_8ZQd41",
    headers={"Authorization": f"Bearer {token}"},
)
response.raise_for_status()
data = response.json()

Go

go
req, err := http.NewRequest("GET", "https://api.example.com/v2/customers/cus_8ZQd41", nil)
if err != nil {
	return err
}
req.Header.Set("Authorization", "Bearer "+os.Getenv("API_TOKEN"))

resp, err := http.DefaultClient.Do(req)
if err != nil {
	return err
}
defer resp.Body.Close()

Try it

The document's servers, or one of your own.

Sent with this request only. It is not saved anywhere.

Service

Liveness, for a load balancer rather than for a person.


GET/status

Liveness.

The one route that takes no credential, so a load balancer can call it.

Authentication

No credential required.

Response

200The service is up.
  • statusok | degradedrequired
  • versionstrrequired
  • regionstr
json
{
  "status": "ok",
  "version": "2.1.0"
}

Request

cURL

bash
curl -X GET 'https://api.example.com/v2/status'

JavaScript

js
const response = await fetch("https://api.example.com/v2/status", {
  method: "GET",
});

if (!response.ok) throw new Error(`HTTP ${response.status}`);
const data = await response.json();

Python

python
import requests

response = requests.get(
    "https://api.example.com/v2/status",
)
response.raise_for_status()
data = response.json()

Go

go
req, err := http.NewRequest("GET", "https://api.example.com/v2/status", nil)
if err != nil {
	return err
}

resp, err := http.DefaultClient.Do(req)
if err != nil {
	return err
}
defer resp.Body.Close()

Try it

The document's servers, or one of your own.

Rendered from example-api.json by @docspack/sheaf-react, with no configuration beyond the document. docspack.dev's own API is at /api.

The same ranking docspack search uses, over the same 13 documents.