> For the complete documentation index, see [llms.txt](https://docs.tryterra.co/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.tryterra.co/vantage-api-docs/getting-started/ordering-your-first-test.md).

# Ordering your first test

**Prerequisites:** Vantage sandbox credentials and a configured webhook endpoint ([Account setup and authentication](/vantage-api-docs/account-setup-and-api-keys.md)). All examples below run against the sandbox.

Key terminology (full detail in [Core concepts](/vantage-api-docs/core-concepts.md)), with a consumer-electronics analogy:

* `Product type`: the broadest category of offering (e.g. iPhone, MacBook, iPad)
* `Product`: individual products within each type (e.g. iPhone 17 Pro, iPhone 16 Pro Max)
* `Product variant`: the specific configuration an end user receives (e.g. iPhone 17 White 256GB) - **this is what you order**

{% hint style="info" %}
**Production:** `https://vantage.tryterra.co` | **Sandbox:** `https://vantage-sandbox.tryterra.co`
{% endhint %}

### 1. Explore product types

{% tabs %}
{% tab title="cURL" %}

```bash
curl 'https://vantage-sandbox.tryterra.co/api/v1/products' \
  -u 'YOUR_DEV_ID:YOUR_API_KEY'
```

{% endtab %}

{% tab title="Python" %}

```python
import requests

url = "https://vantage-sandbox.tryterra.co/api/v1/products"
response = requests.get(url, auth=("YOUR_DEV_ID", "YOUR_API_KEY"))
print(response.text)
```

{% endtab %}

{% tab title="Go" %}

```go
package main

import (
    "fmt"
    "io"
    "net/http"
)

func main() {
    url := "https://vantage-sandbox.tryterra.co/api/v1/products"

    req, _ := http.NewRequest("GET", url, nil)
    req.SetBasicAuth("YOUR_DEV_ID", "YOUR_API_KEY")

    res, _ := http.DefaultClient.Do(req)
    defer res.Body.Close()

    body, _ := io.ReadAll(res.Body)
    fmt.Println(string(body))
}
```

{% endtab %}
{% endtabs %}

{% tabs %}
{% tab title="200" %}

```json
[
  {
    "id": 1,
    "name": "Blood Test",
    "description": "Diagnostic blood panels and biomarker tests"
  }
]
```

{% endtab %}
{% endtabs %}

### 2. Explore products within a product type

Suppose we want a blood test. `1` is the **product type** ID from the response above:

{% tabs %}
{% tab title="cURL" %}

```bash
curl 'https://vantage-sandbox.tryterra.co/api/v1/products/1' \
  -u 'YOUR_DEV_ID:YOUR_API_KEY'
```

{% endtab %}

{% tab title="Python" %}

```python
import requests

product_type_id = 1
url = f"https://vantage-sandbox.tryterra.co/api/v1/products/{product_type_id}"
response = requests.get(url, auth=("YOUR_DEV_ID", "YOUR_API_KEY"))
print(response.text)
```

{% endtab %}
{% endtabs %}

{% tabs %}
{% tab title="200" %}

```json
[
  {
    "id": 10002,
    "product_type_id": 1,
    "name": "Blood Test",
    "description": "At-home blood test kit with lab processing.",
    "base_price_cents": 4999,
    "currency": 840,
    "availability": 1
  }
]
```

{% endtab %}
{% endtabs %}

### 3. Explore product variants

Now let's choose the exact blood test to order. `10002` is the product ID from the response above:

{% tabs %}
{% tab title="cURL" %}

```bash
curl 'https://vantage-sandbox.tryterra.co/api/v1/products/10002/variants' \
  -u 'YOUR_DEV_ID:YOUR_API_KEY'
```

{% endtab %}

{% tab title="Python" %}

```python
import requests

product_id = 10002
url = f"https://vantage-sandbox.tryterra.co/api/v1/products/{product_id}/variants"
response = requests.get(url, auth=("YOUR_DEV_ID", "YOUR_API_KEY"))
print(response.text)
```

{% endtab %}
{% endtabs %}

{% tabs %}
{% tab title="200" %}

```json
[
  {
    "id": 100041,
    "product_id": 10002,
    "product_type_id": 1,
    "variant_name": "Inflammation",
    "variant_defining_attrs": {
      "biomarkers": ["hs-CRP", "Vitamin D"],
      "panel": "Inflammation",
      "turnaround_days": "3-5"
    },
    "descriptive_attrs_override": {
      "notes": "Inflammation marker testing"
    },
    "variant_availability": 1,
    "price_cents": 7900,
    "currency": 840,
    "available_collection_types": ["AT_HOME", "GO_TO_LAB"]
  }
]
```

{% endtab %}
{% endtabs %}

Check `available_collection_types` before offering a collection method to a user - not every variant supports both.

### 4. Order a test kit

Let's order one "Inflammation" kit (`variant_id` `100041`) as an `AT_HOME` order:

* An order needs: your own `client_order_reference_id`, a `collection_type`, the recipient, an address, and the items (`variant_id` + `quantity`).
* `AT_HOME` orders take a `shipping_address`; `GO_TO_LAB` orders take a `requested_lab_address` instead - see [Test Collection Methods](/vantage-api-docs/documentation/test-collection-methods.md).
* Prices are integer cents; `currency` is ISO 4217 numeric (`840` = USD).

{% tabs %}
{% tab title="cURL" %}

```bash
curl --request POST 'https://vantage-sandbox.tryterra.co/api/v1/orders' \
  -u 'YOUR_DEV_ID:YOUR_API_KEY' \
  --header 'Content-Type: application/json' \
  --data-raw '{
    "client_order_reference_id": "TEST-ORDER-001",
    "collection_type": "AT_HOME",
    "recipient": {
        "first_name": "John",
        "last_name": "Smith",
        "email": "john.smith@example.com",
        "phone_number": "+14155551234",
        "date_of_birth": "1995-10-10",
        "gender_at_birth": "male"
    },
    "shipping_address": {
        "address_line_1": "123 Market Street",
        "city": "San Francisco",
        "administrative_area": "CA",
        "country_code": "US",
        "postal_code": "94102"
    },
    "items": [
        {
            "variant_id": "100041",
            "quantity": 1
        }
    ]
}'
```

{% endtab %}

{% tab title="Python" %}

```python
import requests

url = "https://vantage-sandbox.tryterra.co/api/v1/orders"

payload = {
    "client_order_reference_id": "TEST-ORDER-001",
    "collection_type": "AT_HOME",
    "recipient": {
        "first_name": "John",
        "last_name": "Smith",
        "email": "john.smith@example.com",
        "phone_number": "+14155551234",
        "date_of_birth": "1995-10-10",
        "gender_at_birth": "male",
    },
    "shipping_address": {
        "address_line_1": "123 Market Street",
        "city": "San Francisco",
        "administrative_area": "CA",
        "country_code": "US",
        "postal_code": "94102",
    },
    "items": [
        {
            "variant_id": "100041",
            "quantity": 1,
        }
    ],
}

response = requests.post(url, auth=("YOUR_DEV_ID", "YOUR_API_KEY"), json=payload)
print(response.status_code)
print(response.text)
```

{% endtab %}
{% endtabs %}

{% tabs %}
{% tab title="201" %}

```json
{
  "order_id": "251285377984405504",
  "recipient_id": "251285377984405505",
  "order_items": [
    {
      "order_id": "251285377984405504",
      "order_item_id": "251285377984405507",
      "variant_id": "100041",
      "product_type_id": "1",
      "price_per_item_cents": 7900,
      "quantity": 1,
      "currency": 840,
      "results_status": "results.awaiting_sample"
    }
  ],
  "order_status": "order.payment_processing"
}
```

{% endtab %}

{% tab title="400" %}

```json
{
  "type": "https://api.terra-diagnostics.com/errors/validation-error",
  "title": "Validation Failed",
  "status": 400,
  "detail": "One or more required fields are missing or invalid",
  "instance": "/api/v1/orders",
  "invalid_fields": [
    {
      "field": "PhoneNumber",
      "message": "PhoneNumber is not a valid phone number for the provided country code",
      "tag": "phone_with_country",
      "value": "1234567890"
    }
  ]
}
```

{% endtab %}
{% endtabs %}

{% hint style="warning" %}
IDs in order responses and webhooks (`order_id`, `order_item_id`, `recipient_id`, `test_taker_id`) are JSON **strings** - store them as strings. See [Core concepts](/vantage-api-docs/core-concepts.md).
{% endhint %}

Ordering a variant that does not exist returns a `404` problem-detail response; ordering a product you have disabled in your catalog returns `403`. See [Errors](/vantage-api-docs/documentation/errors.md).

### 5. Watch the fulfilment webhooks arrive

As the order progresses, `order.status_changed` webhooks land on your configured endpoint (in sandbox too). For example, once delivery details are available:

```json
{
  "event_type": "order.status_changed",
  "event_id": "249956485092777984",
  "timestamp": 1763661470,
  "data": {
    "order_id": "251285377984405504",
    "status": "order.delivery_fulfilled",
    "tracking_number": "KnD3d5PMZyq5ulNcWkrq"
  }
}
```

{% hint style="info" %}
Webhook payloads use the same `order.*` status vocabulary as REST reads of the order - see [Core concepts](/vantage-api-docs/core-concepts.md#status-lifecycles). In sandbox, payloads additionally carry `supplier_item_id`, which you need for simulating kit activation.
{% endhint %}

Verify the signature on every webhook you receive - see [Webhooks](/vantage-api-docs/documentation/webhooks.md).

### 6. Next: get results

In production you would now wait for the physical kit to reach your user. In sandbox, continue to [Working with Sandbox](/vantage-api-docs/getting-started/working-with-sandbox.md) to simulate the rest of the journey - kit activation, lab processing, and results - and to fetch and acknowledge the result.
