# Usage

### Overview

The Decision API uses a **visitor-centric model** where decisions are made based on:

* **Visitor ID**: A unique identifier for the user
* **Context**: Key-value pairs describing the visitor (device type, location, user attributes, etc.)

The API returns personalized **campaigns** (A/B tests, feature flags) and **modifications** (variations, flag values) tailored to each visitor.

***

### Get Decision

The `/v2/campaigns` endpoint retrieves all active campaigns and their variations for a specific visitor.

#### Concept

When you send a visitor's ID and context, the Decision API:

1. Fetches your configuration from FE\&R
2. Evaluates targeting rules against the visitor's context
3. Assigns the visitor to appropriate campaigns and variations
4. Returns the list of campaigns with their modifications

This is the **primary endpoint** for getting all decisions in one call.

#### Endpoint

```
POST /v2/campaigns
```

#### Request Body

```json
{
  "visitor_id": "unique_visitor_id",
  "context": {
    "key": "value"
  },
  "trigger_hit": false
}
```

**Parameters:**

* `visitor_id` (string, required): Unique identifier for the visitor
* `context` (object, optional): Key-value pairs describing the visitor
* `trigger_hit` (boolean, optional): If `true`, automatically sends an activation hit (default: `false`)

#### Example: Basic Request

```bash
curl -X POST http://localhost:8080/v2/campaigns \
  -H "Content-Type: application/json" \
  -d '{
    "visitor_id": "user_123",
    "context": {
      "platform": "web",
      "device": "desktop"
    }
  }'
```

#### Response

```json
{
  "visitorId": "user_123",
  "campaigns": [
    {
      "id": "c1a2b3c4d5e6f7g8",
      "variationGroupId": "vg1234567890",
      "variation": {
        "id": "var_abc123",
        "modifications": {
          "type": "FLAG",
          "value": {
            "btnColor": "blue",
            "btnText": "Buy Now"
          }
        },
        "reference": false
      }
    },
    {
      "id": "c1a2b3c4d5e6f7g9",
      "variationGroupId": "vg9876543210",
      "variation": {
        "id": "var_xyz789",
        "modifications": {
          "type": "FLAG",
          "value": {
            "enableNewCheckout": true,
            "maxCartItems": 50
          }
        },
        "reference": false
      }
    }
  ]
}
```

**Response Structure:**

* `visitorId`: The visitor ID from the request
* `campaigns`: Array of active campaigns for this visitor
  * `id`: Campaign identifier
  * `variationGroupId`: Variation group identifier
  * `variationGroupName`: Variation group name
  * `variation.id`: Assigned variation identifier
  * `variation.modifications.type`: Modification type
  * `variation.modifications.value`: Key-value pairs with configuration values
  * `variation.reference`: `true` if this is the control group (original)

#### Example: With Context-Based Targeting

```bash
curl -X POST http://localhost:8080/v2/campaigns \
  -H "Content-Type: application/json" \
  -d '{
    "visitor_id": "premium_user_456",
    "context": {
      "userType": "premium",
      "country": "US",
      "appVersion": "2.1.0"
    }
  }'
```

#### Example: With Automatic Activation

```bash
curl -X POST http://localhost:8080/v2/campaigns \
  -H "Content-Type: application/json" \
  -d '{
    "visitor_id": "user_789",
    "context": {
      "platform": "mobile"
    },
    "trigger_hit": true
  }'
```

When `trigger_hit: true`, the API automatically sends activation events for all returned campaigns.

***

### Get Feature Flag

The `/v2/flags` endpoint allows you to retrieves feature flags in a simplified, developer-friendly format.

#### Concept

Feature flags are part of the data included in campaigns and are specifically designed for:

* Enabling/disabling features
* Configuration management
* Progressive rollouts

This endpoint transforms campaign modifications into a **flat key-value structure**, making it easier to check flags in your code.

#### Endpoint

```
POST /v2/flags
```

#### Request Body

```json
{
  "visitor_id": "unique_visitor_id",
  "context": {
    "key": "value"
  }
}
```

