Compliance
Look up regulatory rules by product type and jurisdiction — required age tiers, prohibited products, allowed verification methods, and most-restrictive resolution for mixed carts.
The Compliance API tells you what the rules are before you ask anyone to verify. Give it one or more product types and a jurisdiction, and it returns the required age tier, whether the product is prohibited, and which verification methods that jurisdiction permits. Use it to:
- Pre-check carts — catch prohibited products before checkout, not after the user has verified
- Show age requirements in your UI — display "21+ required in California" before launching verification
- Pick between workflows — when you run multiple published workflows, choose the one whose use case matches what the rules require
- Resolve mixed carts — multiple product types collapse into one
most_restrictivesummary: the highest age tier, the intersected allowed methods
Sessions handle this automatically
When you create a verification session, compliance is resolved internally from the workflow's use case and the user's jurisdiction — you don't need to call this API first. Use it when you want to inspect the rules yourself: pre-checking carts for prohibited products, showing age requirements in your UI, or picking between workflows.
Check compliance
/v1/compliance/checkReturns compliance details for one or more product types in a jurisdiction, plus a most_restrictive summary that merges the rules across all products.
| Parameter | Type | Description |
|---|---|---|
use_casesrequired | string | Comma-separated product types to check (max 10). E.g. "alcohol_delivery,tobacco_nicotine". |
jurisdiction | string | Jurisdiction to check against (e.g. "US-CA", "US-UT"). If omitted, auto-detected from request IP / geo headers. |
Available product types
| Product type | Description |
|---|---|
alcohol_delivery | Alcohol delivery (online orders) |
alcohol_in_person | Alcohol retail (point-of-sale) |
cannabis_dispensary | Cannabis dispensary sales |
cannabis_delivery | Cannabis delivery |
gambling_online | Online gambling / iGaming |
gambling_in_person | In-person gambling / casinos |
tobacco_nicotine | Tobacco and nicotine products |
adult_content | Adult content / pornography |
social_media | Social media age gates |
firearms | Firearms sales |
Example: single product
Check one product type against an explicit jurisdiction:
curl "https://api.stile.id/v1/compliance/check?use_cases=alcohol_delivery&jurisdiction=US-CA" \
-H "Authorization: Bearer stile_sk_..."import requests
res = requests.get(
"https://api.stile.id/v1/compliance/check",
headers={"Authorization": "Bearer stile_sk_..."},
params={"use_cases": "alcohol_delivery", "jurisdiction": "US-CA"},
)
result = res.json()
print(result["most_restrictive"]["required_age_tier"])
# "min_age_21"req, _ := http.NewRequest("GET", "https://api.stile.id/v1/compliance/check?use_cases=alcohol_delivery&jurisdiction=US-CA", nil)
req.Header.Set("Authorization", "Bearer stile_sk_...")
res, _ := http.DefaultClient.Do(req)const result = await stile.compliance.check({
use_cases: ["alcohol_delivery"],
jurisdiction: "US-CA",
});
console.log(result.most_restrictive.required_age_tier);
// "min_age_21"Example: mixed cart
When a cart contains multiple product types, the API returns per-product details and a merged most_restrictive summary with the highest age tier and intersected allowed methods. If any single product is prohibited, any_prohibited flips to true and the offending product types are listed in prohibited_use_cases.
curl "https://api.stile.id/v1/compliance/check?use_cases=alcohol_delivery,tobacco_nicotine&jurisdiction=US-UT" \
-H "Authorization: Bearer stile_sk_..."import requests
res = requests.get(
"https://api.stile.id/v1/compliance/check",
headers={"Authorization": "Bearer stile_sk_..."},
params={
"use_cases": "alcohol_delivery,tobacco_nicotine",
"jurisdiction": "US-UT",
},
)
result = res.json()
if result["most_restrictive"]["any_prohibited"]:
print("Cannot sell:", result["most_restrictive"]["prohibited_use_cases"])req, _ := http.NewRequest("GET", "https://api.stile.id/v1/compliance/check?use_cases=alcohol_delivery,tobacco_nicotine&jurisdiction=US-UT", nil)
req.Header.Set("Authorization", "Bearer stile_sk_...")
res, _ := http.DefaultClient.Do(req)const result = await stile.compliance.check({
use_cases: ["alcohol_delivery", "tobacco_nicotine"],
jurisdiction: "US-UT",
});
// Check if any products are prohibited in this jurisdiction
if (result.most_restrictive.any_prohibited) {
console.log("Cannot sell:", result.most_restrictive.prohibited_use_cases);
// Remove prohibited items from the cart
}
// Per-product details
for (const r of result.results) {
console.log(r.use_case, r.prohibited ? "PROHIBITED" : r.required_age_tier);
}
// Create a session — the workflow carries the use case, and the
// age tier is resolved internally
const session = await stile.verificationSessions.create({
type: "age",
workflow_id: "wf_YOUR_WORKFLOW_ID",
});Response
The response includes the resolved jurisdiction, a results array (one entry per product type), and a most_restrictive summary.
{
"jurisdiction": "US-CA",
"jurisdiction_source": "explicit",
"results": [
{
"use_case": "alcohol_delivery",
"jurisdiction": "US-CA",
"prohibited": false,
"prohibited_reason": null,
"required_age_tier": "min_age_21",
"allowed_methods": ["mdl", "facial_age", "carrier_lookup", "document_capture"],
"mdl_acceptance_status": "supplementary",
"governing_regulator": "State Alcohol Beverage Control Boards",
"consent_required": false,
"credential_validity_days": 365,
"rule_version": "2026-04-02"
}
],
"most_restrictive": {
"required_age_tier": "min_age_21",
"allowed_methods": ["mdl", "facial_age", "carrier_lookup", "document_capture"],
"consent_required": false,
"data_retention_days": null,
"any_prohibited": false,
"prohibited_use_cases": []
}
}Top-level fields
| Parameter | Type | Description |
|---|---|---|
jurisdiction | string | The jurisdiction the check was resolved against. |
jurisdiction_source | string | "explicit" when you passed a jurisdiction, "auto_detected" when it was resolved from the request. |
results | object[] | One entry per product type checked. See per-result fields below. |
most_restrictive | object | Merged summary across all product types. See summary fields below. |
Per-result fields
| Parameter | Type | Description |
|---|---|---|
use_case | string | The product type that was checked. |
jurisdiction | string | The jurisdiction this rule was evaluated against. |
prohibited | boolean | Whether this product is prohibited in the jurisdiction. |
prohibited_reason | string | null | Why the product is prohibited (e.g. state law citation). |
required_age_tier | string | null | The age tier required for this product. E.g. "min_age_21", "min_age_18". |
allowed_methods | string[] | Verification methods permitted in this jurisdiction for this product. |
mdl_acceptance_status | string | How mobile driver's licenses are treated under this rule: "full", "supplementary", "not_recognized", or "unknown". |
governing_regulator | string | null | The regulatory body (e.g. State ABC, FDA). |
consent_required | boolean | Whether explicit user consent is required. |
penalty_description | string | null | Penalty for non-compliance (e.g. "Up to $10K/day per violation"). |
penalty_type | string | null | "CIVIL", "CRIMINAL", or "BOTH". |
credential_validity_days | number | How long a verification credential remains valid (in days). When a user verifies, their credential expires after this many days — forcing re-verification. Varies by jurisdiction and product type (e.g., 30 days for gambling, 365 for alcohol). |
rule_version | string | null | Version identifier of the rule set this result was computed from. |
Most-restrictive summary fields
| Parameter | Type | Description |
|---|---|---|
required_age_tier | string | null | The highest age tier across all non-prohibited products. |
allowed_methods | string[] | Intersection of allowed methods across all non-prohibited products. |
any_prohibited | boolean | True if any product type is prohibited in this jurisdiction. |
prohibited_use_cases | string[] | List of product types that are prohibited. |
consent_required | boolean | True if any product requires explicit consent. |
data_retention_days | number | null | Shortest data retention limit across all products. |
Age tiers are ordered: min_age_13 < min_age_16 < min_age_18 < min_age_21. The summary returns the highest tier required by any non-prohibited product in the cart — a verification at a higher tier satisfies any lower requirement, never the reverse.
Typical integration flow
The Compliance API is informational — it tells you the rules but doesn't enforce them. Your application decides what to do with the results.
Server-side flow:
- Call
GET /v1/compliance/checkwith the product types in the user's cart and their jurisdiction - If any products are prohibited, remove them from the cart or show an error before starting verification
- Create the session with the matching
workflow_id— the age tier is resolved internally from the workflow's use case
Widget flow (automatic):
- Point the widget at a published workflow (
workflow-id, or let yoursession-urlendpoint choose one) - Session creation resolves compliance from the workflow internally — no extra API call needed
Next steps
Verification Sessions
Create and manage sessions — the workflow resolves compliance for you at session time.
Integration Guide
Backend session creation, prohibited products, and returning users end to end.
Node.js private preview
Reference for approved preview users; not publicly installable from npm.
API Overview
Authentication, error shapes, rate limits, and idempotency across the API.