Skip to content

Save payload

Saving an item gives you one JSON object, the save payload, for one product the user chose. You write it into your own records and tell Flume whether that worked.

Save an itemThe user saves in the iframe, your side writes the record, and your page answers. Your backend calls Flume at no point. The same content is listed as text under the diagram.UserFlume iframeYour pageYour backendFlume servers1confirms a save2build the save payload3flume:save_item4save payload5write once per save_uuid6your record id7flume:item_saved8record the result9saved screenpostMessageThe iframe's own callA person actsAny other step

Save an item. The user saves in the iframe, your side writes the record, and your page answers. Your backend calls Flume at no point.

Read this diagram as text
  1. The user confirms a save in the iframe.
  2. The iframe asks Flume for the save payload. If that fails, the iframe shows its own error and your page hears nothing.
  3. The iframe posts flume:save_item with the save payload and its save_uuid.
  4. Your page sends the payload to your backend.
  5. Your backend writes one record per save_uuid, and copies the photo bytes if you keep a photo.
  6. Your backend answers with your record, or with a failure.
  7. Your page replies flume:item_saved with the same save_uuid, within 60 seconds. On a failed write it replies flume:item_save_failed instead.
  8. The iframe tells Flume how the save ended. You make no call for this.
  9. The iframe shows the saved screen.
StepIn the iframeWith the API
1. Build the payloadThe iframe calls FlumeYou call POST /save-item
2. Receive itYour page gets flume:save_itemIt is the response body
3. Write your recordYour page or backendYour backend
4. Report the resultReply flume:item_saved or flume:item_save_failedCall POST /save-item/{save_uuid}/result

The payload is the same object on both paths. Step by step with the API: Save an item.

save_uuid identifies one save. A retry sends the same save_uuid and gets the payload Flume stored the first time.

  • Treat save_uuid as your idempotency key.
  • If you already hold a record for it, return success without writing again.
  • A save_uuid that belongs to another user returns 409 SAVE_CONFLICT.
  • The stored payload keeps its first image links. They may have expired by the time of a retry. Read fresh links with GET /products/{sku_uuid}.
  • Send quote_uuid to include an instant quote's prices.
  • Send option_source to pick the shipping option. Without it, Flume picks the recommended one.
  • Leave quote_uuid out and pricing is null.
  • The quote must be READY, the user's own, not expired, and at or above the option's minimum order. Otherwise the call returns 422 QUOTE_NOT_READY.
  • Copy image bytes. Photo links expire after about 24 hours. In the sandbox they can stop working earlier.
  • Store product_url. It is the durable link back to Flume. It does not expire.
  • Render text as text. Escape every string on output. See Text rules.
  • Reply within 60 seconds in the iframe. Silence counts as a failure.
  • Check prices on your server if they matter. See Can you trust the save payload?

A save also files the product in the user's Flume project, when the search has one.

