← Help Center

Developer Documentation

API integration guide

Connect your platform to Checkstep - send content for analysis, receive moderation decisions via webhooks, and integrate transparency flows for your users.

DeveloperOpenAPI spec ↗

Overview

Integrating with Checkstep involves three steps: send your content via API, receive decisions via webhooks, and optionally redirect users to Checkstep's transparency portal for removal notifications and appeals.

Your platformsends content
Checkstepanalyses & decides
Webhooksback to you
Transparencyuser-facing
Before you start: You must have access granted to Checkstep by the client solutions team. Your account needs to be provisioned before you can use the API.

Authentication

The Checkstep API uses API keys with Bearer authentication over HTTPS.

View and manage your API keys in the Checkstep settings page for each provisioned platform. All requests must include the authorization header:

Authorization: Bearer ${CHECKSTEP_API_KEY}

All API requests must be made over HTTPS - plain HTTP calls will fail. Keep your API keys secure and never share them publicly.

Key rotation

You can create a new API key with a later expiration using an existing key via the management endpoint. New keys may take up to one minute to become active across all APIs. Store new keys with a started_at field set to now + 1 minute and always pick the latest one matching started_at < now.

Structuring your content

Content in Checkstep is flexible - it can combine text, image, audio, and video fields to match your platform's data model. Each piece of content is identified by its type and a unique ID.

Complex types

Checkstep provides standard complex types: profile, post, comment, thread, chat, channel, product, review, reply, and fragment variants. You can also request custom types from the solutions team.

Choose your complex type based on your moderation lifecycle. If you enforce a post as a whole (removing the entire thing when one part violates), send it as a single post. If you enforce parts independently (removing an attachment but keeping the post), send attachments as post-fragment with a parent relationship.

Content fields

Each piece of content contains fields with a unique ID and a simple type (text, image, audio, video, uri, file). Fields can be nested - for example, an image gallery where each image has a text caption.

Relationships

Link content with parent-child relationships by including the parent's type and ID in your ingestion request. Relationships are visible in the moderation UI - when reviewing content, the parent and nearby siblings are displayed for context.

Authors

Always designate the author of content with a unique ID from your platform. This enables Checkstep to build author profiles, track repeated offences, and take action directly against users rather than just individual pieces of content.

Example: a user profile

{
  "id": "009d8aa9-7d25-44ed-bbf5-8410528f96e1",
  "author": "82a277f5-4714-4a09-bdb1-6b8726418ad8",
  "type": "profile",
  "fields": [
    { "id": "name", "type": "text", "src": "John Doe" },
    { "id": "bio", "type": "text", "src": "Hello I am John" }
  ]
}

Asynchronous ingestion

The recommended approach. Send content for analysis and receive results via webhook when processing is complete. You can generate a cURL snippet from the Checkstep UI.

See the full OpenAPI specification for all available fields.

Partial updates

You can send partial content when a field gets updated - just submit the changed fields. Content is aggregated by complex type + content ID. Fields and metadata merge based on their unique id; you don't need to repeat fields like author. To discard all previously submitted fields, use the reset_fields and reset_metadata flags.

Parent relationships

Express parent-child relationships by including a parentobject with the parent's type and ID:

{
  "id": "009d8aa9",
  "type": "comment",
  "fields": [
    { "id": "body", "type": "text", "src": "Aha true, I never thought about that" }
  ],
  "parent": { "type": "thread", "id": "26c1bce6" }
}

Nested fields

Group related fields using nesting - for example, an image with a caption:

{
  "id": "009d8aa9",
  "type": "gallery",
  "fields": [
    {
      "id": "image_1", "type": "image",
      "src": "https://example.com/photo.jpg",
      "fields": [
        { "id": "caption", "type": "text", "src": "Nice view on the lake!" }
      ]
    }
  ]
}

External evaluations

If you have your own classification or scoring, you can send evaluations alongside content. These appear in content cases, show in analytics widgets, and can be used in policy rules. Requires an external strategy configured on your account.

