API reference
Policies
Policies, their versions and the shipped presets.
List policies
/v1/policiesRequest
curl "https://api.getvindex.com/v1/policies" \
-H "Authorization: Bearer $VINDEX_KEY"Response 200
Every policy of the tenant, newest first.
{
"data": [
{
"id": "pol_3f2a0c9e8b7d4c6a9f1e2d3c4b5a6978",
"name": "adult-platform",
"preset": "adult-platform",
"current_version": 1,
"default": true,
"dry_run_version": null,
"created_at": "2026-09-17T08:51:06.000Z"
}
]
}Errors
400Invalid request (malformed JSON, or the body/query failed validation).401Missing, malformed, unknown or revoked API key.429Rate limit exceeded for this API key. SeeRetry-After.
Create a policy from a preset or a document
/v1/policiesCreates the policy with version 1 published. The tenant's first policy becomes its default. Starter includes one policy.
Body
namestringDefaults to the preset's or document's name. 1–120 chars
presetstringStart from a preset (GET /v1/presets). Exactly one of
presetandpolicy.policyPolicyDocumentpolicy.version1requiredpolicy.namestringrequiredpolicy.checksmap of PolicyCheckRulerequiredPer check id (
minors_sexual,adult,real_person,copyrighted_ip).minors_sexualis required and pinned: act 0.5, review 0.3, on_act block.policy.checks.{key}.enabledbooleanpolicy.checks.{key}.actnumberrequired0–1
policy.checks.{key}.reviewnumberrequired0–1
policy.checks.{key}.on_actActionrequiredpolicy.checks.{key}.on_reviewActionrequiredpolicy.adultobjectrequiredHighest adult level (1–5) allowed before
checks.adult.on_actapplies. Interim fixed 0.2-wide bands over the adult score, pending issue #10.policy.adult.max_levelintegerrequired1–5
policy.youth_coded_adult"review" | "block"requiredpolicy.webhooksobject[]requiredpolicy.webhooks[].urlstringrequiredpolicy.webhooks[].events"block" | "review" | "allow" | "tag" | "review.verdict"[]requiredpolicy.webhooks[].secretstringrequiredHMAC-SHA256 signing secret, at least 16 characters. Write-only: reads return "redacted", and sending "redacted" back keeps the stored secret for that url.
policy.tagsmap of objectrequiredpolicy.tags.{key}.descriptionstringdefaultbooleanMake this the tenant's default policy. A tenant's first policy always becomes the default.
Request
curl -X POST "https://api.getvindex.com/v1/policies" \
-H "Authorization: Bearer $VINDEX_KEY" \
-H "Content-Type: application/json" \
-d '{"preset":"adult-platform"}'Response 201
Created.
{
"id": "pol_3f2a0c9e8b7d4c6a9f1e2d3c4b5a6978",
"name": "adult-platform",
"preset": "adult-platform",
"current_version": 1,
"default": true,
"dry_run_version": null,
"created_at": "2026-09-17T08:51:06.000Z",
"policy": {
"version": 1,
"name": "adult-platform",
"checks": {
"minors_sexual": {
"act": 0.5,
"review": 0.3,
"on_act": {
"type": "block"
},
"on_review": {
"type": "review"
}
},
"adult": {
"act": 0.7,
"review": 0.35,
"on_act": {
"type": "tag",
"tag": "adult"
},
"on_review": {
"type": "tag",
"tag": "adult-review"
}
},
"real_person": {
"act": 0.5,
"review": 0.3,
"on_act": {
"type": "review"
},
"on_review": {
"type": "tag",
"tag": "real-person"
}
},
"copyrighted_ip": {
"act": 0.5,
"review": 0.3,
"on_act": {
"type": "tag",
"tag": "ip"
},
"on_review": {
"type": "tag",
"tag": "ip-review"
}
}
},
"adult": {
"max_level": 5
},
"youth_coded_adult": "review",
"webhooks": [],
"tags": {
"adult": {
"description": "NSFW: nudity or sexual content, auto-tagged, not blocked"
},
"adult-review": {
"description": "borderline NSFW, below the adult act threshold"
},
"real-person": {
"description": "a specific real, identifiable person is depicted"
},
"ip": {
"description": "references copyrighted or trademarked material"
},
"ip-review": {
"description": "borderline IP reference, below the act threshold"
}
}
},
"versions": [
{
"version": 1,
"current": true,
"created_at": "2026-09-17T08:51:06.000Z",
"created_by": null
}
]
}Errors
400Invalid request (malformed JSON, or the body/query failed validation).401Missing, malformed, unknown or revoked API key.402The plan's policies are all used (plan_required,limit: policies), or the plan has ended (subscription_inactive).422The document failed policy validation (invalid_policy, withissues), or the preset doesn't exist.429Rate limit exceeded for this API key. SeeRetry-After.
Get a policy, its current document and its versions
/v1/policies/{id}Parameters
idstringpathrequiredPolicy id 1–64 chars
Request
curl "https://api.getvindex.com/v1/policies/$POLICY_ID" \
-H "Authorization: Bearer $VINDEX_KEY"Response 200
The policy.
{
"id": "pol_3f2a0c9e8b7d4c6a9f1e2d3c4b5a6978",
"name": "adult-platform",
"preset": "adult-platform",
"current_version": 1,
"default": true,
"dry_run_version": null,
"created_at": "2026-09-17T08:51:06.000Z",
"policy": {
"version": 1,
"name": "adult-platform",
"checks": {
"minors_sexual": {
"act": 0.5,
"review": 0.3,
"on_act": {
"type": "block"
},
"on_review": {
"type": "review"
}
},
"adult": {
"act": 0.7,
"review": 0.35,
"on_act": {
"type": "tag",
"tag": "adult"
},
"on_review": {
"type": "tag",
"tag": "adult-review"
}
},
"real_person": {
"act": 0.5,
"review": 0.3,
"on_act": {
"type": "review"
},
"on_review": {
"type": "tag",
"tag": "real-person"
}
},
"copyrighted_ip": {
"act": 0.5,
"review": 0.3,
"on_act": {
"type": "tag",
"tag": "ip"
},
"on_review": {
"type": "tag",
"tag": "ip-review"
}
}
},
"adult": {
"max_level": 5
},
"youth_coded_adult": "review",
"webhooks": [],
"tags": {
"adult": {
"description": "NSFW: nudity or sexual content, auto-tagged, not blocked"
},
"adult-review": {
"description": "borderline NSFW, below the adult act threshold"
},
"real-person": {
"description": "a specific real, identifiable person is depicted"
},
"ip": {
"description": "references copyrighted or trademarked material"
},
"ip-review": {
"description": "borderline IP reference, below the act threshold"
}
}
},
"versions": [
{
"version": 1,
"current": true,
"created_at": "2026-09-17T08:51:06.000Z",
"created_by": null
}
]
}Errors
400Invalid request (malformed JSON, or the body/query failed validation).401Missing, malformed, unknown or revoked API key.404No such policy (or version) for this tenant.429Rate limit exceeded for this API key. SeeRetry-After.
Add a new (unpublished) version
/v1/policies/{id}/versionsValidates the document and stores it as the next version. It takes effect only once published.
Parameters
idstringpathrequiredPolicy id 1–64 chars
Body
version1requirednamestringrequiredchecksmap of PolicyCheckRulerequiredPer check id (
minors_sexual,adult,real_person,copyrighted_ip).minors_sexualis required and pinned: act 0.5, review 0.3, on_act block.checks.{key}.enabledbooleanchecks.{key}.actnumberrequired0–1
checks.{key}.reviewnumberrequired0–1
checks.{key}.on_actActionrequiredchecks.{key}.on_reviewActionrequiredadultobjectrequiredHighest adult level (1–5) allowed before
checks.adult.on_actapplies. Interim fixed 0.2-wide bands over the adult score, pending issue #10.adult.max_levelintegerrequired1–5
youth_coded_adult"review" | "block"requiredwebhooksobject[]requiredwebhooks[].urlstringrequiredwebhooks[].events"block" | "review" | "allow" | "tag" | "review.verdict"[]requiredwebhooks[].secretstringrequiredHMAC-SHA256 signing secret, at least 16 characters. Write-only: reads return "redacted", and sending "redacted" back keeps the stored secret for that url.
tagsmap of objectrequiredtags.{key}.descriptionstring
Request
curl -X POST "https://api.getvindex.com/v1/policies/$POLICY_ID/versions" \
-H "Authorization: Bearer $VINDEX_KEY" \
-H "Content-Type: application/json" \
-d '{
"version": 1,
"name": "adult-platform",
"checks": {
"minors_sexual": {
"act": 0.5,
"review": 0.3,
"on_act": {
"type": "block"
},
"on_review": {
"type": "review"
}
},
"adult": {
"act": 0.7,
"review": 0.35,
"on_act": {
"type": "tag",
"tag": "adult"
},
"on_review": {
"type": "tag",
"tag": "adult-review"
}
},
"real_person": {
"act": 0.5,
"review": 0.3,
"on_act": {
"type": "review"
},
"on_review": {
"type": "tag",
"tag": "real-person"
}
},
"copyrighted_ip": {
"act": 0.5,
"review": 0.3,
"on_act": {
"type": "tag",
"tag": "ip"
},
"on_review": {
"type": "tag",
"tag": "ip-review"
}
}
},
"adult": {
"max_level": 5
},
"youth_coded_adult": "review",
"webhooks": [],
"tags": {
"adult": {
"description": "NSFW: nudity or sexual content, auto-tagged, not blocked"
},
"adult-review": {
"description": "borderline NSFW, below the adult act threshold"
},
"real-person": {
"description": "a specific real, identifiable person is depicted"
},
"ip": {
"description": "references copyrighted or trademarked material"
},
"ip-review": {
"description": "borderline IP reference, below the act threshold"
}
}
}'Response 201
The new version.
{
"policy_id": "pol_3f2a0c9e8b7d4c6a9f1e2d3c4b5a6978",
"version": 1,
"current": true,
"policy": {
"version": 1,
"name": "adult-platform",
"checks": {
"minors_sexual": {
"act": 0.5,
"review": 0.3,
"on_act": {
"type": "block"
},
"on_review": {
"type": "review"
}
},
"adult": {
"act": 0.7,
"review": 0.35,
"on_act": {
"type": "tag",
"tag": "adult"
},
"on_review": {
"type": "tag",
"tag": "adult-review"
}
},
"real_person": {
"act": 0.5,
"review": 0.3,
"on_act": {
"type": "review"
},
"on_review": {
"type": "tag",
"tag": "real-person"
}
},
"copyrighted_ip": {
"act": 0.5,
"review": 0.3,
"on_act": {
"type": "tag",
"tag": "ip"
},
"on_review": {
"type": "tag",
"tag": "ip-review"
}
}
},
"adult": {
"max_level": 5
},
"youth_coded_adult": "review",
"webhooks": [],
"tags": {
"adult": {
"description": "NSFW: nudity or sexual content, auto-tagged, not blocked"
},
"adult-review": {
"description": "borderline NSFW, below the adult act threshold"
},
"real-person": {
"description": "a specific real, identifiable person is depicted"
},
"ip": {
"description": "references copyrighted or trademarked material"
},
"ip-review": {
"description": "borderline IP reference, below the act threshold"
}
}
}
}Errors
400Invalid request (malformed JSON, or the body/query failed validation).401Missing, malformed, unknown or revoked API key.402The workspace's plan has ended, so it's read-only (subscription_inactive).404No such policy (or version) for this tenant.422The document failed policy validation (invalid_policy, withissues).429Rate limit exceeded for this API key. SeeRetry-After.
Publish a version
/v1/policies/{id}/publishMakes the version current. Checks pick it up once the policy cache entry is gone everywhere: usually within ~60 s (KV is eventually consistent), at most 5 minutes if a check was caching the old version as you published.
Parameters
idstringpathrequiredPolicy id 1–64 chars
Body
versionintegerrequired≥ 1
Request
curl -X POST "https://api.getvindex.com/v1/policies/$POLICY_ID/publish" \
-H "Authorization: Bearer $VINDEX_KEY" \
-H "Content-Type: application/json" \
-d '{"version":2}'Response 200
Published.
{
"id": "pol_3f2a0c9e8b7d4c6a9f1e2d3c4b5a6978",
"name": "adult-platform",
"preset": "adult-platform",
"current_version": 1,
"default": true,
"dry_run_version": null,
"created_at": "2026-09-17T08:51:06.000Z"
}Errors
400Invalid request (malformed JSON, or the body/query failed validation).401Missing, malformed, unknown or revoked API key.402The workspace's plan has ended, so it's read-only (subscription_inactive).404No such policy (or version) for this tenant.422The version no longer passes validation (invalid_policy, withissues), e.g. a webhook on plain http://. Save a fixed version and publish that.429Rate limit exceeded for this API key. SeeRetry-After.
Make a policy the tenant's default
/v1/policies/{id}/defaultParameters
idstringpathrequiredPolicy id 1–64 chars
Request
curl -X POST "https://api.getvindex.com/v1/policies/$POLICY_ID/default" \
-H "Authorization: Bearer $VINDEX_KEY"Response 200
Now the default.
{
"id": "pol_3f2a0c9e8b7d4c6a9f1e2d3c4b5a6978",
"name": "adult-platform",
"preset": "adult-platform",
"current_version": 1,
"default": true,
"dry_run_version": null,
"created_at": "2026-09-17T08:51:06.000Z"
}Errors
400Invalid request (malformed JSON, or the body/query failed validation).401Missing, malformed, unknown or revoked API key.402The workspace's plan has ended, so it's read-only (subscription_inactive).404No such policy (or version) for this tenant.429Rate limit exceeded for this API key. SeeRetry-After.
Get one version of a policy
/v1/policies/{id}/versions/{version}Parameters
idstringpathrequiredPolicy id 1–64 chars
versionintegerpathrequired≥ 1
Request
curl "https://api.getvindex.com/v1/policies/$POLICY_ID/versions/$VERSION" \
-H "Authorization: Bearer $VINDEX_KEY"Response 200
The version's document (webhook secrets redacted).
{
"policy_id": "pol_3f2a0c9e8b7d4c6a9f1e2d3c4b5a6978",
"version": 1,
"current": true,
"policy": {
"version": 1,
"name": "adult-platform",
"checks": {
"minors_sexual": {
"act": 0.5,
"review": 0.3,
"on_act": {
"type": "block"
},
"on_review": {
"type": "review"
}
},
"adult": {
"act": 0.7,
"review": 0.35,
"on_act": {
"type": "tag",
"tag": "adult"
},
"on_review": {
"type": "tag",
"tag": "adult-review"
}
},
"real_person": {
"act": 0.5,
"review": 0.3,
"on_act": {
"type": "review"
},
"on_review": {
"type": "tag",
"tag": "real-person"
}
},
"copyrighted_ip": {
"act": 0.5,
"review": 0.3,
"on_act": {
"type": "tag",
"tag": "ip"
},
"on_review": {
"type": "tag",
"tag": "ip-review"
}
}
},
"adult": {
"max_level": 5
},
"youth_coded_adult": "review",
"webhooks": [],
"tags": {
"adult": {
"description": "NSFW: nudity or sexual content, auto-tagged, not blocked"
},
"adult-review": {
"description": "borderline NSFW, below the adult act threshold"
},
"real-person": {
"description": "a specific real, identifiable person is depicted"
},
"ip": {
"description": "references copyrighted or trademarked material"
},
"ip-review": {
"description": "borderline IP reference, below the act threshold"
}
}
}
}Errors
400Invalid request (malformed JSON, or the body/query failed validation).401Missing, malformed, unknown or revoked API key.404No such policy (or version) for this tenant.429Rate limit exceeded for this API key. SeeRetry-After.
List preset policies
/v1/presetsRequest
curl "https://api.getvindex.com/v1/presets" \
-H "Authorization: Bearer $VINDEX_KEY"Response 200
The shipped presets.
{
"data": [
{
"name": "adult-platform",
"policy": {
"version": 1,
"name": "adult-platform",
"checks": {
"minors_sexual": {
"act": 0.5,
"review": 0.3,
"on_act": {
"type": "block"
},
"on_review": {
"type": "review"
}
},
"adult": {
"act": 0.7,
"review": 0.35,
"on_act": {
"type": "tag",
"tag": "adult"
},
"on_review": {
"type": "tag",
"tag": "adult-review"
}
},
"real_person": {
"act": 0.5,
"review": 0.3,
"on_act": {
"type": "review"
},
"on_review": {
"type": "tag",
"tag": "real-person"
}
},
"copyrighted_ip": {
"act": 0.5,
"review": 0.3,
"on_act": {
"type": "tag",
"tag": "ip"
},
"on_review": {
"type": "tag",
"tag": "ip-review"
}
}
},
"adult": {
"max_level": 5
},
"youth_coded_adult": "review",
"webhooks": [],
"tags": {
"adult": {
"description": "NSFW: nudity or sexual content, auto-tagged, not blocked"
},
"adult-review": {
"description": "borderline NSFW, below the adult act threshold"
},
"real-person": {
"description": "a specific real, identifiable person is depicted"
},
"ip": {
"description": "references copyrighted or trademarked material"
},
"ip-review": {
"description": "borderline IP reference, below the act threshold"
}
}
}
}
]
}Errors
400Invalid request (malformed JSON, or the body/query failed validation).401Missing, malformed, unknown or revoked API key.429Rate limit exceeded for this API key. SeeRetry-After.