curl --request POST \
--url https://www.closient.com/compliance/api/v1/organizations/{organization_id}/recalls/{recall_id}/products/{gtin}/scopes \
--header 'Content-Type: application/json' \
--header 'X-API-Key: <api-key>' \
--data '
{
"kind": "LOT_LIST",
"values": [
"L2405A",
"L2405B"
]
}
'import requests
url = "https://www.closient.com/compliance/api/v1/organizations/{organization_id}/recalls/{recall_id}/products/{gtin}/scopes"
payload = {
"kind": "LOT_LIST",
"values": ["L2405A", "L2405B"]
}
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({kind: 'LOT_LIST', values: ['L2405A', 'L2405B']})
};
fetch('https://www.closient.com/compliance/api/v1/organizations/{organization_id}/recalls/{recall_id}/products/{gtin}/scopes', 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/compliance/api/v1/organizations/{organization_id}/recalls/{recall_id}/products/{gtin}/scopes",
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([
'kind' => 'LOT_LIST',
'values' => [
'L2405A',
'L2405B'
]
]),
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/compliance/api/v1/organizations/{organization_id}/recalls/{recall_id}/products/{gtin}/scopes"
payload := strings.NewReader("{\n \"kind\": \"LOT_LIST\",\n \"values\": [\n \"L2405A\",\n \"L2405B\"\n ]\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/compliance/api/v1/organizations/{organization_id}/recalls/{recall_id}/products/{gtin}/scopes")
.header("X-API-Key", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"kind\": \"LOT_LIST\",\n \"values\": [\n \"L2405A\",\n \"L2405B\"\n ]\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://www.closient.com/compliance/api/v1/organizations/{organization_id}/recalls/{recall_id}/products/{gtin}/scopes")
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 \"kind\": \"LOT_LIST\",\n \"values\": [\n \"L2405A\",\n \"L2405B\"\n ]\n}"
response = http.request(request)
puts response.read_body{
"date_ai": "",
"id": "s1c2o3p4e5i6d7s8h9o0rt",
"is_active": true,
"kind": "LOT_LIST",
"note": "",
"status": "CONFIRMED",
"values": [
"L2405A",
"L2405B"
]
}{
"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"
}Author a recall scope
Narrow an open recall to the lots, serials, production sites or printed-date window that are actually affected, so unaffected units scan clean. The body is the same scope object used to issue a brand recall. Takes effect on the next scan: a scoped recall changes what consumers are told. Requires the product to be on enhanced resolution (422 otherwise) and the Owner, Manager or Editor role; a read-only key is refused with 403. Authoring does not send any notification.
curl --request POST \
--url https://www.closient.com/compliance/api/v1/organizations/{organization_id}/recalls/{recall_id}/products/{gtin}/scopes \
--header 'Content-Type: application/json' \
--header 'X-API-Key: <api-key>' \
--data '
{
"kind": "LOT_LIST",
"values": [
"L2405A",
"L2405B"
]
}
'import requests
url = "https://www.closient.com/compliance/api/v1/organizations/{organization_id}/recalls/{recall_id}/products/{gtin}/scopes"
payload = {
"kind": "LOT_LIST",
"values": ["L2405A", "L2405B"]
}
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({kind: 'LOT_LIST', values: ['L2405A', 'L2405B']})
};
fetch('https://www.closient.com/compliance/api/v1/organizations/{organization_id}/recalls/{recall_id}/products/{gtin}/scopes', 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/compliance/api/v1/organizations/{organization_id}/recalls/{recall_id}/products/{gtin}/scopes",
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([
'kind' => 'LOT_LIST',
'values' => [
'L2405A',
'L2405B'
]
]),
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/compliance/api/v1/organizations/{organization_id}/recalls/{recall_id}/products/{gtin}/scopes"
payload := strings.NewReader("{\n \"kind\": \"LOT_LIST\",\n \"values\": [\n \"L2405A\",\n \"L2405B\"\n ]\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/compliance/api/v1/organizations/{organization_id}/recalls/{recall_id}/products/{gtin}/scopes")
.header("X-API-Key", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"kind\": \"LOT_LIST\",\n \"values\": [\n \"L2405A\",\n \"L2405B\"\n ]\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://www.closient.com/compliance/api/v1/organizations/{organization_id}/recalls/{recall_id}/products/{gtin}/scopes")
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 \"kind\": \"LOT_LIST\",\n \"values\": [\n \"L2405A\",\n \"L2405B\"\n ]\n}"
response = http.request(request)
puts response.read_body{
"date_ai": "",
"id": "s1c2o3p4e5i6d7s8h9o0rt",
"is_active": true,
"kind": "LOT_LIST",
"note": "",
"status": "CONFIRMED",
"values": [
"L2405A",
"L2405B"
]
}{
"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
Identifier of the organization.
22^[23456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{22}$Identifier of the recall.
22^[23456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{22}$GTIN of your affected product.
8 - 14^[0-9]{8}$|^[0-9]{12,14}$Body
The same scope body, with the per-kind rules checked by the route instead of at parse time.
The kind-dependent rules (a value list for a lot scope, a GLN check digit, a window that ends after it starts) cannot be written in the published JSON Schema, so a body that satisfies the schema can still fail them. Checking at parse time would answer 422 before the route has resolved the organization, the recall and the caller's role; the rules are applied after those checks, so a caller is told about a recall they cannot see (404) or a role they lack (403) before being told their body is malformed.
Which predicate this scope is. Determines whether values or the date fields apply.
LOT_LIST, SERIAL_SET, PRODUCTION_SITE, DATE_WINDOW For LOT_LIST / SERIAL_SET / PRODUCTION_SITE: the recalled lot (AI 10), serial (AI 21) or production-site GLN (AI 416) values. A PRODUCTION_SITE value must be a 13-digit GLN with a valid check digit. Matched exactly and case-sensitively (GS1 CSET 82); surrounding whitespace is trimmed and duplicates are dropped. At least one value is required for these kinds; the maximum list size is server-configured (see RECALL_SCOPE_MAX_VALUES). Ignored for DATE_WINDOW.
10000^[^\x00]{0,}$For DATE_WINDOW: which printed date AI the window applies to (15 or 17). Required for that kind.
15, 17 For DATE_WINDOW: inclusive start of the affected printed-date range (YYYY-MM-DD). Required for that kind.
For DATE_WINDOW: inclusive end of the affected printed-date range (YYYY-MM-DD). Must be >= start. Required for that kind.
Response
Created
A scope on a recall for one of your products, confirmed or suggested.
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}$DATE_WINDOW, LOT_LIST, SERIAL_SET or PRODUCTION_SITE.
CONFIRMED scopes narrow the live recall verdict. SUGGESTED is a regulator-fed draft that narrows nothing until you confirm it.
False once deactivated or dismissed; kept for audit, never deleted.
Lot, serial or production-site GLN values; empty for a date window.
Printed-date AI (15 or 17) of a date window; empty otherwise.
Free-text note on the scope.
Inclusive start of a date window.
Inclusive end of a date window.
Extraction confidence from 0.0 to 1.0 for a suggestion; null for a scope you authored.