"evaluations": [
  { "label": "similar", "field": "name", "score": 0.9, "strategy": "external-multilabels" }
]

Metadata

Attach additional information for moderators using metadata - key-value pairs like user plan, region, or account age. Metadata can be attached to the whole content or to specific fields. Metadata is forwarded back in webhook payloads, making it useful for passing internal identifiers through the pipeline.

Tags

Tag content for queue classification or search. Tags must start with #:

"tags": ["#featured", "#popular"]

Bulk ingestion

Send multiple pieces of content in a single request. Useful for bootstrapping your account with existing content, scanning for violations, and avoiding the round-trips of one-by-one ingestion.

Wrap your content array in a bulk payload with a unique bulk ID. Each item follows the same structure as async ingestion.

{
  "bulk": "2dd1fca2-e303-40de-9172-a7b710b64f99",
  "contents": [
    { "id": "520f3f31", "author": "Hollis", "type": "post",
      "fields": [{ "id": "message", "type": "text", "src": "First post content" }] },
    { "id": "75c3f62f", "author": "Marianna", "type": "post",
      "fields": [{ "id": "message", "type": "text", "src": "Second post content" }] }
  ]
}

Synchronous ingestion

For real-time proactive moderation - send content and get policy violations back in the response. Essential for live chat where you need to block harmful content before other users see it.

See the OpenAPI specification for details.

Limitation:Video and advanced image processing strategies won't run on synchronous ingestion due to their async nature. For proactive moderation of those content types, use async ingestion and consume analysed-content webhooks.

Response with no violations:

{ "id": "34a8f82bbb", "author": "4c0789faff", "type": "chat", "violations": [] }

Response with violations:

{
  "id": "34a8f82bbb", "author": "4c0789faff", "type": "chat",
  "violations": [
    { "policy": "VLC", "confidence": "check", "severity": "medium" },
    { "policy": "HTE", "confidence": "trust", "severity": "low" }
  ]
}

Analysing with context

For chat scenarios, enable contextual analysis by including context=true as a query parameter. You must also set parent and author. Content will be analysed alongside preceding messages with the same parent - preventing false positives where a message looks innocent alone but is harmful in context.

Tip: Only previous content also sent with context=true will be included in the analysis context. Content previously marked as violating with TRUST confidence is excluded from context for subsequent analyses.

Access delegation

Checkstep needs access to your media assets (images, audio, video) for analysis and moderator review. Three options are available depending on your storage infrastructure.

AWS S3

Configure an IAM role with read access to your bucket and allow Checkstep to assume the role. Checkstep generates pre-signed URLs whenever access is needed. Enable S3 versioning to decouple asset hosting. Contact support with your bucket name, region, and role ARN.

Google Cloud Storage

Set up a Workload Identity Federation Pool with an AWS provider and grant a service account Storage Object Viewer access to your bucket. Contact support with the audience from your client library config and your bucket name.

Private token

For storage systems that support token-based access, Checkstep can include an Authorization: Bearer header when accessing your URLs. Contact support with your token and storage domain.

Best practice:Decouple asset hosting between end users and Checkstep. This ensures content remains accessible in the moderation UI even after it's been removed from public view on your platform.

Webhooks

Webhooks notify your platform when events happen in Checkstep - content analysed, moderation decisions taken, incidents closed. Configure your webhook endpoint in the Checkstep settings.

All webhooks are JSON payloads with a timestamp and webhook_type. The type is also available as an HTTP header (X-Webhook-Type) for routing without parsing the body.

Webhook types

decision

Raised when a moderator or ModBot takes action on content. Check the decision field: act (take down), overturn (restore), uphold (keep down after appeal), dismiss (no violation), or escalate. Use content.type and content.id to identify the content to act on.

author-decision

Raised when a moderator takes action on an author. Check decision: act (suspend/terminate and remove content), hold (suspend/terminate but keep content), overturn (restore account). Use author to identify the account.

