---
updatedAt: 2026-10-05T04:43:44.734Z
---

Fetch the complete documentation index at: https://docs.avvio.xyz/llms.txt. Use this file to discover all available pages before exploring further. Append .md to any documentation page URL to get its markdown version.

# Node SDK

`@avvio/payments` v0.8.1: a Node client, the CLI and an MCP server in one package with **zero runtime dependencies**. Node 18 or newer.

```bash
npm i @avvio/payments
```

```js
const { PayoutsClient } = require('@avvio/payments');

const avvio = new PayoutsClient();   // also reads AVVIO_API_KEY and AVVIO_ORG_ID
```

## Paying someone

**Node**

```js title="POST /recipients/{orgId}"
const beneficiary = await avvio.createBeneficiary({
  name: 'María González',
  email: 'maria@example.com',                // optional contact detail
  country: 'MX',
  currency: 'MXN',
  endUserId: 'customer_42',        // your id for the person sending
  externalId: 'cust42_maria',      // makes a repeat create safe
  details: { clabeNumber: '012180000080004471' },
});
const destinationAccountId = beneficiary.method.destinationAccountId; // you pay this
```

**curl**

```bash title="POST /recipients/{orgId}"
IDEMPOTENCY_KEY=$(uuidgen)  # new key per call; reuse it only to retry this exact request
curl -s -X POST "$AVVIO_BASE_URL/recipients/$AVVIO_ORG_ID" \
  -H "x-api-key: $AVVIO_API_KEY" \
  -H "Idempotency-Key: $IDEMPOTENCY_KEY" \
  -H "content-type: application/json" \
  -d '{
        "type": "individual",
        "name": "María González",
        "country": "MX",
        "externalId": "cust42_maria",
        "endUserId": "customer_42",
        "method": {
          "kind": "fiat",
          "currency": "MXN",
          "recipientDetails": {
            "clabeNumber": "012180000080004471"
          }
        }
      }' | tee response.json
export DESTINATION_ACCOUNT_ID=$(jq -r .method.destinationAccountId response.json)
```

**Python**

```python title="POST /recipients/{orgId}"

idempotency_key = str(uuid.uuid4())  # new key per call; reuse it only to retry this exact request

res = requests.post(
    f"{os.environ['AVVIO_BASE_URL']}/recipients/{os.environ['AVVIO_ORG_ID']}",
    headers={
        "x-api-key": os.environ["AVVIO_API_KEY"],
        "Idempotency-Key": idempotency_key,
    },
    json={
        "type": "individual",
        "name": "María González",
        "country": "MX",
        "externalId": "cust42_maria",
        "endUserId": "customer_42",
        "method": {
            "kind": "fiat",
            "currency": "MXN",
            "recipientDetails": {
                "clabeNumber": "012180000080004471"
            }
        }
    },
)
print(res.status_code, res.json())
os.environ["DESTINATION_ACCOUNT_ID"] = res.json()["method"]["destinationAccountId"]  # a later step reads it
```

**CLI**

```bash title="POST /recipients/{orgId}"
avvio-payments beneficiary create \
  --name "María González" --email maria@example.com \
  --currency MXN --country MX \
  --end-user customer_42 --external-id cust42_maria \
  --field clabeNumber=012180000080004471 | tee response.json
export DESTINATION_ACCOUNT_ID=$(jq -r .method.destinationAccountId response.json)
```

**Node**

```js title="POST /payments/organizations/{orgId}/payouts"
const idempotencyKey = crypto.randomUUID(); // persist it with the order so a retry reuses it
const payout = await avvio.payout({
  amount: '200.00',
  destinationAccountId,
  expectDestination: quote.destinationAmount.amount,  // 3384.65
  endUser: { id: 'customer_42' },
  reference: 'ZZ-2026-0042',
  idempotencyKey,
});
```

**curl**

