Skip to main content

Product update

Business scenario

When a merchant updates a product in their integrated system — changing its name, price, SKU, or inventory tracking setting — that change must be reflected in Qoyod for the two systems to remain aligned. If Qoyod holds a stale version of the product, invoices referencing it carry incorrect prices, the chart of accounts records costs against outdated values, and any reporting that draws on product data diverges from the merchant's actual catalog.

This use case covers the integrated system to Qoyod direction: your integration detects that a product has been modified in the integrated system, then sends a request to Qoyod to apply those changes to the matching product record. The Qoyod record is identified by the numeric product id that your integration stored when the product was first created (see New product creation).

A successful update leaves both systems holding the same current attribute values for the product. A missed or failed update leaves Qoyod out of date until the next successful synchronization. Persistent drift between systems requires a sync reconciliation pass to identify and resolve conflicts.

When to use this

Use this when:

  • A product already exists in Qoyod (you have its numeric Qoyod product id stored) and one or more of its attributes have changed in the integrated system.
  • You need to change a product's name, SKU, price, inventory tracking setting, category, or tax association.
  • The change originated in the integrated system and Qoyod should receive it — this is an integrated system to Qoyod flow.

Do not use this when:

  • The product does not yet exist in Qoyod — create it first using New product creation (UC-01).
  • You need to adjust stock quantities — stock is managed through inventory adjustments, not through the product update endpoint.
  • You need to change the product's type classification — type cannot be changed after creation. See Edge cases and gotchas for details.
  • You need to update many products at once as part of a bulk migration — see Initial product import for batch considerations.

Prerequisites

  • A valid OAuth 2.0 access token for the Qoyod account you are integrating with.
  • The Qoyod product id for the product you intend to update. This is the integer ID returned in the 201 Created response when the product was first created and stored by your integration. If you do not have this ID, follow New product creation first — there is no reliable way to update a product without its Qoyod ID.
  • If your update sets or changes category_id, the target category must already exist in Qoyod. Retrieve its integer id from the categories endpoint before sending the update request.
  • If your update sets or changes tax_id, the target tax record must already exist in Qoyod. Retrieve its integer id before sending the update request.

Sequence diagram

Step-by-step

1. Confirm the stored Qoyod product ID

Before sending an update, verify that your integration has a Qoyod product id stored for the item. This ID was returned in the 201 Created response when the product was first created and must be persisted in your integrated system. If no ID is stored, the product does not yet exist in Qoyod — follow New product creation instead.

2. Build the request body with only the changed fields

Wrap the fields you want to update inside a product object. You do not need to send the full product record — only include the fields that have changed. Omitting a field does not clear it; Qoyod leaves unchanged fields at their current values.

Request body — partial update (price and SKU changed)
{
"product": {
"selling_price": 30.00,
"sku": "MUG-BLUE-002"
}
}

If you are updating the product name, send the appropriate name field. Both the English and Arabic name fields accept aliases — use whichever your integration normalizes to.

Request body — name update
{
"product": {
"en_name": "Blue Ceramic Mug — Large",
"name": "كوب سيراميك أزرق - كبير"
}
}

3. Send the PUT request

Send a PUT request to https://api.qoyod.com/2.0/products/{id}, replacing {id} with the stored Qoyod product id. Include the Authorization header with your access token.

Send the update request
curl -X PUT https://api.qoyod.com/2.0/products/{product_id} \
-H "Authorization: Bearer {access_token}" \
-H "Content-Type: application/json" \
-d '{
"product": {
"selling_price": 30.00,
"sku": "MUG-BLUE-002"
}
}'

4. Handle the 200 OK response

A successful update returns 200 OK with the full updated product record nested under a product key. This is the complete current state of the product in Qoyod — not a partial echo of what you sent.

Response — 200 OK
{
"product": {
"id": 1087,
"name_ar": "كوب سيراميك أزرق",
"name_en": "Blue Ceramic Mug",
"type": "Product",
"sku": "MUG-BLUE-002",
"selling_price": 30.0,
"buying_price": 12.0,
"is_sold": true,
"is_bought": true,
"track_quantity": 1,
"category_id": 42,
"updated_at": "2026-05-18T11:45:00.000Z"
}
}

Confirm that the fields you sent appear with the expected values in the response. If a field does not reflect your update, check whether the field name you used is a supported alias — the response always returns canonical field names regardless of the alias used in the request.

5. Verify the update

After confirming the 200 OK response, retrieve the product via GET /2.0/products/{id} to confirm the record reflects the updated values independently of the update response. See the Verification section below.

Field mapping

The table below maps common integrated system concepts to the corresponding Qoyod fields for the product update request. All field names match the PUT /2.0/products/{id} request body exactly. Only send the fields that have changed — the endpoint applies a partial update; untouched fields retain their current values.

Integrated system conceptQoyod fieldRequiredNotes
Product name (English)en_nameNoAlso accepted as name_en. Only send if the name has changed.
Product name (Arabic)nameNoAlso accepted as name_ar or ar_name. Only send if the name has changed.
SKUskuNoPass through from the integrated system.
Selling priceselling_priceNoNumeric. Updates the selling price. If is_sold was previously false, Qoyod sets it to true when this field is present.
Buying pricebuying_priceNoNumeric. Updates the buying price. If is_bought was previously false, Qoyod sets it to true when this field is present.
Inventory tracking enabledtrack_quantityNo0 = untracked, 1 = tracked. Can be changed on update.
Categorycategory_idNoMust reference an existing Qoyod category ID.
Taxtax_idNoMust reference an existing Qoyod tax ID.

For the complete list of fields accepted by this endpoint, see the products reference.

Verification

After the PUT request returns 200 OK, retrieve the product to confirm the update was applied correctly.

Retrieve the updated product
curl -X GET https://api.qoyod.com/2.0/products/{product_id} \
-H "Authorization: Bearer {access_token}"

A successful retrieval returns 200 OK with a product object. Confirm:

  • The id field matches the product ID you updated.
  • Each field you changed in the PUT request reflects the new value.
  • updated_at has advanced to a timestamp after your PUT request.
  • Fields you did not send in the PUT request retain their previous values — this confirms the partial update behavior is working as expected.

If a field does not reflect the expected value, check the alias table in New product creation — the name and en_name fields each accept multiple aliases on input, but the response always returns the canonical field names name_ar and name_en.

note

The verification step is optional but recommended during initial integration development. Once your integration is stable and you trust the 200 OK response, the separate GET request adds latency without additional value for most production flows.

Error scenarios

Status codeWhen it occursWhat to do
422 Unprocessable EntityQoyod could not apply the update due to a validation failure. The response body contains an errors object where keys are field names and values are arrays of error strings.Read the errors object to identify which fields failed validation. Correct the field values in your request body and retry.
422 Unprocessable EntityThe category_id or tax_id you sent does not reference an existing record in Qoyod.Verify the referenced ID by querying the appropriate Qoyod endpoint. Ensure the category or tax record exists before sending the update.
404 Not FoundThe product ID in the request path does not match any product in Qoyod. This typically means the stored Qoyod product ID is stale, was deleted, or was copied from the wrong record. Check your integration's stored product ID for this item. If the product was deleted from Qoyod, re-create it using New product creation and store the new ID.
401 UnauthorizedThe access token is missing, expired, or invalid.Refresh the OAuth 2.0 access token and retry the request.

For retry logic, exponential backoff guidance, and how to interpret the errors response object, see error handling.