curl --request POST \
--url https://www.merchkit.com/api/v1/products/upsert \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"merge_key": "sku",
"attributes": {
"sku": "ARIA-DT-72",
"price": 1349
}
}
'import requests
url = "https://www.merchkit.com/api/v1/products/upsert"
payload = {
"merge_key": "sku",
"attributes": {
"sku": "ARIA-DT-72",
"price": 1349
}
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({merge_key: 'sku', attributes: {sku: 'ARIA-DT-72', price: 1349}})
};
fetch('https://www.merchkit.com/api/v1/products/upsert', 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://www.merchkit.com/api/v1/products/upsert",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'merge_key' => 'sku',
'attributes' => [
'sku' => 'ARIA-DT-72',
'price' => 1349
]
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$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://www.merchkit.com/api/v1/products/upsert"
payload := strings.NewReader("{\n \"merge_key\": \"sku\",\n \"attributes\": {\n \"sku\": \"ARIA-DT-72\",\n \"price\": 1349\n }\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
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.post("https://www.merchkit.com/api/v1/products/upsert")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"merge_key\": \"sku\",\n \"attributes\": {\n \"sku\": \"ARIA-DT-72\",\n \"price\": 1349\n }\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://www.merchkit.com/api/v1/products/upsert")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"merge_key\": \"sku\",\n \"attributes\": {\n \"sku\": \"ARIA-DT-72\",\n \"price\": 1349\n }\n}"
response = http.request(request)
puts response.read_body{
"data": {
"id": "9b2f6c1e-8a04-4c6e-b0d3-5f2f6f7a9e21",
"type": "product",
"label": "Aria Oak Dining Table",
"parent_id": null,
"created_at": "2026-06-02T14:11:09Z",
"updated_at": "2026-07-18T09:30:22Z",
"attributes": {
"sku": "ARIA-DT-72",
"product_name": "Aria Oak Dining Table",
"price": 1299,
"material": "White Oak",
"vendor": {
"id": "77e1b2aa-6b3d-4f19-9d10-8c2a5e7f4b21",
"type": "vendor",
"label": "Nordic Timber Co."
},
"category": {
"id": "c41d09f3-2e85-47a6-b93c-d5f8e1a20c67",
"type": "category",
"label": "Dining Tables"
},
"gallery_images": [
{
"id": "f0a1b2c3-d4e5-4f60-8a7b-9c0d1e2f3a4b",
"type": "image",
"label": "aria-hero.jpg"
},
{
"id": "f0a2c3d4-e5f6-4a70-9b8c-0d1e2f3a4b5c",
"type": "image",
"label": "aria-detail.jpg"
},
{
"id": "f0a3d4e5-f6a7-4b80-8c9d-1e2f3a4b5c6d",
"type": "image",
"label": "aria-side.jpg"
},
{
"id": "f0a4e5f6-a7b8-4c90-9dae-2f3a4b5c6d7e",
"type": "image",
"label": "aria-lifestyle.jpg"
},
{
"id": "f0a5f6a7-b8c9-4da0-8ebf-3a4b5c6d7e8f",
"type": "image",
"label": "aria-packshot.jpg"
}
]
}
}
}{
"data": {
"id": "9b2f6c1e-8a04-4c6e-b0d3-5f2f6f7a9e21",
"type": "product",
"label": "Aria Oak Dining Table",
"parent_id": null,
"created_at": "2026-06-02T14:11:09Z",
"updated_at": "2026-07-18T09:30:22Z",
"attributes": {
"sku": "ARIA-DT-72",
"product_name": "Aria Oak Dining Table",
"price": 1299,
"material": "White Oak",
"vendor": {
"id": "77e1b2aa-6b3d-4f19-9d10-8c2a5e7f4b21",
"type": "vendor",
"label": "Nordic Timber Co."
},
"category": {
"id": "c41d09f3-2e85-47a6-b93c-d5f8e1a20c67",
"type": "category",
"label": "Dining Tables"
},
"gallery_images": [
{
"id": "f0a1b2c3-d4e5-4f60-8a7b-9c0d1e2f3a4b",
"type": "image",
"label": "aria-hero.jpg"
},
{
"id": "f0a2c3d4-e5f6-4a70-9b8c-0d1e2f3a4b5c",
"type": "image",
"label": "aria-detail.jpg"
},
{
"id": "f0a3d4e5-f6a7-4b80-8c9d-1e2f3a4b5c6d",
"type": "image",
"label": "aria-side.jpg"
},
{
"id": "f0a4e5f6-a7b8-4c90-9dae-2f3a4b5c6d7e",
"type": "image",
"label": "aria-lifestyle.jpg"
},
{
"id": "f0a5f6a7-b8c9-4da0-8ebf-3a4b5c6d7e8f",
"type": "image",
"label": "aria-packshot.jpg"
}
]
}
}
}{
"error": {
"code": "validation_failed",
"message": "Unknown attribute key(s): colour.",
"documentation_url": "https://docs.merchkit.com/developers/errors#validation_failed",
"is_retriable": false,
"retry_after_seconds": null,
"alternative_action": "List valid attribute keys via GET /v1/attributes?type=product.",
"request_id": "req_01j9x2k8",
"field_errors": [
{
"field": "colour",
"issue": "not_a_defined_attribute"
}
]
}
}{
"error": {
"code": "validation_failed",
"message": "Unknown attribute key(s): colour.",
"documentation_url": "https://docs.merchkit.com/developers/errors#validation_failed",
"is_retriable": false,
"retry_after_seconds": null,
"alternative_action": "List valid attribute keys via GET /v1/attributes?type=product.",
"request_id": "req_01j9x2k8",
"field_errors": [
{
"field": "colour",
"issue": "not_a_defined_attribute"
}
]
}
}Upsert a product by your own key
Create-or-update by a customer-named merge key: merge_key names any defined text-family attribute (usually sku) and attributes[merge_key] supplies the value to match — trimmed, case-insensitive. No match → create (201); one match → update (200); more than one match → 409 listing the matching ids. Idempotent for ERP-style pushes: address entities by your key, no UUID mapping table needed.
Scope: write:products.
curl --request POST \
--url https://www.merchkit.com/api/v1/products/upsert \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"merge_key": "sku",
"attributes": {
"sku": "ARIA-DT-72",
"price": 1349
}
}
'import requests
url = "https://www.merchkit.com/api/v1/products/upsert"
payload = {
"merge_key": "sku",
"attributes": {
"sku": "ARIA-DT-72",
"price": 1349
}
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({merge_key: 'sku', attributes: {sku: 'ARIA-DT-72', price: 1349}})
};
fetch('https://www.merchkit.com/api/v1/products/upsert', 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://www.merchkit.com/api/v1/products/upsert",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'merge_key' => 'sku',
'attributes' => [
'sku' => 'ARIA-DT-72',
'price' => 1349
]
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$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://www.merchkit.com/api/v1/products/upsert"
payload := strings.NewReader("{\n \"merge_key\": \"sku\",\n \"attributes\": {\n \"sku\": \"ARIA-DT-72\",\n \"price\": 1349\n }\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
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.post("https://www.merchkit.com/api/v1/products/upsert")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"merge_key\": \"sku\",\n \"attributes\": {\n \"sku\": \"ARIA-DT-72\",\n \"price\": 1349\n }\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://www.merchkit.com/api/v1/products/upsert")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"merge_key\": \"sku\",\n \"attributes\": {\n \"sku\": \"ARIA-DT-72\",\n \"price\": 1349\n }\n}"
response = http.request(request)
puts response.read_body{
"data": {
"id": "9b2f6c1e-8a04-4c6e-b0d3-5f2f6f7a9e21",
"type": "product",
"label": "Aria Oak Dining Table",
"parent_id": null,
"created_at": "2026-06-02T14:11:09Z",
"updated_at": "2026-07-18T09:30:22Z",
"attributes": {
"sku": "ARIA-DT-72",
"product_name": "Aria Oak Dining Table",
"price": 1299,
"material": "White Oak",
"vendor": {
"id": "77e1b2aa-6b3d-4f19-9d10-8c2a5e7f4b21",
"type": "vendor",
"label": "Nordic Timber Co."
},
"category": {
"id": "c41d09f3-2e85-47a6-b93c-d5f8e1a20c67",
"type": "category",
"label": "Dining Tables"
},
"gallery_images": [
{
"id": "f0a1b2c3-d4e5-4f60-8a7b-9c0d1e2f3a4b",
"type": "image",
"label": "aria-hero.jpg"
},
{
"id": "f0a2c3d4-e5f6-4a70-9b8c-0d1e2f3a4b5c",
"type": "image",
"label": "aria-detail.jpg"
},
{
"id": "f0a3d4e5-f6a7-4b80-8c9d-1e2f3a4b5c6d",
"type": "image",
"label": "aria-side.jpg"
},
{
"id": "f0a4e5f6-a7b8-4c90-9dae-2f3a4b5c6d7e",
"type": "image",
"label": "aria-lifestyle.jpg"
},
{
"id": "f0a5f6a7-b8c9-4da0-8ebf-3a4b5c6d7e8f",
"type": "image",
"label": "aria-packshot.jpg"
}
]
}
}
}{
"data": {
"id": "9b2f6c1e-8a04-4c6e-b0d3-5f2f6f7a9e21",
"type": "product",
"label": "Aria Oak Dining Table",
"parent_id": null,
"created_at": "2026-06-02T14:11:09Z",
"updated_at": "2026-07-18T09:30:22Z",
"attributes": {
"sku": "ARIA-DT-72",
"product_name": "Aria Oak Dining Table",
"price": 1299,
"material": "White Oak",
"vendor": {
"id": "77e1b2aa-6b3d-4f19-9d10-8c2a5e7f4b21",
"type": "vendor",
"label": "Nordic Timber Co."
},
"category": {
"id": "c41d09f3-2e85-47a6-b93c-d5f8e1a20c67",
"type": "category",
"label": "Dining Tables"
},
"gallery_images": [
{
"id": "f0a1b2c3-d4e5-4f60-8a7b-9c0d1e2f3a4b",
"type": "image",
"label": "aria-hero.jpg"
},
{
"id": "f0a2c3d4-e5f6-4a70-9b8c-0d1e2f3a4b5c",
"type": "image",
"label": "aria-detail.jpg"
},
{
"id": "f0a3d4e5-f6a7-4b80-8c9d-1e2f3a4b5c6d",
"type": "image",
"label": "aria-side.jpg"
},
{
"id": "f0a4e5f6-a7b8-4c90-9dae-2f3a4b5c6d7e",
"type": "image",
"label": "aria-lifestyle.jpg"
},
{
"id": "f0a5f6a7-b8c9-4da0-8ebf-3a4b5c6d7e8f",
"type": "image",
"label": "aria-packshot.jpg"
}
]
}
}
}{
"error": {
"code": "validation_failed",
"message": "Unknown attribute key(s): colour.",
"documentation_url": "https://docs.merchkit.com/developers/errors#validation_failed",
"is_retriable": false,
"retry_after_seconds": null,
"alternative_action": "List valid attribute keys via GET /v1/attributes?type=product.",
"request_id": "req_01j9x2k8",
"field_errors": [
{
"field": "colour",
"issue": "not_a_defined_attribute"
}
]
}
}{
"error": {
"code": "validation_failed",
"message": "Unknown attribute key(s): colour.",
"documentation_url": "https://docs.merchkit.com/developers/errors#validation_failed",
"is_retriable": false,
"retry_after_seconds": null,
"alternative_action": "List valid attribute keys via GET /v1/attributes?type=product.",
"request_id": "req_01j9x2k8",
"field_errors": [
{
"field": "colour",
"issue": "not_a_defined_attribute"
}
]
}
}Authorizations
Workspace-scoped API key (mk_live_...). Each operation lists the scope it requires in x-required-scopes. See the Authentication guide for the full scope table and key management.
Body
A defined text-family attribute key to match on (e.g. sku).
Map of attribute key → new value (sparse — only keys being written). Scalars set the value; null OR "" clears it (the key then disappears from reads). A single-reference key accepts a bare UUID string or an {id} object; a list-reference key accepts an array of either — list writes REPLACE the current set. Read stubs re-sent verbatim are valid writes (extra stub fields like type/label are ignored). Unknown keys are a 400; select values must be one of the attribute's acceptable_values.
Show child attributes
Show child attributes
Response
An existing product matched and was updated (full resource).
The one shape for every entity read and mutation response. System fields live at the top level; every customer-defined key lives in attributes, so customer keys can never collide with system ones.
Show child attributes
Show child attributes
{
"id": "9b2f6c1e-8a04-4c6e-b0d3-5f2f6f7a9e21",
"type": "product",
"label": "Aria Oak Dining Table",
"parent_id": null,
"created_at": "2026-06-02T14:11:09Z",
"updated_at": "2026-07-18T09:30:22Z",
"attributes": {
"sku": "ARIA-DT-72",
"product_name": "Aria Oak Dining Table",
"price": 1299,
"material": "White Oak",
"vendor": {
"id": "77e1b2aa-6b3d-4f19-9d10-8c2a5e7f4b21",
"type": "vendor",
"label": "Nordic Timber Co."
},
"category": {
"id": "c41d09f3-2e85-47a6-b93c-d5f8e1a20c67",
"type": "category",
"label": "Dining Tables"
},
"gallery_images": [
{
"id": "f0a1b2c3-d4e5-4f60-8a7b-9c0d1e2f3a4b",
"type": "image",
"label": "aria-hero.jpg"
},
{
"id": "f0a2c3d4-e5f6-4a70-9b8c-0d1e2f3a4b5c",
"type": "image",
"label": "aria-detail.jpg"
},
{
"id": "f0a3d4e5-f6a7-4b80-8c9d-1e2f3a4b5c6d",
"type": "image",
"label": "aria-side.jpg"
},
{
"id": "f0a4e5f6-a7b8-4c90-9dae-2f3a4b5c6d7e",
"type": "image",
"label": "aria-lifestyle.jpg"
},
{
"id": "f0a5f6a7-b8c9-4da0-8ebf-3a4b5c6d7e8f",
"type": "image",
"label": "aria-packshot.jpg"
}
]
}
}
Was this page helpful?