API reference

Customers and invoices reference

Create reusable customer identities, issue invoices, expose public invoice state, and manage invoice lifecycle edge cases.

POST/api/v1/businesses/:id/customersx-api-keySandbox + live

Create customer

Create a reusable customer identity with permanent deposit addresses.

When to use it

Use before recurring invoicing or when you want to track invoices by a stable customer record.

Idempotency: recommended

FieldLocationRequiredDescriptionExample / default
idpathYesBusiness ID.-
externalRefbodyYesYour internal customer identifier.-
emailbodyNoOptional customer email.-

Cautions

  • For one-off anonymous payments, create invoices without a customerId instead of creating throwaway customers.
  • Address provisioning depends on the business wallet being ready in the selected environment.

Common errors

  • 401: Missing or invalid API key.
  • 400: Payload shape, query params, or business-state validation failed.

Sample request body

json
{
  "externalRef": "customer_001",
  "email": "customer@example.com"
}

Sample response

json
{
  "id": "cus_123",
  "externalRef": "customer_001",
  "email": "customer@example.com",
  "addresses": [
    { "chainFamily": "eth", "address": "0xE5fa2F71065fD49823D33EdD84ecFD2D6245c916" },
    { "chainFamily": "sol", "address": "8gRLe6GiQx2jo9mQFcbwy34u2W4zD2rN5q4mmD8iP2Mp" }
  ]
}

cURL example

bash
curl -X POST "https://api.paychainhq.io/api/v1/businesses/biz_123/customers" \
  -H "Content-Type: application/json" \
  -H "x-api-key: pk_live_your_business_key" \
  -H "Idempotency-Key: example-request-001" \
  -d '{
  "externalRef": "customer_001",
  "email": "customer@example.com"
}'

Node.js example

ts
const response = await fetch('https://api.paychainhq.io/api/v1/businesses/biz_123/customers', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'x-api-key': 'pk_live_your_business_key',
    'Idempotency-Key': 'example-request-001',
  },
  body: JSON.stringify({
  "externalRef": "customer_001",
  "email": "customer@example.com"
}),
});
const payload = await response.json();
console.log(payload);
GET/api/v1/businesses/:id/customersx-api-keySandbox + live

List customers

List customers for the business.

When to use it

Use in CRM syncs, dashboard tables, or reconciliation tooling.

FieldLocationRequiredDescriptionExample / default
idpathYesBusiness ID.-
pagequeryNoPage number.1
limitqueryNoPage size.20

Common errors

  • 401: Missing or invalid API key.

Sample response

json
{
  "data": [
    {
      "id": "cus_123",
      "externalRef": "customer_001",
      "email": "customer@example.com",
      "addresses": [
        { "chainFamily": "eth", "address": "0xE5fa2F71065fD49823D33EdD84ecFD2D6245c916" }
      ]
    }
  ],
  "pagination": {
    "page": 1,
    "limit": 20,
    "total": 1,
    "totalPages": 1,
    "hasMore": false
  }
}

cURL example

bash
curl -X GET "https://api.paychainhq.io/api/v1/businesses/biz_123/customers?page=1&limit=20" \
  -H "Content-Type: application/json" \
  -H "x-api-key: pk_live_your_business_key"

Node.js example

ts
const response = await fetch('https://api.paychainhq.io/api/v1/businesses/biz_123/customers?page=1&limit=20', {
  method: 'GET',
  headers: {
    'Content-Type': 'application/json',
    'x-api-key': 'pk_live_your_business_key',
  },
});
const payload = await response.json();
console.log(payload);
GET/api/v1/businesses/:id/customers/:customerIdx-api-keySandbox + live

Get customer

Return a single customer record and its addresses.

When to use it

Use when showing a single customer detail page or resolving invoice ownership.

FieldLocationRequiredDescriptionExample / default
idpathYesBusiness ID.-
customerIdpathYesCustomer ID.-

Common errors

  • 401: Missing or invalid API key.
  • 404: Requested resource does not exist or is not owned by the business.

Sample response

json
{
  "id": "cus_123",
  "externalRef": "customer_001",
  "email": "customer@example.com",
  "addresses": [
    { "chainFamily": "eth", "address": "0xE5fa2F71065fD49823D33EdD84ecFD2D6245c916" },
    { "chainFamily": "sol", "address": "8gRLe6GiQx2jo9mQFcbwy34u2W4zD2rN5q4mmD8iP2Mp" }
  ]
}

cURL example

bash
curl -X GET "https://api.paychainhq.io/api/v1/businesses/biz_123/customers/cus_123" \
  -H "Content-Type: application/json" \
  -H "x-api-key: pk_live_your_business_key"

