# Terra -> Your backend

This guide will walk you through the essential steps, from connecting and authenticating to managing heartbeats and receiving data.

## Setting up a Consumer Connection

Each developer ID is linked to a single data stream. To set up your consumer connection to the Terra WebSocket service, follow the steps below.

**WebSocket endpoint:** `wss://ws.tryterra.co/connect`

***

## Connecting to the WebSocket

Once you open a WebSocket connection to the server, you will immediately receive an `Op 2 HELLO` payload. This payload contains the `heartbeat_interval` value (in milliseconds), which the client will use to maintain the connection.

Example payload:

```json
{
  "op": 2,
  "d": {
    "heartbeat_interval": 40000
  }
}
```

After receiving this payload, the client must start sending heartbeat messages, as described below.

***

## Heartbeating

{% hint style="info" %}
To keep the WebSocket connection alive, the client **needs** to send regular heartbeats.

This lets the server know the connection is still active and waiting for data.
{% endhint %}

To send a heartbeat, send the following payload:

```json
{
  "op": 0
}
```

You'll always receive the following response (acknowledging your heartbeat):

```json
{
  "op": 1
}
```

{% hint style="danger" %}

* The first heartbeat should be sent after `heartbeat_interval * jitter` milliseconds, where jitter is a random value between 0 and 1.
* After the first heartbeat, continue sending heartbeats **at most** at the interval specified in the HELLO payload.
* If no `HEARTBEAT_ACK` is received, the client should close the connection and establish a new one.
* If the server does not receive a heartbeat within the `heartbeat_interval` window, it will close the connection with code **4005**.
  {% endhint %}

***

## Authenticating the Connection

{% hint style="warning" %}
You must send an IDENTIFY payload **within 15 seconds** of connecting. If the server does not receive IDENTIFY in time, it will close the connection with code **4000**.
{% endhint %}

Once heartbeating is set up, the client must authenticate the connection by sending an `IDENTIFY` payload containing a token.

#### IDENTIFY payload:

```json
{
  "op": 3,
  "d": {
    "token": "your_developer_token_here",
    "type": 1
  }
}
```

The `type` field specifies the connection type:

| Type | Name      | Description                                                                                  |
| ---- | --------- | -------------------------------------------------------------------------------------------- |
| `0`  | USER      | Producer connection (mobile SDKs sending data). Uses a token from `POST /auth/user`.         |
| `1`  | DEVELOPER | Consumer connection (your backend receiving data). Uses a token from `POST /auth/developer`. |

For consumer connections (this guide), use `type: 1` with a developer token.

{% hint style="info" %}
**Tokens are single-use.** Each token is deleted from the server after a successful IDENTIFY. If your connection drops, you must generate a new token before reconnecting.
{% endhint %}

{% hint style="warning" %}
**One connection per developer.** Only one active consumer connection is allowed per developer ID. If you attempt to connect while a previous session is still active, the new connection will be closed with code **4002**. Close the previous connection first.
{% endhint %}

When authentication is successful, the server will respond with an `Op 4 READY` message:

```json
{
  "op": 4
}
```

***

## Listening for Data Updates

Once the connection is established and authenticated, data from your connected users will be streamed to you in real time.

When new data is available, an `Op 5 DISPATCH` payload is sent:

```json
{
  "op": 5,
  "d": {
    "ts": "2022-05-04T10:26:11.268507+01:00",
    "val": 95
  },
  "uid": "user_id_here",
  "seq": 73,
  "t": "HEART_RATE"
}
```

Each dispatch contains:

* `op`: Opcode `5` (DISPATCH).
* `uid`: The Terra user ID of the user whose device produced this data.
* `t`: The data type (e.g., `"HEART_RATE"`, `"STEPS"`, `"ACCELERATION"`, `"ECG"`, `"HRV"`, `"CALORIES"`, `"LOCATION"`, `"GYROSCOPE"`, etc.).
* `seq`: Monotonically increasing sequence number per developer. Used for ordering and [replay](#requesting-missed-data).
* `d`: The data payload:
  * `ts`: ISO 8601 timestamp of the reading.
  * `val`: Scalar value (e.g., heart rate BPM, step count). Present for single-value types.
  * `d`: Array of doubles (e.g., `[x, y, z]` for accelerometer/gyroscope, or `[lat, lng]` for location). Present for multi-axis types.

***

## Requesting missed Data

If your connection drops and you miss some data, you can request it using the REPLAY command once you reconnect.

**REPLAY Command (Op 7)**

```json
{
  "op": 7,
  "d": {
    "after": 28,
    "before": 43
  }
}
```

* `after` (required): Replay messages with sequence numbers **greater than** this value.
* `before` (optional): Replay messages with sequence numbers **less than** this value. Omit to replay everything after `after`.

{% hint style="info" %}
Bounds are **exclusive** — `after: 28, before: 43` replays sequence numbers 29 through 42.

Replayed messages arrive as standard DISPATCH (op 5) payloads.
{% endhint %}

{% hint style="warning" %}
**2-day replay window.** Data payloads older than 2 days are purged from the server. REPLAY only works for data within this window.
{% endhint %}

***

## Error Close Codes

The server may close your WebSocket connection with one of the following custom close codes:

| Code     | Reason                                  | What to do                                                               |
| -------- | --------------------------------------- | ------------------------------------------------------------------------ |
| **4000** | Identify expected but was not received  | Send IDENTIFY within 15 seconds of connecting                            |
| **4001** | Improper token has been passed          | Token is invalid or expired — generate a new one                         |
| **4002** | Duplicate connection                    | Another session is already active for your developer ID — close it first |
| **4003** | Multiple IDENTIFY payloads received     | Don't send IDENTIFY more than once per connection                        |
| **4004** | Invalid opcode was received             | You sent an opcode the server doesn't recognize for your connection type |
| **4005** | Heartbeat expected but was not received | Send heartbeats within the `heartbeat_interval` window                   |

***

## Opcode Reference

| Opcode | Name           | Direction       | Description                                       |
| ------ | -------------- | --------------- | ------------------------------------------------- |
| 0      | HEARTBEAT      | Client → Server | Keep-alive ping                                   |
| 1      | HEARTBEAT\_ACK | Server → Client | Keep-alive acknowledgement                        |
| 2      | HELLO          | Server → Client | Sent on connection, contains `heartbeat_interval` |
| 3      | IDENTIFY       | Client → Server | Authentication with token and connection type     |
| 4      | READY          | Server → Client | Authentication successful                         |
| 5      | DISPATCH       | Server → Client | Real-time data payload                            |
| 6      | SUBMIT         | Client → Server | Data submission (producer connections only)       |
| 7      | REPLAY         | Client → Server | Request missed data by sequence range             |