**Parameters:**

* `visitor_id` (string, required): Unique identifier for the visitor
* `context` (object, optional): Key-value pairs describing the visitor

#### Example: Basic Request

```bash
curl -X POST http://localhost:8080/v2/flags \
  -H "Content-Type: application/json" \
  -d '{
    "visitor_id": "user_123",
    "context": {
      "platform": "web"
    }
  }'
```

#### Response

```json
{
  "enableNewCheckout": {
    "value": true,
    "metadata": {
      "campaignId": "campaign_feature_x",
      "campaignName": "New Checkout Test",
      "slug": null,
      "type": "ab",
      "variationGroupId": "vg9876543210",
      "variationGroupName": "VG New Checkout",
      "variationId": "var_xyz789",
      "variationName": "Variation A",
      "reference": false
    }
  },
  "maxCartItems": {
    "value": 50,
    "metadata": {
      "campaignId": "campaign_feature_x",
      "campaignName": "New Checkout Test",
      "slug": null,
      "type": "ab",
      "variationGroupId": "vg9876543210",
      "variationGroupName": "VG New Checkout",
      "variationId": "var_xyz789",
      "variationName": "Variation A",
      "reference": false
    }
  },
  "btnColor": {
    "value": "blue",
    "metadata": {
      "campaignId": "c1a2b3c4d5e6f7g8",
      "campaignName": "Homepage CTA Test",
      "slug": "homepage-cta",
      "type": "ab",
      "variationGroupId": "vg1234567890",
      "variationGroupName": "VG Homepage",
      "variationId": "var_abc123",
      "variationName": "Blue Button",
      "reference": false
    }
  }
}
```

**Response Structure:**

* Each flag key maps to an object containing:
  * `value`: The flag value (can be any JSON type)
  * `metadata`: Information about the campaign and variation
    * `campaignId`: Campaign identifier
    * `campaignName`: Human-readable campaign name
    * `slug`: Campaign slug (if set)
    * `type`: Campaign type (`ab`, `toggle`, etc.)
    * `variationGroupId`: Variation group identifier
    * `variationGroupName`: Variation group name
    * `variationId`: Assigned variation identifier
    * `variationName`: Variation name
    * `reference`: `true` if this is the control/reference variation

#### Example: Multi-Platform Context

```bash
curl -X POST http://localhost:8080/v2/flags \
  -H "Content-Type: application/json" \
  -d '{
    "visitor_id": "mobile_user_999",
    "context": {
      "platform": "mobile",
      "os": "iOS",
      "osVersion": "17.1",
      "appVersion": "3.2.1"
    }
  }'
```

#### Example: Anonymous Visitor

```bash
curl -X POST http://localhost:8080/v2/flags \
  -H "Content-Type: application/json" \
  -d '{
    "anonymous_id": "anonymous_' $(uuidgen) '",
    "visitor_id": null,
    "context": {
      "isAuthenticated": false
    }
  }'
```

***

### Activate a Campaign

The `/v2/activate` endpoint sends an **activation event** when a visitor is exposed to a campaign variation.

#### Concept

Activation tracking is crucial for **analytics and attribution**. You should activate a campaign when:

* A visitor **sees** the variation (impression tracking)
* A feature is **actually used** (not just loaded)
* You want to track **which users experienced a variation**

**Important:** Only activate when the user is genuinely exposed to the experience. Don't activate on page load if the feature isn't visible.

#### Endpoint

```
POST /v2/activate
```

#### Request Body

```json
{
  "vid": "visitor_id",
  "cid": "environment_id",
  "caid": "variation_group_id",
  "vaid": "variation_id"
}
```

**Parameters:**

* `vid` (string, required): Visitor ID
* `cid` (string, required): Environment ID (your FE\&R environment ID)
* `caid` (string, required): Variation Group ID (from `/v2/campaigns` response: `variationGroupId`)
* `vaid` (string, required): Variation ID (from `/v2/campaigns` response: `variation.id`)
* `aid` (string, optional): Anonymous ID if different from visitor ID