Node.js example

ts
const response = await fetch('https://api.paychainhq.io/api/v1/businesses/biz_123/customers/cus_123', {
  method: 'GET',
  headers: {
    'Content-Type': 'application/json',
    'x-api-key': 'pk_live_your_business_key',
  },
});
const payload = await response.json();
console.log(payload);
POST/api/v1/businesses/:id/invoicesx-api-keySandbox + live

Create invoice

Create a payable invoice and allocate a deposit address.

When to use it

Use whenever you want a deterministic deposit request with tracked lifecycle state.

Idempotency: recommended

FieldLocationRequiredDescriptionExample / default
idpathYesBusiness ID.-
customerIdbodyNoOptional reusable customer record.-
amountbodyYesInvoice amount in token display units.-
tokenbodyYesSettlement token symbol, for example `USDC`.-
chainbodyYesChain family: `eth`, `btc`, or `sol`.-
networkIdbodyNoSpecific network such as `base-mainnet`.-
expiresInbodyNoInvoice lifetime in seconds.-
underpaymentToleranceBpsbodyNoOptional per-invoice tolerance override.-
underpaymentToleranceMaxUsdbodyNoOptional absolute max shortfall override.-

Flags and defaults

  • underpaymentToleranceBps (default: Business default or 0): Accept small underpayments after confirmations.
  • underpaymentToleranceMaxUsd (default: Business default or 0): Absolute cap that works together with bps tolerance.

Cautions

  • Invoice settlement is asset-matched. Native gas top-ups or unsupported tokens will not settle the invoice.
  • Do not share an invoice until provider registration reports `ready` in the response.

Common errors

  • 401: Missing or invalid API key.
  • 400: Payload shape, query params, or business-state validation failed.

Sample request body

json
{
  "customerId": "cus_123",
  "amount": "150",
  "token": "USDC",
  "chain": "eth",
  "networkId": "base-mainnet",
  "expiresIn": 86400,
  "description": "March onramp settlement",
  "underpaymentToleranceBps": 50,
  "underpaymentToleranceMaxUsd": "0.50"
}

Sample response

json
{
  "id": "inv_123",
  "businessId": "biz_123",
  "customerId": "cus_123",
  "status": "pending",
  "token": "USDC",
  "chain": "eth",
  "networkId": "base-mainnet",
  "amount": {
    "raw": "150000000",
    "decimals": 6,
    "display": "150",
    "symbol": "USDC",
    "chain": "eth",
    "networkId": "base-mainnet"
  },
  "depositAddress": "0xE5fa2F71065fD49823D33EdD84ecFD2D6245c916",
  "expiresAt": "2026-03-15T13:00:00.000Z",
  "underpaymentToleranceBps": 50,
  "underpaymentToleranceMaxUsd": "0.50",
  "providerRegistration": {
    "status": "ready",
    "ready": true,
    "message": "Deposit address is registered and ready to share."
  }
}

cURL example

bash
curl -X POST "https://api.paychainhq.io/api/v1/businesses/biz_123/invoices" \
  -H "Content-Type: application/json" \
  -H "x-api-key: pk_live_your_business_key" \
  -H "Idempotency-Key: example-request-001" \
  -d '{
  "customerId": "cus_123",
  "amount": "150",
  "token": "USDC",
  "chain": "eth",
  "networkId": "base-mainnet",
  "expiresIn": 86400,
  "description": "March onramp settlement",
  "underpaymentToleranceBps": 50,
  "underpaymentToleranceMaxUsd": "0.50"
}'

Node.js example

ts
const response = await fetch('https://api.paychainhq.io/api/v1/businesses/biz_123/invoices', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'x-api-key': 'pk_live_your_business_key',
    'Idempotency-Key': 'example-request-001',
  },
  body: JSON.stringify({
  "customerId": "cus_123",
  "amount": "150",
  "token": "USDC",
  "chain": "eth",
  "networkId": "base-mainnet",
  "expiresIn": 86400,
  "description": "March onramp settlement",
  "underpaymentToleranceBps": 50,
  "underpaymentToleranceMaxUsd": "0.50"
}),
});
const payload = await response.json();
console.log(payload);
GET/api/v1/businesses/:id/invoicesx-api-keySandbox + live

List invoices

List invoices for a business with lifecycle and pagination data.

When to use it

Use for admin tables, internal reconciliation, or polling fallback when webhooks are delayed.

FieldLocationRequiredDescriptionExample / default
idpathYesBusiness ID.-
statusqueryNoFilter by invoice status.-
customerIdqueryNoRestrict results to a single customer.-
pagequeryNoPage number.1
limitqueryNoPage size.20

