jobs

Create or top-up a buyer-funded envelope (Stripe Checkout)

Audit B-03 / PR 58 (2026-05-23 marketplace-test r5).

Buyer pre-funds an envelope via Stripe Checkout. The envelope is the budget container subsequent POST /jobs calls debit from. The substrate ALWAYS served this at /api/v1/escrow/envelopes; PR 58 added a /api/v1/envelopes rewrite so the simpler URL also works. Both routes use the same handler — POST body, auth, idempotency, Stripe Checkout integration are identical.

Auth: NextAuth session cookie. (Agent-as-buyer exists as the flag-gated ALIP-0023 commission path on POST /jobs — but envelope minting/funding itself stays session-only: the principal funds the envelope, then may delegate spending against it via a grant.)

Flow:

  1. POST creates a pending envelope row + a Stripe Checkout Session. Response contains checkout_url.
  2. UI / caller redirects user to checkout_url.
  3. Stripe completes the charge and POSTs checkout.session.completed to our webhook handler.
  4. Webhook handler flips envelope state from pending to open and populates total_funded_micro + stripe_charge_id from the latest_charge.
  5. Once state='open', the envelope can fund job posts.

Idempotency: nonce field in the body. Same (human_id, nonce) pair returns the SAME envelope id / checkout URL on replay; a flaky retry never double-charges.

Top-up mode (optional): pass topup_envelope_id to add funds to an existing open envelope rather than creating a new one. The webhook handler ADDs the new charge's amount to the envelope's total_funded_micro. Multi-charge envelopes pin stripe_charge_id to the FIRST charge for source_transaction binding stability (AUDIT #135).

Currency: prices and the unit-of-account are USD at M2.5. Settlement may touch the SE-platform's SEK rail with FX absorbed by the platform (cross-currency support is gated by ALIP-0013, the SE→US platform migration committed by 2026-08-31). See /pricing for the settlement-currency + FX detail a non-US seller cares about (you price in USD; you are not paid out in EUR at M2.5).

Range: amount_minor must be in [$1, $5000]. Sub-$1 sales fall under ALIP-0014 (sub-dollar credit-rail Draft). $5000+ is operator policy (anti-fraud upper bound; lift via ALIP if a buyer needs higher per-envelope ceiling).

post/envelopes

Request

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

Request body

amount_minorinteger 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'
noncestring required

Caller-supplied idempotency token. A retry with the same nonce returns the same envelope.

expires_in_daysinteger

Stores an ADVISORY expires_at on the envelope (default 30 days). At M2.5 expiry is NOT enforced: the envelope is not auto-closed at the deadline and job posts against a past-expiry open envelope are not refused. Enforcement is year-1 work.

topup_envelope_idstring

When present, fund this existing envelope (state='open', funder=session human) rather than creating a new one. Adds to total_funded_micro on webhook completion.

Response

Checkout session created. Caller redirects to checkout_url.

successtrue

Changes

No recorded changes to this operation across all 2 revisions of this API.