#### Example: Basic Activation

```bash
curl -X POST http://localhost:8080/v2/activate \
  -H "Content-Type: application/json" \
  -d '{
    "vid": "user_123",
    "cid": "your_env_id",
    "caid": "vg1234567890",
    "vaid": "var_abc123"
  }'
```

#### Response

**Status Code:** `204 No Content`

The activate endpoint returns an empty response body with a 204 status code on success.

#### Example: Activate Multiple Campaigns

**Default settings:**

* Batch size: **50 hits**
* Batching window: **30 seconds**
* Hits are sent when either condition is met:
  * Batch reaches 50 hits, OR
  * 30 seconds have passed since last send

#### Batch Activate

You can activate multiple campaigns in a **single HTTP request** using the batch format:

```bash
curl -X POST http://localhost:8080/v2/activate \
  -H "Content-Type: application/json" \
  -d '{
    "cid": "your_env_id",
    "batch": [
      {
        "vid": "user_456",
        "caid": "vg_homepage",
        "vaid": "variation_blue_button"
      },
      {
        "vid": "user_456",
        "caid": "vg_checkout",
        "vaid": "variation_express_checkout"
      },
      {
        "vid": "user_456",
        "caid": "vg_feature_x",
        "vaid": "variation_enabled"
      }
    ]
  }'
```

**Batch Format:**

* `cid` (string, required): Environment ID - applies to all items in the batch
* `batch` (array, required): Array of activation objects, each containing:
  * `vid` (string, required): Visitor ID
  * `caid` (string, required): Variation Group ID
  * `vaid` (string, required): Variation ID
  * `aid` (string, optional): Anonymous ID

**Benefits of batching:**

* Reduces HTTP overhead (1 request instead of N)
* Atomic operation - all activations processed together
* Better performance for multiple simultaneous activations

#### Separate Requests

```bash
# Activate first campaign
curl -X POST http://localhost:8080/v2/activate \
  -H "Content-Type: application/json" \
  -d '{
    "vid": "user_456",
    "cid": "your_env_id",
    "caid": "vg_homepage",
    "vaid": "variation_blue_button"
  }'

# Activate second campaign
curl -X POST http://localhost:8080/v2/activate \
  -H "Content-Type: application/json" \
  -d '{
    "vid": "user_456",
    "cid": "your_env_id",
    "caid": "vg_checkout",
    "vaid": "variation_express_checkout"
  }'
```

#### When to Activate

✅ **Do activate when:**

* User sees a variation on their screen
* Feature is rendered/displayed
* User interacts with a feature

❌ **Don't activate when:**

* Just fetching configuration
* Preloading data
* User hasn't seen the variation yet

### Best Practices

#### 1. Use Meaningful Visitor IDs

```bash
# Good: Persistent user ID
"visitor_id": "user_12345"

# Good: Anonymous but trackable
"visitor_id": "device_abc-xyz-123"

# Bad: Random on every request
"visitor_id": "random_' $(uuidgen) '"
```

#### 2. Provide Rich Context

```bash
# Good: Rich targeting context
curl -X POST http://localhost:8080/v2/campaigns \
  -H "Content-Type: application/json" \
  -d '{
    "visitor_id": "user_123",
    "context": {
      "platform": "web",
      "device": "mobile",
      "userType": "premium",
      "country": "US",
      "language": "en",
      "appVersion": "2.1.0"
    }
  }'

# Bad: Minimal context
curl -X POST http://localhost:8080/v2/campaigns \
  -H "Content-Type: application/json" \
  -d '{
    "visitor_id": "user_123"
  }'
```

#### 3. Activate Only on Exposure

```bash
# Good: Activate when feature is shown
if user_sees_feature; then
  curl -X POST http://localhost:8080/v2/activate ...
fi

# Bad: Activate immediately after getting campaigns
curl -X POST http://localhost:8080/v2/campaigns ...
curl -X POST http://localhost:8080/v2/activate ...  # User hasn't seen it yet!
```