Save payload, schema_version 1.0
{
"schema_version": "1.0",
"save_uuid": "2b9d6f1c-7a34-4e58-b0c2-9d1e3f5a7b6c",
"saved_at": "2026-10-16T09:20:05Z",
"source": {
"item_ref": "48213",
"item_label": "T-1",
"project_ref": "proj_7781"
},
"user": {
"external_ref": "u_8812",
"flume_user_uuid": "a4d2c7e1-6b39-4f80-8e15-3c9b7a2d6f04"
},
"project": {
"external_ref": "proj_7781",
"flume_project_uuid": "e7b1f3a9-2c64-4d05-a8f7-6b0e9d4c1a28"
},
"product_url": "https://app.tryflume.ai/?utm_source=acme&utm_medium=partner&save_uuid=2b9d6f1c-7a34-4e58-b0c2-9d1e3f5a7b6c#/product/7f3c2a91-4b0e-4c8d-9a21-1f6b2d5e7c30",
"product": {
"sku_uuid": "7f3c2a91-4b0e-4c8d-9a21-1f6b2d5e7c30",
"name": "Porcelain 24×48″ Matte",
"category": "tile",
"material": "Porcelain",
"finish": "Matte",
"size_label": "24×48″",
"glance": [
{
"label": "Size",
"value": "24×48″"
},
{
"label": "Thickness",
"value": "9 mm"
},
{
"label": "Finish",
"value": "Matte"
},
{
"label": "Slip resistance",
"value": "DCOF over 0.42"
}
],
"spec_rows": [
{
"group": "Slip resistance",
"rows": [
{
"label": "DCOF",
"value": "over 0.42",
"method": "ANSI A326.3",
"note": null
}
]
}
],
"gallery": [
{
"urls": {
"640": "https://sandbox-api.tryflume.ai/partner/v1/images/example-image-main"
}
}
],
"lanes": [
{
"supply_source_type": "OVERSEAS_DIRECT",
"on_request": false,
"minimum_order_sqft": 5000,
"ships_from": {
"country": "ES",
"label": "Ships from Spain"
},
"lead_time": {
"min_days": 90,
"max_days": 120,
"label": "Delivered in 90 to 120 days"
}
},
{
"supply_source_type": "US_WAREHOUSE",
"on_request": false,
"minimum_order_sqft": 1000,
"ships_from": {
"country": "US",
"label": "Ships from the US"
},
"lead_time": {
"min_days": 14,
"max_days": 30,
"label": "Delivered in 14 to 30 days"
}
}
],
"suitable_application_areas": [
{
"code": "INTERIOR_DRY_FLOOR",
"label": "Interior Dry Floor"
}
]
},
"pricing": {
"quote_uuid": "9c1e4b7a-2f3d-4e5b-8a6c-7d8e9f0a1b2c",
"quote_number": "Q-7KD2-M4PA",
"status": "READY",
"created_at": "2026-10-16T09:14:22Z",
"valid_until": "2026-10-23T09:14:22Z",
"destination_zip": "22102",
"currency": "USD",
"picked": {
"sku_uuid": "7f3c2a91-4b0e-4c8d-9a21-1f6b2d5e7c30",
"supply_source_type": "OVERSEAS_DIRECT",
"ships_from_country": "ES",
"is_recommended": true,
"quantity": "6000.00",
"quantity_unit": "SF",
"material_total": "38400.00",
"tax_amount": "3168.00",
"total_excl_tax": "38400.00",
"total_incl_tax": "41568.00",
"unit_landed_price_excl_tax": "6.40",
"saving_vs_other_lane": "10200.00"
},
"lead_time": {
"min_days": 90,
"max_days": 120,
"label": "Delivered in 90 to 120 days"
},
"items": [
{
"sku_uuid": "7f3c2a91-4b0e-4c8d-9a21-1f6b2d5e7c30",
"supply_source_type": "OVERSEAS_DIRECT",
"ships_from_country": "ES",
"is_recommended": true,
"quantity": "6000.00",
"quantity_unit": "SF",
"material_total": "38400.00",
"tax_amount": "3168.00",
"total_excl_tax": "38400.00",
"total_incl_tax": "41568.00",
"unit_landed_price_excl_tax": "6.40",
"saving_vs_other_lane": "10200.00"
},
{
"sku_uuid": "7f3c2a91-4b0e-4c8d-9a21-1f6b2d5e7c30",
"supply_source_type": "US_WAREHOUSE",
"ships_from_country": "US",
"is_recommended": false,
"quantity": "6000.00",
"quantity_unit": "SF",
"material_total": "48600.00",
"tax_amount": "4009.50",
"total_excl_tax": "48600.00",
"total_incl_tax": "52609.50",
"unit_landed_price_excl_tax": "8.10",
"saving_vs_other_lane": null
}
]
},
"match": {
"search_session_uuid": "5f0c1d2e-8a7b-4c3d-9e1f-2a3b4c5d6e7f",
"filters": {
"material": [
{
"code": "PORCELAIN",
"label": "Porcelain"
}
],
"finish": [
{
"code": "MATTE",
"label": "Matte"
}
]
},
"section": "strong",
"rank": 1,
"matched_on": [
"finish",
"material"
]
}
}
FieldTypeNotes
schema_versionstring"1.0"
save_uuidstring (UUID)Identifies the save. Your idempotency key
saved_atstringUTC time
sourceobject or nullYour own ids. null when you call the API yourself
userobjectWho saved
projectobject or nullThe project, when Flume holds one
product_urlstringA durable link to the product in the Flume app
productobjectWhat was saved
pricingobject or nullThe quote's prices. null when the save has no quote
matchobjectHow the product was found
FieldTypeNotes
item_refstringThe item.external_id you sent
item_labelstring or nullThe item.label you sent
project_refstringThe project.external_ref you sent
FieldTypeNotes
external_refstringYour id for the user
flume_user_uuidstring (UUID)The user's id in Flume
FieldTypeNotes
external_refstringYour id for the project
flume_project_uuidstring (UUID)The project's id in Flume
  • Opens the product in the Flume app.
  • The user is not signed in by the link.
  • It does not expire. Store it.
  • Do not parse it. Its host depends on the environment.
