Push vendor stock
Push declared stock for one of your own offers.
Stock
/api/v1/scent/offers/{offerId}/stockApplies availability/quantity INSTANTLY (no review gate) — on an Approved offer this
propagates immediately to the linked supply option’s stock snapshot. Reachable for ANY of
the vendor’s own offers regardless of submission source — stock is a real-world fact about
the vendor’s own SKU, independent of which door the offer’s identity/cost entered through.
declaredInStock is REQUIRED: a body without it (e.g. a typo such as {"quantity":5}) returns
400 VALIDATION_ERRORS and the offer is left unchanged. It must agree with a supplied
declaredStockQuantity — false with a quantity above 0, or true with a quantity of 0,
returns 400 VALIDATION_ERRORS. Idempotent: re-pushing the identical declared state is a pure no-op. Requires
the Stock capability — grantable independently of Offers/Cost. Declared stock is a
sub-resource of the offer it declares availability for.
Path parameters
offerIdstring (uuid)RequiredBody parameters
declaredStockQuantityintegerOptional quantity on hand. Must be 0 (or omitted) when declaredInStock is false, and above 0 (or omitted) when it is true.
declaredInStockbooleanRequiredRequired. Omitting it returns 400 VALIDATION_ERRORS and changes nothing.
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.404Unknown offer id, or one belonging to another vendor.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 PATCH \ --url https://api-omni-vendors.linra.net/api/v1/scent/offers/5b1e3a1c-9d2e-4f3a-8b1c-9f0a2e3d4c5b/stock \ --header 'Authorization: Bearer $TOKEN' \ --header 'Content-Type: application/json' \ --data '{ "declaredStockQuantity": 0, "declaredInStock": true }'const res = await fetch('https://api-omni-vendors.linra.net/api/v1/scent/offers/5b1e3a1c-9d2e-4f3a-8b1c-9f0a2e3d4c5b/stock', { method: 'PATCH', headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json', }, body: JSON.stringify({ declaredStockQuantity: 0, declaredInStock: true }),});const { payload } = await res.json();var response = await httpClient.PatchAsJsonAsync( "https://api-omni-vendors.linra.net/api/v1/scent/offers/5b1e3a1c-9d2e-4f3a-8b1c-9f0a2e3d4c5b/stock", new { declaredStockQuantity = 0, declaredInStock = true });
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}