Cautions

  • Expired invoices may remain raw-pending briefly; UI should treat `expiresAt` as authoritative for effective open state.

Common errors

  • 401: Missing or invalid API key.

Sample response

json
{
  "data": [
    {
      "id": "inv_123",
      "status": "pending",
      "token": "USDC",
      "chain": "eth",
      "networkId": "base-mainnet",
      "amount": {
        "raw": "150000000",
        "decimals": 6,
        "display": "150",
        "symbol": "USDC",
        "chain": "eth",
        "networkId": "base-mainnet"
      },
      "expiresAt": "2026-03-15T13:00:00.000Z"
    }
  ],
  "pagination": {
    "page": 1,
    "limit": 20,
    "total": 1,
    "totalPages": 1,
    "hasMore": false
  }
}

cURL example

bash
curl -X GET "https://api.paychainhq.io/api/v1/businesses/biz_123/invoices?page=1&limit=20" \
  -H "Content-Type: application/json" \
  -H "x-api-key: pk_live_your_business_key"

Node.js example

ts
const response = await fetch('https://api.paychainhq.io/api/v1/businesses/biz_123/invoices?page=1&limit=20', {
  method: 'GET',
  headers: {
    'Content-Type': 'application/json',
    'x-api-key': 'pk_live_your_business_key',
  },
});
const payload = await response.json();
console.log(payload);
GET/api/v1/businesses/invoices/:invoiceIdx-api-keySandbox + live

Get business invoice

Return a business-scoped invoice detail with payment summary and tolerance metadata.

When to use it

Use after webhook receipt or as a fallback read before updating your order state.

FieldLocationRequiredDescriptionExample / default
invoiceIdpathYesInvoice ID.-

Cautions

  • `paidAmount` is always the actual deposited amount. A tolerance-settled invoice does not synthesize the shortfall.

Common errors

  • 401: Missing or invalid API key.
  • 404: Requested resource does not exist or is not owned by the business.

Sample response

json
{
  "id": "inv_123",
  "status": "paid",
  "settledByTolerance": true,
  "underpaymentToleranceBps": 50,
  "underpaymentToleranceMaxUsd": "0.50",
  "toleranceRaw": "500000",
  "toleranceShortfall": {
    "raw": "250000",
    "decimals": 6,
    "display": "0.25",
    "symbol": "USDC",
    "chain": "eth",
    "networkId": "base-mainnet"
  },
  "amount": {
    "raw": "150000000",
    "decimals": 6,
    "display": "150",
    "symbol": "USDC",
    "chain": "eth",
    "networkId": "base-mainnet"
  },
  "paidAmount": {
    "raw": "149750000",
    "decimals": 6,
    "display": "149.75",
    "symbol": "USDC",
    "chain": "eth",
    "networkId": "base-mainnet"
  },
  "depositAddress": "0xE5fa2F71065fD49823D33EdD84ecFD2D6245c916",
  "paymentSummary": {
    "paymentsReceived": 1
  }
}

cURL example

bash
curl -X GET "https://api.paychainhq.io/api/v1/businesses/invoices/inv_123" \
  -H "Content-Type: application/json" \
  -H "x-api-key: pk_live_your_business_key"

Node.js example

ts
const response = await fetch('https://api.paychainhq.io/api/v1/businesses/invoices/inv_123', {
  method: 'GET',
  headers: {
    'Content-Type': 'application/json',
    'x-api-key': 'pk_live_your_business_key',
  },
});
const payload = await response.json();
console.log(payload);
DELETE/api/v1/businesses/:id/invoices/:invoiceIdx-api-keySandbox + live

Cancel invoice

Cancel an invoice that has not reached an irreversible state.

When to use it

Use to retire stale payment requests that should no longer be fulfilled.

Idempotency: recommended

FieldLocationRequiredDescriptionExample / default
idpathYesBusiness ID.-
invoiceIdpathYesInvoice ID.-

Cautions

  • Do not assume cancellation is valid after deposits begin. Always inspect the returned count / state.

Common errors

  • 401: Missing or invalid API key.
  • 404: Requested resource does not exist or is not owned by the business.
  • 400: Payload shape, query params, or business-state validation failed.

Sample response

json
{
  "count": 1
}

cURL example

bash
curl -X DELETE "https://api.paychainhq.io/api/v1/businesses/biz_123/invoices/inv_123" \
  -H "Content-Type: application/json" \
  -H "x-api-key: pk_live_your_business_key" \
  -H "Idempotency-Key: example-request-001"

Node.js example

