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

# Quickstart

> Seed a sandbox, point an SDK at it, read back what your code sent

Five minutes from signup to a provider SDK talking to your own copy of Resend.

## Prerequisites

* An account on [console.twinbay.ai](https://console.twinbay.ai). Email address, no invite code.
* `curl` and `jq`, or the [CLI](/cli).
* Python 3.9+ with `pip install resend` to run the last step.

## 1. Mint an API key

Open **API keys** in the console and create one. The token is readable once, so copy it now.

```bash theme={null}
export TWINBAY_API_KEY="tb_..."
```

Every request sends it in `X-API-Key`. A key acts with the role of the member who created it.

## 2. Create a sandbox

Name the twins you want and describe the state in a sentence.

```bash theme={null}
curl -sX POST https://api.twinbay.ai/sandboxes \
  -H "X-API-Key: $TWINBAY_API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{
    "name": "checkout-tests",
    "twins": [{ "twin": "resend" }],
    "prompt": "one segment with a delivered recipient and a hard-bounce recipient"
  }' | jq
```

The response is a `202`: Twinbay recorded the sandbox and queued each twin for provisioning. Keep the ids.

```bash theme={null}
export SANDBOX=<sandbox id>
export TWIN=<twins[0].id>
```

## 3. Wait for the twin to report ready

```bash theme={null}
curl -s https://api.twinbay.ai/sandboxes/$SANDBOX \
  -H "X-API-Key: $TWINBAY_API_KEY" | jq '.twins[] | {state, url}'
```

Poll until `state` is `ready`, which takes a container start and a seeding pass. The `url` is the private hostname your code will call, such as `https://resend-a1c93f.twinbay.run`. A twin still not serving after two minutes reports `failed` with a `failure` telling you why.

## 4. Collect the credential

```bash theme={null}
curl -sX POST \
  https://api.twinbay.ai/sandboxes/$SANDBOX/twins/$TWIN/credential \
  -H "X-API-Key: $TWINBAY_API_KEY" | jq -r .api_key
```

The twin mints a key shaped like the provider's own. Twinbay hands it over once and refuses a second call, so store it where your test run can read it.

## 5. Point the provider SDK at the twin

Change the base URL and the key. Nothing else.

```python theme={null}
import resend

resend.api_key = "re_twinbay_9f2a..."       # step 4
resend.api_url = "https://resend-a1c93f.twinbay.run"  # step 3

sent = resend.Emails.send({
    "from": "onboarding@resend.dev",
    "to": "delivered@resend.dev",
    "subject": "Hello from the sandbox",
    "html": "<strong>It works.</strong>",
})

print(resend.Emails.get(sent["id"]))
```

## 6. Read back what your code sent

```bash theme={null}
curl -s "https://api.twinbay.ai/sandboxes/$SANDBOX/logs" \
  -H "X-API-Key: $TWINBAY_API_KEY" \
  | jq '.items[] | {method, path, status_code, duration_ms}'
```

Fetch one log by id for the full request and response bodies.

## The same run from the CLI

```bash theme={null}
twinbay auth login
twinbay sandboxes create --name checkout-tests --twins '[{"twin":"resend"}]' \
  --prompt "one segment with a delivered and a hard-bounce recipient"
twinbay sandboxes twins credential --sandbox-id $SANDBOX --sandbox-twin-id $TWIN
twinbay sandboxes logs list --sandbox-id $SANDBOX
```

## Next

<CardGroup cols={2}>
  <Card title="Advance sandbox time" icon="forward" href="/concepts#time-and-advancing">
    Turn a queued email into a delivered or bounced one without waiting.
  </Card>

  <Card title="Edit sandbox state" icon="pen" href="/concepts#records">
    Replace a record the provider would never let you write.
  </Card>

  <Card title="Available twins" icon="layer-group" href="/twins">
    What Resend and Linear model, and where each stops.
  </Card>

  <Card title="Templates" icon="copy" href="/concepts#templates">
    Save a sandbox definition and start every CI job from it.
  </Card>
</CardGroup>

Stuck? Write to [hi@twinbay.ai](mailto:hi@twinbay.ai).