```bash title="POST /payments/organizations/{orgId}/payouts"
IDEMPOTENCY_KEY=$(uuidgen)  # new key per call; reuse it only to retry this exact request
curl -s -X POST "$AVVIO_BASE_URL/payments/organizations/$AVVIO_ORG_ID/payouts" \
  -H "x-api-key: $AVVIO_API_KEY" \
  -H "Idempotency-Key: $IDEMPOTENCY_KEY" \
  -H "content-type: application/json" \
  -d '{
        "amount": "200.00",
        "destinationAccountId": "'"$DESTINATION_ACCOUNT_ID"'",
        "amountLeg": "source",
        "expectDestination": "3384.65",
        "maxDriftBps": 200,
        "reference": "ZZ-2026-0042",
        "endUser": {
          "id": "customer_42"
        }
      }'
```

**Python**

```python title="POST /payments/organizations/{orgId}/payouts"

idempotency_key = str(uuid.uuid4())  # new key per call; reuse it only to retry this exact request

res = requests.post(
    f"{os.environ['AVVIO_BASE_URL']}/payments/organizations/{os.environ['AVVIO_ORG_ID']}/payouts",
    headers={
        "x-api-key": os.environ["AVVIO_API_KEY"],
        "Idempotency-Key": idempotency_key,
    },
    json={
        "amount": "200.00",
        "destinationAccountId": os.environ["DESTINATION_ACCOUNT_ID"],
        "amountLeg": "source",
        "expectDestination": "3384.65",
        "maxDriftBps": 200,
        "reference": "ZZ-2026-0042",
        "endUser": {
            "id": "customer_42"
        }
    },
)
print(res.status_code, res.json())
```

**CLI**

```bash title="POST /payments/organizations/{orgId}/payouts"
avvio-payments pay --amount 200.00 \
  --to "$DESTINATION_ACCOUNT_ID" \
  --expect 3384.65 \
  --end-user customer_42 --reference ZZ-2026-0042
```

## Every method

57 methods, parsed from the `index.d.ts` shipping with the package. `eachEvent`, `eachPayout`, `eachAuditEvent` and `eachBalanceTransaction` are async iterators that handle pagination for you.

### constructor

```ts
constructor(opts?: PayoutsClientOptions);
```

### corridors

The currencies you can pay out to, and what this routing can do. `capabilities.exactOutput` says whether the locking `amountLeg` modes work.

```ts
corridors(currency?: string): Promise<{
  corridors: Corridor[];
  capabilities: { exactOutput: boolean; indicativePricing: boolean };
}>;
```

### requirements

```ts
requirements(currency: string): Promise<Corridor>;
```

### quote

```ts
quote(args: {
  amount: string;
  to: string;
  from?: string;
}): Promise<PreviewQuote>;
```

### createBeneficiary

```ts
createBeneficiary(args: {
  name: string;
  currency: string;
  details: Record<string, string>;
  /** Optional contact address, kept for your records. Stored as null when omitted. */
  email?: string;
  type?: 'individual' | 'business';
  country?: string;
  /** Your id for the person sending. Scopes the beneficiary to them. */
  endUserId?: string;
  /** Your id for this beneficiary. Makes a repeat create safe. */
  externalId?: string;
  idempotencyKey?: string;
}): Promise<Beneficiary>;
```

### listBeneficiaries

```ts
listBeneficiaries(args?: {
  endUserId?: string;
  /** 1 to 100; defaults to 50. */
  limit?: number;
  /** The `nextCursor` from the previous page, unchanged. */
  cursor?: string;
}): Promise<{
  /** 'organization' or the end user the list was scoped to. */
  scope: string;
  recipients: Beneficiary[];
  /** More rows follow; pass `nextCursor` back as `cursor`. */
  hasMore?: boolean;
  nextCursor?: string | null;
}>;
```

### getBeneficiary

One beneficiary, by the id we returned. `NOT_FOUND` if it is not yours.

