---
title: "Create or top-up a buyer-funded envelope (canonical of /envelopes alias)"
method: POST
path: "/escrow/envelopes"
tags: ["jobs"]
---

# Create or top-up a buyer-funded envelope (canonical of /envelopes alias)

`POST /escrow/envelopes`

## Request

- Base URL: `https://pact0.com/api/v1`
- URL: `https://pact0.com/api/v1/escrow/envelopes`
- Auth: API key in cookie `authjs.session-token`

This is the **canonical** envelope-creation endpoint. The
`/envelopes` path (documented above) is a Next.js rewrite
alias to this URL; both serve the same handler. New external
integrators may use either path.

See `/envelopes` for the full request body + response schema
+ idempotency + top-up semantics. The two entries exist so
the spec-coverage drift-immunity test (PR 65) can verify
both URLs resolve to the same route file.

## Request body

- object
  - `amount_minor` integer, required: Money in **micro-units**. 1 USD = 1,000,000 micro. **WARNING — do not confuse with cents.** Every `*_minor` field in this spec uses this convention, NOT the Stripe-style minor-currency-unit (cents) convention. Misreading the suffix as cents and multiplying by 100 yields a 10,000× misposting. Conversion examples: - `$0.05` (the test-pool fixture price) is `5_000_000 ÷ 100 = 50_000` - `$1.00` (the minimum buyer envelope) is `1_000_000` - `$5.00` (the dispute stake floor) is `5_000_000` - `$50.00` (the dispute stake ceiling) is `50_000_000` - `$5,000.00` (the maximum buyer envelope) is `5_000_000_000` Conversion to Stripe's cents (÷10,000, round down) happens only at the API boundary in the platform's wallet-backend implementations. Clients never invert this. **The `_usd` twin.** On job, claim and balance responses every `<base>_minor` / `<base>_micro` field has a `<base>_usd` sibling: the same amount in US dollars, as a number (`amount_minor: 50000` → `amount_usd: 0.05`). Read the twin; do arithmetic on the integer. Trio v8 §4.2 (2026-05-26): added because a REST-only buyer reading bare `{ type: integer, format: int64 }` schemas could plausibly assume cents. The bounds on POST /escrow/envelopes (`minimum: 1000000, maximum: 5000000000`) cap the worst-case misposting but do not close the confusion vector; surfacing the convention at every field site does.
  - `currency` 'USD'
  - `nonce` string, required
  - `expires_in_days` integer
  - `topup_envelope_id` string

## Response `200`

OK — see /envelopes

- object
  - `success` true
  - `data` object
    - `envelope_id` string
    - `checkout_url` string, uri
    - `amount_minor` integer: Money in **micro-units**. 1 USD = 1,000,000 micro. **WARNING — do not confuse with cents.** Every `*_minor` field in this spec uses this convention, NOT the Stripe-style minor-currency-unit (cents) convention. Misreading the suffix as cents and multiplying by 100 yields a 10,000× misposting. Conversion examples: - `$0.05` (the test-pool fixture price) is `5_000_000 ÷ 100 = 50_000` - `$1.00` (the minimum buyer envelope) is `1_000_000` - `$5.00` (the dispute stake floor) is `5_000_000` - `$50.00` (the dispute stake ceiling) is `50_000_000` - `$5,000.00` (the maximum buyer envelope) is `5_000_000_000` Conversion to Stripe's cents (÷10,000, round down) happens only at the API boundary in the platform's wallet-backend implementations. Clients never invert this. **The `_usd` twin.** On job, claim and balance responses every `<base>_minor` / `<base>_micro` field has a `<base>_usd` sibling: the same amount in US dollars, as a number (`amount_minor: 50000` → `amount_usd: 0.05`). Read the twin; do arithmetic on the integer. Trio v8 §4.2 (2026-05-26): added because a REST-only buyer reading bare `{ type: integer, format: int64 }` schemas could plausibly assume cents. The bounds on POST /escrow/envelopes (`minimum: 1000000, maximum: 5000000000`) cap the worst-case misposting but do not close the confusion vector; surfacing the convention at every field site does.
    - `amount_usd` number: amount_minor in US dollars (the `_usd` twin; see MoneyMicro).

## Other responses

- `401`: missing_session
- `422`: `unsupported_funding_currency` — the requested `currency` has no settleable rail; fund in USD (refused before any charge). `balance_envelope_not_topup` — `topup_envelope_id` names a pact0 BALANCE envelope (ALIP-0070), which is funded only by spending a balance, never by a card; omit it to fund a new card budget (refused before any charge).
- `502`: `stripe_unavailable` — Stripe could not create the Checkout funding flow (an upstream Stripe error); transient, retry in a few minutes.

---

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