***

### Custom Visitor Cache Assignment Connector

The Decision API supports **custom visitor cache assignment connectors** to persist visitor assignments when using advanced features:

* **Experience Continuity (XPC)**: Keep visitors in the same variation across sessions
* **1 Visitor 1 Test (1v1t)**: Ensure each visitor is assigned to only one campaign
* **Dynamic Allocation**: Support traffic allocation changes

By default, the Decision API uses an **empty connector** (no persistence). For production use with these features, configure one of the available cache types. The Self-Hosted Decision API provides 4 cache systems to store and retrieve visitor assignments to allow traffic allocation changes for live use cases:

* in memory: the assignments are stored in memory
* local: the assignments are stored in a local file using a key/value database
* redis: the assignments are stored in a redis server
* dynamo: the assignments are stored in an AWS DynamoDB table

If you want to use another cache management system, you still can, but you will need to create a Go application that runs the Decision API package, and implement your own visitor assignment interface.

Here is an example of how you can do that:

{% code fullWidth="false" %}

```go
package main

import (
  "log"
  "net/http"
  "os"
  "time"

  "github.com/flagship-io/decision-api/pkg/connectors"
  "github.com/flagship-io/decision-api/pkg/server"
  common "github.com/flagship-io/flagship-common"
)

type CustomAssignmentManager struct {
}

func (m *CustomAssignmentManager) LoadAssignments(envID string, visitorID string) (*common.VisitorAssignments, error) {
  // TODO implement this method
  return nil, nil
}

func (m *CustomAssignmentManager) ShouldSaveAssignments(context connectors.SaveAssignmentsContext) bool {
  // TODO implement this method
  return true
}

func (m *CustomAssignmentManager) SaveAssignments(envID string, visitorID string, vgIDAssignments map[string]*common.VisitorCache, date time.Time) error {
  // TODO implement this method
  return nil
}

func main() {
  srv, err := server.CreateServer(
    os.Getenv("ENV_ID"),
    os.Getenv("API_KEY"),
    ":8080",
    server.WithAssignmentsManager(&CustomAssignmentManager{}),
  )

  if err != nil {
    log.Fatalf("error when creating server: %v", err)
  }

  log.Printf("server listening on :8080")
  if err := srv.Listen(); err != http.ErrServerClosed {
    log.Fatalf("error when starting server: %v", err)
  }
}
```

{% endcode %}

#### Metrics endpoint

On top of the usual endpoints, the open source Decision API also exposes a /v2/metrics endpoint, which can be used to monitor the API performance, errors and response time.\
The metrics output format looks like:

```json
{
  "cmdline": [
    "./bin/server"
  ],
  "handlers.activate.errors": 0,
  "handlers.activate.response_time.p50": 0,
  "handlers.activate.response_time.p90": 0,
  "handlers.activate.response_time.p95": 0,
  "handlers.activate.response_time.p99": 0,
  "handlers.campaign.errors": 0,
  "handlers.campaign.response_time.p50": 0,
  "handlers.campaign.response_time.p90": 0,
  "handlers.campaign.response_time.p95": 0,
  "handlers.campaign.response_time.p99": 0,
  "handlers.campaigns.errors": 0,
  "handlers.campaigns.response_time.p50": 1,
  "handlers.campaigns.response_time.p90": 4,
  "handlers.campaigns.response_time.p95": 10,
  "handlers.campaigns.response_time.p99": 11,
  "handlers.flags.errors": 0,
  "handlers.flags.response_time.p50": 1,
  "handlers.flags.response_time.p90": 1,
  "handlers.flags.response_time.p95": 1,
  "handlers.flags.response_time.p99": 1,
  "memstats": {}
}
```

#### Swagger endpoint

The Decision API also provides a `/v2/swagger/` endpoint with interactive Swagger UI documentation where you can explore all available endpoints and test API calls directly from your browser.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.abtasty.com/server-side/decision-api/run-on-premise/usage.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
