Create vendor offer
Submit a new offer.
Offers
/api/v1/scent/offersSubmits a new offer through the SAME review workflow the Portal vendor UI uses — nothing
goes live without an internal reviewer’s approval. Idempotent when vendorExternalId is
set: re-submitting the SAME vendorExternalId returns the already-created offer unchanged
rather than creating a duplicate or erroring (a safe retry). Supply variantId for a
vendor-proposed match to an existing catalog variant, or rawBrandName/rawProductName
for an unmatched free-form entry. Requires the Offers capability.
Body parameters
variantIdstring (uuid)A vendor-proposed match to an existing, active catalog variant. Omit for an unmatched free-form entry.
vendorSkustringYour own human-readable SKU for this item.
barcodestringRequiredREQUIRED. The product’s EAN/UPC barcode (GTIN): 8, 12, 13 or 14 digits with a valid GS1 check digit, e.g. 4006381333931. Missing or invalid → 400 VALIDATION_ERRORS (field Barcode).
vendorExternalIdstringOpaque id reserved for API integrations — doubles as the idempotency key.
costnumber (decimal)Wholesale cost Linra pays you, in SAR. Required under a Model-1 (CostPlusMargin) agreement; must be omitted under Model 2.
costIsVatInclusivebooleanREQUIRED whenever cost is present — there is no default. false = exclusive (cost is net, VAT added on top); true = inclusive (cost is the VAT-inclusive gross; net cost + input VAT are back-derived). Omitting this key while cost is present is rejected with 400 rather than assumed: a gross figure silently read as net would overstate your cost basis by the VAT rate.
salePricenumber (decimal)Your own final sale price (SAR), ALREADY including Linra’s + the reselling partner’s full commission share (e.g. a price of 1000 at a 20% supplier percentage means you net 800). Required under a Model-2 (PercentageOfSale) agreement; must be omitted under Model 1.
salePriceIsVatInclusivebooleanREQUIRED whenever salePrice is present — there is no default. false = exclusive; true = inclusive (gross), back-derived to net + VAT the same way costIsVatInclusive works for cost.
declaredStockQuantityintegerYour declared quantity on hand, when you report a number rather than a bare yes/no.
declaredInStockbooleanYour declared availability.
rawBrandNamestringRequired when variantId is omitted — the brand name as you know it.
rawProductNamestringRequired when variantId is omitted — the product name as you know it.
rawConcentrationstringrawSizeMlintegerrawDescriptionstringsaveAsDraftbooleanSave as a Draft (no review queue entry yet) instead of submitting for review immediately.
Response
idstring (uuid)statusstring (enum)Draft (saved, not submitted) → PendingMatch (no variantId, awaiting reviewer match) or PendingReview (a proposed match, awaiting approval) → Approved (live) → Withdrawn/Suspended; Rejected is reachable from Draft/PendingMatch/PendingReview. You never set Approved yourself. PendingRepricing: your agreement’s pricing model was switched by Linra while this offer was Approved or PendingReview — the offer’s linked supply is paused (not sellable) until you resubmit ONLY the new model’s price field (cost under Model 1, sale price under Model 2; stock updates are still accepted and never change this status) and it is re-reviewed, at which point it returns to PendingReview and then Approved as usual.
pricingModelobjectCostPlusMargin (“Model 1”): you declare cost, Linra adds a markup. PercentageOfSale (“Model 2”): you declare the final sale price; Linra + the reselling partner deduct a percentage of it.
vendorExternalIdstringOpaque id reserved for API integrations; doubles as an idempotency key.
product.variantIdstring (uuid)A vendor-proposed match to an existing, active Variant. Null for an unmatched free-form entry.
product.vendorSkustringproduct.barcodestringThe product’s EAN/UPC barcode. Null only on an offer created before the barcode became required, until its next edit.
product.rawBrandNamestringproduct.rawProductNamestringproduct.rawConcentrationstringproduct.rawSizeMlintegerproduct.rawDescriptionstringcost.amountnumber (decimal)The live, stored NET cost Linra pays you (SAR).
cost.isVatInclusivebooleanAlways false — pair amount with this value (false) on a write to safely resubmit it unchanged. This is the one entry mode that can never re-interpret an already-net figure as a fresh gross one. See enteredVatInclusive for how you actually entered it.
cost.enteredVatInclusivebooleanDisplay-only — your actual original entry-mode preference. NEVER accepted on a write; use isVatInclusive (always false) for that.
cost.inputVatnumber (decimal)Your own input VAT on the current cost, back-derived when enteredVatInclusive is true.
cost.pendingobjectA cost change staged by you (or an internal edit) on an Approved offer, awaiting reviewer approval — the live cost above is untouched until applied.
price.amountnumber (decimal)The live, stored NET sale price (SAR).
price.isVatInclusivebooleanAlways false — pair amount with this value (false) on a write to safely resubmit it unchanged. See enteredVatInclusive for how you actually entered it.
price.enteredVatInclusivebooleanDisplay-only — your actual original entry-mode preference. NEVER accepted on a write.
price.vatnumber (decimal)The VAT on the current sale price, back-derived when enteredVatInclusive is true.
price.pendingobjectA sale-price change staged by you on an Approved offer, awaiting reviewer approval — the live sale price above is untouched until applied.
stock.declaredQuantityintegerYour declared quantity on hand, when you report a number rather than a bare yes/no.
stock.declaredInStockbooleanreview.reviewedAtstring (date-time)review.reasonstringOther responses
400Request validation failed.401No bearer token (UNAUTHORIZED_MISSING_TOKEN), an invalid token (UNAUTHORIZED_INVALID_TOKEN) or an expired one (UNAUTHORIZED_TOKEN_EXPIRED — mint a new token). UPSTREAM_AUTH_FAILED is different: a dependent service refused the Gateway itself. That is a server-side fault — retry later and do NOT re-mint your token. See the Rate limits & errors guide.403Your token doesn’t carry the capability this endpoint requires.404No API route matches this path (NOT_FOUND_ROUTE). A missing resource on a real route returns that service’s own NOT_FOUND_* code instead.415The request body is not sent as application/json (UNSUPPORTED_MEDIA_TYPE).429Too many requests. Retry after the Retry-After header (seconds).502A dependent service returned an invalid response (BAD_GATEWAY). Retry with backoff.503The service is temporarily unavailable (SERVICE_UNAVAILABLE). Retry with backoff.504A dependent service did not respond in time (GATEWAY_TIMEOUT). Retry with backoff.curl --request POST \ --url https://api-omni-vendors.linra.net/api/v1/scent/offers \ --header 'Authorization: Bearer $TOKEN' \ --header 'Content-Type: application/json' \ --data '{ "variantId": "5b1e3a1c-9d2e-4f3a-8b1c-9f0a2e3d4c5b", "vendorSku": "string", "barcode": "string", "vendorExternalId": "string", "cost": 0, "costIsVatInclusive": true, "salePrice": 0, "salePriceIsVatInclusive": true, "declaredStockQuantity": 0, "declaredInStock": true, "rawBrandName": "string", "rawProductName": "string", "rawConcentration": "string", "rawSizeMl": 0, "rawDescription": "string", "saveAsDraft": false }'const res = await fetch('https://api-omni-vendors.linra.net/api/v1/scent/offers', { method: 'POST', headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json', }, body: JSON.stringify({ variantId: '5b1e3a1c-9d2e-4f3a-8b1c-9f0a2e3d4c5b', vendorSku: 'string', barcode: 'string', vendorExternalId: 'string', cost: 0, costIsVatInclusive: true, salePrice: 0, salePriceIsVatInclusive: true, declaredStockQuantity: 0, declaredInStock: true, rawBrandName: 'string', rawProductName: 'string', rawConcentration: 'string', rawSizeMl: 0, rawDescription: 'string', saveAsDraft: false }),});const { payload } = await res.json();var response = await httpClient.PostAsJsonAsync( "https://api-omni-vendors.linra.net/api/v1/scent/offers", new { variantId = "5b1e3a1c-9d2e-4f3a-8b1c-9f0a2e3d4c5b", vendorSku = "string", barcode = "string", vendorExternalId = "string", cost = 0, costIsVatInclusive = true, salePrice = 0, salePriceIsVatInclusive = true, declaredStockQuantity = 0, declaredInStock = true, rawBrandName = "string", rawProductName = "string", rawConcentration = "string", rawSizeMl = 0, rawDescription = "string", saveAsDraft = false });
var envelope = await response.Content.ReadFromJsonAsync<ApiResponse<VendorOfferResponse>>();Response
{ "state": "SUCCESS", "payload": { "id": "5b1e3a1c-9d2e-4f3a-8b1c-9f0a2e3d4c5b", "status": "Draft", "pricingModel": {}, "vendorExternalId": "string", "product": { "variantId": "5b1e3a1c-9d2e-4f3a-8b1c-9f0a2e3d4c5b", "vendorSku": "string", "barcode": "string", "rawBrandName": "string", "rawProductName": "string", "rawConcentration": "string", "rawSizeMl": 0, "rawDescription": "string" }, "cost": { "amount": 0, "isVatInclusive": true, "enteredVatInclusive": true, "inputVat": 0, "pending": { "amount": 0, "inputVat": 0 } }, "price": { "amount": 0, "isVatInclusive": true, "enteredVatInclusive": true, "vat": 0, "pending": { "amount": 0, "vat": 0 } }, "stock": { "declaredQuantity": 0, "declaredInStock": true }, "review": { "reviewedAt": "2026-08-22T09:14:03Z", "reason": "string" } }, "details": null}
