API Reference

Complete reference for the Bandit REST API. Integrate treatment assignments, event tracking, and experiment management into your application.

Base URL:https://runbandit.com

Response Format

All endpoints return a consistent JSON envelope:

{
  "success": true,
  "data": { ... },
  "error": "...",
  "timestamp": "2026-01-15T10:00:00.000Z"
}

Authentication

The API supports two authentication methods depending on the endpoint:

api-keyPass your API key via the Authorization: Bearer <key> header or x-api-key header. Used by the SDK for assignment and event endpoints.
sessionAuthenticated via Clerk session cookie. Used by the dashboard.
adminRequires the user to have the admin role within the company.

Limits & Quotas

Bandit doesn't enforce per-second rate limits today. Volume is metered by monthly event quotas with soft overages, and individual requests are bounded by payload-size and batch-size limits.

Request size

  • POST /assignments and POST /events: max body size 100 KB. Over the limit returns 413.
  • POST /events/batch: up to 1,000 events per request. Larger batches must be split client-side.

Monthly event quotas

  • Starter — 10,000 events / month. Traffic pauses at the cap until the next cycle or an upgrade.
  • Pro — 500,000 events / month. Soft cap; additional events billed at $0.10 / 1K.
  • Scale — 5,000,000 events / month. Soft cap; additional events billed at $0.06 / 1K.
  • Enterprise — uncapped, custom volume pricing.

Current quotas track the figures on the pricing page.

Recommended client practices

  • Use POST /events/batch for high-volume tracking instead of one request per event.
  • The JavaScript SDK batches events automatically — prefer it over hand-rolled fetches.
  • Retry on 500 with exponential backoff. Do not retry on 400 / 401 / 413 — those are caller errors.

Assignments

Get treatment assignments for users in experiments

POST/assignments

Create assignment

Request a treatment assignment for a user in an experiment. The bandit algorithm selects the optimal treatment based on historical performance. If the user already has a cached assignment, it is returned instead.

Auth:api-key

Request Body

NameTypeRequiredDescription
experimentIdstringrequiredID of the experiment to assign
userIdstringrequiredUnique identifier for the user
contextRecord<string, string | number | boolean>optionalOptional context for contextual bandit algorithms (e.g. device type, location)

Responses

200Assignment returned successfully
400Experiment is not active
404Experiment not found

Example

Request

{
  "experimentId": "exp_abc123",
  "userId": "user_42",
  "context": {
    "deviceType": "mobile",
    "country": "US"
  }
}

Response

{
  "success": true,
  "data": {
    "assignmentId": "asgn_xyz789",
    "treatmentId": "trt_def456",
    "treatment": {
      "name": "Headline B",
      "config": {
        "content": "Start your free trial today"
      }
    },
    "confidence": 0.87
  },
  "timestamp": "2026-01-15T10:30:00.000Z"
}
GET/assignments/:experimentId

Get assignment

Retrieve a treatment assignment for a user via query parameters. Functionally equivalent to the POST endpoint but useful for simple GET-based integrations.

Auth:api-key

Path Parameters

NameTypeRequiredDescription
experimentIdstringrequiredID of the experiment

Query Parameters

NameTypeRequiredDescription
userIdstringrequiredUnique identifier for the user
contextstring (JSON)optionalJSON-encoded context object for contextual bandits

Responses

200Assignment returned successfully
400Missing userId or experiment not active
404Experiment not found

Events

POST/api/events

Track event

Track a single named event with optional value and metadata. Events are free-form — which event names count as rewards and trigger bandit algorithm updates is configured per experiment in the dashboard. Requires API key authentication.

Auth:api-key

Request Body

NameTypeRequiredDescription
namestringrequiredFree-form event name (e.g. "purchase", "signup", "button_click"). Configure which names count as rewards in the dashboard.
categorystringoptionalOptional category to group related events
sessionIdstringrequiredSession identifier for tracking event attribution
valuenumberoptionalNumeric value for the event (e.g. revenue amount)
metadataRecord<string, any>optionalArbitrary key-value metadata to attach to the event

Responses

201Event tracked successfully
400Invalid request body or validation error
401Invalid or missing API key
413Request payload exceeds maximum size of 100KB

Example

Request

{
  "name": "purchase",
  "category": "conversion",
  "sessionId": "sess_abc123",
  "value": 29.99,
  "metadata": {
    "product": "premium-plan",
    "coupon": "SAVE10"
  }
}

Response

{
  "success": true,
  "data": {
    "tracked": 1
  },
  "timestamp": "2026-01-15T10:30:00.000Z"
}
POST/api/events/batch

Track events (batch)

