Skip to main content
GET
Get resolution rule

Authorizations

X-API-Key
string
header
required

Path Parameters

rule_id
string<shortuuid>
required

URL-safe short_id of the resolution rule (12-char nanoid).

Required string length: 22
Pattern: ^[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.

id
string<shortuuid>
required

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).

Required string length: 22
Pattern: ^[23456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{22}$
scope_type
enum<string>
required

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.

Available options:
ORGANIZATION,
BRAND,
PRODUCT,
BATCH,
SERIAL
order_index
integer
required

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.

enabled
boolean
required

Whether the rule is currently active. Disabled rules are skipped by the evaluator but kept in the listing for easy re-enable.

destination_type
enum<string>
required

Where to send the resolution. HOSTED_PAGE renders the Closient product page; CUSTOM_URL 302s to custom_url.

Available options:
HOSTED_PAGE,
CUSTOM_URL
on_custom_url_dead
enum<string>
required

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.

Available options:
SKIP_RULE,
FALLBACK_TO_HOSTED
created
string<date-time>
required

Server-side ISO 8601 timestamp of when the rule was created (UTC).

modified
string<date-time>
required

Server-side ISO 8601 timestamp of the rule's last modification (UTC).

metadata
Metadata · object

Developer-attached key/value data attached to this object. Up to 50 keys; key max 40 chars, value max 500 chars.

system
boolean
default:false

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.

scope_id
string | null

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.

organization_id
string<shortuuid> | null

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).

Required string length: 22
Pattern: ^[23456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{22}$
product_id
string<shortuuid> | null

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).

Required string length: 22
Pattern: ^[23456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{22}$
absolute_start_at
string<date-time> | null

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.

absolute_end_at
string<date-time> | null

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.

annual_start_mmdd
string | null

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-1501-05 is mid-November to early January). null means no annual constraint.

Maximum string length: 5
Pattern: ^(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01])$
annual_end_mmdd
string | null

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.

Maximum string length: 5
Pattern: ^(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01])$
days_of_week
enum<integer>[] | null

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".

Available options:
0,
1,
2,
3,
4,
5,
6
time_of_day_start
string<time> | null

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:0002:00 is the late-night window). null means no lower bound.

time_of_day_end
string<time> | null

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.

timezone
string | null

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.

Maximum string length: 50

GS1 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.

Maximum string length: 100
location_countries
string[] | null

Allow 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.

location_regions
string[] | null

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.

location_cities
string[] | null

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.

custom_url
string | null

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.

Maximum string length: 2048
section_anchor
string | null

Optional kebab-case section anchor that deep-links a hosted-page scan to a specific section of the product page (e.g. where-to-buy, ingredients, dscsa-recall-status). When set on a HOSTED_PAGE rule the resolver appends #anchor to the redirect URL so the browser scrolls directly to that section. 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 sections available on the resolved product; canonical anchor IDs are defined in apps.products.sections.ProductSection.

Maximum string length: 64
Pattern: ^[a-z0-9](?:[a-z0-9-]{0,62}[a-z0-9])?$