> ## Documentation Index
> Fetch the complete documentation index at: https://docs.apostra.com/llms.txt
> Use this file to discover all available pages before exploring further.

# SDK quickstart

> Install an Apostra SDK, verify account access, preview a campaign launch, and read delivery.

Use the SDK in server-side software that calls Apostra's V3 HTTP API. It does
not open an MCP connection, obtain credentials, or retry writes for you. You
need an API key or M2M access token with access to the intended account, plus a
draft campaign to preview.

This guide uses a provisioned synthetic buyer and draft campaign in automated
checks. Do not put its credentials, or any production credential, in source
code. Run the same steps with your own account and campaign before enabling a
real launch.

## 1. Install the SDK

<CodeGroup>
  ```bash TypeScript theme={null}
  npm install @apostra/sdk
  ```

  ```bash Python theme={null}
  python -m pip install apostra
  ```
</CodeGroup>

TypeScript requires Node.js 22.18 or later. Python requires Python 3.11 or
later. The TypeScript SDK is ESM-only.

## 2. Supply the API key

Keep the key in your server-side secret manager. These examples read the
environment in application code and pass the value to the SDK. The SDK does not
read environment variables itself, persist credentials, or send them anywhere
except the Apostra API.

```bash theme={null}
export APOSTRA_API_KEY='your-server-side-api-key'
export APOSTRA_BASE_URL='https://api.apostra.com/api/v3'
export APOSTRA_ACCOUNT_ID='123'
export APOSTRA_CAMPAIGN_ID='your-draft-campaign-id'
export APOSTRA_START_DATE='2026-09-01'
export APOSTRA_END_DATE='2026-09-30'
```

`APOSTRA_ACCOUNT_ID` is optional when the credential already resolves to one
account. If you set it, it must name an account that credential can reach.

## 3. Verify the account

Call `getStatus` before a write. It returns the account resolved by the
credential, its readiness and any blockers.

<CodeGroup>
  ```typescript TypeScript theme={null}
  import { Apostra } from '@apostra/sdk'

  const api = new Apostra({
    apiKey: process.env.APOSTRA_API_KEY!,
    accountId: process.env.APOSTRA_ACCOUNT_ID,
    baseUrl: process.env.APOSTRA_BASE_URL,
  })
  const status = await api.getStatus({})
  if (!status.account) throw new Error('The credential did not resolve an account')
  ```

  ```python Python theme={null}
  import os
  from apostra import Apostra

  api = Apostra(
      api_key=os.environ['APOSTRA_API_KEY'],
      account_id=os.environ.get('APOSTRA_ACCOUNT_ID'),
      base_url=os.environ.get('APOSTRA_BASE_URL'),
  )
  status = api.get_status({})
  if not status.get('account'):
      raise RuntimeError('The credential did not resolve an account')
  ```
</CodeGroup>

## 4. Preview, then confirm a launch

Use a new idempotency key for each distinct write. Keep the same key only when
retrying the exact same request after its result is uncertain. A launch request
without `confirmLaunch` previews the draft campaign. Inspect that response and
only then make a separate confirmed request.

<CodeGroup>
  ```typescript TypeScript theme={null}
  const previewKey = crypto.randomUUID()
  const preview = await api.saveCampaign(
    {
      campaignId: process.env.APOSTRA_CAMPAIGN_ID!,
      desiredPhase: 'active',
      idempotencyKey: previewKey,
    },
    { idempotencyKey: previewKey },
  )

  // Display and review `preview` before continuing.
  const confirmKey = crypto.randomUUID()
  const launched = await api.saveCampaign(
    {
      campaignId: process.env.APOSTRA_CAMPAIGN_ID!,
      desiredPhase: 'active',
      confirmLaunch: true,
      idempotencyKey: confirmKey,
    },
    { idempotencyKey: confirmKey },
  )
  ```

  ```python Python theme={null}
  from uuid import uuid4

  preview_key = str(uuid4())
  preview = api.save_campaign(
      {
          'campaignId': os.environ['APOSTRA_CAMPAIGN_ID'],
          'desiredPhase': 'active',
          'idempotencyKey': preview_key,
      },
      idempotency_key=preview_key,
  )

  # Display and review `preview` before continuing.
  confirm_key = str(uuid4())
  launched = api.save_campaign(
      {
          'campaignId': os.environ['APOSTRA_CAMPAIGN_ID'],
          'desiredPhase': 'active',
          'confirmLaunch': True,
          'idempotencyKey': confirm_key,
      },
      idempotency_key=confirm_key,
  )
  ```
</CodeGroup>

`confirmLaunch: true` can activate the campaign's staged media buys. Do not put
the confirmation call on an automatic retry path. The current SDK makes zero
automatic retries and sends the key you supply unchanged.

## 5. Read delivery

Use `getDelivery` with the campaign and a reporting window. The result is a
page, not a fixed snapshot: preserve the same query when following a cursor.

<CodeGroup>
  ```typescript TypeScript theme={null}
  const delivery = await api.getDelivery({
    report: 'campaign_delivery',
    filters: { campaignId: process.env.APOSTRA_CAMPAIGN_ID! },
    range: {
      startDate: process.env.APOSTRA_START_DATE!,
      endDate: process.env.APOSTRA_END_DATE!,
    },
    limit: 100,
  })
  ```

  ```python Python theme={null}
  delivery = api.get_delivery(
      {
          'report': 'campaign_delivery',
          'filters': {'campaignId': os.environ['APOSTRA_CAMPAIGN_ID']},
          'range': {
              'startDate': os.environ['APOSTRA_START_DATE'],
              'endDate': os.environ['APOSTRA_END_DATE'],
          },
          'limit': 100,
      }
  )
  api.close()
  ```
</CodeGroup>

The complete runnable examples live in each package: `examples/first-value.ts`
and `examples/first_value.py`. They make the launch confirmation opt-in with
`APOSTRA_CONFIRM_LAUNCH=true` so the default synthetic-seller run stops after
the preview. For transport error and retry behaviour, use the current
[SDK guide](/v2/sdk); future transport improvements do not change this flow.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.