Products
Products are the core of Flint's catalog: physical goods, services, fees, digital items, and gift cards. The product is the parent record; its variants are the sellable units that carry price and SKU. Order lines, payment links, bundles, and subscription plans name a variant, never the product, and Flint copies the variant's name, price, SKU, image, and tax settings onto each line.
Catalog setup walks through creating products with sizes, categories, modifiers, and bundles, then selling them on an order.
Products, variants, and options#
| Record | ID | What it holds |
|---|---|---|
| Product | prod_ | Name, description, product_type, status, categories, images, and a modifier set. No price, SKU, or stock. |
| Variant | var_ | unit_price_money, sku, barcode, tax settings, an inventory link, a delivery profile, unit weight and dimensions, and its own status |
| Option and value | opt_, optv_ | Labels that tell variants apart, such as Size with Small and Large. Each variant selects one value for each active option in selected_options. |
A simple product has one variant, its default_variant_id. An optioned product has options and every variant you list for it: Flint never generates variants from option combinations. Across a product's variants:
- All active variants use the same currency.
- No two variants select the same combination of values.
- No two variants or bundles share a
skuor abarcode. A taken one returns409 ALREADY_EXISTS, with the record that has it indetails[0].current_resource.
An order line that names a variant_id takes its name, price, and tax settings from the catalog, and rejects your own values for them with 400 INVALID_REQUEST and detail code NOT_ALLOWED. To sell something that isn't in the catalog, send a custom line on the order instead.
Create a product#
variant_mode selects the shape of POST /v1/products:
variant_mode | Send | Creates |
|---|---|---|
simple | default_variant | One variant, which becomes default_variant_id |
optioned | options and variants | The options and values, and up to 100 variants. Add more with POST /v1/products/{product_id}/variants. |
Sending fields from the other shape, more than 100 variants, or a price, SKU, or tax field on the product itself returns 400 INVALID_REQUEST with param naming the field. Price, SKU, and tax fields belong on a variant.
Each variant selects its values by option_name and value, so it needs no option or value IDs, even for options created in the same request. Both match case-insensitively and ignore surrounding whitespace.
curl -X POST https://api.withflintpay.com/v1/products \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Idempotency-Key: product-tee-crew" \
-H "Content-Type: application/json" \
-d '{
"variant_mode": "optioned",
"name": "Crew tee",
"product_type": "physical",
"options": [{
"name": "Size",
"values": [{ "value": "Small" }, { "value": "Large" }]
}],
"variants": [
{
"name": "Small",
"sku": "TEE-CREW-S",
"unit_price_money": { "amount": 2800, "currency": "USD" },
"selected_options": [{ "option_name": "Size", "value": "Small" }]
},
{
"name": "Large",
"sku": "TEE-CREW-L",
"unit_price_money": { "amount": 3000, "currency": "USD" },
"selected_options": [{ "option_name": "Size", "value": "Large" }]
}
]
}'
{
"data": {
"product_id": "prod_01K0P7W6A4N9F3J2T8Q5R1C6XN",
"name": "Crew tee",
"product_type": "physical",
"status": "active",
"version": 1,
"variant_count": 2,
"options": [
{
"option_id": "opt_01K0P7W6A4N9F3J2T8Q5R1C6XA",
"name": "Size",
"position": 0,
"status": "active",
"values": [
{ "option_value_id": "optv_01K0P7W6A4N9F3J2T8Q5R1C6XB", "value": "Small", "position": 0, "status": "active" },
{ "option_value_id": "optv_01K0P7W6A4N9F3J2T8Q5R1C6XC", "value": "Large", "position": 1, "status": "active" }
]
}
],
"variants": [
{
"variant_id": "var_01K0P7W6A4N9F3J2T8Q5R1C6XP",
"name": "Small",
"sku": "TEE-CREW-S",
"unit_price_money": { "amount": 2800, "currency": "USD" },
"selected_options": [
{ "option_id": "opt_01K0P7W6A4N9F3J2T8Q5R1C6XA", "option_name": "Size", "option_value_id": "optv_01K0P7W6A4N9F3J2T8Q5R1C6XB", "value": "Small" }
]
},
{
"variant_id": "var_01K0P7W6A4N9F3J2T8Q5R1C6XQ",
"name": "Large",
"sku": "TEE-CREW-L",
"unit_price_money": { "amount": 3000, "currency": "USD" },
"selected_options": [
{ "option_id": "opt_01K0P7W6A4N9F3J2T8Q5R1C6XA", "option_name": "Size", "option_value_id": "optv_01K0P7W6A4N9F3J2T8Q5R1C6XC", "value": "Large" }
]
}
]
}
}
The response is abridged. Only the create response includes variants, ordered by position and then variant_id, so you get every variant_id without another request. Other product responses leave it out: list a product's variants with GET /v1/products/{product_id}/variants.
Product types#
product_type | Delivery | Also |
|---|---|---|
physical | Each variant takes a delivery_profile_id. A variant created without one gets your default delivery profile. | unit_weight and unit_dimensions feed delivery quotes |
service, fee, digital | None. delivery_profile_id is rejected, and delivery_configuration_status is not_applicable. | |
gift_card | None | Sells gift cards; see Gift card products |
You can change product_type with PATCH /v1/products/{product_id}, except to or from gift_card: create a separate product instead.
Status and archiving#
Products and variants share the same three statuses. A product or variant created without status is active.
status on productactiveSellable.available_for_saleistruewhen the product also has at least one active variant, and a variant sells only while it and its product are both active.inactiveNot sellable, and reversible: setstatusback toactiveto sell it again. Use it to pause a product or variant you plan to sell later.archivedFinalSet byDELETE. Archiving a product archives its variants. An archived record stays readable by ID, so past orders keep their references, and lists include it only whenstatus=archivednames it.
Warning: Archiving can't be undone
Any write to an archived product or variant returns 409 ACTION_NOT_ALLOWED with reason: archived and current_status: archived, and details[0] names the archived record in resource_type and resource_id. Creating a variant under an archived product names the product. Set status to inactive for anything you might sell again.
DELETE returns the archived record, the same body a following GET returns. Repeating it returns 200 with that body and changes nothing. A simple product's default variant can't be archived on its own: archive the product instead.
What blocks a change#
Orders keep a snapshot of the catalog, so an open order doesn't stop you from setting a product or variant to inactive. Other records that still sell it do:
| Change | Refused while the product or variant is in |
|---|---|
Set to inactive | An open checkout session, an open invoice payment attempt, an active payment link, a subscription plan that isn't archived, an active subscription, or, for a variant, an active bundle |
Archive with DELETE | Any of those, or an open order |
Change a variant's currency, or a product's product_type or default_variant_id | An open order |
A payment link that lets buyers choose among several variants in variant_ids blocks a variant only when it is the last active one the link lists. A refusal returns 409 RESOURCE_IN_USE. details[0].blocking_resources lists the records in the way, such as order, checkout_session, payment_link, subscription, subscription_plan, or bundle references, and blocking_resource_count gives the total. Close or change those records, then retry.
Options and variant selections#
Every active variant selects one active value for each active option. To change a product's options, send the complete options array in PATCH /v1/products/{product_id} with the version you read as expected_version. Include the option_id and option_value_id of every member you keep, add new members without an ID, and leave out a member to retire it. Change the catalog later shows the request.
Add an option to a product that already has variants#
A new or reactivated option needs a value on every active variant, so send existing_variant_value on that option's entry in options[]. Flint gives that value to each active variant that has no active value for the option after the request. It must match one of the option's active values, ignoring case and surrounding whitespace, and is at most 255 characters. Flint doesn't store or return it.
The option change and the variant selections succeed or fail together. Each variant that gets a value advances its version and sends product_variant.updated, and the product sends product.updated. Inactive and archived variants, and variants that already have an active value for the option, keep what they have. A variant in an active bundle can take the new value, because it only adds a selection. Add an option to a product that has variants has a full example.
Move a variant to other values#
Send the complete selected_options in PATCH /v1/products/{product_id}/variants/{variant_id}, naming one value for each active option. The variant keeps its variant_id, so inventory items, payment links, and bundles still point at it, and orders already placed keep the values they were placed with.
A variant keeps its selection for an option that is no longer active, such as one you removed. Each selected_options entry a variant returns is a valid input once you drop option_id and option_value_id, so you can resend the selection unchanged, or leave out an inactive option and keep its value. You can't change that value or add a selection for an option that is no longer active. If a removed option shares its name with an active one, selecting the active option replaces the old selection for that name. On a product with no active options, "selected_options": [] leaves the selection unchanged.
You can retire a whole option while variants select its values: they keep those selections. A single value of an active option can't be removed or set to inactive while an active variant selects it.
| Response | When |
|---|---|
400 INVALID_REQUEST, detail REQUIRED | Active variants need a value and existing_variant_value is missing. param is the field, such as options[1].existing_variant_value, and the message gives how many variants need one. Nothing changes. |
400 INVALID_REQUEST, detail INVALID_VALUE | existing_variant_value matches none of the option's active values, even when no variant needs it |
409 RESOURCE_IN_USE | You removed or inactivated a value an active variant selects. param is options[i].values, details[0].blocking_resources lists up to 10 product_variant references, and blocking_resource_count gives the total. Move those variants to another value or set them to inactive, then retry with the product's latest version. |
409 ALREADY_EXISTS | Another variant of the product already selects the combination, named in details[0].current_resource. Two variants with the same combination in one create request return 400 INVALID_REQUEST instead. |
409 VERSION_CONFLICT | The product changed since you read it. Read it again and retry with details[0].current_version. |
Gift card products#
A gift_card product sells gift cards. Gift card purchase lines covers selling one on an order and when each card is issued. Its variants:
- Use USD and are non-taxable. Send
taxable: falseor leave it out, and leave outline_item_tax_category. - Don't track inventory, take a modifier set, or need delivery.
- Can't be bundle components or subscription lines.
- Are left out of ordinary cart discounts. Gift card value already on the order can pay for other goods, but not for a new gift card.
gift_card_configuration keeps the value a card carries, face_value_money, separate from the variant's price, unit_price_money. It is accepted only on gift card variants.
price_mode | Rule |
|---|---|
face_value | unit_price_money equals face_value_money. Leaving out the configuration creates a fixed denomination at the variant price in this mode. |
discounted | unit_price_money is less than face_value_money, such as a $100.00 card sold for $90.00 |
Add custom_amount_bounds to let the buyer choose the value, from minimum_money to maximum_money. The bounds must include face_value_money, and every value and bound is in USD and at most 200000 cents. The buyer's choice goes in the order line's gift_card_purchase.face_value_money. This variant sells a $100.00 card for $90.00 and lets the buyer pick from $25.00 to $500.00:
{
"unit_price_money": { "amount": 9000, "currency": "USD" },
"gift_card_configuration": {
"face_value_money": { "amount": 10000, "currency": "USD" },
"price_mode": "discounted",
"custom_amount_bounds": {
"minimum_money": { "amount": 2500, "currency": "USD" },
"maximum_money": { "amount": 50000, "currency": "USD" }
}
}
}
A custom value is priced at the same ratio of unit_price_money to face_value_money, rounded to the nearest cent with ties rounded up:
price = chosen value × unit_price_money ÷ face_value_money
2505 × 9000 ÷ 10000 = 2254.5, charged as 2255 ($22.55 for a $25.05 card)
On a variant update, gift_card_configuration replaces the whole configuration when you send it and stays as it is when you leave it out. null isn't accepted. The configuration you keep must still fit the new price, so to change the price of a face_value variant, send gift_card_configuration with the new face_value_money too. Send expected_version to reject a concurrent change. Gift cards covers the cards themselves.
Inventory, weight, and delivery#
A variant doesn't hold a stock count. Send inventory_item_id, or an inline inventory_item to create one, and inventory_tracking becomes tracked: each sale draws from the inventory item, whose stock lives in inventory levels per Location. Several variants can share one item. Flint never infers tracking from product_type, so an untracked variant sells without a stock check. Send inventory_item_id: null on a variant update to stop tracking. Quantities change through the inventory endpoints, never through product updates; see Track inventory.
unit_weight and unit_dimensions describe one unit of what the variant sells, not a parcel: a variant for a pack of three mugs holds the measurements of the pack. Both are optional, and reads leave out the ones that aren't set. Flint returns the value and unit you sent without converting them. A value out of range, with more than 3 decimal places, an unknown unit, or a missing field returns 400 INVALID_REQUEST with detail code INVALID_VALUE and param naming the field, such as unit_weight.value. Package weight and dimensions on a shipment, and a custom order line's unit_weight and unit_dimensions, use the same shapes and limits.
When an order line is created, Flint records the variant's unit_weight and unit_dimensions on the line, and delivery quotes use those recorded values. A later variant edit changes new orders and subscription renewals, not existing lines. A variant without unit_weight has an unknown weight, so a delivery option that prices by weight isn't offered for a group that contains it. See Record a variant's weight and dimensions.
Categories#
Product writes take category_handles, a set of up to 100 handles of categories that already exist. Handles match exactly: Flint doesn't match names, change letter case, or create a category from a product write. A handle that matches no category returns 404 RESOURCE_NOT_FOUND with param naming the entry, such as category_handles[0], and details[0].resource_type set to category. Reads return each category as {category_id, handle, name}. A handle never changes when its category is renamed, so it is safe to store and to filter the list with category_handle.
Fields that replace the whole value#
Most updates are sparse: send only what changes, and null clears an optional field. These fields replace their whole value instead:
| Field | Where | expected_version |
|---|---|---|
options and their values | PATCH /v1/products/{product_id} | Required |
images | Product and variant PATCH | Required |
category_handles | Product PATCH. [] clears every category. | Not needed |
selected_options | Variant PATCH | Optional |
gift_card_configuration | Variant PATCH. null isn't accepted. | Optional |
unit_weight, unit_dimensions | Variant PATCH. Send every field of the object, or null to clear it. Each is independent of the other. | Optional |
A stale expected_version returns 409 VERSION_CONFLICT with details[0].current_version, including on a repeated DELETE. Keep the version your edit started from; Edit with the version you read explains why. Images covers galleries.
Find products through their variants#
GET /v1/products takes three exact filters that select a product through one of its variants:
| Filter | Matches the variant's | Comparison |
|---|---|---|
sku | sku | Whole value, ignoring case and accents, not trimmed. sku=cafe-12 selects Café-12; sku=Cafe-1 and sku= cafe-12 don't. 1 to 100 characters. |
variant_external_reference_id | external_reference_id | Byte for byte, keeping whitespace, case, and Unicode. 1 to 255 characters. |
inventory_item_id | inventory_item_id | A valid inventory item ID |
The list's external_reference_id filter matches the product's own external_reference_id, byte for byte, never a variant's. A variant's SKU and an inventory item's SKU are separate fields, and sku searches only the variant's, so filter by inventory_item_id to find what sells from an item.
When you send more than one variant filter, a single variant must satisfy all of them. sku=MUG-12&inventory_item_id=invi_01K0P7W6A4N9F3J2T8Q5R1C6XM returns the product only when one variant has that SKU and draws from that item. Inactive variants match, and archived variants never do, so an archived product never matches. A product appears once however many of its variants match.
Send each filter once, with a value. A repeated key, an empty or too-long value, or a malformed inventory_item_id returns 400 INVALID_REQUEST with detail code INVALID_VALUE and param naming the filter. A bracketed key such as sku[] returns detail code UNKNOWN_FIELD. A comma is part of the value, not a separator. The filters apply before pagination, and a valid value that matches nothing returns an empty page.
The matching variant#
When an exact variant filter is supplied, each returned product carries matched_variant: the variant_id, name, and sku of one matching variant, the first by position and then by variant_id. It names one variant even when several match.
curl "https://api.withflintpay.com/v1/products?inventory_item_id=invi_01K0P7W6A4N9F3J2T8Q5R1C6XM" \
-H "Authorization: Bearer YOUR_API_KEY"
{
"data": [
{
"product_id": "prod_01K0P7W6A4N9F3J2T8Q5R1C6XN",
"name": "Ceramic mug",
"matched_variant": {
"variant_id": "var_01K0P7W6A4N9F3J2T8Q5R1C6XP",
"name": "White",
"sku": "MUG-12-WHITE"
}
}
]
}
The product is abridged. Exact filters choose matched_variant even when the request also sends query. With query and no exact filter, matched_variant names the first variant, in the same order, whose SKU contains the query text, and is absent when the query matched the product another way. Product reads by ID never include it.
To read every matching variant, page each product's GET /v1/products/{product_id}/variants with the same filters. The variant list takes sku and inventory_item_id under the same names and rules. Its external_reference_id is the variant's own reference, so send your variant_external_reference_id value there as external_reference_id.
Expand the modifier set#
Product and variant reads and lists accept expand=modifier_set, which adds the modifier set for modifier_set_id, with its groups and choices, or null when there is none. It needs commerce.catalog.read as well as commerce.products.read, and a key without both gets 403 INSUFFICIENT_SCOPE with param: expand. Expand related records covers how lists expand each page.
Webhooks#
| Event | Sent when |
|---|---|
product.created | A product was created. Each of its variants sends product_variant.created. |
product.updated | A product's own fields, options, images, categories, or modifier set changed, including a status change between active and inactive |
product.archived | A product was archived with all its variants. The variants send no events of their own. |
product_variant.created | A variant was created, with its product or on its own |
product_variant.updated | A variant's own fields, images, or modifier set changed, Flint assigned it a delivery profile, or it received a value from existing_variant_value |
product_variant.archived | A variant was archived on its own |
A variant write also changes its product's version, updated_at, and rollups such as price_range and variant_count, without a product event. Keep another system in sync covers mirroring a catalog from these events and backfilling it from the lists.
Related guides#
Catalog setupCreate products with sizes, categories, modifiers, and bundles, then sell them on an order.Track inventoryLink variants to inventory items and hold stock when an order is paid.Catalog eventsEvery catalog event and the fields that change without one.The Product object#
An item offered in the merchant's catalog.
Returned by GET /v1/products/{product_id} and carried by the endpoints below.
Attributes
active_variant_countintegerNumber of active variants belonging to the product.
available_for_salebooleanWhether the product is active and has at least one active variant.
categoriesarray of objectRequiredAlways present. Empty collections are returned as [].
category_idstringRequiredStable identifier of the category.
handlestringRequiredCategory handle recorded with this reference.
namestringRequiredCategory name recorded with this reference.
created_atstringWhen this resource was created, as an RFC3339 timestamp.
default_variantobjectThe product's default variant, when one is set.
available_for_salebooleanRequiredWhether the variant and its product are both active.
barcodestringBarcode assigned to this sellable item.
created_atstringWhen this resource was created, as an RFC3339 timestamp.
delivery_configuration_reasonenumReason the variant's delivery configuration needs attention.
delivery_profile_missingdelivery_profile_inactive
delivery_configuration_statusenumRequiredWhether the variant's delivery configuration is ready, needs attention, or does not apply.
configuredaction_requirednot_applicable
delivery_profile_idstringIdentifier of the delivery profile assigned to this variant.
effective_imagesarray of objectRequiredImages shown for the variant: its own gallery when nonempty, otherwise the product's gallery.
external_reference_idstringCaller-owned identifier for this resource in an external system.
gift_card_configurationobjectGift card issuance terms. face_value_money is the reference denomination; unit_price_money is its price. Custom amounts use that price-to-value ratio, rounded to the nearest cent with ties up.
imagesarray of objectRequiredThe variant's own images in display order. An empty gallery inherits the product's images.
images_inheritedbooleanRequiredWhether effective_images comes from the product's gallery because this variant's gallery is empty.
inventory_item_idstringThe inventory item this variant consumes. Present exactly when inventory_tracking is tracked. Several variants may share one inventory item.
inventory_trackingenumRequiredWhether sales of this variant consume an inventory item.
not_trackedtracked
line_item_tax_categoryenumStored Flint line-item tax category. New digital-product variants default to digital_goods when omitted. The stored value remains editable. Unset uses the merchant default.
generalphysical_goodsdigital_goodssoftwaresaasservicesprofessional_servicesfoodprepared_foodclothingmedical_goodsadmission
merchant_idstringIdentifier of the merchant that owns this resource.
metadatamap of stringCaller-owned metadata stored on this resource.
modifier_setobject or nullAttached modifier set, included when expand=modifier_set is requested. Requires commerce.catalog.read in addition to the resource's read scope. Present only when `expand` includes `modifier_set`; `null` when expanded and there is no related modifier set.
modifier_set_idstring or nullRequiredAttached modifier set. Send null on update to remove it.
namestringVariant name that distinguishes it from the product's other variants.
positionintegerRequiredDisplay order among the product's variants, starting at zero.
product_idstringRequiredIdentifier of the product this variant belongs to.
selected_optionsarray of objectRequiredAlways present. Empty collections are returned as [].
skustringStock keeping unit assigned to this sellable item.
statusenumRequiredVariant lifecycle status. Archived variants remain readable and cannot be edited.
activeinactivearchived
taxablebooleanWhether this item is subject to tax.
unit_dimensionsobjectPer-unit measurement. Omitted when unknown.
unit_price_moneyobjectRequiredPrice charged for one unit, in the currency's smallest unit.
unit_weightobjectPer-unit measurement. Omitted when unknown.
updated_atstringWhen this resource last changed, as an RFC3339 timestamp.
variant_idstringRequiredStable identifier of the product variant.
versionintegerRequiredCurrent resource version. Send it as expected_version to reject a write if the resource has changed.
default_variant_idstringIdentifier of the variant chosen as this product's default, when one is set.
delivery_configuration_statusenumRequiredDelivery readiness aggregated across the product's non-archived variants.
configuredaction_requirednot_applicable
descriptionstringDescription of the product shown to buyers.
external_reference_idstringCaller-owned identifier for this resource in an external system.
imagesarray of objectRequiredImages attached to this resource, in display order. The first image is primary.
altstringAlternative text describing the image for accessibility.
file_idstringIdentifier of the file attached as this image.
heightintegerRequiredImage height in pixels, when known.
source_referencestringCaller-owned reference identifying this attachment within its gallery.
urlstringRequiredURL of the image.
widthintegerRequiredImage width in pixels, when known.
matched_variantobjectOn product list rows, the first non-archived variant by position, then variant_id, that matches all exact variant filters. Without exact variant filters, identifies the first variant whose SKU matches query. Omitted when no variant matches; a product name or description match alone does not set it. Page the product's variants to find all matches.
namestringName of the matching variant, when set.
product_idstringRequiredIdentifier of the product the matching variant belongs to.
skustringStock keeping unit of the matching variant, when set.
variant_idstringRequiredIdentifier of the variant that matched the product list's variant filters or query.
merchant_idstringIdentifier of the merchant that owns this resource.
metadatamap of stringCaller-owned metadata stored on this resource.
modifier_setobject or nullAttached modifier set, included when expand=modifier_set is requested. Requires commerce.catalog.read in addition to the resource's read scope. Present only when `expand` includes `modifier_set`; `null` when expanded and there is no related modifier set.
created_atstringWhen the modifier set was created, as an RFC3339 timestamp.
external_reference_idstringCaller-owned identifier for this resource in an external system.
merchant_idstringIdentifier of the merchant that owns this modifier set.
metadatamap of stringCaller-owned metadata. Values can't be empty strings. Keys starting with flint_ are reserved for Flint, are not returned, and cannot be written through the public API.
modifier_groupsarray of one ofRequiredOrdered group entries in this set, including references to reusable groups and groups owned by the set.
modifier_set_idstringRequiredStable identifier of the modifier set assigned to catalog items.
namestringRequiredName used to identify this modifier set.
statusenumRequiredLifecycle status of the modifier set. Only active sets can be offered to buyers; archived sets remain readable and cannot be edited.
activeinactivearchived
updated_atstringWhen the modifier set, its group entries, or its inline groups last changed, as an RFC3339 timestamp.
versionintegerRequiredVersion of the modifier set, its group entries, and its inline groups. Send it as expected_version when replacing modifier_groups.
modifier_set_idstring or nullRequiredAttached modifier set. Send null on update to remove it.
namestringRequiredProduct name shown to buyers.
option_countintegerNumber of active options belonging to the product.
optionsarray of objectRequiredProduct options and their non-archived values. Empty when the product has no options.
created_atstringWhen this resource was created, as an RFC3339 timestamp.
metadatamap of stringCaller-owned metadata stored on this resource.
namestringRequiredOption name, such as Size or Color.
option_idstringRequiredStable identifier of the product option.
positionintegerRequiredDisplay order among the product's options, starting at zero.
product_idstringRequiredIdentifier of the product this option belongs to.
statusenumRequiredOption lifecycle status. Every active variant must select an active value for each active option.
activeinactivearchived
updated_atstringWhen this resource last changed, as an RFC3339 timestamp.
valuesarray of objectValues offered for this option, such as Small, Medium, and Large for Size.
price_rangeobjectLowest and highest unit prices among active variants. Omitted when there are no active variants or their currencies differ.
max_unit_price_moneyobjectRequiredHighest unit price among the product's active variants.
min_unit_price_moneyobjectRequiredLowest unit price among the product's active variants.
product_idstringRequiredStable identifier of the product.
product_typeenumRequiredKind of goods or service this product represents. New variants of digital products store digital_goods when line_item_tax_category is omitted; explicit categories are preserved.
physicalservicefeedigitalgift_card
statusenumRequiredProduct lifecycle status. Archived products remain readable and cannot be edited.
activeinactivearchived
updated_atstringWhen this resource last changed, as an RFC3339 timestamp.
variant_countintegerNumber of non-archived variants belonging to the product.
variantsarray of objectThe variants this request created, ordered by `position` and then `variant_id`. Present only on the `POST /v1/products` response. Read variants later with `GET /v1/products/{product_id}/variants`.
available_for_salebooleanRequiredWhether the variant and its product are both active.
barcodestringBarcode assigned to this sellable item.
created_atstringWhen this resource was created, as an RFC3339 timestamp.
delivery_configuration_reasonenumReason the variant's delivery configuration needs attention.
delivery_profile_missingdelivery_profile_inactive
delivery_configuration_statusenumRequiredWhether the variant's delivery configuration is ready, needs attention, or does not apply.
configuredaction_requirednot_applicable
delivery_profile_idstringIdentifier of the delivery profile assigned to this variant.
effective_imagesarray of objectRequiredImages shown for the variant: its own gallery when nonempty, otherwise the product's gallery.
external_reference_idstringCaller-owned identifier for this resource in an external system.
gift_card_configurationobjectGift card issuance terms. face_value_money is the reference denomination; unit_price_money is its price. Custom amounts use that price-to-value ratio, rounded to the nearest cent with ties up.
imagesarray of objectRequiredThe variant's own images in display order. An empty gallery inherits the product's images.
images_inheritedbooleanRequiredWhether effective_images comes from the product's gallery because this variant's gallery is empty.
inventory_item_idstringThe inventory item this variant consumes. Present exactly when inventory_tracking is tracked. Several variants may share one inventory item.
inventory_trackingenumRequiredWhether sales of this variant consume an inventory item.
not_trackedtracked
line_item_tax_categoryenumStored Flint line-item tax category. New digital-product variants default to digital_goods when omitted. The stored value remains editable. Unset uses the merchant default.
generalphysical_goodsdigital_goodssoftwaresaasservicesprofessional_servicesfoodprepared_foodclothingmedical_goodsadmission
merchant_idstringIdentifier of the merchant that owns this resource.
metadatamap of stringCaller-owned metadata stored on this resource.
modifier_setobject or nullAttached modifier set, included when expand=modifier_set is requested. Requires commerce.catalog.read in addition to the resource's read scope. Present only when `expand` includes `modifier_set`; `null` when expanded and there is no related modifier set.
modifier_set_idstring or nullRequiredAttached modifier set. Send null on update to remove it.
namestringVariant name that distinguishes it from the product's other variants.
positionintegerRequiredDisplay order among the product's variants, starting at zero.
product_idstringRequiredIdentifier of the product this variant belongs to.
selected_optionsarray of objectRequiredAlways present. Empty collections are returned as [].
skustringStock keeping unit assigned to this sellable item.
statusenumRequiredVariant lifecycle status. Archived variants remain readable and cannot be edited.
activeinactivearchived
taxablebooleanWhether this item is subject to tax.
unit_dimensionsobjectPer-unit measurement. Omitted when unknown.
unit_price_moneyobjectRequiredPrice charged for one unit, in the currency's smallest unit.
unit_weightobjectPer-unit measurement. Omitted when unknown.
updated_atstringWhen this resource last changed, as an RFC3339 timestamp.
variant_idstringRequiredStable identifier of the product variant.
versionintegerRequiredCurrent resource version. Send it as expected_version to reject a write if the resource has changed.
versionintegerRequiredCurrent resource version. Send it as expected_version to reject a write if the resource has changed.
{
"active_variant_count": 1,
"available_for_sale": true,
"categories": [
{
"category_id": "ctg_01KEZF7C00V7HCPYBVVD8PX976",
"handle": "tickets",
"name": "Tickets"
},
{
"category_id": "ctg_01KEZF7C00VWQMSGG3M5G79GQR",
"handle": "events",
"name": "Events"
}
],
"created_at": "2026-03-17T14:30:00Z",
"default_variant_id": "var_01KEZF7C00SDPKNHP9DAVYBQZ9",
"delivery_configuration_status": "configured",
"images": [],
"merchant_id": "mer_01KEZF7C00MPP0T9S0KH5BB4CC",
"metadata": {
"event_id": "evt_123"
},
"modifier_set_id": null,
"name": "General Admission",
"option_count": 0,
"options": [],
"price_range": {
"max_unit_price_money": {
"amount": 2500,
"currency": "USD"
},
"min_unit_price_money": {
"amount": 2500,
"currency": "USD"
}
},
"product_id": "prod_01KEZF7C00027JTCXQ7TQF86X8",
"product_type": "physical",
"status": "active",
"updated_at": "2026-03-17T14:30:00Z",
"variant_count": 1,
"version": 1
}List products#
/v1/productsRequires scope commerce.products.read or commerce.products.write
Rate limit: read
Returns a paginated list of products for the authenticated merchant. Default order: created_at descending, then product_id descending.
Query parameters
page_sizeintegerMaximum number of results to return, from 1 to 100. Defaults to 20.
page_tokenstringOpaque next_page_token from the previous response. Omit on the first request. You may change `page_size` between pages. Reuse it with the same endpoint, filters, sort, and request context. Do not parse or construct tokens. An invalid, expired, or mismatched token returns a validation error.
product_typearray of enumFilter by product type. Values are trimmed and deduplicated in first-seen order; empty or unknown entries are rejected. Values within this filter are ORed; separate filters are ANDed.
physicalservicefeedigitalgift_card
statusarray of enumFilter by status. Omitted, the list leaves out archived rows; name archived to include them. Values are trimmed and deduplicated in first-seen order; empty or unknown entries are rejected. Values within this filter are ORed; separate filters are ANDed.
activeinactivearchived
category_handlestringFilter by category handle.
external_reference_idstringExact match on the product's own `external_reference_id`. To find a product by a variant's reference, use `variant_external_reference_id`.
skustringFull-value match on ProductVariant.sku, case- and accent-insensitive, with no trimming. All exact variant filters must match the same non-archived variant, including inactive variants. matched_variant is the first matching variant by position, then variant_id; exact predicates take precedence over query for this witness.
variant_external_reference_idstringByte-sensitive whole-value match on ProductVariant.external_reference_id, preserving whitespace, casing, and Unicode. All exact variant filters must match the same non-archived variant. matched_variant is one deterministic witness; page the nested variant list to enumerate all matches.
inventory_item_idstringExact match on ProductVariant.inventory_item_id. Multiple variants may share one inventory item; this does not match or synchronize the inventory item's SKU. On products, all exact variant filters must match the same non-archived variant.
querystringSearch across product ID, external reference ID, name, description, and SKU. Text fields match any part of the value, and %, _ and \ are ordinary characters, not wildcards. IDs match from the start and need the type prefix, such as prod_01.
delivery_profile_idstringFilter products with at least one non-deleted variant assigned to this delivery profile.
delivery_configuration_statusarray of enumFilter by aggregated delivery readiness across non-deleted variants. Values are trimmed and deduplicated in first-seen order; empty or unknown entries are rejected. Values within this filter are ORed; separate filters are ANDed.
configuredaction_requirednot_applicable
sort_byenumField to sort by. Defaults to created_at; ties are broken by product_id.
namecreated_atupdated_at
sort_directionenumSort direction. Defaults to desc.
ascdesc
created_afterstringInclusive lower bound on created_at.
created_beforestringExclusive upper bound on created_at.
updated_afterstringInclusive lower bound on updated_at.
updated_beforestringExclusive upper bound on updated_at.
expandarray of enumInclude related objects in the response. Supported expansions: modifier_set. Include the requested related resources using scoped batch reads for this page. Each relationship requires its existing target read scopes. Expansion changes the representation without changing pagination tokens. Limits: at most 10 unique expand paths per request.
modifier_set
Response · 200
A page of products.
dataarray of objectRequiredThe requested product data.
active_variant_countintegerNumber of active variants belonging to the product.
available_for_salebooleanWhether the product is active and has at least one active variant.
categoriesarray of objectRequiredAlways present. Empty collections are returned as [].
created_atstringWhen this resource was created, as an RFC3339 timestamp.
default_variantobjectThe product's default variant, when one is set.
default_variant_idstringIdentifier of the variant chosen as this product's default, when one is set.
delivery_configuration_statusenumRequiredDelivery readiness aggregated across the product's non-archived variants.
configuredaction_requirednot_applicable
descriptionstringDescription of the product shown to buyers.
external_reference_idstringCaller-owned identifier for this resource in an external system.
imagesarray of objectRequiredImages attached to this resource, in display order. The first image is primary.
matched_variantobjectOn product list rows, the first non-archived variant by position, then variant_id, that matches all exact variant filters. Without exact variant filters, identifies the first variant whose SKU matches query. Omitted when no variant matches; a product name or description match alone does not set it. Page the product's variants to find all matches.
merchant_idstringIdentifier of the merchant that owns this resource.
metadatamap of stringCaller-owned metadata stored on this resource.
modifier_setobject or nullAttached modifier set, included when expand=modifier_set is requested. Requires commerce.catalog.read in addition to the resource's read scope. Present only when `expand` includes `modifier_set`; `null` when expanded and there is no related modifier set.
modifier_set_idstring or nullRequiredAttached modifier set. Send null on update to remove it.
namestringRequiredProduct name shown to buyers.
option_countintegerNumber of active options belonging to the product.
optionsarray of objectRequiredProduct options and their non-archived values. Empty when the product has no options.
price_rangeobjectLowest and highest unit prices among active variants. Omitted when there are no active variants or their currencies differ.
product_idstringRequiredStable identifier of the product.
product_typeenumRequiredKind of goods or service this product represents. New variants of digital products store digital_goods when line_item_tax_category is omitted; explicit categories are preserved.
physicalservicefeedigitalgift_card
statusenumRequiredProduct lifecycle status. Archived products remain readable and cannot be edited.
activeinactivearchived
updated_atstringWhen this resource last changed, as an RFC3339 timestamp.
variant_countintegerNumber of non-archived variants belonging to the product.
variantsarray of objectThe variants this request created, ordered by `position` and then `variant_id`. Present only on the `POST /v1/products` response. Read variants later with `GET /v1/products/{product_id}/variants`.
versionintegerRequiredCurrent resource version. Send it as expected_version to reject a write if the resource has changed.
metaobjectAdditional information about this response.
api_versionstringAPI version used to produce this response.
idempotency_replayedbooleanWhether this response replays a stored result for the supplied Idempotency-Key.
trace_idstringTrace identifier to include when contacting Flint about this request.
warningsarray of objectConditions that need attention even though the request succeeded.
next_page_tokenstringToken for the next page. Omitted when there are no more results.
request_idstringRequiredIdentifier of this API request, useful when contacting support.
curl https://api.withflintpay.com/v1/products \
-H "Flint-Version: 2026-09-07" \
-H "Authorization: Bearer YOUR_API_KEY"A page of products.
{
"data": [
{
"active_variant_count": 1,
"available_for_sale": true,
"categories": [
{
"category_id": "ctg_01KEZF7C00V7HCPYBVVD8PX976",
"handle": "tickets",
"name": "Tickets"
},
{
"category_id": "ctg_01KEZF7C00VWQMSGG3M5G79GQR",
"handle": "events",
"name": "Events"
}
],
"created_at": "2026-03-17T14:30:00Z",
"default_variant_id": "var_01KEZF7C00SDPKNHP9DAVYBQZ9",
"delivery_configuration_status": "configured",
"images": [],
"merchant_id": "mer_01KEZF7C00MPP0T9S0KH5BB4CC",
"metadata": {
"event_id": "evt_123"
},
"modifier_set_id": null,
"name": "General Admission",
"option_count": 0,
"options": [],
"price_range": {
"max_unit_price_money": {
"amount": 2500,
"currency": "USD"
},
"min_unit_price_money": {
"amount": 2500,
"currency": "USD"
}
},
"product_id": "prod_01KEZF7C00027JTCXQ7TQF86X8",
"product_type": "physical",
"status": "active",
"updated_at": "2026-03-17T14:30:00Z",
"variant_count": 1,
"version": 1
}
],
"meta": {
"api_version": "2026-09-07"
},
"request_id": "req_01KWM61KKS71NZR1XSQXVAK4HP"
}Create product#
/v1/productsIdempotentRequires scope commerce.products.write
Rate limit: write
Creates a product, the catalog item buyers purchase through orders, checkout, payment links, and subscriptions. Send `name`, `product_type`, and `variant_mode`. A `simple` product takes one `default_variant`; an `optioned` product takes `options` and `variants`, each variant selecting one value for every option. Price, SKU, and inventory settings live on variants. A SKU or barcode that another variant or bundle already uses fails with `ALREADY_EXISTS`, and a category handle that doesn't exist fails with `RESOURCE_NOT_FOUND`.
Request body
Send exactly one of these
The `simple` variant of `CreateProductRequest`.
category_handlesarray of stringRelationship set of category handles that must already exist. Each handle has 1 to 100 characters (Unicode code points). Unknown handles return RESOURCE_NOT_FOUND. Replaces the whole set when present; send [] to clear it. On PATCH, omission leaves it unchanged. Does not require expected_version.
default_variantobjectRequiredThe single variant to create as the product's default. Send either default_variant or both options and variants.
barcodestringBarcode assigned to this sellable item.
delivery_profile_idstringIdentifier of the delivery profile to assign to this variant.
external_reference_idstringCaller-owned identifier for this resource in an external system.
gift_card_configurationobjectOnly valid for product_type gift_card. Omission creates a fixed denomination at unit_price_money. Discounted pricing requires an explicit face_value_money and price_mode discounted.
imagesarray of one ofThe complete desired gallery in display order. The first image is primary. Send [] to clear the gallery.
inventory_itemobjectNew inventory item to create and track for this variant. Send either inventory_item or inventory_item_id.
inventory_item_idstringIdentifier of an existing inventory item to track for this variant. Send either inventory_item_id or inventory_item.
line_item_tax_categoryenumFlint line-item tax category to store. Omit for a digital product to store digital_goods; explicit categories are preserved. For other product types, omission uses the merchant default.
generalphysical_goodsdigital_goodssoftwaresaasservicesprofessional_servicesfoodprepared_foodclothingmedical_goodsadmission
metadatamap of stringCaller-owned metadata. Values can't be empty strings. Keys starting with flint_ are reserved for Flint, are not returned, and cannot be written through the public API.
modifier_set_idstring or nullAttached modifier set. Send null on update to remove it.
namestringVariant name that distinguishes it from the product's other variants.
positionintegerDisplay order among the product's variants, starting at zero. When omitted in the variants array on product create, defaults to the variant's array index. For default_variant, defaults to zero. When creating a variant separately, defaults to the highest position among the product's variants plus one, or zero for the first variant.
selected_optionsarray of objectOption name and value selections for this variant. When present on an update, replaces the entire selection. Omit to leave unchanged. Select one active value for every active option. null is invalid.
skustringStock keeping unit assigned to this sellable item.
statusenumWhether the variant is active or inactive. An inactive variant cannot be sold.
activeinactive
taxablebooleanWhether this item is subject to tax.
unit_dimensionsobjectPer-unit measurement. Omitted when unknown.
unit_price_moneyobjectRequiredPrice charged for one unit, in the currency's smallest unit.
unit_weightobjectPer-unit measurement. Omitted when unknown.
descriptionstringDescription of the product shown to buyers.
external_reference_idstringCaller-owned identifier for this resource in an external system.
imagesarray of one ofThe complete desired gallery in display order. The first image is primary. Send [] to clear the gallery.
Send exactly one of these
The `Source URL` variant of `ImageInput`.
altstringAlternative text describing the image for accessibility.
source_referencestringAn opaque reference for this attachment, unique within its gallery. Whitespace and case are preserved.
source_urlstringRequiredA public image URL for Flint to fetch, or an untransformed canonical image.url returned by Flint. Send exactly one of source_url or file_id. Canonical Flint URLs attach without another fetch. Flint doesn't download a source_url again while the image it produced is still in this field.
metadatamap of stringCaller-owned metadata. Values can't be empty strings. Keys starting with flint_ are reserved for Flint, are not returned, and cannot be written through the public API.
modifier_set_idstring or nullAttached modifier set. Send null on update to remove it.
namestringRequiredProduct name shown to buyers.
product_typeenumRequiredKind of goods or service this product represents. New variants of digital products store digital_goods when line_item_tax_category is omitted; explicit categories are preserved.
physicalservicefeedigitalgift_card
statusenumWhether the product is active or inactive. An inactive product's variants cannot be sold.
activeinactive
variant_modeenumRequiredSelects the variant mode branch.
simple
The `optioned` variant of `CreateProductRequest`.
category_handlesarray of stringRelationship set of category handles that must already exist. Each handle has 1 to 100 characters (Unicode code points). Unknown handles return RESOURCE_NOT_FOUND. Replaces the whole set when present; send [] to clear it. On PATCH, omission leaves it unchanged. Does not require expected_version.
descriptionstringDescription of the product shown to buyers.
external_reference_idstringCaller-owned identifier for this resource in an external system.
imagesarray of one ofThe complete desired gallery in display order. The first image is primary. Send [] to clear the gallery.
Send exactly one of these
The `Source URL` variant of `ImageInput`.
altstringAlternative text describing the image for accessibility.
source_referencestringAn opaque reference for this attachment, unique within its gallery. Whitespace and case are preserved.
source_urlstringRequiredA public image URL for Flint to fetch, or an untransformed canonical image.url returned by Flint. Send exactly one of source_url or file_id. Canonical Flint URLs attach without another fetch. Flint doesn't download a source_url again while the image it produced is still in this field.
metadatamap of stringCaller-owned metadata. Values can't be empty strings. Keys starting with flint_ are reserved for Flint, are not returned, and cannot be written through the public API.
modifier_set_idstring or nullAttached modifier set. Send null on update to remove it.
namestringRequiredProduct name shown to buyers.
optionsarray of objectRequiredOptions and values that distinguish this product's variants. Send with variants instead of default_variant.
existing_variant_valuestringValue of this option given to every active variant that has no active value for it after this request, such as when you add an option to a product that already has active variants. It must match one of this option's active `values`, ignoring case and surrounding whitespace. Not stored; the variants keep the value.
metadatamap of stringCaller-owned metadata. Values can't be empty strings. Keys starting with flint_ are reserved for Flint, are not returned, and cannot be written through the public API.
namestringRequiredOption name, such as Size or Color.
positionintegerDisplay order among the product's options, starting at zero. Defaults to the option's array index when omitted.
statusenumWhether the option is active or inactive. Active variants must select an active value for every active option.
activeinactive
valuesarray of objectValues offered for this option, such as Small, Medium, and Large for Size.
product_typeenumRequiredKind of goods or service this product represents. New variants of digital products store digital_goods when line_item_tax_category is omitted; explicit categories are preserved.
physicalservicefeedigitalgift_card
statusenumWhether the product is active or inactive. An inactive product's variants cannot be sold.
activeinactive
variant_modeenumRequiredSelects the variant mode branch.
optioned
variantsarray of objectRequiredThe variants of an optioned product, sent together with `options` and without `default_variant`. Each variant selects one active value for every option. At most 100; add more later with `POST /v1/products/{product_id}/variants`.
barcodestringBarcode assigned to this sellable item.
delivery_profile_idstringIdentifier of the delivery profile to assign to this variant.
external_reference_idstringCaller-owned identifier for this resource in an external system.
gift_card_configurationobjectOnly valid for product_type gift_card. Omission creates a fixed denomination at unit_price_money. Discounted pricing requires an explicit face_value_money and price_mode discounted.
imagesarray of one ofThe complete desired gallery in display order. The first image is primary. Send [] to clear the gallery.
inventory_itemobjectNew inventory item to create and track for this variant. Send either inventory_item or inventory_item_id.
inventory_item_idstringIdentifier of an existing inventory item to track for this variant. Send either inventory_item_id or inventory_item.
line_item_tax_categoryenumFlint line-item tax category to store. Omit for a digital product to store digital_goods; explicit categories are preserved. For other product types, omission uses the merchant default.
generalphysical_goodsdigital_goodssoftwaresaasservicesprofessional_servicesfoodprepared_foodclothingmedical_goodsadmission
metadatamap of stringCaller-owned metadata. Values can't be empty strings. Keys starting with flint_ are reserved for Flint, are not returned, and cannot be written through the public API.
modifier_set_idstring or nullAttached modifier set. Send null on update to remove it.
namestringVariant name that distinguishes it from the product's other variants.
positionintegerDisplay order among the product's variants, starting at zero. When omitted in the variants array on product create, defaults to the variant's array index. For default_variant, defaults to zero. When creating a variant separately, defaults to the highest position among the product's variants plus one, or zero for the first variant.
selected_optionsarray of objectOption name and value selections for this variant. When present on an update, replaces the entire selection. Omit to leave unchanged. Select one active value for every active option. null is invalid.
skustringStock keeping unit assigned to this sellable item.
statusenumWhether the variant is active or inactive. An inactive variant cannot be sold.
activeinactive
taxablebooleanWhether this item is subject to tax.
unit_dimensionsobjectPer-unit measurement. Omitted when unknown.
unit_price_moneyobjectRequiredPrice charged for one unit, in the currency's smallest unit.
unit_weightobjectPer-unit measurement. Omitted when unknown.
Response · 201
The created product.
dataobjectRequiredThe requested product data.
active_variant_countintegerNumber of active variants belonging to the product.
available_for_salebooleanWhether the product is active and has at least one active variant.
categoriesarray of objectRequiredAlways present. Empty collections are returned as [].
created_atstringWhen this resource was created, as an RFC3339 timestamp.
default_variantobjectThe product's default variant, when one is set.
default_variant_idstringIdentifier of the variant chosen as this product's default, when one is set.
delivery_configuration_statusenumRequiredDelivery readiness aggregated across the product's non-archived variants.
configuredaction_requirednot_applicable
descriptionstringDescription of the product shown to buyers.
external_reference_idstringCaller-owned identifier for this resource in an external system.
imagesarray of objectRequiredImages attached to this resource, in display order. The first image is primary.
matched_variantobjectOn product list rows, the first non-archived variant by position, then variant_id, that matches all exact variant filters. Without exact variant filters, identifies the first variant whose SKU matches query. Omitted when no variant matches; a product name or description match alone does not set it. Page the product's variants to find all matches.
merchant_idstringIdentifier of the merchant that owns this resource.
metadatamap of stringCaller-owned metadata stored on this resource.
modifier_setobject or nullAttached modifier set, included when expand=modifier_set is requested. Requires commerce.catalog.read in addition to the resource's read scope. Present only when `expand` includes `modifier_set`; `null` when expanded and there is no related modifier set.
modifier_set_idstring or nullRequiredAttached modifier set. Send null on update to remove it.
namestringRequiredProduct name shown to buyers.
option_countintegerNumber of active options belonging to the product.
optionsarray of objectRequiredProduct options and their non-archived values. Empty when the product has no options.
price_rangeobjectLowest and highest unit prices among active variants. Omitted when there are no active variants or their currencies differ.
product_idstringRequiredStable identifier of the product.
product_typeenumRequiredKind of goods or service this product represents. New variants of digital products store digital_goods when line_item_tax_category is omitted; explicit categories are preserved.
physicalservicefeedigitalgift_card
statusenumRequiredProduct lifecycle status. Archived products remain readable and cannot be edited.
activeinactivearchived
updated_atstringWhen this resource last changed, as an RFC3339 timestamp.
variant_countintegerNumber of non-archived variants belonging to the product.
variantsarray of objectThe variants this request created, ordered by `position` and then `variant_id`. Present only on the `POST /v1/products` response. Read variants later with `GET /v1/products/{product_id}/variants`.
versionintegerRequiredCurrent resource version. Send it as expected_version to reject a write if the resource has changed.
metaobjectAdditional information about this response.
api_versionstringAPI version used to produce this response.
idempotency_replayedbooleanWhether this response replays a stored result for the supplied Idempotency-Key.
trace_idstringTrace identifier to include when contacting Flint about this request.
warningsarray of objectConditions that need attention even though the request succeeded.
request_idstringRequiredIdentifier of this API request, useful when contacting support.
curl -X POST https://api.withflintpay.com/v1/products \
-H "Flint-Version: 2026-09-07" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: a-unique-key" \
-d '{
"category_handles": [
"tickets",
"events"
],
"default_variant": {
"sku": "ga-001",
"unit_price_money": {
"amount": 2500,
"currency": "USD"
}
},
"metadata": {
"event_id": "evt_123"
},
"name": "General Admission",
"product_type": "physical",
"variant_mode": "simple"
}'Get product#
/v1/products/{product_id}Requires scope commerce.products.read or commerce.products.write
Rate limit: read
Returns a single product by ID.
Path parameters
product_idstringRequiredFlint product ID.
Query parameters
expandarray of enumInclude related objects in the response. Supported expansions: modifier_set. Expand the attached modifier set. Limits: at most 10 unique expand paths per request.
modifier_set
curl https://api.withflintpay.com/v1/products/prod_01KEZF7C00BVSHCNWVH528HB66 \
-H "Flint-Version: 2026-09-07" \
-H "Authorization: Bearer YOUR_API_KEY"The requested product.
{
"data": {
"active_variant_count": 1,
"available_for_sale": true,
"categories": [
{
"category_id": "ctg_01KEZF7C00V7HCPYBVVD8PX976",
"handle": "tickets",
"name": "Tickets"
},
{
"category_id": "ctg_01KEZF7C00VWQMSGG3M5G79GQR",
"handle": "events",
"name": "Events"
}
],
"created_at": "2026-03-17T14:30:00Z",
"default_variant_id": "var_01KEZF7C00SDPKNHP9DAVYBQZ9",
"delivery_configuration_status": "configured",
"images": [],
"merchant_id": "mer_01KEZF7C00MPP0T9S0KH5BB4CC",
"metadata": {
"event_id": "evt_123"
},
"modifier_set_id": null,
"name": "General Admission",
"option_count": 0,
"options": [],
"price_range": {
"max_unit_price_money": {
"amount": 2500,
"currency": "USD"
},
"min_unit_price_money": {
"amount": 2500,
"currency": "USD"
}
},
"product_id": "prod_01KEZF7C00027JTCXQ7TQF86X8",
"product_type": "physical",
"status": "active",
"updated_at": "2026-03-17T14:30:00Z",
"variant_count": 1,
"version": 1
},
"meta": {
"api_version": "2026-09-07"
},
"request_id": "req_01KWM61KKS71NZR1XSQXVAK4HP"
}Update product#
/v1/products/{product_id}IdempotentRequires scope commerce.products.write
Rate limit: write
Applies a sparse update to product-parent fields. When category_handles is present, it replaces the full category list; send [] to clear it. Sellable price, SKU, and inventory live on variants. Fails with `ACTION_NOT_ALLOWED` and reason `archived` when the resource, or the parent it belongs to, is archived. The error names the archived resource and its `current_status`.
Path parameters
product_idstringRequiredFlint product ID.
Request body
category_handlesarray of stringRelationship set of category handles that must already exist. Each handle has 1 to 100 characters (Unicode code points). Unknown handles return RESOURCE_NOT_FOUND. Replaces the whole set when present; send [] to clear it. On PATCH, omission leaves it unchanged. Does not require expected_version.
default_variant_idstring or nullSend null to clear it.
descriptionstring or nullSend null to clear it.
expected_versionintegerResource version last read by the caller. Required when options or images is present.
external_reference_idstring or nullCaller-owned identifier for this resource in an external system. Send null to clear it.
imagesarray of one ofThe complete desired gallery in display order. The first image is primary. Send [] to clear the gallery.
Send exactly one of these
The `Source URL` variant of `ImageInput`.
altstringAlternative text describing the image for accessibility.
source_referencestringAn opaque reference for this attachment, unique within its gallery. Whitespace and case are preserved.
source_urlstringRequiredA public image URL for Flint to fetch, or an untransformed canonical image.url returned by Flint. Send exactly one of source_url or file_id. Canonical Flint URLs attach without another fetch. Flint doesn't download a source_url again while the image it produced is still in this field.
metadatamap of string or nullCaller-owned metadata. Omit this field to leave metadata unchanged. Send an object to merge by key, set a key to null to remove it, or set metadata to null to clear all caller-owned metadata. An empty object makes no change. Values can't be empty strings. Keys starting with flint_ are reserved for Flint, are not returned, and cannot be written through the public API. This operation also limits the metadata object you send, before merging: at most 50 keys, counting null deletions, each key 1 to 256 Unicode code points, and at most 32768 UTF-8 bytes of keys plus values.
modifier_set_idstring or nullAttached modifier set. Send null on update to remove it.
namestringProduct name shown to buyers.
optionsarray of objectReplaces all product options and values atomically. Include existing option_id and option_value_id values to retain members. Omitted members are archived. Null is not accepted.
existing_variant_valuestringValue of this option given to every active variant that has no active value for it after this request, such as when you add an option to a product that already has active variants. It must match one of this option's active `values`, ignoring case and surrounding whitespace. Not stored; the variants keep the value.
metadatamap of string or nullComplete caller-owned metadata for this option. Retained options are replaced as members of the options array, so omitting metadata, sending null, or sending {} clears it. A null-valued key is omitted from the replacement. Values can't be empty strings. Keys starting with flint_ are reserved and cannot be written through the public API.
namestringRequiredOption name, such as Size or Color.
option_idstringIdentifier of an existing option to retain. Omit it to create a new option.
positionintegerDisplay order among the product's options, starting at zero. Defaults to the option's array index when omitted.
statusenumWhether the option is active or inactive. Active variants must select an active value for every active option.
activeinactive
valuesarray of objectValues offered for this option, such as Small, Medium, and Large for Size.
product_typeenumKind of goods or service this product represents. Changing to digital fills variants' unset line_item_tax_category with digital_goods and advances their versions. Explicit categories are preserved. Returns 409 ACTION_NOT_ALLOWED with reason mixed_tax_treatment and blocking_resources if a containing bundle would become mixed.
physicalservicefeedigitalgift_card
statusenumWhether the product is active or inactive. An inactive product's variants cannot be sold.
activeinactive
curl -X PATCH https://api.withflintpay.com/v1/products/prod_01KEZF7C00BVSHCNWVH528HB66 \
-H "Flint-Version: 2026-09-07" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: a-unique-key" \
-d '{
"category_handles": [
"vip",
"events"
],
"expected_version": 1,
"name": "VIP Admission",
"status": "inactive"
}'Retire product#
/v1/products/{product_id}IdempotentRequires scope commerce.products.write
Rate limit: write
Archives a product and returns its final state. Returns the archived resource as a read does. Deleting an already archived resource returns it again without changing its version or `updated_at`, sending a webhook, or checking references. A stale `expected_version` fails with `VERSION_CONFLICT` and the `current_version`, even when the resource is already archived.
Path parameters
product_idstringRequiredFlint product ID.
Query parameters
expected_versionintegerOptional product version last read by the caller.
curl -X DELETE https://api.withflintpay.com/v1/products/prod_01KEZF7C00BVSHCNWVH528HB66 \
-H "Flint-Version: 2026-09-07" \
-H "Authorization: Bearer YOUR_API_KEY"List product options#
/v1/products/{product_id}/optionsRequires scope commerce.products.read or commerce.products.write
Rate limit: read
List product options. Default order: position ascending, then option_id ascending.
Path parameters
product_idstringRequiredFlint product ID.
Query parameters
page_sizeintegerMaximum number of results to return, from 1 to 100. Defaults to 20.
page_tokenstringOpaque next_page_token from the previous response. Omit on the first request. You may change `page_size` between pages. Reuse it with the same endpoint, filters, sort, and request context. Do not parse or construct tokens. An invalid, expired, or mismatched token returns a validation error.
statusarray of enumFilter by status. Omitted, the list leaves out archived rows; name archived to include them. Values are trimmed and deduplicated in first-seen order; empty or unknown entries are rejected. Values within this filter are ORed; separate filters are ANDed.
activeinactivearchived
Response · 200
Successful response.
dataarray of objectRequiredThe requested product option data.
created_atstringWhen this resource was created, as an RFC3339 timestamp.
metadatamap of stringCaller-owned metadata stored on this resource.
namestringRequiredOption name, such as Size or Color.
option_idstringRequiredStable identifier of the product option.
positionintegerRequiredDisplay order among the product's options, starting at zero.
product_idstringRequiredIdentifier of the product this option belongs to.
statusenumRequiredOption lifecycle status. Every active variant must select an active value for each active option.
activeinactivearchived
updated_atstringWhen this resource last changed, as an RFC3339 timestamp.
valuesarray of objectValues offered for this option, such as Small, Medium, and Large for Size.
metaobjectAdditional information about this response.
api_versionstringAPI version used to produce this response.
idempotency_replayedbooleanWhether this response replays a stored result for the supplied Idempotency-Key.
trace_idstringTrace identifier to include when contacting Flint about this request.
warningsarray of objectConditions that need attention even though the request succeeded.
next_page_tokenstringToken for the next page. Omitted when there are no more results.
request_idstringRequiredIdentifier of this API request, useful when contacting support.
curl https://api.withflintpay.com/v1/products/prod_01KEZF7C00BVSHCNWVH528HB66/options \
-H "Flint-Version: 2026-09-07" \
-H "Authorization: Bearer YOUR_API_KEY"Successful response.
{
"data": [],
"meta": {
"api_version": "2026-09-07"
},
"next_page_token": "example",
"request_id": "req_01KWM6BH96R4V5XE6XBWK603S4"
}Get product option#
/v1/products/{product_id}/options/{option_id}Requires scope commerce.products.read or commerce.products.write
Rate limit: read
Returns one option of a product, such as size or color, with its values and position.
Path parameters
product_idstringRequiredFlint product ID.
option_idstringRequiredFlint product option ID.
Response · 200
The product option.
dataobjectRequiredThe requested product option data.
created_atstringWhen this resource was created, as an RFC3339 timestamp.
metadatamap of stringCaller-owned metadata stored on this resource.
namestringRequiredOption name, such as Size or Color.
option_idstringRequiredStable identifier of the product option.
positionintegerRequiredDisplay order among the product's options, starting at zero.
product_idstringRequiredIdentifier of the product this option belongs to.
statusenumRequiredOption lifecycle status. Every active variant must select an active value for each active option.
activeinactivearchived
updated_atstringWhen this resource last changed, as an RFC3339 timestamp.
valuesarray of objectValues offered for this option, such as Small, Medium, and Large for Size.
metaobjectAdditional information about this response.
api_versionstringAPI version used to produce this response.
idempotency_replayedbooleanWhether this response replays a stored result for the supplied Idempotency-Key.
trace_idstringTrace identifier to include when contacting Flint about this request.
warningsarray of objectConditions that need attention even though the request succeeded.
request_idstringRequiredIdentifier of this API request, useful when contacting support.
curl https://api.withflintpay.com/v1/products/prod_01KEZF7C00BVSHCNWVH528HB66/options/opt_01KEZF7C008R5Q9BG9B4B4KQH8 \
-H "Flint-Version: 2026-09-07" \
-H "Authorization: Bearer YOUR_API_KEY"The product option.
{
"data": {
"created_at": "2026-03-17T14:30:00Z",
"name": "Seat",
"option_id": "opt_01KEZF7C00GWX8X74KCS8FMPTX",
"position": 0,
"product_id": "prod_01KEZF7C00027JTCXQ7TQF86X8",
"status": "active",
"updated_at": "2026-03-17T14:30:00Z",
"values": [
{
"created_at": "2026-03-17T14:30:00Z",
"option_value_id": "optv_01KEZF7C00HR3J3B0BM7EG3121",
"position": 0,
"status": "active",
"updated_at": "2026-03-17T14:30:00Z",
"value": "Balcony"
}
]
},
"meta": {
"api_version": "2026-09-07"
},
"request_id": "req_01KWM6Q1QWTAXD3WYFF4HPEYTJ"
}List product variants#
/v1/products/{product_id}/variantsRequires scope commerce.products.read or commerce.products.write
Rate limit: read
List product variants. Default order: position ascending, then variant_id ascending.
Path parameters
product_idstringRequiredFlint product ID.
Query parameters
page_sizeintegerMaximum number of results to return, from 1 to 100. Defaults to 20.
page_tokenstringOpaque next_page_token from the previous response. Omit on the first request. You may change `page_size` between pages. Reuse it with the same endpoint, filters, sort, and request context. Do not parse or construct tokens. An invalid, expired, or mismatched token returns a validation error.
statusarray of enumFilter by status. Omitted, the list leaves out archived rows; name archived to include them. Values are trimmed and deduplicated in first-seen order; empty or unknown entries are rejected. Values within this filter are ORed; separate filters are ANDed.
activeinactivearchived
external_reference_idstringByte-sensitive whole-value match on ProductVariant.external_reference_id, preserving whitespace, casing, and Unicode.
skustringFull-value match on ProductVariant.sku, case- and accent-insensitive, with no trimming. Does not search the inventory item's SKU.
inventory_item_idstringExact match on ProductVariant.inventory_item_id. Multiple variants may share one inventory item; this does not match or synchronize the inventory item's SKU. On products, all exact variant filters must match the same non-archived variant.
querystringSearch across variant ID, external reference ID, name, SKU, and barcode. Text fields match any part of the value, and %, _ and \ are ordinary characters, not wildcards. IDs match from the start and need the type prefix, such as var_01.
sort_byenumField to sort by. Defaults to position; ties are broken by variant_id.
positioncreated_atupdated_atunit_price_money
sort_directionenumSort direction. Defaults to asc for position and desc for other sort fields.
ascdesc
delivery_profile_idstringFilter by assigned delivery profile ID.
delivery_configuration_statusarray of enumFilter by delivery readiness. Values are trimmed and deduplicated in first-seen order; empty or unknown entries are rejected. Values within this filter are ORed; separate filters are ANDed.
configuredaction_requirednot_applicable
created_afterstringInclusive lower bound on created_at.
created_beforestringExclusive upper bound on created_at.
updated_afterstringInclusive lower bound on updated_at.
updated_beforestringExclusive upper bound on updated_at.
expandarray of enumInclude related objects in the response. Supported expansions: modifier_set. Include the requested related resources using scoped batch reads for this page. Each relationship requires its existing target read scopes. Expansion changes the representation without changing pagination tokens. Limits: at most 10 unique expand paths per request.
modifier_set
Response · 200
Successful response.
dataarray of objectRequiredThe requested product variant data.
available_for_salebooleanRequiredWhether the variant and its product are both active.
barcodestringBarcode assigned to this sellable item.
created_atstringWhen this resource was created, as an RFC3339 timestamp.
delivery_configuration_reasonenumReason the variant's delivery configuration needs attention.
delivery_profile_missingdelivery_profile_inactive
delivery_configuration_statusenumRequiredWhether the variant's delivery configuration is ready, needs attention, or does not apply.
configuredaction_requirednot_applicable
delivery_profile_idstringIdentifier of the delivery profile assigned to this variant.
effective_imagesarray of objectRequiredImages shown for the variant: its own gallery when nonempty, otherwise the product's gallery.
external_reference_idstringCaller-owned identifier for this resource in an external system.
gift_card_configurationobjectGift card issuance terms. face_value_money is the reference denomination; unit_price_money is its price. Custom amounts use that price-to-value ratio, rounded to the nearest cent with ties up.
imagesarray of objectRequiredThe variant's own images in display order. An empty gallery inherits the product's images.
images_inheritedbooleanRequiredWhether effective_images comes from the product's gallery because this variant's gallery is empty.
inventory_item_idstringThe inventory item this variant consumes. Present exactly when inventory_tracking is tracked. Several variants may share one inventory item.
inventory_trackingenumRequiredWhether sales of this variant consume an inventory item.
not_trackedtracked
line_item_tax_categoryenumStored Flint line-item tax category. New digital-product variants default to digital_goods when omitted. The stored value remains editable. Unset uses the merchant default.
generalphysical_goodsdigital_goodssoftwaresaasservicesprofessional_servicesfoodprepared_foodclothingmedical_goodsadmission
merchant_idstringIdentifier of the merchant that owns this resource.
metadatamap of stringCaller-owned metadata stored on this resource.
modifier_setobject or nullAttached modifier set, included when expand=modifier_set is requested. Requires commerce.catalog.read in addition to the resource's read scope. Present only when `expand` includes `modifier_set`; `null` when expanded and there is no related modifier set.
modifier_set_idstring or nullRequiredAttached modifier set. Send null on update to remove it.
namestringVariant name that distinguishes it from the product's other variants.
positionintegerRequiredDisplay order among the product's variants, starting at zero.
product_idstringRequiredIdentifier of the product this variant belongs to.
selected_optionsarray of objectRequiredAlways present. Empty collections are returned as [].
skustringStock keeping unit assigned to this sellable item.
statusenumRequiredVariant lifecycle status. Archived variants remain readable and cannot be edited.
activeinactivearchived
taxablebooleanWhether this item is subject to tax.
unit_dimensionsobjectPer-unit measurement. Omitted when unknown.
unit_price_moneyobjectRequiredPrice charged for one unit, in the currency's smallest unit.
unit_weightobjectPer-unit measurement. Omitted when unknown.
updated_atstringWhen this resource last changed, as an RFC3339 timestamp.
variant_idstringRequiredStable identifier of the product variant.
versionintegerRequiredCurrent resource version. Send it as expected_version to reject a write if the resource has changed.
metaobjectAdditional information about this response.
api_versionstringAPI version used to produce this response.
idempotency_replayedbooleanWhether this response replays a stored result for the supplied Idempotency-Key.
trace_idstringTrace identifier to include when contacting Flint about this request.
warningsarray of objectConditions that need attention even though the request succeeded.
next_page_tokenstringToken for the next page. Omitted when there are no more results.
request_idstringRequiredIdentifier of this API request, useful when contacting support.
curl https://api.withflintpay.com/v1/products/prod_01KEZF7C00BVSHCNWVH528HB66/variants \
-H "Flint-Version: 2026-09-07" \
-H "Authorization: Bearer YOUR_API_KEY"Successful response.
{
"data": [
{
"available_for_sale": true,
"created_at": "2026-03-17T14:30:00Z",
"delivery_configuration_status": "configured",
"effective_images": [],
"images": [],
"images_inherited": true,
"inventory_tracking": "not_tracked",
"merchant_id": "mer_01KEZF7C00MPP0T9S0KH5BB4CC",
"modifier_set_id": null,
"position": 0,
"product_id": "prod_01KEZF7C00027JTCXQ7TQF86X8",
"selected_options": [],
"status": "active",
"unit_price_money": {
"amount": 2500,
"currency": "USD"
},
"updated_at": "2026-03-17T14:30:00Z",
"variant_id": "var_01KEZF7C00SDPKNHP9DAVYBQZ9",
"version": 1
}
],
"meta": {
"api_version": "2026-09-07"
},
"request_id": "req_01KWM66H24G2C0HA5CB33ERJ2P"
}Create product variant#
/v1/products/{product_id}/variantsIdempotentRequires scope commerce.products.write
Rate limit: write
Adds a variant to a product that has options. The variant selects one value for every option. Two variants can't select the same combination, and a SKU or barcode that another variant or bundle already uses is refused; both fail with `ALREADY_EXISTS`. A product without active options fails with `ACTION_NOT_ALLOWED` and reason `configuration_required`: change a simple product through its default variant instead. Fails with `ACTION_NOT_ALLOWED` and reason `archived` when the resource, or the parent it belongs to, is archived. The error names the archived resource and its `current_status`.
Path parameters
product_idstringRequiredFlint product ID.
Request body
barcodestringBarcode assigned to this sellable item.
delivery_profile_idstringIdentifier of the delivery profile to assign to this variant.
external_reference_idstringCaller-owned identifier for this resource in an external system.
gift_card_configurationobjectOnly valid for product_type gift_card. Omission creates a fixed denomination at unit_price_money. Discounted pricing requires an explicit face_value_money and price_mode discounted.
custom_amount_boundsobjectMinimum and maximum gift card values buyers can choose. Omit for a fixed denomination.
face_value_moneyobjectRequiredGift card value issued for one unit of this variant, in the same currency as its unit price. Currency must be USD. Amount must be between 1 and 200000 minor units, inclusive.
price_modeenumRequiredWhether the gift card is sold at its face value or at a discounted price.
face_valuediscounted
imagesarray of one ofThe complete desired gallery in display order. The first image is primary. Send [] to clear the gallery.
Send exactly one of these
The `Source URL` variant of `ImageInput`.
altstringAlternative text describing the image for accessibility.
source_referencestringAn opaque reference for this attachment, unique within its gallery. Whitespace and case are preserved.
source_urlstringRequiredA public image URL for Flint to fetch, or an untransformed canonical image.url returned by Flint. Send exactly one of source_url or file_id. Canonical Flint URLs attach without another fetch. Flint doesn't download a source_url again while the image it produced is still in this field.
inventory_itemobjectNew inventory item to create and track for this variant. Send either inventory_item or inventory_item_id.
barcodestringBarcode assigned to the new inventory item.
metadatamap of stringCaller-owned metadata for the new inventory item.
namestringRequiredName of the inventory item to create for this variant.
skustringStock keeping unit assigned to the new inventory item.
inventory_item_idstringIdentifier of an existing inventory item to track for this variant. Send either inventory_item_id or inventory_item.
line_item_tax_categoryenumFlint line-item tax category to store. Omit for a digital product to store digital_goods; explicit categories are preserved. For other product types, omission uses the merchant default.
generalphysical_goodsdigital_goodssoftwaresaasservicesprofessional_servicesfoodprepared_foodclothingmedical_goodsadmission
metadatamap of stringCaller-owned metadata. Values can't be empty strings. Keys starting with flint_ are reserved for Flint, are not returned, and cannot be written through the public API.
modifier_set_idstring or nullAttached modifier set. Send null on update to remove it.
namestringVariant name that distinguishes it from the product's other variants.
positionintegerDisplay order among the product's variants, starting at zero. When omitted in the variants array on product create, defaults to the variant's array index. For default_variant, defaults to zero. When creating a variant separately, defaults to the highest position among the product's variants plus one, or zero for the first variant.
selected_optionsarray of objectOption name and value selections for this variant. When present on an update, replaces the entire selection. Omit to leave unchanged. Select one active value for every active option. null is invalid.
option_namestringRequiredName of one of the product's options. Limited to 255 characters (Unicode code points) before trimming surrounding whitespace. Matches case-insensitively after trimming surrounding whitespace. On a variant update, an option that is no longer active is accepted only when the entry matches the variant's current selection for that option; omit it to keep that selection.
valuestringRequiredValue of the named option. Limited to 255 characters (Unicode code points) before trimming surrounding whitespace. Matches the option's values case-insensitively after trimming surrounding whitespace. A value that is no longer active is accepted only on a variant update, when it matches the variant's current selection for that option.
skustringStock keeping unit assigned to this sellable item.
statusenumWhether the variant is active or inactive. An inactive variant cannot be sold.
activeinactive
taxablebooleanWhether this item is subject to tax.
unit_dimensionsobjectPer-unit measurement. Omitted when unknown.
heightnumberRequiredDistance along this dimension, in the specified unit.
lengthnumberRequiredDistance along this dimension, in the specified unit.
unitenumRequiredLength unit for length, width, and height. Use millimeter, centimeter, or inch.
millimetercentimeterinch
widthnumberRequiredDistance along this dimension, in the specified unit.
unit_price_moneyobjectRequiredPrice charged for one unit, in the currency's smallest unit.
amountintegerRequiredAmount in the currency's minor unit, such as cents for USD.
currencystringRequiredISO 4217 currency code for this amount.
unit_weightobjectPer-unit measurement. Omitted when unknown.
unitenumRequiredWeight unit. Use gram, kilogram, ounce, or pound.
gramkilogramouncepound
valuenumberRequiredWeight measured in the specified unit.
Response · 201
The created product variant.
dataobjectRequiredThe requested product variant data.
available_for_salebooleanRequiredWhether the variant and its product are both active.
barcodestringBarcode assigned to this sellable item.
created_atstringWhen this resource was created, as an RFC3339 timestamp.
delivery_configuration_reasonenumReason the variant's delivery configuration needs attention.
delivery_profile_missingdelivery_profile_inactive
delivery_configuration_statusenumRequiredWhether the variant's delivery configuration is ready, needs attention, or does not apply.
configuredaction_requirednot_applicable
delivery_profile_idstringIdentifier of the delivery profile assigned to this variant.
effective_imagesarray of objectRequiredImages shown for the variant: its own gallery when nonempty, otherwise the product's gallery.
external_reference_idstringCaller-owned identifier for this resource in an external system.
gift_card_configurationobjectGift card issuance terms. face_value_money is the reference denomination; unit_price_money is its price. Custom amounts use that price-to-value ratio, rounded to the nearest cent with ties up.
imagesarray of objectRequiredThe variant's own images in display order. An empty gallery inherits the product's images.
images_inheritedbooleanRequiredWhether effective_images comes from the product's gallery because this variant's gallery is empty.
inventory_item_idstringThe inventory item this variant consumes. Present exactly when inventory_tracking is tracked. Several variants may share one inventory item.
inventory_trackingenumRequiredWhether sales of this variant consume an inventory item.
not_trackedtracked
line_item_tax_categoryenumStored Flint line-item tax category. New digital-product variants default to digital_goods when omitted. The stored value remains editable. Unset uses the merchant default.
generalphysical_goodsdigital_goodssoftwaresaasservicesprofessional_servicesfoodprepared_foodclothingmedical_goodsadmission
merchant_idstringIdentifier of the merchant that owns this resource.
metadatamap of stringCaller-owned metadata stored on this resource.
modifier_setobject or nullAttached modifier set, included when expand=modifier_set is requested. Requires commerce.catalog.read in addition to the resource's read scope. Present only when `expand` includes `modifier_set`; `null` when expanded and there is no related modifier set.
modifier_set_idstring or nullRequiredAttached modifier set. Send null on update to remove it.
namestringVariant name that distinguishes it from the product's other variants.
positionintegerRequiredDisplay order among the product's variants, starting at zero.
product_idstringRequiredIdentifier of the product this variant belongs to.
selected_optionsarray of objectRequiredAlways present. Empty collections are returned as [].
skustringStock keeping unit assigned to this sellable item.
statusenumRequiredVariant lifecycle status. Archived variants remain readable and cannot be edited.
activeinactivearchived
taxablebooleanWhether this item is subject to tax.
unit_dimensionsobjectPer-unit measurement. Omitted when unknown.
unit_price_moneyobjectRequiredPrice charged for one unit, in the currency's smallest unit.
unit_weightobjectPer-unit measurement. Omitted when unknown.
updated_atstringWhen this resource last changed, as an RFC3339 timestamp.
variant_idstringRequiredStable identifier of the product variant.
versionintegerRequiredCurrent resource version. Send it as expected_version to reject a write if the resource has changed.
metaobjectAdditional information about this response.
api_versionstringAPI version used to produce this response.
idempotency_replayedbooleanWhether this response replays a stored result for the supplied Idempotency-Key.
trace_idstringTrace identifier to include when contacting Flint about this request.
warningsarray of objectConditions that need attention even though the request succeeded.
request_idstringRequiredIdentifier of this API request, useful when contacting support.
curl -X POST https://api.withflintpay.com/v1/products/prod_01KEZF7C00BVSHCNWVH528HB66/variants \
-H "Flint-Version: 2026-09-07" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: a-unique-key" \
-d '{
"sku": "ga-balcony-001",
"unit_price_money": {
"amount": 2500,
"currency": "USD"
}
}'Get product variant#
/v1/products/{product_id}/variants/{variant_id}Requires scope commerce.products.read or commerce.products.write
Rate limit: read
Returns one variant of a product, including its price, SKU, selected options, inventory settings, and delivery configuration status.
Path parameters
product_idstringRequiredFlint product ID.
variant_idstringRequiredFlint product variant ID.
Query parameters
expandarray of enumInclude related objects in the response. Supported expansions: modifier_set. Expand the attached modifier set. Limits: at most 10 unique expand paths per request.
modifier_set
curl https://api.withflintpay.com/v1/products/prod_01KEZF7C00BVSHCNWVH528HB66/variants/var_01KEZF7C004GSH2KT8CNYVMHGX \
-H "Flint-Version: 2026-09-07" \
-H "Authorization: Bearer YOUR_API_KEY"The product variant.
{
"data": {
"available_for_sale": true,
"created_at": "2026-03-17T14:30:00Z",
"delivery_configuration_status": "configured",
"effective_images": [],
"images": [],
"images_inherited": true,
"inventory_tracking": "not_tracked",
"merchant_id": "mer_01KEZF7C00MPP0T9S0KH5BB4CC",
"modifier_set_id": null,
"position": 0,
"product_id": "prod_01KEZF7C00027JTCXQ7TQF86X8",
"selected_options": [],
"status": "active",
"unit_price_money": {
"amount": 2500,
"currency": "USD"
},
"updated_at": "2026-03-17T14:30:00Z",
"variant_id": "var_01KEZF7C00SDPKNHP9DAVYBQZ9",
"version": 1
},
"meta": {
"api_version": "2026-09-07"
},
"request_id": "req_01KWM66H24G2C0HA5CB33ERJ2P"
}Update product variant#
/v1/products/{product_id}/variants/{variant_id}IdempotentRequires scope commerce.products.write
Rate limit: write
Applies a sparse update to a variant: only the fields you send change. A SKU or barcode that another variant or bundle already uses, or an option combination that another variant selects, fails with `ALREADY_EXISTS`. Changes to name, price, SKU, and similar fields apply to new checkouts, links, and plans; existing orders keep what they were charged. Setting the variant inactive, or changing its price currency, fails with `RESOURCE_IN_USE` while an open order, checkout session, active payment link, subscription, subscription plan, or active bundle uses it. Send `expected_version` to reject the update when the variant changed since you read it. Fails with `ACTION_NOT_ALLOWED` and reason `archived` when the resource, or the parent it belongs to, is archived. The error names the archived resource and its `current_status`.
Path parameters
product_idstringRequiredFlint product ID.
variant_idstringRequiredFlint product variant ID.
Request body
barcodestring or nullSend null to clear it.
delivery_profile_idstring or nullSend null to clear it.
expected_versionintegerResource version last read by the caller. Required when images is present.
external_reference_idstring or nullCaller-owned identifier for this resource in an external system. Send null to clear it.
gift_card_configurationobjectReplaces the complete gift card configuration. Omission preserves it. Null is not accepted. Include expected_version to reject a concurrent variant change.
custom_amount_boundsobjectMinimum and maximum gift card values buyers can choose. Omit for a fixed denomination.
face_value_moneyobjectRequiredGift card value issued for one unit of this variant, in the same currency as its unit price. Currency must be USD. Amount must be between 1 and 200000 minor units, inclusive.
price_modeenumRequiredWhether the gift card is sold at its face value or at a discounted price.
face_valuediscounted
imagesarray of one ofReplaces the authored variant gallery atomically. Send [] to clear it and resume product-image inheritance.
Send exactly one of these
The `Source URL` variant of `ImageInput`.
altstringAlternative text describing the image for accessibility.
source_referencestringAn opaque reference for this attachment, unique within its gallery. Whitespace and case are preserved.
source_urlstringRequiredA public image URL for Flint to fetch, or an untransformed canonical image.url returned by Flint. Send exactly one of source_url or file_id. Canonical Flint URLs attach without another fetch. Flint doesn't download a source_url again while the image it produced is still in this field.
inventory_itemobjectNew inventory item to create and track for this variant. Send either inventory_item or inventory_item_id.
barcodestringBarcode assigned to the new inventory item.
metadatamap of stringCaller-owned metadata for the new inventory item.
namestringRequiredName of the inventory item to create for this variant.
skustringStock keeping unit assigned to the new inventory item.
inventory_item_idstring or nullInventory item tracked by this variant. Send null to stop tracking inventory.
line_item_tax_categoryenum or nullFlint line-item tax category to store. Send null to clear it and use the merchant default. Returns 409 ACTION_NOT_ALLOWED with reason mixed_tax_treatment and blocking_resources if a containing bundle would become mixed.
generalphysical_goodsdigital_goodssoftwaresaasservicesprofessional_servicesfoodprepared_foodclothingmedical_goodsadmissionnull
metadatamap of string or nullCaller-owned metadata. Omit this field to leave metadata unchanged. Send an object to merge by key, set a key to null to remove it, or set metadata to null to clear all caller-owned metadata. An empty object makes no change. Values can't be empty strings. Keys starting with flint_ are reserved for Flint, are not returned, and cannot be written through the public API. This operation also limits the metadata object you send, before merging: at most 50 keys, counting null deletions, each key 1 to 256 Unicode code points, and at most 32768 UTF-8 bytes of keys plus values.
modifier_set_idstring or nullAttached modifier set. Send null on update to remove it.
namestring or nullSend null to clear it.
positionintegerDisplay order among the product's variants, starting at zero.
selected_optionsarray of objectOption name and value selections for this variant. When present on an update, replaces the entire selection. Omit to leave unchanged. Select one active value for every active option. null is invalid.
option_namestringRequiredName of one of the product's options. Limited to 255 characters (Unicode code points) before trimming surrounding whitespace. Matches case-insensitively after trimming surrounding whitespace. On a variant update, an option that is no longer active is accepted only when the entry matches the variant's current selection for that option; omit it to keep that selection.
valuestringRequiredValue of the named option. Limited to 255 characters (Unicode code points) before trimming surrounding whitespace. Matches the option's values case-insensitively after trimming surrounding whitespace. A value that is no longer active is accepted only on a variant update, when it matches the variant's current selection for that option.
skustring or nullSend null to clear it.
statusenumWhether the variant is active or inactive. An inactive variant cannot be sold.
activeinactive
taxablebooleanWhether this item is subject to tax.
unit_dimensionsobject or nullReplaces the complete object. Send null to clear it.
heightnumberRequiredDistance along this dimension, in the specified unit.
lengthnumberRequiredDistance along this dimension, in the specified unit.
unitenumRequiredLength unit for length, width, and height. Use millimeter, centimeter, or inch.
millimetercentimeterinch
widthnumberRequiredDistance along this dimension, in the specified unit.
unit_price_moneyobjectPrice charged for one unit, in the currency's smallest unit.
amountintegerRequiredAmount in the currency's minor unit, such as cents for USD.
currencystringRequiredISO 4217 currency code for this amount.
unit_weightobject or nullReplaces the complete object. Send null to clear it.
unitenumRequiredWeight unit. Use gram, kilogram, ounce, or pound.
gramkilogramouncepound
valuenumberRequiredWeight measured in the specified unit.
curl -X PATCH https://api.withflintpay.com/v1/products/prod_01KEZF7C00BVSHCNWVH528HB66/variants/var_01KEZF7C004GSH2KT8CNYVMHGX \
-H "Flint-Version: 2026-09-07" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: a-unique-key" \
-d '{
"expected_version": 1,
"name": "Balcony admission"
}'Retire product variant#
/v1/products/{product_id}/variants/{variant_id}IdempotentRequires scope commerce.products.write
Rate limit: write
Archives a variant and returns its final state. Returns the archived resource as a read does. Deleting an already archived resource returns it again without changing its version or `updated_at`, sending a webhook, or checking references. A stale `expected_version` fails with `VERSION_CONFLICT` and the `current_version`, even when the resource is already archived.
Path parameters
product_idstringRequiredFlint product ID.
variant_idstringRequiredFlint product variant ID.
Query parameters
expected_versionintegerOptional product variant version last read by the caller.
curl -X DELETE https://api.withflintpay.com/v1/products/prod_01KEZF7C00BVSHCNWVH528HB66/variants/var_01KEZF7C004GSH2KT8CNYVMHGX \
-H "Flint-Version: 2026-09-07" \
-H "Authorization: Bearer YOUR_API_KEY"Was this helpful?
