Partner dashboard
API contract v2

Partner API

Build carts from product URLs, handle reviewed quotes as a normal asynchronous state, and pay server-authoritative orders.

Contract
Server-authoritative totals
Review
Asynchronous and resumable
Payment gate
`payment_ready` only

Authentication and authority

Keep credentials and all partner API calls on your server.

X-API-Key: sp3nd_...
X-API-Secret: sp3nd_sec_...
SP3ND resolves product facts and owns the final price, shipping, tax, fees, total, currency, payment memo, and recipient. Caller values are never payment authority.
Base URL
https://us-central1-sp3nddotshop-prod.cloudfunctions.net
schema_version
Version 2 is additive; existing response fields remain available.
payment_ready
The only supported signal that payment can begin.

Order lifecycle

A review state is a successful order creation, not an API failure.

Ready immediately
{
  "status": "Created",
  "checkout_role": "direct_payment",
  "pricing_status": "ready_for_payment",
  "requires_manual_quote": false,
  "payment_ready": true
}
Team review
{
  "status": "Awaiting Review",
  "checkout_role": "manual_review",
  "pricing_status": "awaiting_team_quote",
  "requires_manual_quote": true,
  "payment_ready": false
}
Shipping choice
{
  "checkout_role": "manual_review",
  "pricing_status": "shipping_selection_required",
  "payment_ready": false,
  "selected_shipping_option_id": null
}

If any item in a mixed cart needs manual review, the entire cart becomes one `Awaiting Review` order in v2. It is not split into child orders.

checkout_role
Exactly `direct_payment` or `manual_review`; stored legacy roles are normalized.
pricing_status
Primary values are `awaiting_team_quote`, `shipping_selection_required`, and `ready_for_payment`; this field is informational.
payment_ready
The sole payment gate. No role, status, quote, or total authorizes payment by itself.

Create a destination-aware cart

Send URLs and quantities. SP3ND resolves product metadata and commerce values.

const response = await fetch(
  'https://us-central1-sp3nddotshop-prod.cloudfunctions.net/createPartnerCart',
  {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'X-API-Key': process.env.SP3ND_API_KEY,
      'X-API-Secret': process.env.SP3ND_API_SECRET
    },
    body: JSON.stringify({
      ship_to_country: 'United States',
      ship_to_postal_code: '10007',
      items: [{
        product_url: 'https://www.ebay.com/itm/123456789',
        quantity: 1
      }]
    })
  }
);

Carts expire after 30 minutes. A complete `shipping_address` can replace the country/postal shortcut. Legacy clients can send extra item metadata, but caller-supplied titles and prices are not treated as verified data.

Create an idempotent order

One stable idempotency key represents one checkout attempt.

const response = await fetch(
  'https://us-central1-sp3nddotshop-prod.cloudfunctions.net/createPartnerOrder',
  {
    method: 'POST',
    headers: {
      ...authHeaders,
      'Idempotency-Key': checkoutAttemptId
    },
    body: JSON.stringify({
      cart_id: cart.cart_id,
      customer_email: 'buyer@example.com',
      shipping_address: {
        name: 'Ada Buyer',
        recipient: 'Ada Buyer',
        address1: '123 Main Street',
        address2: 'Suite 4',
        city: 'New York',
        state: 'NY',
        postalCode: '10007',
        country: 'United States',
        phone: '+12125550123'
      }
    })
  }
);
Idempotency-Key
Preferred header. `idempotency_key` in the body is supported for compatibility.
same key + same request
Returns the original order and can include `idempotent_replay: true`.
same key + changed request
Returns `409 IDEMPOTENCY_CONFLICT`.

Review quotes and shipping

Poll the order, present current choices, and submit an opaque option ID.

GET https://us-central1-sp3nddotshop-prod.cloudfunctions.net/getPartnerOrder?order_id=abc123

