curl --request POST \
--url https://www.merchkit.com/api/v1/images/upsert \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"merge_key": "file_name",
"attributes": {
"file_name": "aria-hero.jpg",
"alt_text": "Aria Oak Dining Table — front hero shot"
}
}
'import requests
url = "https://www.merchkit.com/api/v1/images/upsert"
payload = {
"merge_key": "file_name",
"attributes": {
"file_name": "aria-hero.jpg",
"alt_text": "Aria Oak Dining Table — front hero shot"
}
}
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: 'file_name',
attributes: {
file_name: 'aria-hero.jpg',
alt_text: 'Aria Oak Dining Table — front hero shot'
}
})
};
fetch('https://www.merchkit.com/api/v1/images/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/images/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' => 'file_name',
'attributes' => [
'file_name' => 'aria-hero.jpg',
'alt_text' => 'Aria Oak Dining Table — front hero shot'
]
]),
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/images/upsert"
payload := strings.NewReader("{\n \"merge_key\": \"file_name\",\n \"attributes\": {\n \"file_name\": \"aria-hero.jpg\",\n \"alt_text\": \"Aria Oak Dining Table — front hero shot\"\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/images/upsert")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"merge_key\": \"file_name\",\n \"attributes\": {\n \"file_name\": \"aria-hero.jpg\",\n \"alt_text\": \"Aria Oak Dining Table — front hero shot\"\n }\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://www.merchkit.com/api/v1/images/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\": \"file_name\",\n \"attributes\": {\n \"file_name\": \"aria-hero.jpg\",\n \"alt_text\": \"Aria Oak Dining Table — front hero shot\"\n }\n}"
response = http.request(request)
puts response.read_body{
"data": {
"id": "f0a1b2c3-d4e5-4f60-8a7b-9c0d1e2f3a4b",
"type": "image",
"label": "aria-hero.jpg",
"parent_id": null,
"created_at": "2026-06-02T14:11:09Z",
"updated_at": "2026-07-18T09:30:22Z",
"attributes": {
"file_name": "aria-hero.jpg",
"image_url": "https://cdn.merchkit.example/aria/aria-hero.jpg",
"alt_text": "Aria Oak Dining Table — front hero shot"
}
}
}{
"data": {
"id": "f0a1b2c3-d4e5-4f60-8a7b-9c0d1e2f3a4b",
"type": "image",
"label": "aria-hero.jpg",
"parent_id": null,
"created_at": "2026-06-02T14:11:09Z",
"updated_at": "2026-07-18T09:30:22Z",
"attributes": {
"file_name": "aria-hero.jpg",
"image_url": "https://cdn.merchkit.example/aria/aria-hero.jpg",
"alt_text": "Aria Oak Dining Table — front hero shot"
}
}
}{
"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 an image 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:images.
curl --request POST \
--url https://www.merchkit.com/api/v1/images/upsert \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"merge_key": "file_name",
"attributes": {
"file_name": "aria-hero.jpg",
"alt_text": "Aria Oak Dining Table — front hero shot"
}
}
'import requests
url = "https://www.merchkit.com/api/v1/images/upsert"
payload = {
"merge_key": "file_name",
"attributes": {
"file_name": "aria-hero.jpg",
"alt_text": "Aria Oak Dining Table — front hero shot"
}
}
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: 'file_name',
attributes: {
file_name: 'aria-hero.jpg',
alt_text: 'Aria Oak Dining Table — front hero shot'
}
})
};
fetch('https://www.merchkit.com/api/v1/images/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/images/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' => 'file_name',
'attributes' => [
'file_name' => 'aria-hero.jpg',
'alt_text' => 'Aria Oak Dining Table — front hero shot'
]
]),
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/images/upsert"
payload := strings.NewReader("{\n \"merge_key\": \"file_name\",\n \"attributes\": {\n \"file_name\": \"aria-hero.jpg\",\n \"alt_text\": \"Aria Oak Dining Table — front hero shot\"\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/images/upsert")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"merge_key\": \"file_name\",\n \"attributes\": {\n \"file_name\": \"aria-hero.jpg\",\n \"alt_text\": \"Aria Oak Dining Table — front hero shot\"\n }\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://www.merchkit.com/api/v1/images/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\": \"file_name\",\n \"attributes\": {\n \"file_name\": \"aria-hero.jpg\",\n \"alt_text\": \"Aria Oak Dining Table — front hero shot\"\n }\n}"
response = http.request(request)
puts response.read_body{
"data": {
"id": "f0a1b2c3-d4e5-4f60-8a7b-9c0d1e2f3a4b",
"type": "image",
"label": "aria-hero.jpg",
"parent_id": null,
"created_at": "2026-06-02T14:11:09Z",
"updated_at": "2026-07-18T09:30:22Z",
"attributes": {
"file_name": "aria-hero.jpg",
"image_url": "https://cdn.merchkit.example/aria/aria-hero.jpg",
"alt_text": "Aria Oak Dining Table — front hero shot"
}
}
}{
"data": {
"id": "f0a1b2c3-d4e5-4f60-8a7b-9c0d1e2f3a4b",
"type": "image",
"label": "aria-hero.jpg",
"parent_id": null,
"created_at": "2026-06-02T14:11:09Z",
"updated_at": "2026-07-18T09:30:22Z",
"attributes": {
"file_name": "aria-hero.jpg",
"image_url": "https://cdn.merchkit.example/aria/aria-hero.jpg",
"alt_text": "Aria Oak Dining Table — front hero shot"
}
}
}{
"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 image 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?