```ts
getBeneficiary(recipientId: string): Promise<Beneficiary>;
```

### getBeneficiaryByExternalId

One beneficiary, by your id for them: the same `externalId` that makes creation idempotent. Unique per organization, so this is exactly one beneficiary or a `NOT_FOUND`, rather than paging your whole book.

```ts
getBeneficiaryByExternalId(externalId: string): Promise<Beneficiary>;
```

### updateBeneficiary

Correct a beneficiary's own details. Only the fields you pass are changed. **Bank details cannot be edited.** The rail validated that account, and swapping it underneath would send the next payout somewhere you never registered. A wrong account is a new payment method, and the old one is deleted with `deleteBeneficiaryMethod`.

```ts
updateBeneficiary(
  recipientId: string,
  patch: {
    type?: 'individual' | 'business';
    name?: string;
    email?: string;
    phone?: string;
    /** ISO-3166 alpha-2. */
    country?: string;
  },
  opts?: { idempotencyKey?: string },
): Promise<Beneficiary>;
```

### deleteBeneficiary

Remove a beneficiary and every payment method on it. Payouts already sent are history, not references; this cancels nothing in flight.

```ts
deleteBeneficiary(
  recipientId: string,
  opts?: { idempotencyKey?: string },
): Promise<{ success: true }>;
```

### deleteBeneficiaryMethod

Remove one way of paying a beneficiary, such as an account that closed, or one entered wrong. Returns the beneficiary without it; the `destinationAccountId` that method carried stops being payable.

```ts
deleteBeneficiaryMethod(
  recipientId: string,
  methodId: string,
  opts?: { idempotencyKey?: string },
): Promise<Beneficiary>;
```

### getBeneficiaryMethodDetails

The full account details behind one payment method. Lists carry only `last4`. Deliberately loose: the fields are the corridor's own, so they differ by rail exactly as `requirements()` does.

```ts
getBeneficiaryMethodDetails(
  recipientId: string,
  methodId: string,
): Promise<Record<string, unknown>>;
```

### paymentReasons

The stated payment reasons this organization may use: the vocabulary `purposeOfPayment` on a payout, and `paymentReason` on a quote you accept, are validated against. Read it rather than guessing: a rejected value is a 400 on a payout you have already promised somebody.

```ts
paymentReasons(): Promise<{ payment_reasons: Record<string, unknown>[] }>;
```

### eachEvent

Every event after a watermark, paged for you. `since` is exclusive, so resuming from a saved `nextSince` does not re-read it; still at-least-once (a crash before you save the watermark replays events). Dedupe on `id`.

```ts
eachEvent(args?: {
  since?: string;
  limit?: number;
  payoutId?: string;
  /** Event types to include; a string (`'payout.completed,payout.returned'`) or an array. */
  type?: PayoutEventType | PayoutEventType[] | string;
}): AsyncIterableIterator<PayoutEvent>;
```

### eachAuditEvent

Every audit event matching a filter, newest first, paged for you.

```ts
eachAuditEvent(
  args?: AuditEventFilters & {
    limit?: number;
  },
): AsyncIterableIterator<AuditEvent>;
```

### eachPayout

Every payout matching a filter, paged for you.

```ts
eachPayout(args?: {
  limit?: number;
  status?: string;
  endUserId?: string;
  reference?: string;
  updatedSince?: string;
}): AsyncIterableIterator<Payout>;
```

### request

The raw escape hatch: any method, any path, with auth and error handling applied. For an endpoint the typed methods do not cover yet.

```ts
request(
  method: string,
  path: string,
  opts?: {
    body?: unknown;
    query?: Record<string, unknown>;
    idempotencyKey?: string;
    headers?: Record<string, string>;
  },
): Promise<unknown>;
```

### cancelPayout

Stop a payout that has not been funded yet. Once funded it cannot be canceled, and you get `PAYOUT_NOT_CANCELABLE`.

