API Reference

Invoices

Create one-time payment requests and read their status.

The Invoice object

A one-time request for a specific amount of Bitcoin. Creating an invoice mints a dedicated on-chain deposit address; the invoice settles when a matching payment confirms.

objectstring
Always `"invoice"`.
idstring
Unique identifier for the invoice.
statusstring
Lifecycle state.
assetstring
Settlement asset. Currently always `BTC`.
amount_satsinteger
Amount due, in satoshis.
amount_usd_quotenumber | null
USD value quoted at creation. `null` if the price was unavailable.
descriptionstring | null
Optional memo you supplied.
customer_emailstring | null
Optional customer email you supplied.
deposit_addressstring | null
On-chain BTC address to pay. `null` for a brief moment right after creation while the address is minted.
tx_hashstring | null
On-chain transaction hash once paid.
payment_link_idstring | null
The payment link that generated this invoice, if any.
pay_urlstring
Hosted checkout page you can redirect customers to.
expires_atstring | null
ISO 8601 expiry timestamp, if set.
paid_atstring | null
ISO 8601 timestamp the invoice was paid.
created_atstring
ISO 8601 creation timestamp.

Example invoice

application/json
{
  "object": "invoice",
  "id": "inv_3n8Kd0Qz",
  "status": "open",
  "asset": "BTC",
  "amount_sats": 132099,
  "amount_usd_quote": 100,
  "description": "Order #1001",
  "customer_email": "buyer@example.com",
  "deposit_address": "bc1qxy2kgdygjrsqtzq2n0yrf2493p83kkfjhx0wlh",
  "tx_hash": null,
  "payment_link_id": null,
  "pay_url": "https://markgroup.app/pay/inv_3n8Kd0Qz",
  "expires_at": "2026-09-17T18:00:00.000Z",
  "paid_at": null,
  "created_at": "2026-09-16T18:00:00.000Z"
}

Create an invoice

writeIdempotent
POST/api/v1/invoices

Creates an invoice for a USD amount, converted to satoshis at the live BTC rate. A dedicated on-chain deposit address is minted for the invoice. If the live price is unavailable the request fails with `price_unavailable` rather than guessing a rate.

Body parameters

amount_usdnumberRequired
Amount to charge in USD.> 0, max 1,000,000
descriptionstringOptional
Memo shown on the invoice and hosted checkout.max 500 chars
customer_emailstringOptional
Customer email to associate with the invoice.max 320 chars
expires_in_hoursnumberOptional
Hours until the invoice expires. Omit for no expiry.> 0, max 8,760

Request

curl -X POST "https://markgroup.app/api/v1/invoices" \
  -H "Authorization: Bearer $MG_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{
  "amount_usd": 100,
  "description": "Order #1001",
  "customer_email": "buyer@example.com",
  "expires_in_hours": 24
}'

Response · 201

application/json
{
  "object": "invoice",
  "id": "inv_3n8Kd0Qz",
  "status": "open",
  "asset": "BTC",
  "amount_sats": 132099,
  "amount_usd_quote": 100,
  "description": "Order #1001",
  "customer_email": "buyer@example.com",
  "deposit_address": "bc1qxy2kgdygjrsqtzq2n0yrf2493p83kkfjhx0wlh",
  "tx_hash": null,
  "payment_link_id": null,
  "pay_url": "https://markgroup.app/pay/inv_3n8Kd0Qz",
  "expires_at": "2026-09-17T18:00:00.000Z",
  "paid_at": null,
  "created_at": "2026-09-16T18:00:00.000Z"
}

Errors

  • 400invalid_requestThe request was malformed — a field is missing, the wrong type, or out of range. The message names the offending field.
  • 403forbiddenThe key is valid but read-only, and the operation requires a write-scoped key.
  • 409conflictAn Idempotency-Key is still processing, or was reused with a different body.
  • 413payload_too_largeThe request body exceeded the maximum allowed size.
  • 503price_unavailableThe live BTC price needed to convert USD → sats is temporarily unavailable. Retry shortly.

List invoices

read
GET/api/v1/invoices

Returns a list of invoices belonging to the authenticated merchant, optionally filtered by status.

Query parameters

limitintegerOptional
Maximum number of items to return, newest first.1–100 · Default: 50
statusstringOptional
Filter by lifecycle status.One of: open paid expired canceled

Request

curl "https://markgroup.app/api/v1/invoices" \
  -H "Authorization: Bearer $MG_API_KEY"

Response · 200

application/json
{
  "object": "list",
  "data": [
    {
      "object": "invoice",
      "id": "inv_3n8Kd0Qz",
      "status": "open",
      "asset": "BTC",
      "amount_sats": 132099,
      "amount_usd_quote": 100,
      "description": "Order #1001",
      "customer_email": "buyer@example.com",
      "deposit_address": "bc1qxy2kgdygjrsqtzq2n0yrf2493p83kkfjhx0wlh",
      "tx_hash": null,
      "payment_link_id": null,
      "pay_url": "https://markgroup.app/pay/inv_3n8Kd0Qz",
      "expires_at": "2026-09-17T18:00:00.000Z",
      "paid_at": null,
      "created_at": "2026-09-16T18:00:00.000Z"
    }
  ]
}

Errors

  • 400invalid_requestThe request was malformed — a field is missing, the wrong type, or out of range. The message names the offending field.

Retrieve an invoice

read
GET/api/v1/invoices/{id}

Returns the invoice with the given id. Poll this endpoint to watch for `status` moving to `paid`.

Path parameters

idstringRequired
The invoice id.

Request

curl "https://markgroup.app/api/v1/invoices/inv_3n8Kd0Qz" \
  -H "Authorization: Bearer $MG_API_KEY"

Response · 200

application/json
{
  "object": "invoice",
  "id": "inv_3n8Kd0Qz",
  "status": "open",
  "asset": "BTC",
  "amount_sats": 132099,
  "amount_usd_quote": 100,
  "description": "Order #1001",
  "customer_email": "buyer@example.com",
  "deposit_address": "bc1qxy2kgdygjrsqtzq2n0yrf2493p83kkfjhx0wlh",
  "tx_hash": null,
  "payment_link_id": null,
  "pay_url": "https://markgroup.app/pay/inv_3n8Kd0Qz",
  "expires_at": "2026-09-17T18:00:00.000Z",
  "paid_at": null,
  "created_at": "2026-09-16T18:00:00.000Z"
}

Errors

  • 404not_foundNo resource with that id belongs to the authenticated merchant.