# A/B Tests

Create A/B Tests using the `/api/experiments` endpoint. An experiment or A/B test is a set of distinct push notification variants sent to subsets of an audience. You can create up to 26 notification variants and send each variant to an audience subset.


{{< important >}}
The A/B Tests API is unrelated to the [current version of A/B testing](/docs/guides/experimentation/a-b-tests/messages/). For more information about this API, including its dashboard equivalent, see [Legacy message A/B tests](/docs/guides/experimentation/a-b-tests/messages-legacy/).
{{< /important >}}

## Create experiment (A/B Test) {#createexperiment}

Create an experiment. The body of the request should consist of a single experiment object. The experiment is processed and sent immediately unless a schedule is present.

[Jump to examples ↓](#createexperiment-examples)

### `POST /api/experiments`

{{< important >}}
The A/B Tests API is unrelated to the [current version of A/B testing](/docs/guides/experimentation/a-b-tests/messages/). For more information about this API, including its dashboard equivalent, see [Legacy message A/B tests](/docs/guides/experimentation/a-b-tests/messages-legacy/).
{{< /important >}}

**Security:**

- [basicAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-basicAuth)

**Request body**

**Content-Type:** `application/json`

[Experiment object]({{< ref "/developer/rest-api/ua/schemas/others/" >}}#experimentobject)

**Responses**

**`201`** The experiment was created.

Response headers:

| Name | Type | Description |
|------|------|-------------|
| `Location` | `string` | The newly created experiment. |

Response body:

**Content-Type:** `application/json`

- **`experiment_id`** `string`

  Unique identifier for an experiment.

  Format: `uuid`

  Example: `0f7704e9-5dc0-4f7d-9964-e89055701b0a`

- **`ok`** `boolean` **REQUIRED**

  If true, the experiment was successfully created. If false, the experiment was not created.

- **`operation_id`** `string`

  A unique string that represents a single API call, used to identify the operation or side effects in reporting and troubleshooting logs.

  Format: `uuid`

  Example: `ef625038-70a3-41f1-826f-57bc11dd625a`

- **`push_id`** `string`

  Unique identifier for a push.

  Format: `uuid`

  Example: `7e13f060-594c-11e4-8ed6-0800200c9a66`

**`400`** There was a parsing or validation error in the request. Bad Request errors typically include `path` and `location` in the response to help you find the cause of the error.

Response body:

**Content-Type:** `application/json`

[Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error)

**`401`** Authentication information (the app key and secret or bearer token) was either incorrect or missing.

Response body:

**Content-Type:** `text/plain`

[Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error)

**Examples**

*Example*

```http
POST /api/experiments HTTP/1.1
Authorization: Basic <authorization string>
Accept: application/vnd.urbanairship+json; version=3
Content-Type: application/json

{
    "name": "Experiment 1",
    "audience": {"tag": "earlyBirds"},
    "device_types": [ "ios", "android" ],
    "variants": [
        {
            "push": {
                "notification": {
                    "alert": "message 1"
                }
            }
        },
        {
            "push": {
                "notification": {
                    "alert": "message 2"
                }
            }
        }
    ]
}

```

```http
HTTP/1.1 201 Created
Content-Length: 123
Location: https://go.urbanairship.com/api/experiments/0f7704e9-5dc0-4f7d-9964-e89055701b0a
Content-Type: application/vnd.urbanairship+json; version=3

  {
    "ok" : "true",
    "operation_id" : "03ca94a3-2b27-42f6-be7e-41efc2612cd4",
    "experiment_id" : "0f7704e9-5dc0-4f7d-9964-e89055701b0a",
    "push_id" : "7e13f060-594c-11e4-8ed6-0800200c9a66"
  }

```

```java
UrbanAirshipClient client = UrbanAirshipClient.newBuilder()
        .setKey("<app key>")
        .setSecret("<master secret>")
        .build();

Schedule schedule = Schedule.newBuilder()
        .setScheduledTimestamp(DateTime.now().plusMinutes(5))
        .build();

Variant variantOne = Variant.newBuilder()
        .setPushPayload(VariantPushPayload.newBuilder()
        .setNotification(Notification.newBuilder()
                .setAlert("message 1")
                .build()
        )
        .build())
        .setSchedule(schedule)
        .build();

Variant variantTwo = Variant.newBuilder()
        .setPushPayload(VariantPushPayload.newBuilder()
        .setNotification(Notification.newBuilder()
                .setAlert("message 2")
                .build()
        )
        .build())
        .setSchedule(schedule)
        .build();

Experiment experiment = Experiment.newBuilder()
        .setName("Experiment 1")
        .setDescription("Testing description")
        .setDeviceTypes(DeviceTypeData.of(DeviceType.IOS, DeviceType.ANDROID))
        .setAudience(Selectors.tag("earlyBirds"))
        .addVariant(variantOne)
        .addVariant(variantTwo)
        .build();

ExperimentRequest request = ExperimentRequest.newRequest(experiment);
Response<ExperimentResponse> response = client.execute(request);

```

```python
from urbanairship import (
    BasicAuthClient, ABTest, Experiment, Variant
)
from urbanairship.push import notification

client = BasicAuthClient(
    key='<app_key>',
    secret='<master_secret>'
)

# Create push notifications for variants
push_1 = notification(alert='message 1')
push_2 = notification(alert='message 2')

# Create variants
variants = [
    Variant(push=push_1),
    Variant(push=push_2)
]

# Create experiment
experiment = Experiment(
    audience={'tag': 'earlyBirds'},
    device_types=['ios', 'android'],
    variants=variants,
    name='Experiment 1'
)

# Create and send experiment
ab_test = ABTest(airship=client)
response = ab_test.create(experiment=experiment)

```

```ruby
require 'urbanairship'

UA = Urbanairship
airship = UA::Client.new(key: '<app key>', secret: '<master secret>')

variant_one = UA::Variant.new(client: airship)
variant_one.push = {
    "notification": {
        "alert": "message 1"
    }
}
variant_two = UA::Variant.new(client: airship)
variant_two.push = {
    "notification": {
        "alert": "message 2"
    }
}
experiment = UA::Experiment.new(client: airship)
experiment.name = 'Experiment 1'
experiment.description = 'Example experiment'
experiment.audience = UA.tag('earlyBirds')
experiment.device_types = ['ios','android']
experiment.variants << variant_one.payload
experiment.variants << variant_two.payload
ab_test = UA::AbTest.new(client: airship)
ab_test.experiment_object = experiment.payload
ab_test.create_ab_test

```

---

## Delete experiment {#deleteexperiment}

Delete a scheduled experiment. You can only delete experiments before they start; attempting to delete an experiment that has already started or completed will return an HTTP 405 response ("Method not allowed").

[Jump to examples ↓](#deleteexperiment-examples)

### `DELETE /api/experiments/scheduled/{experiment_id}`

**Security:**

- [basicAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-basicAuth)

**Path parameters:**

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `experiment_id` | `string` | Required | The unique identifier of the experiment. |

**Responses**

**`200`** Returned if the experiment has been successfully deleted.

Response body:

**Content-Type:** `application/json`

- **`ok`** `boolean` **REQUIRED**

  Success.

- **`operation_id`** `string`

  A unique string that represents a single API call, used to identify the operation or side effects in reporting and troubleshooting logs.

  Format: `uuid`

  Example: `ef625038-70a3-41f1-826f-57bc11dd625a`

**`401`** Authentication information (the app key and secret or bearer token) was either incorrect or missing.

Response body:

**Content-Type:** `text/plain`

[Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error)

**`404`** The requested resource doesn't exist.

Response body:

**Content-Type:** `application/vnd.urbanairship+json`

[Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error)

**`405`** Returned when a request is made using an HTTP method not supported by the endpoint. For example, sending a DELETE to /api/schedules.

Response body:

**Content-Type:** `application/json`

[Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error)

**Examples**

*Example*

```http
DELETE /api/experiments/scheduled/0f7704e9-5dc0-4f7d-9964-e89055701b0a HTTP/1.1
Authorization: Basic <authorization string>
Accept: application/vnd.urbanairship+json; version=3

```

```http
HTTP/1.1 200 OK
Content-Length: 123
Content-Type: application/vnd.urbanairship+json; version=3

{
  "ok" : "true",
  "operation_id" : "03ca94a3-2b27-42f6-be7e-41efc2612cd4"
}

```

```java
UrbanAirshipClient client = UrbanAirshipClient.newBuilder()
        .setKey("<app key>")
        .setSecret("<master secret>")
        .build();

ExperimentDeleteRequest request = ExperimentDeleteRequest.newRequest("0f7704e9-5dc0-4f7d-9964-e89055701b0a");
Response<ExperimentResponse> response = client.execute(request);

```

```python
from urbanairship import (
    BasicAuthClient, ABTest
)

client = BasicAuthClient(
    key='<app_key>',
    secret='<master_secret>'
)

ab_test = ua.ABTest(client)
ab_test.experiment_id = "0f7704e9-5dc0-4f7d-9964-e89055701b0a"

response = ab_test.delete()

```

```ruby
require 'urbanairship'

UA = Urbanairship
airship = UA::Client.new(key: '<app key>', secret: '<master secret>')

ab_test = UA::AbTest.new(client: airship)
ab_test.experiment_id = '0f7704e9-5dc0-4f7d-9964-e89055701b0a'
ab_test.delete_ab_test

```

---

## Experiment listing {#getexperiments}

List experiments, sorted by `created_at` [date-time](/docs/developer/rest-api/ua/introduction/#date-time-format) from newest to oldest. Responses are paginated. Use optional `limit` and `offset` parameters to navigate results.

[Jump to examples ↓](#getexperiments-examples)

### `GET /api/experiments`

**Security:**

- [basicAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-basicAuth)

**Query parameters:**

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `limit` | `integer` |  | Positive maximum number of elements to return per page. The default `limit` is 10 entries with a maximum of 100 entries. Min: 1 Max: 100 |
| `offset` | `integer` |  | A zero-based integer offset into the result set. If you do not use an offset, results will begin with the most recently sent experiment. If `offset` is greater than the number of queryable experiments, an empty result will be returned. |

**Responses**

**`200`** Returned on success, with the JSON representation of the experiments in the body of the response.

Response body:

**Content-Type:** `application/json`

- **`count`** `integer`

  The number of items returned in this page of results.

- **`experiments`** `array` <[Experiment object]({{< ref "/developer/rest-api/ua/schemas/others/" >}}#experimentobject)>

  Experiment objects sorted by either `created_at` from newest to oldest. The number of objects will never exceed the limit specified in the request.

- **`next_page`** `string`

  A relative URL leading to the next page of results. If there are no more results, next_page is absent.

- **`ok`** `boolean` **REQUIRED**

  If true, the call was successful.

- **`total_count`** `integer`

  The total number of results.

**`401`** Authentication information (the app key and secret or bearer token) was either incorrect or missing.

Response body:

**Content-Type:** `text/plain`

[Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error)

**Examples**

*Example*

```http
GET /api/experiments HTTP/1.1
Authorization: Basic <authorization string>
Accept: application/vnd.urbanairship+json; version=3

```

```http
HTTP/1.1 200 OK
Content-Length: 123
Data-Attribute: experiments
Count: 2
Total-Count: 2
Content-Type: application/vnd.urbanairship+json; version=3

 {
   "ok" : "true",
   "count" : 2,
   "total_count" : 2,
   "experiments" : [{
     "name" : "Experiment 1",
     "control" : 0.33,
     "audience" : "all",
     "device_types": [ "ios", "android" ],
     "variants" : [{
       "push" : {
         "notification" : {
           "alert" : "message 1"
         }
       },
       "id" : 0,
     },
     {
       "push" : {
           "notification" : {
             "alert" : "message 2"
           }
       },
       "id" : 1,
     }],
     "id" : "b5bc3dd1-9ea4-4208-b5f1-9e7ac3fe0502",
     "created_at" : "2020-03-03T21:08:05",
     "push_id" : "07cec298-6b8c-49f9-8e03-0448a06f4aac"
   }, {
     "name" : "Experiment 2",
     "description" : "The second experiment",
     "audience" : "all",
     "device_types": [ "ios", "android" ],
     "variants" : [{
       "push" : {
         "notification" : {
           "alert" : "message 1"
         }
       },
       "id" : 0,
     },
     {
       "push" : {
           "notification" : {
             "alert" : "message 2"
           }
       },
       "id" : 1,
     }],
     "id" : "e464aa7e-be40-4994-a290-1bbada7187d8",
     "created_at" : "2020-03-03T21:08:05",
     "push_id" : "07cec298-6b8c-49f9-8e03-0448a06f4aac"
   }]
}

```

```python
from urbanairship import (
    BasicAuthClient, ABTest
)

client = BasicAuthClient(
    key='<app_key>',
    secret='<master_secret>'
)
ab_test = ABTest(airship=client)
response = ab_test.list_experiments()

```

```ruby
require 'urbanairship'

UA = Urbanairship
airship = UA::Client.new(key: '<app key>', secret: '<master secret>')

ab_test = UA::AbTest.new(client: airship)
ab_test.limit = 5
ab_test.list_ab_test

```

---

## Experiment lookup {#getexperiment}

Look up an experiment (A/B Test).

[Jump to examples ↓](#getexperiment-examples)

### `GET /api/experiments/{experiment_id}`

**Security:**

- [basicAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-basicAuth)

**Path parameters:**

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `experiment_id` | `string` | Required | The ID of the experiment you want to look up. |

**Responses**

**`200`** Returned on success, with the JSON representation of the experiment in the body of the response.

Response body:

**Content-Type:** `application/json`

- **`experiment`** `object` <[Experiment object]({{< ref "/developer/rest-api/ua/schemas/others/" >}}#experimentobject)>

  An experiment object describes an A/B test, including the audience and variant portions.

- **`ok`** `boolean` **REQUIRED**

  If true, the operation completed successfully and returns a result set.

**`401`** Authentication information (the app key and secret or bearer token) was either incorrect or missing.

Response body:

**Content-Type:** `text/plain`

[Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error)

**`404`** The requested resource doesn't exist.

Response body:

**Content-Type:** `application/vnd.urbanairship+json`

[Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error)

**Examples**

*Example*

```http
GET /api/experiments/0f7704e9-5dc0-4f7d-9964-e89055701b0a HTTP/1.1
Authorization: Basic <authorization string>
Accept: application/vnd.urbanairship+json; version=3

```

```http
HTTP/1.1 200 OK
Content-Length: 123
Data-Attribute: experiment
Content-Type: application/vnd.urbanairship+json; version=3

{
   "ok" : "true",
   "experiment" : {
      "id" : "0f7704e9-5dc0-4f7d-9964-e89055701b0a",
      "push_id": "d00f07b0-594c-11e4-8ed6-0800200c9a66",
      "name" : "Experiment 1",
      "audience" : "all",
      "device_types": [ "ios", "android" ],
      "variants" : [{
            "push" : {
               "notification" : {
                  "alert" : "message 1"
               }
            },
            "id" : 0,
         },
         {
            "push" : {
               "notification" : {
               "alert" : "message 2"
            }
         },
         "id" : 1,
     }]
   }
}

```

```python
from urbanairship import BasicAuthClient, ABTest

client = BasicAuthClient(
    key='<app_key>',
    secret='<master_secret>'
)
ab_test = ABTest(client)
response = ab_test.lookup(experiment_id='0f7704e9-5dc0-4f7d-9964-e89055701b0a')

```

```ruby
require 'urbanairship'
UA = Urbanairship

airship = UA::Client.new(key: '<app key>', secret: '<master secret>')
ab_test = UA::AbTest.new(client: airship)

ab_test.experiment_id = '0f7704e9-5dc0-4f7d-9964-e89055701b0a'
ab_test.lookup_ab_test

```

---

## Scheduled experiment listing {#getscheduledexperiments}

List scheduled experiments in order, from closest to the current [date-time](/docs/developer/rest-api/ua/introduction/#date-time-format) to farthest (i.e., the experiments scheduled to occur soonest will appear at the top of the list). Responses are paginated, using optional `limit` and `offset` parameters.

[Jump to examples ↓](#getscheduledexperiments-examples)

### `GET /api/experiments/scheduled`

**Security:**

- [basicAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-basicAuth)

**Query parameters:**

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `limit` | `integer` |  | Positive maximum number of elements to return per page. The default `limit` is 10 entries with a maximum of 100 entries. Min: 1 Max: 100 |
| `offset` | `integer` |  | A zero-based integer offset into the result set. If you do not use an offset, results will begin with experiment scheduled to begin at the soonest [date-time](/docs/developer/rest-api/ua/introduction/#date-time-format). If the `offset` is greater than the number of queryable experiments, the result set will be empty. |

**Responses**

**`200`** Returned on success, with the JSON representation of the experiments in the body of the response.

Response body:

**Content-Type:** `application/json`

- **`count`** `integer`

  The number of items in this page of results.

- **`experiments`** `array` <[Experiment object]({{< ref "/developer/rest-api/ua/schemas/others/" >}}#experimentobject)>

  Experiments listed by `scheduled_time` in ascending time order. The number of objects will never exceed the `limit` specified in the request.

- **`next_page`** `string`

  A relative URL leading to the next page of results. If there are no more results, next_page is absent.

- **`ok`** `boolean` **REQUIRED**

  If true, the operation completed successfully and returns an expected result set.

- **`total_count`** `integer`

  The total number of results.

**`401`** Authentication information (the app key and secret or bearer token) was either incorrect or missing.

Response body:

**Content-Type:** `text/plain`

[Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error)

**Examples**

*Example*

```http
GET /api/experiments/scheduled HTTP/1.1
Authorization: Basic <authorization string>
Accept: application/vnd.urbanairship+json; version=3

```

```http
HTTP/1.1 200 OK
Content-Length: 123
Data-Attribute: experiments
Content-Type: application/vnd.urbanairship+json; version=3

{
    "ok": "true",
    "count": 2,
    "total_count": 2,
    "experiments": [
        {
            "id": "0f7704e9-5dc0-4f7d-9964-e89055701b0a",
            "name": "Experiment 1",
            "audience": "all",
            "device_types": [ "ios", "android" ],
            "variants": [
                {
                    "id": 0,
                    "schedule": {
                        "scheduled_time": "2020-11-17T20:58:00Z"
                    },
                    "push": {
                        "notification": {
                            "alert": "message 1"
                        }
                    }
                },
                {
                    "id": 1,
                    "schedule": {
                        "scheduled_time": "2020-11-17T20:58:00Z"
                    },
                    "push": {
                        "notification": {
                            "alert": "message 2"
                        }
                    }
                }
            ]
        },
        {
            "id": "29705c10-5951-11e4-8ed6-0800200c9a66",
            "name": "Experiment 2",
            "audience": "all",
            "device_types": [ "ios", "android" ],
            "variants": [
                {
                    "id": 0,
                    "schedule": {
                        "scheduled_time": "2020-12-17T20:58:00Z"
                    },
                    "push": {
                        "notification": {
                            "alert": "message 1"
                        }
                    }
                },
                {
                    "id": 1,
                    "schedule": {
                        "scheduled_time": "2020-12-17T20:58:00Z"
                    },
                    "push": {
                        "notification": {
                            "alert": "message 2"
                        }
                    }
                }
            ]
        }
    ]
}

```

```python
from urbanairship import (
    BasicAuthClient, ABTest
)

client = BasicAuthClient(
    key='<app_key>',
    secret='<master_secret>'
)
ab_test = ABTest(client)
response = ab_test.list_scheduled_experiment()

```

```ruby
require 'urbanairship'

UA = Urbanairship
airship = UA::Client.new(key: '<app key>', secret: '<master secret>')

ab_test = UA::AbTest.new(client: airship)
ab_test.list_scheduled_ab_test

```

---

## Validate experiment {#validateexperiment}

Accepts the same range of payloads as `/api/experiments`, but only parses and validates the payload without creating the experiment. This does the same amount of validation as the creation endpoint, including platform-specific validation, e.g., APNs byte limit checks. While this operation ensures the experiment is technically valid, it does not guarantee that a resulting push will succeed. An experiment may validate and still fail to be delivered. For example, you may have a valid experiment with no devices in your audience.

[Jump to examples ↓](#validateexperiment-examples)

### `POST /api/experiments/validate`

**Security:**

- [basicAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-basicAuth)

**Request body**

A single experiment object.

**Content-Type:** `application/json`

[Experiment object]({{< ref "/developer/rest-api/ua/schemas/others/" >}}#experimentobject)

**Responses**

**`200`** The experiment is valid.

Response body:

**Content-Type:** `application/json`

- **`ok`** `boolean` **REQUIRED**

  If true, the operation completed successfully and returns an expected response.

- **`operation_id`** `string`

  A unique string that represents a single API call, used to identify the operation or side effects in reporting and troubleshooting logs.

  Format: `uuid`

  Example: `ef625038-70a3-41f1-826f-57bc11dd625a`

**`400`** There was a parsing or validation error in the request. Bad Request errors typically include `path` and `location` in the response to help you find the cause of the error.

Response body:

**Content-Type:** `application/json`

[Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error)

**`401`** Authentication information (the app key and secret or bearer token) was either incorrect or missing.

Response body:

**Content-Type:** `text/plain`

[Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error)

**Examples**

*Example*

```http
POST /api/experiments/validate HTTP/1.1
Authorization: Basic <authorization string>
Accept: application/vnd.urbanairship+json; version=3
Content-Type: application/json

{
    "name": "Experiment 1",
    "audience": {"tag": "earlyBirds"},
    "device_types": [ "ios", "android" ],
    "variants": [
        {
            "push": {
                "notification": {
                    "alert": "message 1"
                }
            }
        },
        {
            "push": {
                "notification": {
                    "alert": "message 2"
                }
            }
        }
    ]
}

```

```http
HTTP/1.1 200 OK
Content-Length: 123
Content-Type: application/vnd.urbanairship+json; version=3

{
  "ok" : "true",
  "operation_id" : "03ca94a3-2b27-42f6-be7e-41efc2612cd4"
}

```

```java
UrbanAirshipClient client = UrbanAirshipClient.newBuilder()
        .setKey("<app key>")
        .setSecret("<master secret>")
        .build();

Schedule schedule = Schedule.newBuilder()
        .setScheduledTimestamp(DateTime.now().plusMinutes(5))
        .build();

Variant variantOne = Variant.newBuilder()
        .setPushPayload(VariantPushPayload.newBuilder()
        .setNotification(Notification.newBuilder()
                .setAlert("message 1")
                .build()
        )
        .build())
        .setSchedule(schedule)
        .build();

Variant variantTwo = Variant.newBuilder()
        .setPushPayload(VariantPushPayload.newBuilder()
        .setNotification(Notification.newBuilder()
                .setAlert("message 2")
                .build()
        )
        .build())
        .setSchedule(schedule)
        .build();

Experiment experiment = Experiment.newBuilder()
        .setName("Experiment 1")
        .setDescription("Testing description")
        .setDeviceTypes(DeviceTypeData.of(DeviceType.IOS, DeviceType.ANDROID))
        .setAudience(Selectors.tag("earlyBirds"))
        .addVariant(variantOne)
        .addVariant(variantTwo)
        .build();

ExperimentRequest request = ExperimentRequest.newRequest(experiment).setValidateOnly(true);
Response<ExperimentResponse> response = client.execute(request);

```

```python
from urbanairship import (
    BasicAuthClient, ABTest, Experiment, Variant
)
from urbanairship.push import notification

client = BasicAuthClient(
    key='<app_key>',
    secret='<master_secret>'
)

# Create push notifications for variants
push_1 = notification(alert='message 1')
push_2 = notification(alert='message 2')

# Create variants
variants = [
    Variant(push=push_1),
    Variant(push=push_2)
]

# Create experiment
experiment = Experiment(
    audience={'tag': 'earlyBirds'},
    device_types=['ios', 'android'],
    variants=variants,
    name='Experiment 1'
)

# Validate experiment
ab_test = ABTest(airship=client)
response = ab_test.validate(experiment=experiment)

```

```ruby
require 'urbanairship'

UA = Urbanairship
airship = UA::Client.new(key: '<app key>', secret: '<master secret>')

variant_one = UA::Variant.new(client: airship)
variant_one.push = {
    "notification": {
        "alert": "message 1"
    }
}
variant_two = UA::Variant.new(client: airship)
variant_two.push = {
    "notification": {
        "alert": "message 2"
    }
}
experiment = UA::Experiment.new(client: airship)
experiment.name = 'Experiment 1'
experiment.description = 'Example experiment'
experiment.audience = UA.tag('earlyBirds')
experiment.device_types = ['ios','android']
experiment.variants << variant_one.payload
experiment.variants << variant_two.payload
ab_test = UA::AbTest.new(client: airship)
ab_test.experiment_object = experiment.payload
ab_test.validate_ab_test

```

---