```ts
cancelPayout(
  payoutId: string,
  opts?: { idempotencyKey?: string },
): Promise<Payout>;
```

### pricePayout

The two halves of `createPayout`, exposed for callers that need to show a binding quote before committing.

```ts
pricePayout(args: {
  amount: string;
  destinationAccountId: string;
  purposeOfPayment?: string;
  // Deliberately loose: the snapshot is the rail's own quote object and its
  // shape varies by routing. Pass it straight back to `send()`.
}): Promise<{ id: string; best_quote_id?: string; [k: string]: unknown }>;
```

### send

```ts
send(args: {
  snapshotId: string;
  quoteId?: string;
  endUser?: EndUser;
  reference?: string;
  idempotencyKey?: string;
}): Promise<Payout>;
```

### payout

Price and send in one call, with the drift guard applied.

```ts
payout(args: PayoutArgs): Promise<Payout>;
```

### listEvents

Everything that has happened to your payouts, in order. The reconciliation primitive. Events are written once and never change, so carrying `nextSince` gives you exactly what is new, including a bank return that lands days after you booked the payout as settled, which listing payouts (ordered by creation) can never surface. At-least-once: dedupe on `id`.

```ts
listEvents(args?: {
  /** The `nextSince` from your last page. */
  since?: string;
  limit?: number;
  /** Everything that ever happened to one payout. */
  payoutId?: string;
  /**
   * Event types to include; a string (`'payout.completed,payout.returned'`)
   * or an array. Unknown values are a 400, never an empty page.
   */
  type?: PayoutEventType | PayoutEventType[] | string;
}): Promise<{
  data: PayoutEvent[];
  hasMore: boolean;
  nextSince: string | null;
}>;
```

### listApprovals

Payouts and batch runs waiting on your approvers. `payout()` and `confirmPayoutBatch()` answer 202 with a `PendingApproval` when the organization's policy holds them; this is that queue. Approving and rejecting are dashboard actions. A key cannot take them, so there is no method.

```ts
listApprovals(args?: {
  status?: PayoutApprovalStatus;
  /** 1–100, default 50. */
  limit?: number;
}): Promise<{ data: PayoutApproval[] }>;
```

### getApproval

One approval, by the `approvalId` a 202 gave you.

```ts
getApproval(approvalId: string): Promise<PayoutApproval>;
```

### listAuditEvents

A page of audit events, newest first: who did what, from where, with which credential. `id` is the cursor. A read-only key may read this.

```ts
listAuditEvents(
  args?: AuditEventFilters & {
    /** 1–100, default 50. */
    limit?: number;
    /** A `nextCursor` we issued: rows strictly older than it. */
    cursor?: string;
  },
): Promise<{
  data: AuditEvent[];
  hasMore: boolean;
  nextCursor: string | null;
}>;
```

### getFunding

How to fund a payout that came back with `requiresFunding: true`. Your funds stay in your wallet until you move them. A pure read; poll it freely.

```ts
getFunding(payoutId: string): Promise<{
  payoutId: string;
  amount: string;
  currency: string;
  depositAddress: string;
  network: string;
  /**
   * Normally `null`. There is no countdown on the deposit address. The rail
   * decides when an unfunded payout is over and reports that as the payout's
   * own status, so read `getPayout()` before sending against instructions you
   * fetched a while ago; do not build a timer on it.
   */
  expiresAt: string | null;
  instructions: string;
}>;
```

### confirmFunding

Proof you sent the funds: the transaction hash you broadcast.

```ts
confirmFunding(
  payoutId: string,
  proof: {
    transactionHash: string;
    idempotencyKey?: string;
  },
): Promise<Payout>;
```

### getPayout

Always live. More authoritative than a webhook you may have missed.

```ts
getPayout(payoutId: string): Promise<Payout>;
```

### listPayouts

A page of payouts, not an array: read the rows from the page and follow its cursor.