POST https://us-central1-sp3nddotshop-prod.cloudfunctions.net/selectPartnerOrderShippingOption
{
  "order_id": "abc123",
  "shipping_option_id": "standard"
}
quote_revision
Identifies the current team quote.
quote_expires_at
After expiry, fetch a new quote before continuing.
shipping_options
Each option uses shipping_option_id and carries label, shipping_amount, tax_amount, total_amount, and currency; description and estimated_delivery are optional.
selected_shipping_option_id
The canonical opaque identifier for the selected option, or null while a choice is required.
selected_shipping_option
The current reviewed choice, normalized to the same shape as an option.
selected_manual_shipping_option
Deprecated compatibility alias containing the same normalized object as selected_shipping_option.

Quote revision and expiry are enforced on selection. If the server returns a conflict, refresh the order and show the current options. Never calculate or patch the total client-side.

Pay a ready order

Payment requests identify an order; they do not define the payment.

POST https://us-central1-sp3nddotshop-prod.cloudfunctions.net/createPartnerTransaction
{
  "order_id": "abc123"
}

// x402 agents use the same order identity:
POST https://us-central1-sp3nddotshop-prod.cloudfunctions.net/payAgentOrder
{
  "order_id": "abc123"
}

`order_number` is optional for compatibility and is validated when sent. Caller-provided `amount`, `currency`, `memo`, and `recipient_address` are ignored. Payment endpoints derive all of them from the latest ready order. Payment can begin only when the latest response has `payment_ready: true`; `pricing_status` is informational and is never a second payment gate.

For x402, sign the payment requirements returned by `payAgentOrder`, then submit the signed `PAYMENT-SIGNATURE` back to SP3ND `payAgentOrder`. Do not call a facilitator's verify or settle endpoints directly. SP3ND is the sole settlement authority; after submission, poll the SP3ND order for its authoritative state.

`ORDER_NOT_PAYMENT_READY` means keep the customer in review and poll the order. `PAYMENT_SETTLEMENT_IN_PROGRESS` also means poll without resubmitting payment. If `PAYMENT_SETTLEMENT_UNKNOWN` is returned, do not retry: retain the order ID and request manual reconciliation.

Supported endpoints

Cloud Function endpoint names are part of the public contract.

POSTcreatePartnerCartCreate a 30-minute cart
POSTaddItemToPartnerCart/{cartId}Add one item
PATCHupdateCartItemQuantity/{cartId}/{itemId}Change quantity
DELETEremoveCartItem/{cartId}/{itemId}Remove an item
PATCHupdateCartShippingAddress/{cartId}Change destination and reprice
GETgetPartnerCart/{cartId}Read a cart
POSTcreatePartnerOrderCreate an order
GETgetPartnerOrder?order_id=...Read one order
GETgetPartnerOrdersList orders
POSTselectPartnerOrderShippingOptionChoose reviewed shipping
POSTcreatePartnerTransactionCreate payment instructions
POSTpayAgentOrderPay with x402

To list all orders, omit `status` or use `status=all`. The plural `addItemsToPartnerCart` endpoint is not supported in v2.

Lifecycle conflicts

Use machine-readable codes and refresh state after quote conflicts.

ORDER_NOT_PAYMENT_READY

Poll the order; do not submit payment.

ORDER_NOT_PAYABLE

Stop; this order cannot accept payment.

PAYMENT_SETTLEMENT_IN_PROGRESS

Do not resubmit payment; poll the order.

PAYMENT_SETTLEMENT_UNKNOWN

Do not retry; retain the order ID for manual reconciliation.

IDEMPOTENCY_CONFLICT

Use the original payload or a new checkout key.

QUOTE_EXPIRED

Fetch the current order and quote.

QUOTE_REVISION_CONFLICT

Refresh before selecting shipping.

CART_EXPIRED

Create and price a new cart.

RATE_LIMITED

Back off before retrying.

Migration checklist

Persist order_id, not only order_number.
Gate payment on payment_ready.
Treat Awaiting Review as resumable.
Poll getPartnerOrder with backoff.
Submit shipping option IDs unchanged.
Let SP3ND derive every payment field.
Use one idempotency key per checkout.
Handle mixed carts as one review order.

Support

Email support@sp3nd.shop with your partner name, endpoint, timestamp, and `order_id` or `cart_id`. Never send an API secret or signed payment payload.