# REST API

## Overview

This document provides a comprehensive guide for integrating with Metica's REST API. It covers prerequisites, endpoints, request headers, authentication, payload structure, and advanced usage examples for event ingestion, personalized offers, smart configurations, and useful event data.

***

## Prerequisites

Before initiating API requests, the Metica onboarding team will provide the following:

* **API Key**: Used to authenticate requests.
* **Application ID**: Used to identify the target application.

These credentials will be referred to as `API_KEY` and `APP_ID` throughout this document.

***

## API Conventions

### Base Endpoint

All API requests should be directed to the following base endpoint:

<https://api-gateway.prod-eu.metica.com>

***

### Request Headers

Metica's API uses JSON for both request and response payloads. Additionally, some `GET` endpoints may use parameters formatted as `application/x-www-form-urlencoded` query strings in the URL.

<table><thead><tr><th width="216">Header Name</th><th>Expected Value</th></tr></thead><tbody><tr><td><code>Content-Type</code></td><td><code>application/json; charset=utf-8</code></td></tr></tbody></table>

***

## Authentication

Metica's API uses API keys for authentication and authorization. Include your API key in the `X-API-KEY` header for all API requests.

#### Example Using `curl`

```bash
curl --url https://api-gateway.prod-eu.metica.com/... \
  --header 'X-API-KEY: <API_KEY>'
```

***

## HTTP Status Codes

Metica's API utilises standard HTTP status codes to indicate the outcome of an operation.

<table><thead><tr><th width="100">Code</th><th>Description</th></tr></thead><tbody><tr><td>200</td><td><strong>Successful Request</strong> - The request was processed successfully.</td></tr><tr><td>202</td><td><strong>Accepted</strong> - The payload was accepted, and the request was completed successfully.</td></tr><tr><td>400</td><td><strong>Bad Request</strong> - The request is invalid (e.g., malformed syntax or missing parameters).</td></tr><tr><td>401</td><td><strong>Unauthorized</strong> - The request lacks valid authentication credentials.</td></tr><tr><td>403</td><td><strong>Forbidden</strong> - The API key does not have sufficient permissions for the requested operation.</td></tr><tr><td>404</td><td><strong>Not Found</strong> - The requested resource could not be located.</td></tr><tr><td>429</td><td><strong>Too Many Requests</strong> - The rate limit has been exceeded; retry after a delay.</td></tr><tr><td>5xx</td><td><strong>Internal Server Error</strong> - The server encountered an unexpected condition that prevented it from completing the request.</td></tr></tbody></table>

In cases of client errors (e.g., `400`), responses may include a payload describing the invalid part of the request to assist in troubleshooting.

***

## Event Ingestion

The event ingestion endpoint is the primary method for submitting user in-app behavior data to Metica.

### Endpoint

`/ingest/v1/events`

***

### Request Headers

<table><thead><tr><th width="220">Header Name</th><th>Expected Value</th></tr></thead><tbody><tr><td><code>X-API-KEY</code></td><td>Your unique API key.</td></tr><tr><td><code>Content-Type</code></td><td><code>application/json; charset=utf-8</code></td></tr></tbody></table>

***

### Request Payload

The payload should include a list of events, with each event containing key-value pairs representing individual user actions.

#### Example Payload

```json5
{
  "events": [
    {
      "userId": "u1",
      "appId": "<APP_ID>",
      "eventTime": "2024-11-28T15:19:07.458Z",
      "eventType": "purchase",
      "offerId": "a",
      "totalAmount": 1
    },
    {
      "userId": "u2",
      "appId": "<APP_ID>",
      "eventTime": "2024-11-28T15:24:07.000Z",
      "eventType": "login"
    }
  ]
}
```

***

### Example Request Using `curl`

```bash
curl --request POST \
  --url https://api-gateway.prod-eu.metica.com/ingest/v1/events \
  --header 'Content-Type: application/json' \
  --header 'X-API-KEY: <API_KEY>' \
  --data '{
    "events": [
      {
        "userId": "u1",
        "appId": "<APP_ID>",
        "eventTime": "2024-11-28T15:19:07.458Z",
        "eventType": "purchase",
        "offerId": "a",
        "totalAmount": 1
      },
      {
        "userId": "u2",
        "appId": "<APP_ID>",
        "eventTime": "2024-11-28T15:24:07.000Z",
        "eventType": "login"
      }
    ]
  }'
```