```ts
listPayouts(args?: {
  limit?: number;
  cursor?: string;
  status?: string;
  endUserId?: string;
  reference?: string;
  /**
   * **The change feed.** Payouts whose state changed at or after this time,
   * oldest-changed first.
   *
   * Ordinary listing is newest-first by creation, which by construction can
   * never tell you an old payout changed, and `completed → failed` on a bank
   * return, days later, is exactly the change a ledger cannot afford to miss.
   * Page forward, carry the highest `updatedAt` you have seen as your
   * watermark, and you observe every revision at least once.
   *
   * `updatedSince` is inclusive, so resuming re-reads the row at your
   * watermark. Dedupe on payoutId + updatedAt.
   */
  updatedSince?: string;
}): Promise<{ data: Payout[]; hasMore: boolean; nextCursor: string | null }>;
```

### createPayoutBatch

Submit up to 1,000 payouts as one run. `202` means received, not paid: every line is validated first (nothing priced, nothing debited), then the valid lines become ordinary payouts, each with its own `payoutId`.

```ts
createPayoutBatch(args: PayoutBatchArgs): Promise<PayoutBatch>;
```

### listPayoutBatches

A page of batches, newest first, not an array.

```ts
listPayoutBatches(args?: {
  status?: PayoutBatchStatus;
  /** Exact match on your own run id. */
  externalReferenceId?: string;
  /** 1–100, default 50. */
  limit?: number;
  /** A `nextCursor` we issued. Anything else is a 400, never an empty page. */
  cursor?: string;
}): Promise<{
  data: PayoutBatch[];
  hasMore: boolean;
  nextCursor: string | null;
}>;
```

### getPayoutBatch

One run, with its counts. Authoritative for the batch, not the payouts.

```ts
getPayoutBatch(batchId: string): Promise<PayoutBatch>;
```

### listPayoutBatchItems

The lines of a run, instruction echoed back verbatim. `status: 'invalid'` is the review screen after `awaiting_confirmation`; `'created'` joins the run to the payout ledger. The CSV export (`?format=csv`) is a plain file download; this method returns the JSON page.

```ts
listPayoutBatchItems(
  batchId: string,
  args?: {
    status?: PayoutBatchItemStatus;
    /** 1–1,000, default 100. */
    limit?: number;
    /** The `nextCursor` from your previous page: the last line index. */
    cursor?: string;
  },
): Promise<{
  data: PayoutBatchItem[];
  hasMore: boolean;
  nextCursor: string | null;
}>;
```

### confirmPayoutBatch

Proceed with the valid lines of a held run. Only legal from `awaiting_confirmation`; anything else is `PAYOUT_BATCH_NOT_CONFIRMABLE`.

```ts
confirmPayoutBatch(
  batchId: string,
  opts?: { idempotencyKey?: string },
): Promise<PayoutBatch>;
```

### cancelPayoutBatch

Stop a run before any payout exists. Once creation begins the run is committed and this is `PAYOUT_BATCH_NOT_CANCELABLE`. A payout the run created can be canceled with `cancelPayout` only while it waits on your own funding.

```ts
cancelPayoutBatch(
  batchId: string,
  opts?: { idempotencyKey?: string },
): Promise<PayoutBatch>;
```

### fundingAccounts

```ts
fundingAccounts(): Promise<unknown>;
```

### getPolicy

What your organization is bound by, read live. Read it first: caps, approval threshold, features, rate limits, idempotency windows and the currencies that need a `purposeOfPayment`.

```ts
getPolicy(): Promise<Policy>;
```

### balance

Everything a payout can draw on (cached up to 60 s): what the payment network holds for you (`provider`) plus the USD stablecoins in your own wallet (`wallet`, per chain, at face value), summed per currency into `balances` with USD as the `amount` headline. Size payouts against that, knowing wallet figures are face value before the network and conversion cost of moving them onto the settling rail. A payout for exactly `amount` can fail to fund when the money must be gathered from several chains first. `ledger` is our own append-only record of the network-held part, with what holds currently reserve. Never summed with the others; a difference from `provider` is what `listBalanceTransactions()` explains. `unavailable` names any source that failed to read: when non-empty the figures are a floor, not the balance, so retry before concluding you cannot fund a payout.

