curl --request POST \
--url https://www.closient.com/products/api/v1/products/{gtin}/images/from-url \
--header 'Content-Type: application/json' \
--header 'X-API-Key: <api-key>' \
--data '
{
"source_retailer": "sephora_catalog",
"source_url": "https://images.example-dam.com/sephora/s2512345-main-zoom.jpg"
}
'import requests
url = "https://www.closient.com/products/api/v1/products/{gtin}/images/from-url"
payload = {
"source_retailer": "sephora_catalog",
"source_url": "https://images.example-dam.com/sephora/s2512345-main-zoom.jpg"
}
headers = {
"X-API-Key": "<api-key>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {'X-API-Key': '<api-key>', 'Content-Type': 'application/json'},
body: JSON.stringify({
source_retailer: 'sephora_catalog',
source_url: 'https://images.example-dam.com/sephora/s2512345-main-zoom.jpg'
})
};
fetch('https://www.closient.com/products/api/v1/products/{gtin}/images/from-url', 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.closient.com/products/api/v1/products/{gtin}/images/from-url",
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([
'source_retailer' => 'sephora_catalog',
'source_url' => 'https://images.example-dam.com/sephora/s2512345-main-zoom.jpg'
]),
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://www.closient.com/products/api/v1/products/{gtin}/images/from-url"
payload := strings.NewReader("{\n \"source_retailer\": \"sephora_catalog\",\n \"source_url\": \"https://images.example-dam.com/sephora/s2512345-main-zoom.jpg\"\n}")
req, _ := http.NewRequest("POST", 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.post("https://www.closient.com/products/api/v1/products/{gtin}/images/from-url")
.header("X-API-Key", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"source_retailer\": \"sephora_catalog\",\n \"source_url\": \"https://images.example-dam.com/sephora/s2512345-main-zoom.jpg\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://www.closient.com/products/api/v1/products/{gtin}/images/from-url")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["X-API-Key"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"source_retailer\": \"sephora_catalog\",\n \"source_url\": \"https://images.example-dam.com/sephora/s2512345-main-zoom.jpg\"\n}"
response = http.request(request)
puts response.read_body{
"image_id": "im_2N4kq7ZxYQ8vR3sT1bWnCp",
"status": "created"
}{
"detail": "The requested resource was not found.",
"error_code": "not_found",
"retryable": false,
"status": 404,
"timestamp": "2026-03-31T12:00:00+00:00",
"title": "Not Found",
"type": "https://closient.com/docs/errors/not_found"
}{
"detail": "The requested resource was not found.",
"error_code": "not_found",
"retryable": false,
"status": 404,
"timestamp": "2026-03-31T12:00:00+00:00",
"title": "Not Found",
"type": "https://closient.com/docs/errors/not_found"
}{
"detail": "The requested resource was not found.",
"error_code": "not_found",
"retryable": false,
"status": 404,
"timestamp": "2026-03-31T12:00:00+00:00",
"title": "Not Found",
"type": "https://closient.com/docs/errors/not_found"
}{
"detail": "The requested resource was not found.",
"error_code": "not_found",
"retryable": false,
"status": 404,
"timestamp": "2026-03-31T12:00:00+00:00",
"title": "Not Found",
"type": "https://closient.com/docs/errors/not_found"
}{
"detail": "The requested resource was not found.",
"error_code": "not_found",
"retryable": false,
"status": 404,
"timestamp": "2026-03-31T12:00:00+00:00",
"title": "Not Found",
"type": "https://closient.com/docs/errors/not_found"
}{
"detail": "dimensions (9000, 1) out of bounds (max 8000px) for https://images.example-dam.com/sephora/s2512345-main-zoom.jpg",
"reason": "invalid_dimensions"
}{
"detail": "The requested resource was not found.",
"error_code": "not_found",
"retryable": false,
"status": 404,
"timestamp": "2026-03-31T12:00:00+00:00",
"title": "Not Found",
"type": "https://closient.com/docs/errors/not_found"
}Attach a product image from a vendor-supplied URL
Download source_url and attach it as this product’s image. Unlike the retailer catalog import (which stores a URL discovered in a feed for later background ingestion), this call downloads synchronously and is meant for a URL a human already vetted — a private link a retailer’s vendor-relations team handed back for a SKU whose catalog image was blocked. Idempotent: re-posting the same source_url for a product that already has it returns skipped_existing rather than re-downloading.
curl --request POST \
--url https://www.closient.com/products/api/v1/products/{gtin}/images/from-url \
--header 'Content-Type: application/json' \
--header 'X-API-Key: <api-key>' \
--data '
{
"source_retailer": "sephora_catalog",
"source_url": "https://images.example-dam.com/sephora/s2512345-main-zoom.jpg"
}
'import requests
url = "https://www.closient.com/products/api/v1/products/{gtin}/images/from-url"
payload = {
"source_retailer": "sephora_catalog",
"source_url": "https://images.example-dam.com/sephora/s2512345-main-zoom.jpg"
}
headers = {
"X-API-Key": "<api-key>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {'X-API-Key': '<api-key>', 'Content-Type': 'application/json'},
body: JSON.stringify({
source_retailer: 'sephora_catalog',
source_url: 'https://images.example-dam.com/sephora/s2512345-main-zoom.jpg'
})
};
fetch('https://www.closient.com/products/api/v1/products/{gtin}/images/from-url', 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.closient.com/products/api/v1/products/{gtin}/images/from-url",
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([
'source_retailer' => 'sephora_catalog',
'source_url' => 'https://images.example-dam.com/sephora/s2512345-main-zoom.jpg'
]),
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://www.closient.com/products/api/v1/products/{gtin}/images/from-url"
payload := strings.NewReader("{\n \"source_retailer\": \"sephora_catalog\",\n \"source_url\": \"https://images.example-dam.com/sephora/s2512345-main-zoom.jpg\"\n}")
req, _ := http.NewRequest("POST", 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.post("https://www.closient.com/products/api/v1/products/{gtin}/images/from-url")
.header("X-API-Key", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"source_retailer\": \"sephora_catalog\",\n \"source_url\": \"https://images.example-dam.com/sephora/s2512345-main-zoom.jpg\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://www.closient.com/products/api/v1/products/{gtin}/images/from-url")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["X-API-Key"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"source_retailer\": \"sephora_catalog\",\n \"source_url\": \"https://images.example-dam.com/sephora/s2512345-main-zoom.jpg\"\n}"
response = http.request(request)
puts response.read_body{
"image_id": "im_2N4kq7ZxYQ8vR3sT1bWnCp",
"status": "created"
}{
"detail": "The requested resource was not found.",
"error_code": "not_found",
"retryable": false,
"status": 404,
"timestamp": "2026-03-31T12:00:00+00:00",
"title": "Not Found",
"type": "https://closient.com/docs/errors/not_found"
}{
"detail": "The requested resource was not found.",
"error_code": "not_found",
"retryable": false,
"status": 404,
"timestamp": "2026-03-31T12:00:00+00:00",
"title": "Not Found",
"type": "https://closient.com/docs/errors/not_found"
}{
"detail": "The requested resource was not found.",
"error_code": "not_found",
"retryable": false,
"status": 404,
"timestamp": "2026-03-31T12:00:00+00:00",
"title": "Not Found",
"type": "https://closient.com/docs/errors/not_found"
}{
"detail": "The requested resource was not found.",
"error_code": "not_found",
"retryable": false,
"status": 404,
"timestamp": "2026-03-31T12:00:00+00:00",
"title": "Not Found",
"type": "https://closient.com/docs/errors/not_found"
}{
"detail": "The requested resource was not found.",
"error_code": "not_found",
"retryable": false,
"status": 404,
"timestamp": "2026-03-31T12:00:00+00:00",
"title": "Not Found",
"type": "https://closient.com/docs/errors/not_found"
}{
"detail": "dimensions (9000, 1) out of bounds (max 8000px) for https://images.example-dam.com/sephora/s2512345-main-zoom.jpg",
"reason": "invalid_dimensions"
}{
"detail": "The requested resource was not found.",
"error_code": "not_found",
"retryable": false,
"status": 404,
"timestamp": "2026-03-31T12:00:00+00:00",
"title": "Not Found",
"type": "https://closient.com/docs/errors/not_found"
}Authorizations
Path Parameters
GTIN barcode (8, 12, 13, or 14 digits). Normalized to GTIN-14 for lookup.
^[0-9]{8,14}$Body
A vendor-vetted URL to fetch and attach as a product image.
HTTPS URL a human obtained directly from the retailer for this specific product (e.g. a DAM export link), not a URL discovered by crawling. Downloaded synchronously, capped at 20 MB, sniffed from magic bytes, and rejected if the format or dimensions fall outside what the catalog accepts.
2000Which retailer supplied this URL, for provenance and dedup attribution.
ulta_catalog, sephora_catalog