curl --request PUT \
--url https://api.example.com/products/{productId} \
--header 'Content-Type: application/json' \
--header 'X-API-Key: <api-key>' \
--data '
{
"description": "Ukelele",
"productKey": 60131324,
"price": 345.6,
"taxIncluded": true,
"taxability": "02",
"taxes": [],
"localTaxes": [],
"unitKey": "H87",
"unitName": "Elemento",
"sku": "UKL-001",
"livemode": true
}
'import requests
url = "https://api.example.com/products/{productId}"
payload = {
"description": "Ukelele",
"productKey": 60131324,
"price": 345.6,
"taxIncluded": True,
"taxability": "02",
"taxes": [],
"localTaxes": [],
"unitKey": "H87",
"unitName": "Elemento",
"sku": "UKL-001",
"livemode": True
}
headers = {
"X-API-Key": "<api-key>",
"Content-Type": "application/json"
}
response = requests.put(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'PUT',
headers: {'X-API-Key': '<api-key>', 'Content-Type': 'application/json'},
body: JSON.stringify({
description: 'Ukelele',
productKey: 60131324,
price: 345.6,
taxIncluded: true,
taxability: '02',
taxes: [],
localTaxes: [],
unitKey: 'H87',
unitName: 'Elemento',
sku: 'UKL-001',
livemode: true
})
};
fetch('https://api.example.com/products/{productId}', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.example.com/products/{productId}",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "PUT",
CURLOPT_POSTFIELDS => json_encode([
'description' => 'Ukelele',
'productKey' => 60131324,
'price' => 345.6,
'taxIncluded' => true,
'taxability' => '02',
'taxes' => [
],
'localTaxes' => [
],
'unitKey' => 'H87',
'unitName' => 'Elemento',
'sku' => 'UKL-001',
'livemode' => true
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"X-API-Key: <api-key>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.example.com/products/{productId}"
payload := strings.NewReader("{\n \"description\": \"Ukelele\",\n \"productKey\": 60131324,\n \"price\": 345.6,\n \"taxIncluded\": true,\n \"taxability\": \"02\",\n \"taxes\": [],\n \"localTaxes\": [],\n \"unitKey\": \"H87\",\n \"unitName\": \"Elemento\",\n \"sku\": \"UKL-001\",\n \"livemode\": true\n}")
req, _ := http.NewRequest("PUT", url, payload)
req.Header.Add("X-API-Key", "<api-key>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.put("https://api.example.com/products/{productId}")
.header("X-API-Key", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"description\": \"Ukelele\",\n \"productKey\": 60131324,\n \"price\": 345.6,\n \"taxIncluded\": true,\n \"taxability\": \"02\",\n \"taxes\": [],\n \"localTaxes\": [],\n \"unitKey\": \"H87\",\n \"unitName\": \"Elemento\",\n \"sku\": \"UKL-001\",\n \"livemode\": true\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.example.com/products/{productId}")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Put.new(url)
request["X-API-Key"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"description\": \"Ukelele\",\n \"productKey\": 60131324,\n \"price\": 345.6,\n \"taxIncluded\": true,\n \"taxability\": \"02\",\n \"taxes\": [],\n \"localTaxes\": [],\n \"unitKey\": \"H87\",\n \"unitName\": \"Elemento\",\n \"sku\": \"UKL-001\",\n \"livemode\": true\n}"
response = http.request(request)
puts response.read_body{
"id": "590ce6c56d04f840aa8438af",
"organizationId": "org-uuid",
"livemode": false,
"description": "Ukelele",
"productKey": 60131324,
"price": 345.6,
"taxIncluded": true,
"taxability": "01",
"taxes": [
{
"type": "IVA",
"rate": 0.16,
"withholding": false,
"factor": "Tasa"
}
],
"localTaxes": [
{
"type": "IVA",
"rate": 0.16,
"withholding": false,
"factor": "Tasa"
}
],
"unitKey": "H87",
"unitName": "Elemento",
"createdAt": "2023-11-07T05:31:56Z",
"updatedAt": "2023-11-07T05:31:56Z",
"sku": "UKL-001"
}Update Product
curl --request PUT \
--url https://api.example.com/products/{productId} \
--header 'Content-Type: application/json' \
--header 'X-API-Key: <api-key>' \
--data '
{
"description": "Ukelele",
"productKey": 60131324,
"price": 345.6,
"taxIncluded": true,
"taxability": "02",
"taxes": [],
"localTaxes": [],
"unitKey": "H87",
"unitName": "Elemento",
"sku": "UKL-001",
"livemode": true
}
'import requests
url = "https://api.example.com/products/{productId}"
payload = {
"description": "Ukelele",
"productKey": 60131324,
"price": 345.6,
"taxIncluded": True,
"taxability": "02",
"taxes": [],
"localTaxes": [],
"unitKey": "H87",
"unitName": "Elemento",
"sku": "UKL-001",
"livemode": True
}
headers = {
"X-API-Key": "<api-key>",
"Content-Type": "application/json"
}
response = requests.put(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'PUT',
headers: {'X-API-Key': '<api-key>', 'Content-Type': 'application/json'},
body: JSON.stringify({
description: 'Ukelele',
productKey: 60131324,
price: 345.6,
taxIncluded: true,
taxability: '02',
taxes: [],
localTaxes: [],
unitKey: 'H87',
unitName: 'Elemento',
sku: 'UKL-001',
livemode: true
})
};
fetch('https://api.example.com/products/{productId}', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.example.com/products/{productId}",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "PUT",
CURLOPT_POSTFIELDS => json_encode([
'description' => 'Ukelele',
'productKey' => 60131324,
'price' => 345.6,
'taxIncluded' => true,
'taxability' => '02',
'taxes' => [
],
'localTaxes' => [
],
'unitKey' => 'H87',
'unitName' => 'Elemento',
'sku' => 'UKL-001',
'livemode' => true
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"X-API-Key: <api-key>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.example.com/products/{productId}"
payload := strings.NewReader("{\n \"description\": \"Ukelele\",\n \"productKey\": 60131324,\n \"price\": 345.6,\n \"taxIncluded\": true,\n \"taxability\": \"02\",\n \"taxes\": [],\n \"localTaxes\": [],\n \"unitKey\": \"H87\",\n \"unitName\": \"Elemento\",\n \"sku\": \"UKL-001\",\n \"livemode\": true\n}")
req, _ := http.NewRequest("PUT", url, payload)
req.Header.Add("X-API-Key", "<api-key>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.put("https://api.example.com/products/{productId}")
.header("X-API-Key", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"description\": \"Ukelele\",\n \"productKey\": 60131324,\n \"price\": 345.6,\n \"taxIncluded\": true,\n \"taxability\": \"02\",\n \"taxes\": [],\n \"localTaxes\": [],\n \"unitKey\": \"H87\",\n \"unitName\": \"Elemento\",\n \"sku\": \"UKL-001\",\n \"livemode\": true\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.example.com/products/{productId}")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Put.new(url)
request["X-API-Key"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"description\": \"Ukelele\",\n \"productKey\": 60131324,\n \"price\": 345.6,\n \"taxIncluded\": true,\n \"taxability\": \"02\",\n \"taxes\": [],\n \"localTaxes\": [],\n \"unitKey\": \"H87\",\n \"unitName\": \"Elemento\",\n \"sku\": \"UKL-001\",\n \"livemode\": true\n}"
response = http.request(request)
puts response.read_body{
"id": "590ce6c56d04f840aa8438af",
"organizationId": "org-uuid",
"livemode": false,
"description": "Ukelele",
"productKey": 60131324,
"price": 345.6,
"taxIncluded": true,
"taxability": "01",
"taxes": [
{
"type": "IVA",
"rate": 0.16,
"withholding": false,
"factor": "Tasa"
}
],
"localTaxes": [
{
"type": "IVA",
"rate": 0.16,
"withholding": false,
"factor": "Tasa"
}
],
"unitKey": "H87",
"unitName": "Elemento",
"createdAt": "2023-11-07T05:31:56Z",
"updatedAt": "2023-11-07T05:31:56Z",
"sku": "UKL-001"
}This endpoint takes noorganizationIdin the URL. Authenticate with either a Supabase Bearer session (send theX-Organization-Id: <org-id>header — the user must be a member of that organization) or an API key (the organization resolves automatically from the key; anyX-Organization-Idheader sent alongside an API key is ignored).
Authentication
Accepts either:- A Supabase Bearer session (
Authorization: Bearer <token>) with theX-Organization-Id: <org-id>header — the authenticated user must be a member of that organization. - An API key (
X-API-Key: sk_...) with thewrite:productsscope — the organization is resolved from the key itself.
Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
productId | string (UUID) | Yes | Product ID |
Request Body
All fields are optional.| Field | Type | Description |
|---|---|---|
description | string | Product or service description |
productKey | integer | SAT product/service key |
price | number | Unit price |
taxIncluded | boolean | Whether taxes are included in the price. Only supported when the only transferred tax is IVA at a rate (Tasa). |
taxability | string | SAT taxability code. The resulting product (stored values plus your changes) must agree with its taxes: "02" requires at least one tax; "01", "03" and "04" must have none — otherwise 400. |
taxes | array | List of applicable taxes (replaces existing) |
localTaxes | array | Not supported yet — must be empty ([]); a non-empty list is rejected with a 400. |
unitKey | string | SAT unit of measure key |
unitName | string | Unit of measure name |
sku | string | Internal product SKU |
livemode | boolean | Whether this is a live mode product |
Example Request
curl -X PUT https://api.timbrix.mx/products/590ce6c56d04f840aa8438af \
-H "Authorization: Bearer <your_token>" \
-H "X-Organization-Id: 550e8400-e29b-41d4-a716-446655440000" \
-H "Content-Type: application/json" \
-d '{
"price": 400.0,
"sku": "UKL-002"
}'
import { Timbrix } from "@timbrix/sdk"
const client = new Timbrix({ bearerToken: "<your_token>" })
const product = await client.products.update(
"590ce6c56d04f840aa8438af",
{
price: 400.0,
sku: "UKL-002",
},
"550e8400-e29b-41d4-a716-446655440000"
)
console.log(product)
Example Response
{
"id": "590ce6c56d04f840aa8438af",
"organizationId": "550e8400-e29b-41d4-a716-446655440000",
"livemode": true,
"description": "Ukelele",
"productKey": 60131324,
"price": 400.0,
"taxIncluded": true,
"taxability": "02",
"taxes": [{ "type": "IVA", "rate": 0.16 }],
"localTaxes": [],
"unitKey": "H87",
"unitName": "Elemento",
"sku": "UKL-002",
"createdAt": "2025-01-26T10:00:00Z",
"updatedAt": "2025-01-26T11:00:00Z"
}
Common Errors
400 Bad Request
MissingX-Organization-Id header on a session-authenticated request.
401 Unauthorized
Missing or invalid Bearer token / API key.403 Forbidden
The authenticated user is not a member of the organization sent inX-Organization-Id, or the API key does not have the write:products scope.
404 Not Found
Product does not exist or does not belong to the organization.409 Conflict
A product with the new SKU already exists in this organization.Authorizations
API Key for authentication (format: sk_...)
Headers
Required for Supabase session auth. Ignored when authenticating with an API key (the organization resolves from the key).
Path Parameters
Body
Product or service description
"Ukelele"
SAT product/service key (clave de producto o servicio)
60131324
Unit price
345.6
Whether taxes are already included in the price
true
SAT taxability code (objeto de impuesto). If omitted, it is derived: "02" when taxes is not empty, "01" otherwise. Must agree with taxes: "02" requires at least one tax; "01", "03" and "04" must have none.
"02"
Applicable taxes
Show child attributes
Show child attributes
Applicable local taxes
Show child attributes
Show child attributes
SAT unit of measure key (clave de unidad)
"H87"
Unit of measure name
"Elemento"
Internal SKU or identifier
"UKL-001"
Whether this is a live mode product
true
Response
"590ce6c56d04f840aa8438af"
"org-uuid"
false
"Ukelele"
60131324
345.6
true
"01"
Show child attributes
Show child attributes
Show child attributes
Show child attributes
"H87"
"Elemento"
"UKL-001"