Назад към всички

postalform-machine-order

// Send real postal mail through PostalForm using machine payments: prepare/validate print-and-mail payloads, submit `POST /api/machine/orders`, settle x402 payment with any compatible wallet client (purl or custom), and poll fulfillment through completion. Use when an agent must autonomously mail a re

$ git log --oneline --stat
stars:1,933
forks:367
updated:March 4, 2026
SKILL.mdreadonly
SKILL.md Frontmatter
namepostalform-machine-order
descriptionSend real postal mail through PostalForm using machine payments: prepare/validate print-and-mail payloads, submit `POST /api/machine/orders`, settle x402 payment with any compatible wallet client (purl or custom), and poll fulfillment through completion. Use when an agent must autonomously mail a real physical letter/document with strong first-pass correctness and idempotent retry behavior.

PostalForm Machine Order

Use this workflow when an agent needs to send real postal mail (a physical print-and-mail order) reliably on the first attempt.

Workflow

1. Collect inputs and choose address strategy

Require these inputs:

  • buyer_name, buyer_email
  • sender_name, recipient_name
  • PDF source (upload_token, { download_url, file_id }, data URL, or allowed https URL)
  • Mailing options (double_sided, color, mail_class, certified)

For each party (sender, recipient), choose exactly one strategy:

  • Manual address: *_address_type: "Manual" + *_address_manual
  • Loqate address: *_address_type: "Address" + *_address_id + *_address_text

Do not mix manual + Loqate for the same party.

2. Build payload with strict idempotency

Generate a UUID request_id once and keep payload bytes stable across retries.

Set buyer_email every time (required for Stripe receipt routing).

For manual addresses:

  • Include line1, city, state, zip
  • Include line2 only when it has a non-empty string value
  • Omit optional fields instead of sending null

Use the tested template in references/payload_templates.md.

3. Preflight with validate endpoint (recommended)

Call:

  • POST https://postalform.com/api/machine/orders/validate

If response is 200, confirm:

  • quote.page_count matches expected page count
  • quote.price_usd and options are acceptable

If response is 422, fix payload before paying.

4. Create order and settle x402 payment

Endpoint:

  • POST https://postalform.com/api/machine/orders

Flow:

  1. Send order payload without payment header.
  2. Receive 402 with PAYMENT-REQUIRED.
  3. Create payment using your wallet stack on the requested network.
  4. Retry the exact same request body with PAYMENT-SIGNATURE.
  5. Expect 202 and settlement metadata.

Payment client options:

  • purl CLI (fastest path when available)
  • Any x402-compliant client (@x402/core, @x402/evm, or equivalent custom signer flow)

If using purl:

  • Prefer wallet alias/keystore over raw private keys
  • Use --password from secure runtime input
  • Set a protective --max-amount
  • Match --network to PAYMENT-REQUIRED network

5. Poll order status until post-payment completion

Call:

  • GET https://postalform.com/api/machine/orders/:request_id

Treat this as complete when:

  • is_paid = true
  • current_step has advanced through processing (commonly to email_sent)
  • order_complete_url is a real URL

Handle transitional state:

  • status: "settled_pending_webhook" can persist briefly after on-chain settlement
  • Continue polling with backoff; do not resubmit a changed payload under the same request_id

First-Pass Reliability Rules

Required invariants

  • Keep request_id constant for retries of the same logical order.
  • Keep payload unchanged when retrying after 402.
  • Send buyer_email always.
  • Match payment network to PAYMENT-REQUIRED; do not hardcode network.
  • Use only valid US addresses and one address strategy per party.
  • Verify page count and quoted price before payment.

Observed failure modes and prevention

  • 422 invalid_type on manual line2:
    • Cause: empty optional fields normalized as null.
    • Prevent: omit line2 unless non-empty string.
  • Delay after successful payment (settled_pending_webhook):
    • Cause: settlement acknowledged before webhook reconciliation completes.
    • Prevent: poll for up to several minutes with retry/backoff.
  • Occasional non-JSON/transient server response during polling:
    • Cause: temporary upstream/render errors.
    • Prevent: parse defensively; if response is non-JSON or 5xx, retry without changing request_id or payload.
  • 409 request_id_mismatch:
    • Cause: same request_id reused with modified payload.
    • Prevent: generate a new UUID for changed orders; reuse ID only for exact retries.

Security Rules

  • Avoid printing wallet passwords, private keys, or sensitive env vars in logs.
  • Prefer encrypted keystore wallets over raw private keys when tooling supports both.
  • Use a payment cap (max amount) to avoid accidental overpayment.

Operator Output

Return these values after execution:

  • request_id / order_id
  • price/quote summary (including page_count)
  • payment settlement details (network, pay_to, settlement_tx, settled_at)
  • latest status (is_paid, current_step)
  • order_complete_url when available

Reference examples and command snippets:

  • references/payload_templates.md