Track multiple events in a single request for better performance and reduced network overhead. Accepts 1-1000 events per batch. The SDK automatically batches events — prefer it over hand-rolled batch requests. Requires API key authentication.

Auth:api-key

Request Body

NameTypeRequiredDescription
eventsArray<Event>requiredArray of 1-1000 event objects. Each event has: name (required string), category (optional string), sessionId (required string), value (optional number), metadata (optional object).

Responses

201Batch tracked successfully
400Invalid request body, validation error, or batch exceeds 1000 events
401Invalid or missing API key
413Request payload exceeds maximum size of 100KB

Example

Request

{
  "events": [
    {
      "name": "page_view",
      "category": "engagement",
      "sessionId": "sess_abc123",
      "metadata": {
        "page": "/pricing"
      }
    },
    {
      "name": "button_click",
      "category": "interaction",
      "sessionId": "sess_abc123",
      "metadata": {
        "button": "cta-primary"
      }
    },
    {
      "name": "purchase",
      "category": "conversion",
      "sessionId": "sess_abc123",
      "value": 49.99,
      "metadata": {
        "product": "pro-plan"
      }
    }
  ]
}

Response

{
  "success": true,
  "data": {
    "tracked": 3
  },
  "timestamp": "2026-01-15T10:30:00.000Z"
}
GET/events/:experimentId

List events

Retrieve event history for a specific experiment. Results are paginated with limit and offset query parameters.

Auth:session

Path Parameters

NameTypeRequiredDescription
experimentIdstringrequiredID of the experiment

Query Parameters

NameTypeRequiredDescription
limitnumberoptionalMaximum number of events to return (default: 100)
offsetnumberoptionalNumber of events to skip (default: 0)

Responses

200Events returned successfully
404Experiment not found

Experiments

Create and manage experiments

GET/experiments

List experiments

Retrieve all experiments belonging to the authenticated company. Returns experiments with their treatments.

Auth:session

Responses

200Experiments returned successfully
POST/experiments

Create experiment

Create a new experiment in DRAFT status. Optionally include initial treatments. The experiment must be activated separately via PUT after adding at least one treatment.

Auth:session

Request Body

NameTypeRequiredDescription
namestringrequiredHuman-readable name for the experiment
descriptionstringoptionalDescription of the experiment goals
algorithmBanditAlgorithmrequiredAlgorithm to use: THOMPSON_SAMPLING or CONTEXTUAL_LINEAR
forgettingForgettingConfigoptionalHow the algorithm forgets old results. { mode: 'none' } (default) counts every result forever; { mode: 'discounted', halfLifeMs } halves a result's weight every half-life; { mode: 'sliding_window', windowMs } counts only results inside the window.
contentTypeContentTypeoptionalContent type of treatments (default: PLAIN_TEXT)
algorithmConfigRecord<string, any>optionalAlgorithm-specific configuration
assignmentTtlnumberoptionalAssignment cache TTL in seconds (default: 86400 = 24 hours)
treatmentsTreatment[]optionalOptional initial treatments to create with the experiment

Responses

201Experiment created in DRAFT status
400Validation error

Example

Request

{
  "name": "Homepage Headline Test",
  "description": "Test different headlines on the landing page",
  "algorithm": "THOMPSON_SAMPLING",
  "forgetting": {
    "mode": "discounted",
    "halfLifeMs": 604800000
  },
  "treatments": [
    {
      "name": "Control",
      "config": {
        "content": "Welcome to our platform"
      }
    },
    {
      "name": "Urgency",
      "config": {
        "content": "Limited time offer - start free today!"
      }
    }
  ]
}

Response

{
  "success": true,
  "data": {
    "id": "exp_abc123",
    "name": "Homepage Headline Test",
    "algorithm": "THOMPSON_SAMPLING",
    "status": "draft",
    "treatments": [
      "..."
    ]
  },
  "timestamp": "2026-01-15T10:00:00.000Z"
}
PATCH/experiments/:id

Update experiment

Update experiment properties including name, description, status, and TTL. To activate an experiment, set status to ACTIVE. Activation requires at least one treatment.

Auth:session

Path Parameters

NameTypeRequiredDescription
idstringrequiredID of the experiment to update

Request Body

NameTypeRequiredDescription
namestringoptionalUpdated name
descriptionstringoptionalUpdated description
statusExperimentStatusoptionalNew status: DRAFT, ACTIVE, PAUSED, COMPLETED, or ARCHIVED
assignmentTtlnumberoptionalUpdated assignment TTL in seconds
endAtstring (ISO 8601)optionalScheduled end date for the experiment

Responses

200Experiment updated successfully
400Cannot activate without treatments
404Experiment not found
GET/experiments/:id

Get experiment

