Skip to contentPostalForm

MPP flowers

PostalForm MPP flower endpoint instructions

Use this file for MPP-paid flower letters only. A flower letter is a fresh flower arrangement delivered through Florist One with a short recipient note.

Published Jun 17, 2026 • Updated Jun 19, 2026

Catalog prep endpoints

These endpoints are not MPP-paid, but agents use them before validation:

Purpose Method and path
List categories GET /api/flowers/categories
List products GET /api/flowers/products?category=bs&count=18&start=1&sorttype=pa
List delivery dates GET /api/flowers/delivery-dates?zipcode=32503

Product responses include Florist One fields such as CODE, NAME, PRICE, DESCRIPTION, SMALL, and LARGE. Treat PRICE as the arrangement price before delivery and tax. The validate endpoint is the source of truth for the final amount due.

MPP flower endpoints

Purpose Method and path
Validate product, ZIP, delivery date, and final quote POST /api/machine/mpp/flower-letters/validate
Create unpaid flower order, receive 402, and retry after MPP payment POST /api/machine/mpp/flower-letters
Poll payment and florist submission status GET /api/machine/mpp/flower-letters/{id}

Flow

  1. Choose the recipient delivery ZIP.
  2. List products and choose a product CODE.
  3. Fetch delivery dates for the recipient ZIP and choose a valid delivery_date.
  4. Build the flower-letter JSON body.
  5. Validate with POST /api/machine/mpp/flower-letters/validate.
  6. Show the final quote, including delivery and tax when present.
  7. Create the unpaid order with POST /api/machine/mpp/flower-letters and no Authorization header.
  8. Parse the WWW-Authenticate: Payment ... challenges from the 402 response.
  9. Pay one returned Tempo or Stripe SPT challenge.
  10. Retry the exact same create body and request_id with Authorization: Payment <serialized-mpp-credential>.
  11. Read Payment-Receipt.
  12. Poll GET /api/machine/mpp/flower-letters/{id} until payment_status is paid.

Required fields

Top-level fields:

  • request_id: UUID idempotency key.
  • buyer_name: buyer or agent owner name.
  • buyer_email: required for machine payment receipt delivery.
  • note: recipient note, 1 to 200 characters.
  • zipcode: recipient delivery ZIP; must match recipient.zipcode.
  • product_code: selected Florist One product CODE.
  • delivery_date: one returned by the delivery-dates endpoint.
  • customer: sender object.
  • recipient: delivery recipient object.
  • allow_substitutions: optional, defaults to true.
  • special_instructions: optional, max 100 characters.

Address objects:

  • name: required.
  • phone: required and must normalize to 10 US digits.
  • address1: required.
  • address2: optional.
  • city: required.
  • state: required two-letter state.
  • zipcode: required ZIP.
  • country: optional two-letter country; omit or use US.

customer.email is optional and defaults to buyer_email.

recipient.institution is optional (max 100 characters); use it for a business, hospital, or office name at the delivery address.

Validate example

curl -sS https://postalform.com/api/machine/mpp/flower-letters/validate \
  -H 'Content-Type: application/json' \
  --json '{
    "request_id": "0bc151ff-31a9-47a6-a0a4-2853cd75ff2a",
    "buyer_name": "Agent Owner",
    "buyer_email": "owner@example.com",
    "note": "For your desk, your day, and the smile I hope this brings.",
    "zipcode": "32503",
    "product_code": "F1-509",
    "delivery_date": "2026-07-03",
    "customer": {
      "name": "Agent Owner",
      "phone": "8505550100",
      "address1": "123 Sender St",
      "city": "Pensacola",
      "state": "FL",
      "zipcode": "32503",
      "country": "US"
    },
    "recipient": {
      "name": "Recipient Example",
      "phone": "8505550199",
      "address1": "456 Recipient Ave",
      "city": "Pensacola",
      "state": "FL",
      "zipcode": "32503",
      "country": "US"
    },
    "allow_substitutions": true
  }'

Expected validation shape:

{
  "protocol": "mpp",
  "methods": ["tempo", "stripe_spt"],
  "product_type": "flower_letter",
  "status": "validated_new_order",
  "quote": {
    "product": {
      "code": "F1-509",
      "priceCents": 4999
    },
    "total": {
      "orderTotalCents": 6999,
      "deliveryChargeCents": 1500,
      "taxTotalCents": 500
    }
  }
}

For this guide, use tempo or stripe_spt.

Create and pay

Create the unpaid flower order using the same JSON body:

curl -i https://postalform.com/api/machine/mpp/flower-letters \
  -H 'Content-Type: application/json' \
  --json @mpp-flower-body.json

Expected unpaid response:

  • HTTP status 402.
  • X-Payment-Protocol: mpp.
  • One or more WWW-Authenticate: Payment ... headers.
  • JSON body with payment-required details.
  • Flower-specific price_breakdown when final quote details are available.

Retry after paying one challenge:

curl -i https://postalform.com/api/machine/mpp/flower-letters \
  -H 'Content-Type: application/json' \
  -H 'Authorization: Payment <serialized-mpp-credential>' \
  --json @mpp-flower-body.json

Expected paid response:

  • HTTP status 200.
  • Payment-Receipt header.
  • JSON body with order_id, payment_status, product_type: "flower_letter", payment_channel: "mpp_machine", and order_complete_url when available.

Stripe SPT requirements

For the Stripe challenge:

  1. Parse the Stripe challenge from WWW-Authenticate.
  2. Mint or obtain a buyer-approved spt_... token for the exact amount, currency, and seller network id in the challenge.
  3. Serialize the original challenge and { "spt": "..." } into an MPP credential.
  4. Send the full serialized credential as Authorization: Payment ....

Do not send only the bare spt_... token.

Tempo requirements

Tempo clients should parse the returned WWW-Authenticate: Payment ... challenge and retry with Authorization: Payment ....

mppx \
  https://postalform.com/api/machine/mpp/flower-letters \
  --account my-tempo-wallet \
  --json-body "$(cat mpp-flower-body.json)" \
  --include \
  --verbose

Poll status

curl -sS https://postalform.com/api/machine/mpp/flower-letters/0bc151ff-31a9-47a6-a0a4-2853cd75ff2a

Status responses include:

  • awaiting_payment: unpaid flower order exists.
  • settled_pending_submission: payment was accepted and florist submission is queued.
  • paid: payment was accepted and submission processing has started.

Flower-specific rules

  • note is printed with the flower delivery and must be 200 characters or fewer.
  • zipcode must be the recipient delivery ZIP and must match recipient.zipcode.
  • Validate final price before paying. Catalog PRICE is not the final amount due.
  • PostalForm validates product, ZIP, delivery date, and total before issuing a payment challenge.
  • PostalForm checks the delivery date again when submitting the paid order to Florist One.
  • Machine flower totals are capped. If validation returns amount_exceeds_limit, choose a lower-priced arrangement.
  • Use a fresh request_id for a different flower delivery.

Flower-specific errors

  • 422 invalid_request: fix schema validation issues.
  • 422 invalid_flower_order: product, ZIP, date, address, or final quote validation failed.
  • 409 request_id_mismatch: the same request_id was reused with a different flower payload.
  • 422 missing_buyer_email: add a valid buyer_email.
  • 402 payment_required: normal MPP challenge response.
  • 429 rate_limited: wait before creating more unpaid drafts.

Related MPP docs

  • All MPP endpoints: https://postalform.com/mpp.md
  • Mail-only MPP guide: https://postalform.com/mpp-mail.md
  • OpenAPI: https://postalform.com/openapi.json