incident-closed

Raised when an incident is fully resolved - slightly delayed after the decision. Use this for user notifications. Check resolution: enforced, dismissed, overturned, upheld, or terminated. The reporters array lists users who filed community reports.

analysed-content

Raised shortly after content is ingested and scanned. Provides early insights into potential violations before a final decision. Use this for pre-publication holds - if violations are detected, hold the content until a decision webhook arrives.

Error handling and retries

Checkstep considers a webhook successful on any 2xx response. On 4xx or 5xx, the webhook retries a few minutes later, up to three attempts. Contact support if your system is down for an extended period to request additional retries.

Payload signing

Optionally verify webhook authenticity using HMAC signatures. When enabled, webhooks include x-auth-signature, x-auth-date, and x-auth-nonce headers. Compute the signature by hashing the body + date + nonce with SHA-256, then HMAC the hash with your signing key. During key rotation, two signatures are included for 24 hours.

Amazon SQS

All webhook events can also be delivered to an Amazon SQS queue as messages with the same payloads. Configure by providing your queue URL and role ARN. The webhook type is available in message attributes as X-Webhook-Type.

Transparency

When content is removed, regulations require that users are informed and given the right to appeal. Checkstep provides a hosted Transparency Portal and redirect endpoints to handle this flow.

Statement of reason and appeal

When an author's content is enforced, present them a "View more" or "More info" link. On click, call the redirect endpoint to get a unique authenticated URL, then redirect the user to the Transparency Portal. The portal shows the removed content, the violated policy, and an appeal form.

Security:Never share a redirect URL with anyone other than the content's author. The URL contains a unique authentication token that expires after 6 hours.

Community reports

Let users report content by calling the report redirect endpoint to get a link to the reporting form. You can prefill the reporter's email using the reporter query parameter.

Custom domain and translations

By default the portal is hosted under checkstep.com. Contact support to set up a custom domain. Add the lang query parameter to display the portal in a supported language: cz, de, dk, en, es, fr, hu, it, jp, se. Policy names and descriptions also display in translated form if translations are configured.

Headless integration

If you want to build your own UI for community reports, statements of reason, appeals, and moderation decisions - instead of using Checkstep's hosted flows - use these endpoints.

Community reports

Receive reports from community members via the report endpoint. Provide the content's type and ID, a reporter identifier, the reason, and potential policy violations. If the content was previously ingested, the report is associated with it automatically.

{
  "id": "3e5cb4b2", "type": "post",
  "reporter": "john@doe.com",
  "reason": "Remove this hateful post please!",
  "potential_violations": [{ "policy": "HTE" }]
}

Statement of reason

Call the case endpoint to get the current status of a content case. Statuses progress through: no-incidentenforced (with statement of reason) → appealed (pending review) → appeal-ruled (with ruling).

Appeals

Submit an appeal via the appeal endpoint with the content's type, ID, author, and the user's statement. Returns a 202 Accepted.

External decisions

If you make moderation decisions outside Checkstep, send them back to maintain transparency records. Supported decisions for content: act, dismiss, escalate, overturn, uphold. For authors: act, overturn, escalate, hold.

Inquiries

Open a new incident on content manually by creating an inquiry - useful when you want moderators to review content that wasn't flagged by automation.

Quick reference

Key endpoints and patterns at a glance.

ActionMethodEndpoint
Ingest contentPOST/content
Bulk ingestPOST/content/bulk
Sync ingestPOST/content/sync
Community reportPOST/content/report
AppealPOST/content/appeal
Statement of reasonGET/review/cases
Content decisionPOST/review/cases/decisions
Author decisionPOST/review/authors/decisions
InquiryPOST/review/cases/inquiries
Redirect (SoR)GET/review/redirect/my-case
Redirect (report)GET/review/redirect/report
Rotate API keyPOST/api-keys

All endpoints are under https://api.checkstep.com/api/v2. For full request/response schemas, see the interactive OpenAPI documentation ↗.