***

### Response Codes

<table><thead><tr><th width="100">Code</th><th>Description</th></tr></thead><tbody><tr><td>202</td><td>The request was processed successfully. <strong>Note</strong> A 202 response indicates the request was accepted but does not guarantee the validity of the payload content.</td></tr><tr><td>4xx</td><td>Client error; refer to the HTTP Status Codes section for details.</td></tr><tr><td>5xx</td><td>Server error; refer to the HTTP Status Codes section for details.</td></tr></tbody></table>

***

## Event Schema

This section lists the schema for core events that Metica can ingest. Each core event requires specific properties to be included in the event payload, as described below.

### Base Fields

The base fields are **common** to **all core events** and must be included in every event payload.

<table><thead><tr><th width="172">Name</th><th width="151">Type</th><th width="100">Required</th><th>Description</th></tr></thead><tbody><tr><td>eventType</td><td>string</td><td>Yes</td><td>Enum that describes the type of the event (check <a href="#core-events">core events</a>).</td></tr><tr><td>eventId</td><td>string</td><td>No</td><td>Uniquely identifies the event; if undefined, it will be created at ingestion time by Metica.</td></tr><tr><td>appId</td><td>string</td><td>Yes</td><td>Refers to the external application ID defined during onboarding.</td></tr><tr><td>eventTime</td><td><p>bigint | </p><p><a href="https://en.wikipedia.org/wiki/ISO_8601">ISO 8601 string</a></p></td><td>Yes</td><td>UTC timestamp of when the event occurred.</td></tr><tr><td>userId</td><td>string</td><td>Yes</td><td>Uniquely identifies the user within this application.</td></tr><tr><td>customPayload</td><td>object</td><td>No</td><td>Represents a custom object defined by each client. This property is valid for all events apart from <code>Full</code> and <code>Partial User State Update</code></td></tr></tbody></table>

***

### Core Events

#### Purchase

An event triggered every time an in-app purchase is made within the game.

<table><thead><tr><th width="188">Name</th><th width="146">Type</th><th width="100">Required</th><th>Description</th></tr></thead><tbody><tr><td>productId</td><td>string</td><td>No</td><td>Unique ID of an in-game product. Only one between <code>productId</code> and <code>meticaAttributes</code> should be populated.</td></tr><tr><td>meticaAttributes</td><td>object</td><td>No</td><td>Object provided by Metica, takes priority over <code>productId</code>. This object will be returned by the <a href="#example-response">Personalized Offer</a> endpoint</td></tr><tr><td>currencyCode</td><td>string | <a href="https://en.wikipedia.org/wiki/ISO_4217">ISO 4217 string</a></td><td>Yes</td><td>Currency of the purchase (<code>fiat</code> or <code>in-game</code> currency)</td></tr><tr><td>totalAmount</td><td>number</td><td>Yes</td><td>Total amount of the purchase expressed as double.</td></tr></tbody></table>

**Example Payload:**

```json
{
  "eventId": "550e8400-e29b-41d4-a716-446655440000",
  "appId": "<APP_ID>",
  "eventTime": "2024-11-01T10:00:00Z",
  "userId": "d8973ecd-c2b5-4efb-8b91-935ae4c5b201",
  "eventType": "purchase",
  "meticaAttributes": {
    "offer": {
      "offerId": "offer123",
      "variantId": "variant456",
      "bundleId": "bundle789"
    },
    "placementId": "placement001"
  },
  "currencyCode": "EUR",
  "totalAmount": 25.00
}
```

or

```json
{
  "eventId": "550e8400-e29b-41d4-a716-446655440000",
  "appId": "<APP_ID>",
  "eventTime": "2024-11-01T10:00:00Z",
  "userId": "d8973ecd-c2b5-4efb-8b91-935ae4c5b201",
  "eventType": "purchase",
  "productId": "12345",
  "currencyCode": "EUR",
  "totalAmount": 25.50
}
```

