curl --request GET \
--url https://www.closient.com/resolver/api/v1/resolution-rules/{rule_id} \
--header 'X-API-Key: <api-key>'import requests
url = "https://www.closient.com/resolver/api/v1/resolution-rules/{rule_id}"
headers = {"X-API-Key": "<api-key>"}
response = requests.get(url, headers=headers)
print(response.text)const options = {method: 'GET', headers: {'X-API-Key': '<api-key>'}};
fetch('https://www.closient.com/resolver/api/v1/resolution-rules/{rule_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/resolver/api/v1/resolution-rules/{rule_id}",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => [
"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"
"net/http"
"io"
)
func main() {
url := "https://www.closient.com/resolver/api/v1/resolution-rules/{rule_id}"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("X-API-Key", "<api-key>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.get("https://www.closient.com/resolver/api/v1/resolution-rules/{rule_id}")
.header("X-API-Key", "<api-key>")
.asString();require 'uri'
require 'net/http'
url = URI("https://www.closient.com/resolver/api/v1/resolution-rules/{rule_id}")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
request["X-API-Key"] = '<api-key>'
response = http.request(request)
puts response.read_body{
"annual_end_mmdd": "01-05",
"annual_start_mmdd": "11-15",
"created": "2025-10-01T09:00:00Z",
"custom_url": "https://acmesnacks.com/holiday-promo",
"destination_type": "CUSTOM_URL",
"enabled": true,
"metadata": {
"order_id": "6735"
},
"modified": "2025-10-15T14:30:00Z",
"on_custom_url_dead": "SKIP_RULE",
"order_index": 1,
"organization_id": "b2c3d4e5-f678-9012-abcd-ef2345678901",
"product_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"scope_id": "00012345678905",
"scope_type": "PRODUCT",
"timezone": "America/New_York"
}{
"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"
}Get resolution rule
Fetch a single resolution rule by its short_id. Returns 404 if the rule does not exist or belongs to an organization the caller cannot see.
curl --request GET \
--url https://www.closient.com/resolver/api/v1/resolution-rules/{rule_id} \
--header 'X-API-Key: <api-key>'import requests
url = "https://www.closient.com/resolver/api/v1/resolution-rules/{rule_id}"
headers = {"X-API-Key": "<api-key>"}
response = requests.get(url, headers=headers)
print(response.text)const options = {method: 'GET', headers: {'X-API-Key': '<api-key>'}};
fetch('https://www.closient.com/resolver/api/v1/resolution-rules/{rule_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/resolver/api/v1/resolution-rules/{rule_id}",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => [
"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"
"net/http"
"io"
)
func main() {
url := "https://www.closient.com/resolver/api/v1/resolution-rules/{rule_id}"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("X-API-Key", "<api-key>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.get("https://www.closient.com/resolver/api/v1/resolution-rules/{rule_id}")
.header("X-API-Key", "<api-key>")
.asString();require 'uri'
require 'net/http'
url = URI("https://www.closient.com/resolver/api/v1/resolution-rules/{rule_id}")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
request["X-API-Key"] = '<api-key>'
response = http.request(request)
puts response.read_body{
"annual_end_mmdd": "01-05",
"annual_start_mmdd": "11-15",
"created": "2025-10-01T09:00:00Z",
"custom_url": "https://acmesnacks.com/holiday-promo",
"destination_type": "CUSTOM_URL",
"enabled": true,
"metadata": {
"order_id": "6735"
},
"modified": "2025-10-15T14:30:00Z",
"on_custom_url_dead": "SKIP_RULE",
"order_index": 1,
"organization_id": "b2c3d4e5-f678-9012-abcd-ef2345678901",
"product_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"scope_id": "00012345678905",
"scope_type": "PRODUCT",
"timezone": "America/New_York"
}{
"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
URL-safe short_id of the resolution rule (22-char shortuuid).
22^[23456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{22}$Response
OK
A resolution rule as read from the API.
Returned by GET /resolution-rules/{id} and the list/reorder
endpoints. Mirrors :class:apps.resolver.models.ResolutionRule.
C-4190: scope_id is an API-level alias, not a column. It resolves
through resolve_scope_id below to ResolutionRule.scope_ref_key --
the canonical text of the rule's typed scope FK. The emitted string is
identical to what the dropped column held, so this is deliberately not a
breaking change: external consumers are not made to migrate because we
changed how the scope is stored.
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}$Hierarchy level at which this rule applies. Mirrors apps.resolver.models.ScopeType. Specificity ascends ORGANIZATION → BRAND → PRODUCT → BATCH → SERIAL — the evaluator walks scopes most-specific first, so a rule scoped to a single serial beats a rule scoped to the whole brand.
ORGANIZATION, BRAND, PRODUCT, BATCH, SERIAL Evaluation order within the rule's (scope_type, scope_id) bucket. Lower values are evaluated first; the first matching rule wins. Unique per (scope_type, scope_id, order_index) — duplicates are rejected by a per-scope unique index in the database.
Whether the rule is currently active. Disabled rules are skipped by the evaluator but kept in the listing for easy re-enable.
Where to send the resolution. HOSTED_PAGE renders the Closient product page; CUSTOM_URL 302s to custom_url.
HOSTED_PAGE, CUSTOM_URL Behavior when the URL-health monitor has marked custom_url dead. SKIP_RULE falls through to the next matching rule; FALLBACK_TO_HOSTED short-circuits to the Closient-hosted product page. Live URLs are followed regardless of this setting.
SKIP_RULE, FALLBACK_TO_HOSTED Server-side ISO 8601 timestamp of when the rule was created (UTC).
Server-side ISO 8601 timestamp of the rule's last modification (UTC).
Developer-attached key/value data attached to this object. Up to 50 keys; key max 40 chars, value max 500 chars.
Show child attributes
Show child attributes
Whether this is the implicit, system-managed default rule rather than a user-created one. Always false for rules returned by the list/CRUD endpoints — those are all user-managed DB rows. The default rule (the baseline hosted-page fallback applied when no other rule matches) is served separately by GET .../resolution-rules/default with system set to true; it cannot be created, edited, deleted, or reordered.
Identifier of the scoped entity. Required when scope_type != 'ORGANIZATION' (organization-wide rules use the implicit organization from the URL). Which entity it names depends on scope_type: the brand for BRAND, the product for PRODUCT, the lot/serial for BATCH/SERIAL, the group for LOT_GROUP/SERIAL_GROUP. Accepted in either the 22-character short id or the canonical 36-character UUID form; responses always return the short id. The entity must exist and belong to the calling organization -- an id that names nothing is rejected with a 422 rather than stored (C-4187). Internally the scope is a typed foreign key, not this string (C-4190); scope_id remains the request/response field so consumers are not asked to migrate for a storage change.
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}$Inclusive lower bound of the rule's active window — the rule matches when now() >= absolute_start_at. null means no lower bound. Compared in the rule's timezone.
Exclusive upper bound of the rule's active window — the rule matches when now() < absolute_end_at. null means no upper bound. Compared in the rule's timezone.
Annually-recurring start date in MM-DD format (e.g. 11-15). When annual_start_mmdd is later in the year than annual_end_mmdd the window wraps year-end (e.g. 11-15 → 01-05 is mid-November to early January). null means no annual constraint.
5^(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01])$Annually-recurring end date in MM-DD format (e.g. 01-05). See annual_start_mmdd for wrap-around semantics. null means no annual constraint. Both ends should be set together; setting only one is accepted by the API but ignored by the evaluator.
5^(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01])$Days the rule may match, using Python's datetime.weekday() convention: 0 = Monday, 6 = Sunday. Duplicates are deduplicated and the result is sorted ascending. null (or empty list) means every day matches. Evaluated in the rule's timezone.
Day-of-week value for ResolutionRule.days_of_week.
Uses the Python datetime.weekday() convention: Monday=0,
Sunday=6. Stored as small integers in the underlying
ArrayField(SmallIntegerField); exposed as a typed enum so the
OpenAPI spec advertises the full valid range (enum: [0..6])
instead of the previous "any int".
0, 1, 2, 3, 4, 5, 6 Inclusive lower bound on time-of-day, HH:MM 24-hour. Rule matches when current_time >= time_of_day_start in the rule's timezone. When start is later than end the window wraps midnight (e.g. 22:00 → 02:00 is the late-night window). null means no lower bound.
Exclusive upper bound on time-of-day, HH:MM 24-hour. Rule matches when current_time < time_of_day_end in the rule's timezone. See time_of_day_start for wrap-around semantics. null means no upper bound.
IANA timezone name used to evaluate every other time-criteria field (annual_*, days_of_week, time_of_day_*, absolute_*). E.g. America/New_York, Europe/Berlin, UTC. Falls back to the organization's OrganizationResolverSettings.routing_timezone when null.
50GS1 Web Vocabulary CURIE that the rule applies to (e.g. gs1:pip for Product Information Page, gs1:hasRecallInformation for recall redirects). When present the rule only matches resolutions for that link type; null matches all link types. See the GS1 Web Vocabulary for the full set of CURIEs.
100Allow list of ISO 3166-1 alpha-2 country codes the rule applies to. Matched against the IP-derived country of the scan request. null or empty list = any country. Case-insensitive.
Allow list of subdivision (state / province / region) names the rule applies to. Matched against the IP-derived region name of the scan request. null or empty list = any region. Case-insensitive.
Allow list of city names the rule applies to. Matched against the IP-derived city name of the scan request. null or empty list = any city. Case-insensitive.
External URL to redirect to. Required when destination_type == 'CUSTOM_URL' (enforced both at the schema level and by a database CHECK constraint). Maximum 2048 characters. On write the URL is stored as a reusable custom-URL catalog entry for the organization (deduped by URL); on read it reflects that catalog entry. Health is monitored out-of-band; see on_custom_url_dead for failure behavior.
2048Optional section anchor that deep-links a hosted-page scan to a specific kebab-case section of the product page (e.g. where-to-buy, ingredients, dscsa-recall-status), or to one specific brand CTA link within the brand-links section, addressed by its bare camelCase GS1 link-type short name (e.g. review, leaveReview, promotion). When set on a HOSTED_PAGE rule the resolver appends #anchor to the redirect URL so the browser scrolls directly to that section or link. Must be null whenever destination_type != 'HOSTED_PAGE' — for CUSTOM_URL rules, embed any anchor directly in custom_url. The frontend resolver-config picker is responsible for enumerating the anchors available on the resolved product; canonical section anchors are defined in apps.products.sections.ProductSection, and canonical per-link anchors by apps.resolver.gs1_link_types.get_product_link_anchor_short_names.
accessories, activityIdeas, alerts, apps, backgroundInfo, brand-links, brandHomepageClinical, brandHomepagePatient, careersInfo, certifications, claims, consumables, dscsa-drug-id, dscsa-recall-status, dscsa-safety, dscsa-traceability, epcis, epil, eventsInfo, expiry-notice, faq, firmware, gallery, homepage, ingredients, instructions, jws, leaveReview, locationInfo, logisticsInfo, loyaltyProgram, manual, masterData, menuInfo, nutrition, openingHoursInfo, parts, paymentLink, product-info, promotion, quick-facts, recipes, recycling, register-product, registryEntry, reportFound, retailer-badges, review, safety-notices, scheduleTime, sensitivities, smpc, socials, statisticInfo, subscribe, traceability, unverified-unit, userAgreement, verificationService, warranty, whatsInTheBox, where-to-buy