curl --request PUT \
--url https://www.closient.com/products/api/v1/product-links/{link_id} \
--header 'Content-Type: application/json' \
--header 'X-API-Key: <api-key>' \
--data '
{
"label": "Leave a review",
"order": 1
}
'import requests
url = "https://www.closient.com/products/api/v1/product-links/{link_id}"
payload = {
"label": "Leave a review",
"order": 1
}
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({label: 'Leave a review', order: 1})
};
fetch('https://www.closient.com/products/api/v1/product-links/{link_id}', 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/product-links/{link_id}",
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([
'label' => 'Leave a review',
'order' => 1
]),
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/product-links/{link_id}"
payload := strings.NewReader("{\n \"label\": \"Leave a review\",\n \"order\": 1\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://www.closient.com/products/api/v1/product-links/{link_id}")
.header("X-API-Key", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"label\": \"Leave a review\",\n \"order\": 1\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://www.closient.com/products/api/v1/product-links/{link_id}")
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 \"label\": \"Leave a review\",\n \"order\": 1\n}"
response = http.request(request)
puts response.read_body{
"anchor": "review",
"created": "2026-09-01T09:00:00Z",
"description": "",
"display_label": "Rate it on Untappd",
"id": "keATfB8VP2gSjcnTbsMNQL",
"label": "Rate it on Untappd",
"link_type": "gs1:review",
"modified": "2026-09-01T09:00:00Z",
"order": 0,
"product_id": "SBjSX6xUJPPHQKUXBpYX2C",
"url": "https://untappd.com/b/container-brewing-seawise-giant/3533900",
"use_ai_substitution": false
}{
"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": "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"
}Update product link
Partial update — only the keys in the request body are applied. Returns 404 if the link doesn’t exist or the caller lacks CONTRIBUTE permission; 422 on a validation failure (e.g. an unrecognised link_type).
curl --request PUT \
--url https://www.closient.com/products/api/v1/product-links/{link_id} \
--header 'Content-Type: application/json' \
--header 'X-API-Key: <api-key>' \
--data '
{
"label": "Leave a review",
"order": 1
}
'import requests
url = "https://www.closient.com/products/api/v1/product-links/{link_id}"
payload = {
"label": "Leave a review",
"order": 1
}
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({label: 'Leave a review', order: 1})
};
fetch('https://www.closient.com/products/api/v1/product-links/{link_id}', 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/product-links/{link_id}",
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([
'label' => 'Leave a review',
'order' => 1
]),
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/product-links/{link_id}"
payload := strings.NewReader("{\n \"label\": \"Leave a review\",\n \"order\": 1\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://www.closient.com/products/api/v1/product-links/{link_id}")
.header("X-API-Key", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"label\": \"Leave a review\",\n \"order\": 1\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://www.closient.com/products/api/v1/product-links/{link_id}")
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 \"label\": \"Leave a review\",\n \"order\": 1\n}"
response = http.request(request)
puts response.read_body{
"anchor": "review",
"created": "2026-09-01T09:00:00Z",
"description": "",
"display_label": "Rate it on Untappd",
"id": "keATfB8VP2gSjcnTbsMNQL",
"label": "Rate it on Untappd",
"link_type": "gs1:review",
"modified": "2026-09-01T09:00:00Z",
"order": 0,
"product_id": "SBjSX6xUJPPHQKUXBpYX2C",
"url": "https://untappd.com/b/container-brewing-seawise-giant/3533900",
"use_ai_substitution": false
}{
"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": "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"
}Authorizations
Path Parameters
Id of the product link.
22^[23456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{22}$Body
Payload for PUT /product-links/{link_id}.
Partial update — only the keys present in the request body are applied.
product_id/brand_id are not accepted here: a link's owner is fixed
at creation.
GS1 Web Vocabulary link-type CURIE, e.g. gs1:promotion, gs1:loyaltyProgram, gs1:homepage. Validated against the live GS1 Web Vocabulary link-type set — an unknown or resolver-only CURIE (gs1:defaultLink, gs1:handledBy, …) is rejected with 422.
gs1:activityIdeas, gs1:allergenInfo, gs1:appDownload, gs1:backgroundInfo, gs1:brandHomepageClinical, gs1:brandHomepagePatient, gs1:careersInfo, gs1:certificationInfo, gs1:consumerHandlingStorageInfo, gs1:dpp, gs1:eifu, gs1:epcis, gs1:epil, gs1:eventsInfo, gs1:faqs, gs1:hasRetailers, gs1:homepage, gs1:ingredientsInfo, gs1:instructions, gs1:jws, gs1:leaveReview, gs1:locationInfo, gs1:logisticsInfo, gs1:loyaltyProgram, gs1:masterData, gs1:menuInfo, gs1:nutritionalInfo, gs1:openingHoursInfo, gs1:paymentLink, gs1:pip, gs1:promotion, gs1:purchaseSuppliesOrAccessories, gs1:quickStartGuide, gs1:recallStatus, gs1:recipeInfo, gs1:registerProduct, gs1:registryEntry, gs1:relatedImage, gs1:relatedVideo, gs1:reportFound, gs1:review, gs1:safetyInfo, gs1:scheduleTime, gs1:serviceInfo, gs1:smartLabel, gs1:smpc, gs1:socialMedia, gs1:statisticInfo, gs1:subscribe, gs1:support, gs1:sustainabilityInfo, gs1:traceability, gs1:tutorial, gs1:userAgreement, gs1:verificationService, gs1:whatsInTheBox Destination URL. May include {gtin}/{lot}/{serial} substitution tokens to prefill the brand's page from the scan context when use_ai_substitution is set.
2048Link label shown on the hosted page. Defaults to the GS1 link type's title when blank.
120Optional longer description shown alongside the link.
Display order within the link type's group on the hosted page (ascending).
x >= 0When set, treat url as a template and inject the scanned GS1 AIs (GTIN/lot/serial) at render time.
Response
OK
A product link as read from the API. Mirrors :class:apps.products.models.ProductLink.
URL-safe 22-character shortuuid encoding of the row's UUID primary key. Stable across the row's lifetime; suitable for sharing in URLs, log lines, and external SDK clients. Accepted on input as either the shortuuid form or the canonical UUID form (xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx).
22^[23456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{22}$GS1 Web Vocabulary link-type CURIE, e.g. gs1:promotion, gs1:loyaltyProgram, gs1:homepage. Validated against the live GS1 Web Vocabulary link-type set — an unknown or resolver-only CURIE (gs1:defaultLink, gs1:handledBy, …) is rejected with 422.
64Destination URL. May include {gtin}/{lot}/{serial} substitution tokens to prefill the brand's page from the scan context when use_ai_substitution is set.
2048Display order within the link type's group on the hosted page (ascending).
x >= 0When set, treat url as a template and inject the scanned GS1 AIs (GTIN/lot/serial) at render time.
Hosted-page fragment anchor this link's group renders under.
Label to render — the explicit label, else the link type's title.
Server-side ISO 8601 timestamp of creation (UTC).
Server-side ISO 8601 timestamp of last modification (UTC).
URL-safe 22-character shortuuid encoding of the row's UUID primary key. Stable across the row's lifetime; suitable for sharing in URLs, log lines, and external SDK clients. Accepted on input as either the shortuuid form or the canonical UUID form (xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx).
22^[23456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{22}$URL-safe 22-character shortuuid encoding of the row's UUID primary key. Stable across the row's lifetime; suitable for sharing in URLs, log lines, and external SDK clients. Accepted on input as either the shortuuid form or the canonical UUID form (xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx).
22^[23456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{22}$Link label shown on the hosted page. Defaults to the GS1 link type's title when blank.
120Optional longer description shown alongside the link.