***

#### Offer Impression

This event triggers every time an offer is displayed.

<table><thead><tr><th width="228">Name</th><th width="100">Type</th><th width="100">Required</th><th>Description</th></tr></thead><tbody><tr><td>productId</td><td>string</td><td>No</td><td>Unique ID of an in-game product. Only one between <code>productId</code> and <code>meticaAttributes</code> should be populated.</td></tr><tr><td>meticaAttributes</td><td>object</td><td>No</td><td>This object will be returned by the <a href="#example-response">Personalized Offer</a> endpoint</td></tr></tbody></table>

**Example Payload:**

```json
{
  "eventId": "550e8400-e29b-41d4-a716-446655440000",
  "appId": "<APP_ID>",
  "eventTime": "2024-11-01T10:00:00Z",
  "userId": "d8973ecd-c2b5-4efb-8b91-935ae4c5b201",
  "eventType": "impression",
  "meticaAttributes": {
    "placementId": "placement001",
    "offer": {
      "offerId": "offer123",
      "variantId": "variant456",
      "bundleId": "bundle789"
    }
  }
}
```

or

```json
{
  "eventId": "550e8400-e29b-41d4-a716-446655440000",
  "appId": "<APP_ID>",
  "eventTime": "2024-11-01T10:00:00Z",
  "userId": "d8973ecd-c2b5-4efb-8b91-935ae4c5b201",
  "eventType": "impression",
  "productId": "12345"
}
```

***

#### Offer Interaction

Event triggers every time an interaction is made with an offer (e.g., click, dismiss).

<table><thead><tr><th width="229">Name</th><th width="100">Type</th><th width="100">Required</th><th>Description</th></tr></thead><tbody><tr><td>productId</td><td>string</td><td>No</td><td>Unique ID of an in-game product. Mandatory if <code>meticaAttributes</code> is missing.</td></tr><tr><td>interactionType</td><td>string</td><td>No</td><td>String that defines the type of interaction, i.e. <code>click</code>, <code>rejected</code>, etc...; mandatory if <code>meticaAttributes</code> is missing.</td></tr><tr><td>meticaAttributes</td><td>object</td><td>No</td><td>This object will be returned by the <a href="#example-response">Personalized Offer</a> endpoint</td></tr></tbody></table>

**Example Payload:**

```json
{
  "eventId": "550e8400-e29b-41d4-a716-446655440000",
  "appId": "<APP_ID>",
  "eventTime": "2024-11-01T10:00:00Z",
  "userId": "d8973ecd-c2b5-4efb-8b91-935ae4c5b201",
  "eventType": "interaction",
  "meticaAttributes": {
    "placementId": "placement001",
    "offer": {
      "offerId": "offer123",
      "variantId": "variant456",
      "bundleId": "bundle789"
    },
    "interactionType": "click"
  }
}
```

or

```json
{
  "eventId": "550e8400-e29b-41d4-a716-446655440000",
  "appId": "<APP_ID>",
  "eventTime": "2024-11-01T10:00:00Z",
  "userId": "d8973ecd-c2b5-4efb-8b91-935ae4c5b201",
  "eventType": "interaction",
  "productId": "12345",
  "interactionType": "click"
}
```

***

#### AdRevenue

An event triggered every time revenue is generated by an ad within the game.

<table><thead><tr><th width="188">Name</th><th width="146">Type</th><th width="100">Required</th><th>Description</th></tr></thead><tbody><tr><td>currencyCode</td><td><a href="https://en.wikipedia.org/wiki/ISO_4217">ISO 4217 string</a></td><td>Yes</td><td>Currency of the total amount</td></tr><tr><td>totalAmount</td><td>number</td><td>Yes</td><td>Total amount generated by the ad expressed as double.</td></tr><tr><td>placement</td><td>string</td><td>No</td><td>String that represents the place where the ad has been displayed inside the game, i.e. <code>shop_daily_reward</code></td></tr><tr><td>type</td><td>string</td><td>No</td><td>Type of ad that has been displayed, i.e. <code>INTER</code>, <code>REWARDED</code>, etc...</td></tr><tr><td>source</td><td>string</td><td>No</td><td>Source of the ad, i.e. <code>Unity Ads</code>, <code>Liftoff Monetize</code>, etc... </td></tr></tbody></table>