FieldTypeNotes
sku_uuidstring (UUID)The product's id
namestringWritten by Flume from the product's specification
categorystringtile or vinyl
materialstring or nullFor example Porcelain
finishstring or nullFor example Matte
size_labelstring or nullFor example 24×48″
glancearrayKey facts: label, value
spec_rowsarrayThe full specification, in groups
galleryarrayEvery product photo the product page shows, in order
lanesarrayThe shipping options
suitable_application_areasarrayWhere the product can be used: code, label

spec_rows entries:

FieldTypeNotes
groupstringThe group's heading
rows[].labelstringA label can repeat within a group
rows[].valuestringThe property's value
rows[].methodstring or nullThe test standard, when one is stated
rows[].notestring or nullAn extra note, when there is one

Each rows entry has label, value, method and note.

gallery entries:

FieldTypeNotes
urlsobjectImage links by size. They expire. Copy the bytes

lanes entries, one per shipping option:

FieldTypeNotes
supply_source_typestringUS_WAREHOUSE or OVERSEAS_DIRECT
on_requestbooleantrue when Flume's sales team prices this option
minimum_order_sqftintegerThe smallest order for this option
ships_fromobject or nullcountry (two letters) and label
lead_timeobject or nullThe delivery window the product page shows: min_days, max_days, label. null when the option is priced on request

Present when the save names a quote.

FieldTypeNotes
quote_uuidstring (UUID)The quote's id
quote_numberstringAs the user sees it in Flume, for example Q-7KD2-M4PA
statusstringAlways READY
created_at, valid_untilstringUTC. Prices hold until valid_until
destination_zipstringThe delivery ZIP code
currencystringUSD
pickedobjectThe option the user chose. Same fields as an items entry
lead_timeobjectFor the picked option: min_days, max_days, label
itemsarrayEvery option of the quote for this product, cheapest first

picked and each items entry:

FieldTypeNotes
sku_uuidstring (UUID)The product priced
supply_source_typestringUS_WAREHOUSE or OVERSEAS_DIRECT
ships_from_countrystring or nullTwo letters
is_recommendedbooleanThe option Flume led with
quantitydecimal stringThe quantity the user asked for
quantity_unitstringThe unit of quantity
unit_landed_price_excl_taxdecimal stringDelivered price per unit, before tax
total_excl_taxdecimal stringDelivered price, before tax
material_totaldecimal stringAlways equal to total_excl_tax
tax_amountdecimal string or nullSales tax
total_incl_taxdecimal stringtotal_excl_tax plus tax_amount
saving_vs_other_lanedecimal string or nullOn the recommended option: how much less it costs than the other, before tax

Money is a decimal string. Do not parse it as a float.

How do the quote and the payload name the same thing?

Section titled “How do the quote and the payload name the same thing?”

A quote from the API and the pricing block describe the same shipping option with different field names.

Meaningquote.options[] (API)pricing.items[] (save payload)
How it shipssourcesupply_source_type
Where it ships fromships_from_countryships_from_country
Quantityquantity_sqftquantity
Delivered price per unit, before taxprice_per_sqftunit_landed_price_excl_tax
Delivered price, before taxsubtotaltotal_excl_tax
Sales taxsales_taxtax_amount
Delivered price, with taxtotaltotal_incl_tax
Delivery timelead_time_min_days, lead_time_max_dayspricing.lead_time, for the picked option
FieldTypeNotes
search_session_uuidstring (UUID)The search that found the product
filtersobjectThe filters that search ran with. List values carry code and label
sectionstring or nullWhere the product appeared. strong for a strong match
rankinteger or nullIts position in the results
matched_onarray of stringsFor a strong match: the filters it met. Otherwise empty

Flume cleans every string before it sends the payload.

  • No control characters.
  • No < or >. A comparison before a number becomes a word: > 0.42 reads over 0.42.
  • Labels are cut at 200 characters. Values are cut at 500.
  • Links are not cut.

Quotes and & are not removed. Escape every string on output. Never build HTML, or an HTML attribute, by joining these strings.

schema_version is "1.0". Read it before you map the payload, and log a value you do not know.