Retrieve a single experiment by ID, including all associated treatments and their configurations.

Auth:session

Path Parameters

NameTypeRequiredDescription
idstringrequiredID of the experiment

Responses

200Experiment returned successfully
404Experiment not found
POST/experiments/:id/generate-variant

AI generate variant

Use AI to generate a new treatment variant based on the experiment's existing treatments and performance data. The AI analyzes what's working and generates a new variant using one of eight strategies (emotional appeal, urgency, social proof, etc.).

Auth:session

Path Parameters

NameTypeRequiredDescription
idstringrequiredID of the experiment

Responses

201AI variant generated and added as a new treatment
404Experiment not found
POST/experiments/:id/refresh

Refresh algorithm state

Rebuild the in-memory algorithm state from the event history in the database. Useful after manual data changes or if algorithm state has drifted.

Auth:session

Path Parameters

NameTypeRequiredDescription
idstringrequiredID of the experiment

Responses

200Algorithm state refreshed successfully
404Experiment not found
POST/experiments/:id/treatments

Add treatment

Add a new treatment (variant) to an experiment. Each treatment has a name, content configuration, optional weight for traffic allocation, and an optional control flag.

Auth:session

Path Parameters

NameTypeRequiredDescription
idstringrequiredID of the experiment

Request Body

NameTypeRequiredDescription
namestringrequiredName of the treatment variant
descriptionstringoptionalDescription of this variant
config{ content: string, metadata?: Record<string, any> }requiredTreatment configuration with content and optional metadata
weightnumberoptionalTraffic weight (default: 1.0)

Responses

201Treatment added successfully
404Experiment not found
DELETE/experiments/:id/treatments/:treatmentId

Remove treatment

Remove a treatment from an experiment. The treatment must belong to the specified experiment.

Auth:session

Path Parameters

NameTypeRequiredDescription
idstringrequiredID of the experiment
treatmentIdstringrequiredID of the treatment to remove

Responses

200Treatment removed successfully
400Treatment does not belong to experiment
404Experiment or treatment not found

Funnels

Create and manage multi-step experiment funnels

GET/funnels

List funnels

Retrieve all funnels belonging to the authenticated company. Each funnel links multiple experiments into a sequential conversion path.

Auth:session

Responses

200Funnels returned successfully
POST/funnels

Create funnel

Create a new funnel linking one or more experiments into a multi-step conversion path. Requires at least one experiment ID.

Auth:session

Request Body

NameTypeRequiredDescription
namestringrequiredHuman-readable name for the funnel
descriptionstringoptionalDescription of the funnel goals
experimentIdsstring[]requiredOrdered list of experiment IDs that form the funnel steps (minimum 1)

Responses

201Funnel created successfully
400Validation error (e.g. missing name or empty experimentIds)

Example

Request

{
  "name": "Onboarding Flow",
  "description": "Test headline → CTA → pricing across the onboarding funnel",
  "experimentIds": [
    "exp_headline",
    "exp_cta",
    "exp_pricing"
  ]
}

Response

{
  "success": true,
  "data": {
    "id": "fnl_abc123",
    "name": "Onboarding Flow",
    "description": "Test headline → CTA → pricing across the onboarding funnel",
    "experimentIds": [
      "exp_headline",
      "exp_cta",
      "exp_pricing"
    ],
    "status": "draft"
  },
  "timestamp": "2026-01-15T12:00:00.000Z"
}
GET/funnels/:id

Get funnel

Retrieve a single funnel by ID, including details about its linked experiments and their current status.

Auth:session

Path Parameters

NameTypeRequiredDescription
idstringrequiredID of the funnel

Responses

200Funnel returned successfully
404Funnel not found
PUT/funnels/:id

Update funnel

Update funnel properties such as name, description, or status.

Auth:session

Path Parameters

NameTypeRequiredDescription
idstringrequiredID of the funnel to update

Request Body

NameTypeRequiredDescription
namestringoptionalUpdated name
descriptionstringoptionalUpdated description
statusstringoptionalNew status: draft, active, paused, or completed

Responses

200Funnel updated successfully
400Validation error
404Funnel not found
DELETE/funnels/:id

Delete funnel

Delete a funnel. This does not delete the linked experiments, only the funnel grouping.

Auth:session

Path Parameters

NameTypeRequiredDescription
idstringrequiredID of the funnel to delete

Responses

200Funnel deleted successfully
400Failed to delete funnel
POST/funnels/:id/reward

Record funnel reward

Record a reward (conversion value) for a user who completed the funnel. Updates the bandit algorithm state for all experiments in the funnel based on the treatments the user was assigned. Each user can only have one reward per funnel.

Auth:session

Path Parameters

NameTypeRequiredDescription
idstringrequiredID of the funnel

