Update a product
API v2 is in public beta: endpoints and fields can change before general availability. See the changelog
/preorders/productsCosts 2 rate-limit points · Rate limits
Save rows of the store-wide Preorders > Products tab: link each variant to one offer or to none, and set its shipping text and quantity limit on the offers it is in.
variants is a list of up to 100 rows. A row's offer_id replaces every offer the variant is in with that one, and null takes it out of all of them, as the tab's 'Offer linked' select does; omit offer_id to leave the links. Offers that sell in selected markets only cannot be picked, and a variant in one is skipped (skipped_market_shopify_variant_ids); change those on the offer itself. offers sets this variant's shipping_text and max_count on offers it is in; shipping_text only on an offer whose shipping text is per variant, max_count (1 or more) only on an out-of-stock offer. null clears either one; a key left out is unchanged. max_count is the variant's own limit, the same field GET /preorders/products returns, so writing a read value back changes nothing. On an offer with batches on, limits are per batch: max_count (a value or null) returns 422 there, so set batch_limits on PATCH /preorders/offers/:id/products/variants/:shopify_variant_id instead. quantity_limit is read-only. inventory_policy (CONTINUE or DENY) also sets 'Continue selling' on the variants whose offer_id changed, as the save confirm's Turn on / Turn off does; omit it for 'Don't change'. Variants STOQ has not stored yet are read from Shopify. Finishes before the response.
Also searched aslink product to offermove variant to offerchange offer linkedunlink product from offerset shipping text for variantset quantity limit for variantsave products tab
Headers
Idempotency-KeystringA fresh unique key for every write (a new UUID, say); reuse it only to retry that write. Keys are remembered for 1 hour: the same key and the same request within that hour returns the first result, with
Idempotent-Replayed: true, without running again; the same key with a different method, path or body is refused (422idempotency_key_reused); a retry while the first is still running gets 409idempotency_key_in_progress. Keys are per store. Server errors and rate limits are not kept, so their retry runs.
Request body
variantsstringExample:stringinventory_policystringExample:string
Errors
Missing or invalid X-Auth-Token.
An earlier request with the same Idempotency-Key is still running. Wait, then resend the same request with the same key.
The request failed validation.
Rate limited: cost-weighted per token (read 1, write 2; 360 points / 60s). Check Retry-After.
Every error has the same shape: see Errors.
curl -X PATCH "https://app.stoqapp.com/api/v2/external/preorders/products" \
-H "X-Auth-Token: $STOQ_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"variants": "string",
"inventory_policy": "string"
}'const res = await fetch("https://app.stoqapp.com/api/v2/external/preorders/products", {
method: "PATCH",
headers: {
"X-Auth-Token": process.env.STOQ_API_KEY,
"Content-Type": "application/json",
},
body: JSON.stringify({
"variants": "string",
"inventory_policy": "string"
}),
});
const data = await res.json();import os
import requests
res = requests.patch(
"https://app.stoqapp.com/api/v2/external/preorders/products",
headers={"X-Auth-Token": os.environ["STOQ_API_KEY"]},
json={
"variants": "string",
"inventory_policy": "string"
},
)
data = res.json()require "net/http"
require "json"
uri = URI("https://app.stoqapp.com/api/v2/external/preorders/products")
req = Net::HTTP::Patch.new(uri, "X-Auth-Token" => ENV["STOQ_API_KEY"], "Content-Type" => "application/json")
req.body = {
variants: "string",
inventory_policy: "string"
}.to_json
res = Net::HTTP.start(uri.host, uri.port, use_ssl: true) { |http| http.request(req) }
data = JSON.parse(res.body){
"job_id": "job_a1b2c3",
"status_url": "/api/v2/external/jobs/job_a1b2c3"
}{
"errors": [
"Invalid API key"
],
"code": "auth_invalid",
"details": [
{
"code": "auth_invalid",
"message": "Invalid API key",
"path": null,
"value": null,
"expected": null
}
]
}{
"errors": [
"A request with this Idempotency-Key is still running"
],
"code": "idempotency_key_in_progress",
"details": [
{
"code": "idempotency_key_in_progress",
"message": "A request with this Idempotency-Key is still running",
"path": null,
"value": null,
"expected": null
}
]
}{
"errors": [
"name is required"
],
"code": "validation_failed",
"details": [
{
"code": "validation_failed",
"message": "name is required",
"path": null,
"value": null,
"expected": null
}
]
}{
"errors": [
"Rate limit exceeded"
],
"code": "rate_limited",
"details": [
{
"code": "rate_limited",
"message": "Rate limit exceeded",
"path": null,
"value": null,
"expected": null
}
]
}