curl --request POST \
--url https://www.closient.com/products/api/v1/product-links \
--header 'Content-Type: application/json' \
--header 'X-API-Key: <api-key>' \
--data '
{
"label": "Rate it on Untappd",
"link_type": "gs1:review",
"product_id": "SBjSX6xUJPPHQKUXBpYX2C",
"url": "https://untappd.com/b/container-brewing-seawise-giant/3533900"
}
'import requests
url = "https://www.closient.com/products/api/v1/product-links"
payload = {
"label": "Rate it on Untappd",
"link_type": "gs1:review",
"product_id": "SBjSX6xUJPPHQKUXBpYX2C",
"url": "https://untappd.com/b/container-brewing-seawise-giant/3533900"
}
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({
label: 'Rate it on Untappd',
link_type: 'gs1:review',
product_id: 'SBjSX6xUJPPHQKUXBpYX2C',
url: 'https://untappd.com/b/container-brewing-seawise-giant/3533900'
})
};
fetch('https://www.closient.com/products/api/v1/product-links', 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",
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([
'label' => 'Rate it on Untappd',
'link_type' => 'gs1:review',
'product_id' => 'SBjSX6xUJPPHQKUXBpYX2C',
'url' => 'https://untappd.com/b/container-brewing-seawise-giant/3533900'
]),
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"
payload := strings.NewReader("{\n \"label\": \"Rate it on Untappd\",\n \"link_type\": \"gs1:review\",\n \"product_id\": \"SBjSX6xUJPPHQKUXBpYX2C\",\n \"url\": \"https://untappd.com/b/container-brewing-seawise-giant/3533900\"\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/product-links")
.header("X-API-Key", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"label\": \"Rate it on Untappd\",\n \"link_type\": \"gs1:review\",\n \"product_id\": \"SBjSX6xUJPPHQKUXBpYX2C\",\n \"url\": \"https://untappd.com/b/container-brewing-seawise-giant/3533900\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://www.closient.com/products/api/v1/product-links")
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 \"label\": \"Rate it on Untappd\",\n \"link_type\": \"gs1:review\",\n \"product_id\": \"SBjSX6xUJPPHQKUXBpYX2C\",\n \"url\": \"https://untappd.com/b/container-brewing-seawise-giant/3533900\"\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"
}Create product link
Create a new CTA link for a product or brand. Returns 404 if the referenced product/brand doesn’t exist or the caller lacks CONTRIBUTE permission on its owning organization; 422 if link_type isn’t a recognised GS1 Web Vocabulary CURIE.
curl --request POST \
--url https://www.closient.com/products/api/v1/product-links \
--header 'Content-Type: application/json' \
--header 'X-API-Key: <api-key>' \
--data '
{
"label": "Rate it on Untappd",
"link_type": "gs1:review",
"product_id": "SBjSX6xUJPPHQKUXBpYX2C",
"url": "https://untappd.com/b/container-brewing-seawise-giant/3533900"
}
'import requests
url = "https://www.closient.com/products/api/v1/product-links"
payload = {
"label": "Rate it on Untappd",
"link_type": "gs1:review",
"product_id": "SBjSX6xUJPPHQKUXBpYX2C",
"url": "https://untappd.com/b/container-brewing-seawise-giant/3533900"
}
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({
label: 'Rate it on Untappd',
link_type: 'gs1:review',
product_id: 'SBjSX6xUJPPHQKUXBpYX2C',
url: 'https://untappd.com/b/container-brewing-seawise-giant/3533900'
})
};
fetch('https://www.closient.com/products/api/v1/product-links', 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",
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([
'label' => 'Rate it on Untappd',
'link_type' => 'gs1:review',
'product_id' => 'SBjSX6xUJPPHQKUXBpYX2C',
'url' => 'https://untappd.com/b/container-brewing-seawise-giant/3533900'
]),
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"
payload := strings.NewReader("{\n \"label\": \"Rate it on Untappd\",\n \"link_type\": \"gs1:review\",\n \"product_id\": \"SBjSX6xUJPPHQKUXBpYX2C\",\n \"url\": \"https://untappd.com/b/container-brewing-seawise-giant/3533900\"\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/product-links")
.header("X-API-Key", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"label\": \"Rate it on Untappd\",\n \"link_type\": \"gs1:review\",\n \"product_id\": \"SBjSX6xUJPPHQKUXBpYX2C\",\n \"url\": \"https://untappd.com/b/container-brewing-seawise-giant/3533900\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://www.closient.com/products/api/v1/product-links")
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 \"label\": \"Rate it on Untappd\",\n \"link_type\": \"gs1:review\",\n \"product_id\": \"SBjSX6xUJPPHQKUXBpYX2C\",\n \"url\": \"https://untappd.com/b/container-brewing-seawise-giant/3533900\"\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
Body
- ProductLinkCreate
- ProductLinkCreate
- ProductLinkCreate
- ProductLinkCreate
Payload for POST /product-links.
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.
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.
2048URL-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.
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
Created
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.