```ts
balance(): Promise<{
  currency: string;
  amount: string;
  balances: Money[];
  provider: Money[];
  /** Always empty in sandbox. */
  wallet: WalletBalance[];
  /** Sources that failed to read; non-empty results are not cached, so retry. */
  unavailable: Array<'network' | 'wallet'>;
  ledger: LedgerBalance[];
}>;
```

### listBalanceTransactions

A page of balance transactions, newest first, not an array. Every change to what you can spend, each with `balanceAfter`; `id` is the cursor and the dedupe key. Served on every environment; an empty page means no rows yet, not an error.

```ts
listBalanceTransactions(
  args?: BalanceTransactionFilters & {
    /** 1–100, default 100. */
    limit?: number;
    /** A `nextCursor` we issued: rows strictly older than it. */
    cursor?: string;
  },
): Promise<{
  data: BalanceTransaction[];
  hasMore: boolean;
  nextCursor: string | null;
}>;
```

### eachBalanceTransaction

Every balance transaction matching a filter, newest first, paged for you.

```ts
eachBalanceTransaction(
  args?: BalanceTransactionFilters & {
    limit?: number;
  },
): AsyncIterableIterator<BalanceTransaction>;
```

### fund

Credit a sandbox balance. Test keys only.

```ts
fund(amount?: string, idempotencyKey?: string): Promise<{ balance: string }>;
```

### createPayoutLink

Mint a one-time link for the person being paid, so they enter their own bank details and you never hold them. The token the recipient's page needs is the part of `url` after `/l/`.

```ts
createPayoutLink(args: {
  amount: string;
  /** e.g. 'MXN'. `to` is accepted as an alias. */
  destinationCurrency?: string;
  to?: string;
  endUserId: string;
  /** The sender (your end user). `email` is where the Reg E receipt goes. */
  endUser?: { name?: string; email?: string };
  reference?: string;
  /** Defaults to 60. Capped at 7 days. */
  expiresInMinutes?: number;
  idempotencyKey?: string;
}): Promise<{
  payoutLinkId: string;
  url: string;
  expiresAt: string;
  status: string;
}>;
```

### createCheckoutLink

Create a checkout link; with `publish: true` the response carries `shareUrl`. An idempotency key is minted when you do not pass one (the server requires it on every checkout write). A refused publish does not reject: the promise resolves with the kept draft, `status: 'draft'` and `publishError` set. Branch on `link.status !== 'sent'`.

```ts
createCheckoutLink(args: CreateCheckoutLinkArgs): Promise<CheckoutLink>;
```

### getCheckoutLink

```ts
getCheckoutLink(linkId: string): Promise<CheckoutLink>;
```

### listCheckoutLinks

```ts
listCheckoutLinks(args?: {
  status?: CheckoutLinkStatus;
  /** `api`: made with an API key. `dashboard`: made by a person. Omit for both. */
  source?: CheckoutLinkSource;
  limit?: number;
  cursor?: string;
}): Promise<{ items: CheckoutLink[]; nextCursor?: string }>;
```

### updateCheckoutLink

Edit a draft, or move a live link's deadline. A `sent` link accepts `expiresAt` alone (an instant, or `null` to clear); anything else on a live link is a 400.

```ts
updateCheckoutLink(
  linkId: string,
  args: UpdateCheckoutLinkArgs,
): Promise<CheckoutLink>;
```

### pauseCheckoutLink

Permanent: a paused link cannot be republished.

```ts
pauseCheckoutLink(linkId: string): Promise<CheckoutLink>;
```

### listCheckoutPayments

Newest first. Base units with `decimals`; the webhook uses decimal strings.

