# SDK Quickstart

The SDK API (`/v2/sdk`) powers CTV and DOOH measurement: census-based audience enrichment, QR scan attribution, and impression ingestion with GIVT dedup and frequency counting. Use it from a device SDK, a server-side measurement pipeline, or a pixel proxy.

**Base URL:** `https://api.trillboards.com`

## 1. Get an API key

SDK keys have the prefix `tb_dat_` (issued via the [portal](https://trillboards.com/developers)). They must carry SDK scopes such as `sdk:enrich`, `sdk:qr`, and `sdk:impression`. Pass the key in the `X-API-Key` header on every request.

## 2. Enrich an impression context

Census enrichment returns a stable household ID, IAB demographic segments, and connection-type hints for the caller's IP.

```bash
curl -s -X POST "https://api.trillboards.com/v2/sdk/enrich" \
  -H "X-API-Key: tb_dat_xxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{}'
```

Success response:

```json
{
  "geohash6": "dr5ruq",
  "iabIncomeSegmentId": "1003",
  "iabIncomeSegmentName": "$75,000-$99,999",
  "iabAgeSegmentId": "2004",
  "iabAgeSegmentName": "35-44",
  "educationTier": "bachelors_plus",
  "connectionType": "residential",
  "householdId": "a8c3f1d7b2e4...",
  "source": "maxmind"
}
```

`source` names the geolocation database behind the record: `maxmind` (MaxMind GeoLite2), `dbip` ([IP Geolocation by DB-IP](https://db-ip.com), CC BY 4.0), or `ipinfo` when neither is loaded.

Pass an optional `geohash6` (6-character geohash) in the body when the client knows its location more precisely than the caller IP suggests.

## 3. Handle errors

Authentication, validation, and rate-limit failures all return the canonical envelope:

```json
{
  "error": {
    "type": "rate_limit_error",
    "code": "rate_limit_exceeded",
    "message": "Rate limit exceeded. Please retry after the specified time.",
    "request_id": "req_a1b2c3d4e5f6789012345678901234ab",
    "doc_url": "https://api.trillboards.com/docs/errors#rate_limit_exceeded"
  }
}
```

429 responses also include the standard `Retry-After` header. The enrich endpoint is capped at 300 req/min per key; QR beacon at 200 req/min; impression at 1000 req/min. Back off on the client side — don't stack retries.

## 4. Ingest impressions

Once enriched, post impressions to `/v2/sdk/impression` with a client-generated `impressionId` (UUID) so GIVT dedup can latch across retries. Required fields include `adId`, `placementId`, and `channel` (`ctv`, `dooh`, or `web`). See `validation/sdkSchemas.js` or the generated OpenAPI for the full body shape.

## Next steps

- Reference: [`/docs/sdk`](https://api.trillboards.com/docs/sdk)
- QR attribution flow: `POST /v2/sdk/qr/scan` then `POST /v2/sdk/qr/beacon`
- Error catalog: [`/docs/errors`](https://api.trillboards.com/docs/errors)
