# A/B Bucketing API
> Deterministic A/B testing and feature-flag assignment — no database, no stored state. The bucket endpoint hashes a key (a user id, session or device) into a stable bucket from 0 to N-1 that never changes for that key, and can decide whether the key is inside a percentage rollout; because the decision is monotonic, raising the percentage only ever adds users, so a gradual ramp-up is sticky and no one flips back out. The variant endpoint assigns one of several weighted variants — a simple control/treatment split or any multivariate test — consistently for the same key, honouring custom weights. Mixing in an experiment name keeps independent experiments independent, and because the same inputs always produce the same answer, your client and server (and any edge function) agree on the assignment without any coordination or lookups. Hashing is FNV-1a with an avalanche mix, giving uniform, stable buckets across languages and machines. It runs entirely locally, so it is instant, deterministic and private. Ideal for feature flags and gradual rollouts, A/B and multivariate experiments, canary releases, holdouts and kill-switches, and consistent UI bucketing across web and mobile. Pure local computation — no key, no third-party service, instant. Live, nothing stored. 3 endpoints. This assigns experiments deterministically; to test whether a result is statistically significant use a statistics API.

## Authentication
All requests require your oanor API key in the `x-oanor-key` header. Get one at https://www.oanor.com/developer/keys.

```bash
curl -H "x-oanor-key: oanor_live_…" "https://api.oanor.com/abtest-api/..."
```

## Pricing
- **Free** (Free) — 3,035 calls/Mo, 2 req/s
- **Starter** ($5/Mo) — 12,550 calls/Mo, 8 req/s
- **Pro** ($24/Mo) — 176,500 calls/Mo, 20 req/s
- **Mega** ($62/Mo) — 925,000 calls/Mo, 50 req/s

## Endpoints

### A/B

#### `GET /v1/bucket` — Bucket a key

**Parameters:**
- `key` (query, required, string) — The unit to bucket — user id, session, etc. Example: `user-42`
- `experiment` (query, optional, string) — Experiment/salt name so experiments are independent Example: `exp1`
- `buckets` (query, optional, string) — Number of buckets (default 100)
- `percentage` (query, optional, string) — If set, also return enabled = inside this % rollout Example: `50`

**Example:**
```bash
curl -H "x-oanor-key: $KEY" \
  "https://api.oanor.com/abtest-api/v1/bucket?key=user-42&experiment=exp1&percentage=50"
```

**Response:**
```json
{
    "data": {
        "key": "user-42",
        "hash": 2066987872,
        "ratio": 0.481258,
        "bucket": 48,
        "buckets": 100,
        "enabled": true,
        "experiment": "exp1",
        "percentage": 50
    },
    "meta": {
        "timestamp": "2026-06-03T09:25:01.927Z",
        "request_id": "fe553bc6-79e1-40ca-b8dd-3fb4a6690d77"
    },
    "status": "ok",
    "message": "Bucket a key",
    "success": true
}
```

#### `GET /v1/variant` — Assign a variant

**Parameters:**
- `key` (query, required, string) — The unit Example: `user-42`
- `experiment` (query, optional, string) — Experiment/salt name Example: `cta`
- `variants` (query, required, string) — JSON array of {name,weight}, "a:50,b:50", or "a,b,c" Example: `control:70,treatment:30`

**Example:**
```bash
curl -H "x-oanor-key: $KEY" \
  "https://api.oanor.com/abtest-api/v1/variant?key=user-42&experiment=cta&variants=control%3A70%2Ctreatment%3A30"
```

**Response:**
```json
{
    "data": {
        "key": "user-42",
        "hash": 2472422117,
        "variant": "control",
        "weights": [
            {
                "name": "control",
                "share": 0.7,
                "weight": 70
            },
            {
                "name": "treatment",
                "share": 0.3,
                "weight": 30
            }
        ],
        "experiment": "cta"
    },
    "meta": {
        "timestamp": "2026-06-03T09:25:02.030Z",
        "request_id": "55d3d8cd-a193-4303-8f1c-e90378ac7cc5"
    },
    "status": "ok",
    "message": "Assign a variant",
    "success": true
}
```

### Meta

#### `GET /v1/meta` — Spec

**Example:**
```bash
curl -H "x-oanor-key: $KEY" \
  "https://api.oanor.com/abtest-api/v1/meta"
```

**Response:**
```json
{
    "data": {
        "name": "A/B Bucketing API",
        "notes": "Hashing is FNV-1a (32-bit) with an avalanche mix, so buckets are uniform and stable across languages and machines. Bucketing and variant assignment use independent hash domains. This assigns experiments; to test whether a result is statistically significant use a statistics API. Nothing is stored.",
        "version": "v1",
        "endpoints": [
            {
                "path": "/v1/bucket",
                "params": {
                    "key": "the unit to bucket — user id, session, etc. (required)",
                    "buckets": "number of buckets (default 100)",
                    "experiment": "experiment/salt name so experiments are independent",
                    "percentage": "if set, also return enabled = inside this % rollout"
                },
                "returns": "the stable bucket (and rollout decision)"
            },
            {
                "path": "/v1/variant",
                "params": {
                    "key": "the unit (required)",
                    "variants": "JSON array of {name,weight}, \"a:50,b:50\", or \"a,b,c\" (equal weights)",
                    "experiment": "experiment/salt name"
                },
                "returns": "the assigned variant and the weight shares"
            },
            {
                "path": "/v1/meta",
                "params": [],
                "returns": "this document"
            }
        ],
        "descrip
…(truncated, see openapi.json for full schema)
```


---
Marketplace page: https://www.oanor.com/api/abtest-api
OpenAPI spec: https://www.oanor.com/api/abtest-api/openapi.json