```ts
listCheckoutPayments(
  linkId: string,
  args?: { limit?: number; cursor?: string },
): Promise<{ items: CheckoutPayment[]; nextCursor?: string }>;
```

### refundCheckoutPayment

Moves money: refunds a card payment, whole (omit `amount`) or in part. The key needs the `refunds` scope. Retry a timeout with the same `idempotencyKey`. Resolves with the payment after the refund and the refund just made.

```ts
refundCheckoutPayment(
  paymentId: string,
  args?: RefundCheckoutPaymentArgs,
): Promise<CheckoutPayment & { refund: CheckoutRefund | null }>;
```

### simulateCheckoutPayment

Pay a sandbox link, as a buyer would. Test keys only. The link's amount picks the outcome; `listCheckoutSandboxScenarios()` is the table.

```ts
simulateCheckoutPayment(
  linkId: string,
  p?: { reference?: string; clientReferenceId?: string; idempotencyKey?: string },
): Promise<{ id: string; status: CheckoutPaymentStatus }>;
```

### simulateCheckoutPaymentOutcome

Force an outcome now instead of waiting out the timeline. Test keys only.

```ts
simulateCheckoutPaymentOutcome(
  paymentId: string,
  action: 'refund' | 'chargeback' | 'fail',
  idempotencyKey?: string,
): Promise<{ id: string; status: CheckoutPaymentStatus; moved: boolean }>;
```

### listCheckoutSandboxScenarios

What each amount does in the sandbox. Test keys only.

```ts
listCheckoutSandboxScenarios(): Promise<
  { suffix: string; description: string }[]
>;
```

### createProduct

```ts
createProduct(args: CreateProductArgs): Promise<CheckoutProduct>;
```

### listProducts

```ts
listProducts(): Promise<CheckoutProduct[]>;
```

### createWebhookEndpoint

Register a sandbox webhook endpoint. The `secret` is returned once and is not retrievable afterwards. Test keys only. Sends no `Idempotency-Key` and is never retried: a stored replay would keep the secret.

```ts
createWebhookEndpoint(args: { url: string; events?: string[] }): Promise<{
  id: string;
  url: string;
  events: string[];
  secret: string;
  warning: string;
}>;
```

### webhookEndpoints

The webhook endpoints registered for your organization. Read-only by design, and there is no create/pause/delete counterpart here: a key that could repoint its own webhook URL could redirect every payout notification. The signing secret is never returned; it is shown once, at creation.

```ts
webhookEndpoints(): Promise<
  {
    id: string;
    url: string;
    events: string[];
    /** Non-null while the endpoint is paused or auto-disabled. */
    disabledAt: string | null;
    disabledReason: 'paused_by_owner' | 'auto_disabled_after_failures' | null;
    /** Retry ladders exhausted since the last accepted delivery. */
    consecutiveFailures: number;
    lastSuccessAt: string | null;
    lastFailureAt: string | null;
    createdAt: string;
  }[]
>;
```

### webhookEndpointDeliveries

The 50 most recent delivery attempts for one endpoint, newest first. No payloads. Replay from the dashboard if you need the body, which re-fires under the same `eventId` so your dedupe still holds.

```ts
webhookEndpointDeliveries(endpointId: string): Promise<
  {
    id: string;
    /** The event id: the `svix-id` we sent and the feed row's `id`. Dedupe on this. */
    eventId: string;
    eventType: string;
    attempts: number;
    /** Null until an attempt is accepted. */
    deliveredAt: string | null;
    /** When we will try again. Retries back off over roughly 70 hours. */
    nextAttemptAt: string | null;
    /** Your server's response on the most recent failure. */
    lastError: string | null;
    createdAt: string;
  }[]
>;
```

### webhookDeliveries

What we sent, what came back, and what we retried. Sandbox endpoints.

```ts
webhookDeliveries(endpointId: string): Promise<unknown>;
```