```json
{
  "eventId": "550e8400-e29b-41d4-a716-446655440000",
  "appId": "<APP_ID>",
  "eventTime": "2024-11-01T10:00:00Z",
  "userId": "d8973ecd-c2b5-4efb-8b91-935ae4c5b201",
  "eventType": "adRevenue",
  "currencyCode": "EUR",
  "totalAmount": 0.00123373762,
  "placement": "shop_daily_reward_double",
  "type": "video",
  "source": "unity"
}
```

***

#### Full User State Update

Event triggers at regular intervals, indicating the user’s current state.

{% hint style="info" %}
Be aware this event doesn't allow the `customPayload` property
{% endhint %}

<table><thead><tr><th>Name</th><th width="92">Type</th><th width="120">Required</th><th>Description</th></tr></thead><tbody><tr><td>userStateAttributes</td><td>object</td><td>Yes</td><td>Attributes that represent the user's current state.</td></tr></tbody></table>

**Example Payload:**

```json
{
  "eventId": "550e8400-e29b-41d4-a716-446655440000",
  "appId": "<APP_ID>",
  "eventTime": "2024-11-01T10:00:00Z",
  "userId": "d8973ecd-c2b5-4efb-8b91-935ae4c5b201",
  "eventType": "fullStateUpdate",
  "userStateAttributes": {
    "level": 5,
    "inventoryBalance": 100,
    "isActive": true
  }
}
```

***

#### Partial User State Update

Triggers when the user state changes, updating only the affected properties.

<table><thead><tr><th>Name</th><th width="96">Type</th><th width="115">Required</th><th>Description</th></tr></thead><tbody><tr><td>userStateAttributes</td><td>object</td><td>Yes</td><td>Attributes that have changed values in the user's state.</td></tr></tbody></table>

**Example Payload:**

```json
{
  "eventId": "550e8400-e29b-41d4-a716-446655440000",
  "appId": "<APP_ID>",
  "eventTime": "2024-11-01T10:00:00Z",
  "userId": "d8973ecd-c2b5-4efb-8b91-935ae4c5b201",
  "eventType": "partialStateUpdate",
  "userStateAttributes": {
    "level": 6
  }
}
```

***

#### Login

Event triggers when the user enters the app, one event per session.

<table><thead><tr><th>Name</th><th width="100">Type</th><th width="124">Required</th><th>Description</th></tr></thead><tbody><tr><td>(No Fields)</td><td></td><td>Yes</td><td>No additional fields required.</td></tr></tbody></table>

**Example Payload:**

```json
{
  "eventId": "550e8400-e29b-41d4-a716-446655440000",
  "appId": "<APP_ID>",
  "eventTime": "2024-11-01T10:00:00Z",
  "userId": "d8973ecd-c2b5-4efb-8b91-935ae4c5b201",
  "eventType": "login"
}
```

***

#### Install

Event triggers when the user installs the app.

<table><thead><tr><th>Name</th><th width="100">Type</th><th width="129">Required</th><th>Description</th></tr></thead><tbody><tr><td>(No Fields)</td><td></td><td>Yes</td><td>No additional fields required.</td></tr></tbody></table>

**Example Payload:**

```json
{
  "eventId": "550e8400-e29b-41d4-a716-446655440000",
  "appId": "<APP_ID>",
  "eventTime": "2024-11-01T10:00:00Z",
  "userId": "d8973ecd-c2b5-4efb-8b91-935ae4c5b201",
  "eventType": "install"
}
```

***

## Personalized Offers

