Skip to main content
POST /api/v2/storefront/proposals Saves a discover-products response against a buyer (operator) binding and mints a shareable proposalCode. The server reads the cached snapshot for the named discovery session, freezes the chosen proposal as the offer, and binds it to the operator. The buyer redeems the code on discover_products to receive the exact frozen products and proposals. The proposal is created in active status.

Request

curl -X POST https://api.interchange.io/api/v2/storefront/proposals \
  -H "Authorization: Bearer $SCOPE3_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "operatorId": { "domain": "acme.com" },
    "label": "Acme Q3 RFP — CTV",
    "notes": "Offline RFP follow-up; honors the upfront rate.",
    "expiresAt": "2026-09-30T23:59:59Z",
    "discoveryId": "disc_a1b2c3",
    "proposalId": "proposal_abc123"
  }'

Parameters

FieldTypeRequiredNotes
operatorIdstring or objectYesBuyer binding for redemption. Prefer { "domain": "brand.example" }; legacy strings are treated as domain bindings, and customer:<id> is decoded as { "customerId": id }.
labelstringYesSeller’s internal label for the proposal (1..255 chars)
expiresAtstringYesWhen the code expires (ISO 8601). Must be no later than the underlying proposal.expiresAt
discoveryIdstringYesDiscovery session ID from a recent discover_products call. Must be scoped to this seller and restricted to its storefront sales agents (1..255 chars)
proposalIdstringYesWhich proposal from the discovery snapshot to freeze and bind to the code (1..255 chars)
notesstringNoFree-form notes about the offline RFP (max 4000 chars)

Response

201 Created with the new proposal:
{
  "id": 318,
  "proposalCode": "PRP-XK4A29",
  "operatorId": "acme.com",
  "operatorRef": { "domain": "acme.com" },
  "label": "Acme Q3 RFP — CTV",
  "notes": "Offline RFP follow-up; honors the upfront rate.",
  "status": "active",
  "expiresAt": "2026-09-30T23:59:59Z",
  "proposalId": "proposal_abc123",
  "discoverySessionId": "disc_a1b2c3",
  "snapshot": { "products": [], "proposals": [] },
  "createdAt": "2026-06-07T15:00:00Z",
  "createdBy": "seller@acme-media.example.com",
  "firstViewedAt": null,
  "lastViewedAt": null,
  "redeemedAt": null,
  "redeemedInMediaBuyId": null
}
proposalCode is the short handle you hand to the buyer; they pass it to discover_products to redeem. id is the numeric row ID you pass to every sibling operation. snapshot holds the frozen products[] and proposals[] returned to the buyer on redemption.

Errors

  • 400 VALIDATION_ERROR — missing required field, expiresAt later than the underlying proposal.expiresAt, or a discoveryId not scoped to this seller’s storefront sales agents.
See Errors for the full error contract.

Proposal tasks

All proposal operations

Proposals overview

Lifecycle and concepts

Get proposal

Read back the saved snapshot

Revoke proposal

Withdraw a code before redemption