ts
const response = await fetch('https://api.paychainhq.io/api/v1/businesses/biz_123/invoices/inv_123', {
  method: 'DELETE',
  headers: {
    'Content-Type': 'application/json',
    'x-api-key': 'pk_live_your_business_key',
    'Idempotency-Key': 'example-request-001',
  },
});
const payload = await response.json();
console.log(payload);
GET/api/v1/invoices/:invoiceIdPublicSandbox + live

Get public invoice payload

Return the payer-facing invoice state, deposit address, and progress details.

When to use it

Use to power a public payment link, hosted payment screen, or payer-side polling loop.

FieldLocationRequiredDescriptionExample / default
invoiceIdpathYesInvoice ID.-

Cautions

  • This payload is public. Do not place internal-only notes or operator metadata into invoice descriptions.
  • Treat it as payer-facing status, not as your sole reconciliation source.

Common errors

  • 404: Requested resource does not exist or is not owned by the business.

Sample response

json
{
  "id": "inv_123",
  "status": "confirming",
  "state": "confirming",
  "amount": {
    "raw": "150000000",
    "decimals": 6,
    "display": "150",
    "symbol": "USDC",
    "chain": "eth",
    "networkId": "base-mainnet"
  },
  "paidAmount": {
    "raw": "149750000",
    "decimals": 6,
    "display": "149.75",
    "symbol": "USDC",
    "chain": "eth",
    "networkId": "base-mainnet"
  },
  "paymentProgress": {
    "percentPaid": "99.83",
    "status": "Paid within tolerance",
    "remainingAmount": {
      "display": "0"
    }
  },
  "depositAddress": "0xE5fa2F71065fD49823D33EdD84ecFD2D6245c916"
}

cURL example

bash
curl -X GET "https://api.paychainhq.io/api/v1/invoices/inv_123" \
  -H "Content-Type: application/json"

Node.js example

ts
const response = await fetch('https://api.paychainhq.io/api/v1/invoices/inv_123', {
  method: 'GET',
  headers: {
    'Content-Type': 'application/json',
  },
});
const payload = await response.json();
console.log(payload);
PATCH/api/v1/invoices/:invoiceId/statusx-api-keySandbox + live

Patch invoice status for reconciliation

Trigger or override invoice status reconciliation in controlled cases.

When to use it

Use only for manual recovery or explicit reconciliation tooling.

Idempotency: recommended

FieldLocationRequiredDescriptionExample / default
invoiceIdpathYesInvoice ID.-
statusbodyYesTarget status or reconciliation directive.-

Cautions

  • This is not the normal happy-path payment confirmation flow. Prefer webhook-driven settlement and invoice reads first.

Common errors

  • 401: Missing or invalid API key.
  • 400: Payload shape, query params, or business-state validation failed.

Sample request body

json
{
  "status": "paid"
}

Sample response

json
{
  "id": "inv_123",
  "status": "paid",
  "settledByTolerance": true,
  "underpaymentToleranceBps": 50,
  "underpaymentToleranceMaxUsd": "0.50",
  "toleranceRaw": "500000",
  "toleranceShortfall": {
    "raw": "250000",
    "decimals": 6,
    "display": "0.25",
    "symbol": "USDC",
    "chain": "eth",
    "networkId": "base-mainnet"
  },
  "amount": {
    "raw": "150000000",
    "decimals": 6,
    "display": "150",
    "symbol": "USDC",
    "chain": "eth",
    "networkId": "base-mainnet"
  },
  "paidAmount": {
    "raw": "149750000",
    "decimals": 6,
    "display": "149.75",
    "symbol": "USDC",
    "chain": "eth",
    "networkId": "base-mainnet"
  },
  "depositAddress": "0xE5fa2F71065fD49823D33EdD84ecFD2D6245c916",
  "paymentSummary": {
    "paymentsReceived": 1
  }
}

cURL example

bash
curl -X PATCH "https://api.paychainhq.io/api/v1/invoices/inv_123/status" \
  -H "Content-Type: application/json" \
  -H "x-api-key: pk_live_your_business_key" \
  -H "Idempotency-Key: example-request-001" \
  -d '{
  "status": "paid"
}'

Node.js example

ts
const response = await fetch('https://api.paychainhq.io/api/v1/invoices/inv_123/status', {
  method: 'PATCH',
  headers: {
    'Content-Type': 'application/json',
    'x-api-key': 'pk_live_your_business_key',
    'Idempotency-Key': 'example-request-001',
  },
  body: JSON.stringify({
  "status": "paid"
}),
});
const payload = await response.json();
console.log(payload);
Customers and invoices reference | PayChainHQ