Compliance
Check product-level regulatory compliance rules by jurisdiction. Resolve required age tiers, prohibited products, and allowed verification methods.
The Compliance API lets you check regulatory rules for specific products in specific jurisdictions. Use it to:
- Determine the required age tier before creating a verification session
- Check if a product is prohibited in the user's jurisdiction
- Get the allowed verification methods for a jurisdiction
- Handle mixed carts with multiple product types by resolving the most restrictive rules
Widget handles this automatically
If you're using the widget SDK with the products attribute, compliance is resolved automatically — you don't need to call this API directly. This API is for server-side integrations where you create sessions manually.
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
curl "https://api.stile.dev/v1/compliance/check?use_cases=alcohol_delivery&jurisdiction=US-CA" \
-H "Authorization: Bearer vk_test_..."import requests
res = requests.get(
"https://api.stile.dev/v1/compliance/check",
headers={"Authorization": "Bearer vk_test_..."},
params={"use_cases": "alcohol_delivery", "jurisdiction": "US-CA"},
)
result = res.json()
print(result["most_restrictive"]["required_age_tier"])
# "over_21"req, _ := http.NewRequest("GET", "https://api.stile.dev/v1/compliance/check?use_cases=alcohol_delivery&jurisdiction=US-CA", nil)
req.Header.Set("Authorization", "Bearer vk_test_...")
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);
// "over_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.
curl "https://api.stile.dev/v1/compliance/check?use_cases=alcohol_delivery,tobacco_nicotine&jurisdiction=US-UT" \
-H "Authorization: Bearer vk_test_..."import requests
res = requests.get(
"https://api.stile.dev/v1/compliance/check",
headers={"Authorization": "Bearer vk_test_..."},
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.dev/v1/compliance/check?use_cases=alcohol_delivery,tobacco_nicotine&jurisdiction=US-UT", nil)
req.Header.Set("Authorization", "Bearer vk_test_...")
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 — pass the use case, age tier is resolved internally
const session = await stile.verificationSessions.create({
type: "age",
use_case: "alcohol_delivery",
});Response
The response includes 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": "over_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": "over_21",
"allowed_methods": ["mdl", "facial_age", "carrier_lookup", "document_capture"],
"consent_required": false,
"data_retention_days": null,
"any_prohibited": false,
"prohibited_use_cases": []
}
}Per-result fields
| Parameter | Type | Description |
|---|---|---|
use_case | string | The product type that was checked. |
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. "over_21", "over_18". |
allowed_methods | string[] | Verification methods permitted in this jurisdiction for this product. |
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). |
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. |
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
stile.compliance.check()with 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
- Pass the
use_casetostile.verificationSessions.create()— the age tier is resolved internally
Widget flow (automatic):
- Set
products="alcohol_delivery,tobacco_nicotine"on the<stile-button>element - The widget calls the Compliance API internally, resolves the age tier, and creates the session — no server code needed