Request Body

NameTypeRequiredDescription
userIdstringrequiredID of the user who completed the funnel
valuenumberrequiredReward value (must be >= 0, e.g. revenue amount)

Responses

200Reward recorded and algorithm state updated
404Funnel not found or no assignments found for this user
409Reward already recorded for this user in this funnel
500Internal error recording reward

Example

Request

{
  "userId": "user_42",
  "value": 49.99
}

Response

{
  "success": true,
  "data": {
    "funnelId": "fnl_abc123",
    "userId": "user_42",
    "value": 49.99
  },
  "timestamp": "2026-01-15T14:00:00.000Z"
}

Bundles

Simultaneous multi-experiment assignments with joint optimization across all slots. The bundle bandit learns combinations of treatments that maximize the collective reward.

POST/bundles/:id/reward

Record bundle reward

Record a reward (conversion value) for a user who completed a bundle conversion. Updates the bandit algorithm state for all experiments in the bundle based on the combination of treatments the user was served. Each user can only have one reward per bundle within the conversion window.

Auth:api-key

Path Parameters

NameTypeRequiredDescription
idstringrequiredID of the bundle

Request Body

NameTypeRequiredDescription
userIdstringrequiredID of the user who completed the bundle conversion
valuenumberrequiredReward value (must be >= 0, e.g., revenue amount in dollars)

Responses

200Reward recorded and algorithm state updated
400Bundle is in a funnel (reward the funnel instead) or no bundle assignment found for user
401Invalid or inactive API key
404Bundle not found

Example

Request

{
  "userId": "user_42",
  "value": 49.99
}

Response

{
  "success": true,
  "data": {
    "experimentsUpdated": 2
  },
  "timestamp": "2026-08-26T19:35:00.000Z"
}
POST/bundles/assignment

Get bundle assignment

Request assignments for all experiments in a bundle. The bundle bandit algorithm selects the optimal combination of treatments across all slots based on joint performance. If the user already has a live bundle assignment, it is returned (stickiness).

Auth:api-key

Request Body

NameTypeRequiredDescription
bundleIdstringrequiredID of the bundle to assign
userIdstringrequiredUnique identifier for the user
contextRecord<string, string | number | boolean>optionalOptional context shared across all slots in the bundle
sessionIdstringoptionalSession ID for event attribution (auto-generated by SDK)

Responses

200Bundle assignment returned successfully
400Bundle is not active or has no member experiments
401Invalid or inactive API key
404Bundle not found

Example

Request

{
  "bundleId": "bnd_abc123",
  "userId": "user_42",
  "context": {
    "deviceType": "mobile",
    "country": "US"
  }
}

Response

{
  "success": true,
  "data": {
    "bundleAssignmentId": "ba_xyz789",
    "slots": {
      "homepage-headline": {
        "assignmentId": "asgn_h1",
        "experimentId": "exp_headline",
        "treatmentId": "trt_urgency",
        "config": {
          "content": "Limited time offer!"
        }
      },
      "cta-button": {
        "assignmentId": "asgn_cta",
        "experimentId": "exp_cta",
        "treatmentId": "trt_green",
        "config": {
          "content": "Start Free Trial",
          "color": "#00FF00"
        }
      }
    }
  },
  "timestamp": "2026-08-26T19:30:00.000Z"
}

Identity

Link anonymous user IDs to identified users (email, account ID) with attribution

POST/identify

Link anonymous user to identified user

Link an anonymous user ID to a durable identity (email, account ID). All historical assignments and events for the anonymous ID are re-attributed to the identified user. Future calls to getAssignment() with either ID will resolve to the same assignment. Requires admin authentication with a personal access token (PAT), not an API key.

Auth:pat

Request Body

NameTypeRequiredDescription
anonymousIdstringrequiredTemporary or anonymous user ID (e.g., crypto.randomUUID())
identifiedUserIdstringrequiredPermanent user ID (e.g., email, database ID)
mergeReasonstringoptionalWhy the identification is happening: user_signup, email_verification, social_login, account_recovery, or manual (default: manual)

Responses

200User identity linked successfully
401User authentication required (use PAT, not API key)
403Admin access required
409User already identified with a different canonical ID

Example

Request

{
  "anonymousId": "anon_550e8400-e29b-41d4-a716-446655440000",
  "identifiedUserId": "user@example.com",
  "mergeReason": "user_signup"
}

Response

{
  "success": true,
  "data": {
    "anonymousId": "anon_550e8400-e29b-41d4-a716-446655440000",
    "identifiedUserId": "user@example.com",
    "alreadyMapped": false
  },
  "timestamp": "2026-08-26T19:30:00.000Z"
}