The personalized offers endpoint enables you to fetch offers tailored to specific users based on their [attributes](#full-user-state-update) or [device](#request-body-schema) information. These offers are returned grouped by placements. Each placement can contain one or more offers.

***

### Endpoint

`POST /offers/v1/apps/<APP_ID>`

Use this endpoint to retrieve personalized offers for specific placements within your app.

***

### Request Headers

<table><thead><tr><th width="206">Header Name</th><th>Expected Value</th></tr></thead><tbody><tr><td><code>X-API-KEY</code></td><td>Your unique API key.</td></tr><tr><td><code>Content-Type</code></td><td><code>application/json; charset=utf-8</code></td></tr></tbody></table>

***

### Request Parameters

<table><thead><tr><th width="155">Name</th><th width="80">Type</th><th width="99">Required</th><th width="242">Description</th><th>Example</th></tr></thead><tbody><tr><td><code>placements</code></td><td>string</td><td>No</td><td>A comma-separated list of placements for which offers should be returned. If not provided, offers for all placements will be returned.</td><td><code>?placements=main,shop</code></td></tr></tbody></table>

***

### Request Body Schema

A JSON-encoded body must be included in the request. The request body should adhere to the following schema:

<table><thead><tr><th width="216">Field Name</th><th width="90">Type</th><th width="101">Required</th><th width="202">Description</th><th>Example</th></tr></thead><tbody><tr><td><code>userId</code></td><td>string</td><td>Yes</td><td>Unique identifier for the user.</td><td><code>"abc"</code></td></tr><tr><td><code>deviceInfo</code></td><td>object</td><td>No</td><td>Information about the user's device. Can be partially filled.</td><td>See fields below.</td></tr><tr><td><code>deviceInfo.store</code></td><td>string</td><td>No</td><td>The platform's app store (<code>AppStore</code> or <code>GooglePlayStore</code>)</td><td><code>"AppStore"</code></td></tr><tr><td><code>deviceInfo.timezone</code></td><td>string</td><td>No</td><td>Device timezone as an IANA identifier or UTC offset.</td><td><code>"Europe/London"</code> or <code>"+05:00"</code></td></tr><tr><td><code>deviceInfo.appVersion</code></td><td>string</td><td>No</td><td>The app version, following the Semantic Versioning format.</td><td><code>"1.4.5"</code></td></tr><tr><td><code>deviceInfo.locale</code></td><td>string</td><td>No</td><td>The user's locale, formatted according to IETF BCP 47.</td><td><code>"en-US"</code></td></tr><tr><td><code>userData</code></td><td>object</td><td>No</td><td>Real-time user state data to override pre-ingested <a href="#Full-User-State-Update">user state attributes</a>, conforms to its <code>userStateAttributes</code> property.</td><td>See example below.</td></tr></tbody></table>

**Example Request Body:**

```json
{
  "userId": "abc",
  "deviceInfo": {
    "store": "AppStore",
    "timezone": "+05:00",
    "appVersion": "1.4.5",
    "locale": "en-US"
  },
  "userData": {
    "level": 10,
    "inventory": {
      "potion": {
        "quantity": 30
      }
    },
    "gemBalance": 51
  }
}
```

***

### Response Schema

The response includes a list of offers for each placement, sorted from the most important to the least important. Each offer contains details about the offer's ID, items, pricing, and additional metadata.

<table><thead><tr><th width="199">Field Name</th><th width="128">Type</th><th width="287">Description</th><th>Example</th></tr></thead><tbody><tr><td><code>placements</code></td><td>object</td><td>A mapping of placement IDs to their corresponding offers.</td><td>See example below.</td></tr><tr><td><code>offerId</code></td><td>string</td><td>Unique identifier for the offer.</td><td><code>"offer_abc"</code></td></tr><tr><td><code>creativeId</code></td><td>string | undefined</td><td>Reference to the creative ID associated with the offer.</td><td><code>"creative_large"</code></td></tr><tr><td><code>creativeOverride</code></td><td>string | undefined</td><td>Override for the creative associated with the offer.</td><td><code>"override_123"</code></td></tr><tr><td><code>items</code></td><td>array</td><td>List of items included in the offer, each with an ID and quantity.</td><td>See below.</td></tr><tr><td><code>items[].id</code></td><td>string</td><td>The external ID of the item.</td><td><code>"potion"</code></td></tr><tr><td><code>items[].quantity</code></td><td>number</td><td>The quantity of the item included in the offer.</td><td><code>1</code></td></tr><tr><td><code>expirationTime</code></td><td>string | undefined</td><td>Expiration time of the offer in ISO 8601 format.</td><td><code>"2025-01-16T12:00:00Z"</code></td></tr><tr><td><code>iap</code></td><td>string | undefined</td><td>IAP product ID associated with the offer.</td><td><code>"iap_product_45"</code></td></tr><tr><td><code>price</code></td><td>number | undefined</td><td>Price of the offer.</td><td><code>50</code></td></tr><tr><td><code>discount</code></td><td>number | undefined</td><td>Discount applied to the offer, expressed as a value between 0 and 1 (e.g., 0.23 = 23%).</td><td><code>0.23</code></td></tr><tr><td><code>currencyId</code></td><td>string | undefined</td><td>Currency used for the offer price (e.g., fiat or in-game currency).</td><td><code>"gems"</code></td></tr><tr><td><code>customPayload</code></td><td>object | undefined</td><td>Custom object defined by the client.</td><td><code>{...}</code></td></tr><tr><td><code>metrics</code></td><td>object</td><td>Metrics to track the offer lifecycle events. This object should be returned inside the <a href="#purchase">purchase</a> event as <code>meticaAttributes</code>.</td><td><code>{...}</code></td></tr></tbody></table>

***

### Example Response

```json
{
  "placements": {
    "p1": [
      {
        "offerId": "offer_abc",
        "creativeId": "creative_large_bundle_94",
        "items": [
          {
            "id": "potion",
            "quantity": 1
          }
        ],
        "expirationTime": "2025-01-16T12:00:00Z",
        "iap": "iap_potion_bundle",
        "price": 50,
        "discount": 0.23,
        "currencyId": "gems",
        "customPayload": {
          "additionalInfo": "special offer"
        },
        "metrics": {
          "purchase": {
            "userId": "abc",
            "appId": "<APP_ID>",
            "meticaAttributes": {
              "offer": {
                "offerId": "11655",
                "variantId": "14554",
                "bundleId": "14904"
              },
              "placementId": "6200"
            },
            "eventType": "meticaOfferInAppPurchase"
          },
          "display": {
            "userId": "abc",
            "appId": "<APP_ID>",
            "meticaAttributes": {
              "offer": {
                "offerId": "11655",
                "variantId": "14554",
                "bundleId": "14904"
              },
              "placementId": "6200"
            },
            "eventType": "meticaOfferImpression"
          },
          "interaction": {
            "userId": "abc",
            "appId": "<APP_ID>",
            "meticaAttributes": {
              "offer": {
                "offerId": "11655",
                "variantId": "14554",
                "bundleId": "14904"
              },
              "placementId": "6200"
            },
            "eventType": "meticaOfferInteraction"
          }
        },
      }
    ],
    "p2": []
  }
}
```

***

### Example Request Using `curl`

```bash
curl -X POST 'https://api-gateway.prod-eu.metica.com/offers/v1/apps/<APP_ID>?placements=p1,p2' \
--header 'Content-Type: application/json; charset=utf-8' \
--header 'X-API-KEY: <API_KEY>' \
--data '{
  "userId": "abc",
  "deviceInfo": {
    "store": "AppStore",
    "timezone": "+05:00",
    "appVersion": "1.4.5",
    "locale": "en-US"
  },
  "userData": {
    "level": 10,
    "inventory": {
      "potion": { "quantity": 30 }
    },
    "gemBalance": 51
  }
}'
```

***

### Notes

* The `placements` parameter is optional. If omitted, the response will include offers for all available placements.
* Only `userId` is mandatory in the request body; other fields are optional and can be partially filled.
* The `metrics` field in the response payload contains lifecycle event tracking data that should be reported back to Metica when corresponding events occur.
* Replace `<APP_ID>` and `<API_KEY>` with your application's unique identifiers.

***

## Smart Config

The Smart Config endpoint allows you to fetch dynamic and personalized configurations tailored to specific users based on their [attributes](#full-user-state-update) or [device](#request-body-schema-1) information. The set of configuration keys can be restricted using the `keys` parameter. If no keys are specified, all the configurations will be returned.

***

### Endpoint

`POST /configs/v1/apps/<APP_ID>`

Use this endpoint to retrieve personalized configurations for a specific application.

***

### Request Headers

<table><thead><tr><th width="213">Header Name</th><th>Expected Value</th></tr></thead><tbody><tr><td><code>X-API-KEY</code></td><td>Your unique API key.</td></tr><tr><td><code>Content-Type</code></td><td><code>application/json; charset=utf-8</code></td></tr></tbody></table>

***

### Request Parameters

<table><thead><tr><th width="100">Name</th><th width="85">Type</th><th width="100">Required</th><th width="274">Description</th><th>Example</th></tr></thead><tbody><tr><td><code>keys</code></td><td>string</td><td>No</td><td>A comma-separated list of configuration keys to fetch. If not provided, all configuration keys will be returned.</td><td><code>?keys=difficulty,suggested_prices</code></td></tr></tbody></table>

***

### Request Body Schema

<table><thead><tr><th width="235">Field Name</th><th width="81">Type</th><th width="101">Required</th><th width="213">Description</th><th>Example</th></tr></thead><tbody><tr><td><code>userId</code></td><td>string</td><td>Yes</td><td>Unique identifier for the user.</td><td><code>"abc"</code></td></tr><tr><td><code>deviceInfo</code></td><td>object</td><td>No</td><td>Information about the user's device. Can be partially filled.</td><td>See fields below.</td></tr><tr><td><code>deviceInfo.store</code></td><td>string</td><td>No</td><td>The platform's app store (<code>AppStore</code> or <code>GooglePlayStore</code>).</td><td><code>"AppStore"</code></td></tr><tr><td><code>deviceInfo.timezone</code></td><td>string</td><td>No</td><td>Device timezone as an IANA identifier or UTC offset.</td><td><code>"Europe/London"</code> or <code>+05:00</code></td></tr><tr><td><code>deviceInfo.appVersion</code></td><td>string</td><td>No</td><td>The app version, following the Semantic Versioning format.</td><td><code>"1.4.5"</code></td></tr><tr><td><code>deviceInfo.locale</code></td><td>string</td><td>No</td><td>The user's locale, formatted according to IETF BCP 47.</td><td><code>"en-US"</code></td></tr><tr><td><code>userData</code></td><td>object</td><td>No</td><td>Real-time user state data to override pre-ingested <a href="#Full-User-State-Update">user state attributes</a>, conforms to <code>userStateAttributes</code>.</td><td>See example below.</td></tr></tbody></table>

**Example Request Body:**

```json
{
  "userId": "abc",
  "deviceInfo": {
    "store": "AppStore",
    "timezone": "+05:00",
    "appVersion": "1.4.5",
    "locale": "en-US"
  },
  "userData": {
    "level": 10,
    "inventory": {
      "potion": {
        "quantity": 30
      }
    },
    "gemBalance": 51
  }
}
```

***

### Example Request Using `curl`

```bash
curl -X POST 'https://api-gateway.prod-eu.metica.com/configs/v1/apps/<APP_ID>?keys=difficulty,suggested_prices' \
--header 'Content-Type: application/json; charset=utf-8' \
--header 'X-API-KEY: <API_KEY>' \
--data '{
  "userId": "abc",
  "deviceInfo": {
    "store": "AppStore",
    "timezone": "+05:00",
    "appVersion": "1.4.5",
    "locale": "en-US"
  },
  "userData": {
    "level": 10,
    "inventory": {
      "potion": { "quantity": 30 }
    },
    "gemBalance": 51
  }
}'
```

***

### Response Schema

The response includes a mapping of configuration keys to their respective values defined inside the Metica platform. Each configuration key can return various types of data, such as numbers, strings, arrays, or objects.

**Example response body of two configured keys:**

```json
{
  "difficulty": "hard",
  "suggested_prices": [
    4.99,
    9.99,
    12.99
  ]
}
```

### Notes

* The `keys` parameter is optional. If omitted, the response will include all available configuration keys.
* Only `userId` is mandatory in the request body; other fields are optional and can be partially filled.
* The returned configurations are dynamically generated based on the provided user attributes.
* Replace `<APP_ID>` and `<API_KEY>` with your application's unique identifiers.


---

# 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.metica.com/api/integration.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.
