# Quickstart

Make a key, install the SDK and make your first call. You never name a company: the key implies it. To go live, you
swap the key.

## 1. Make a sandbox

A sandbox is a test company linked to yours. It follows your plan, your company pays for its usage, and it does not
send bids or texts to anyone outside it. See [Environments and sandboxes](https://developers.exayard.com/environments.md).

An admin opens the Developer page in Settings
([app.exayard.com/settings/developer](https://app.exayard.com/settings/developer)), goes to **Sandboxes**, clicks
**New sandbox** and names it. Then **Open** switches you into the sandbox.

You can skip this step and work in your real company from the start. Everything below works the same there.

## 2. Make an app and a key

In the sandbox's Developer page:

1. Under **Apps**, click **New app**. Give it any name, such as "Acme estimator", and pick its scopes.
2. In the app, under **Keys**, click **New key**. Name it and leave **Scopes** on **All**, or pick only what you need.
3. Copy the key. It is shown once. A key made in a sandbox starts with `exa_test_`.

Keep the key out of your code. Put it in an environment variable:

```bash
export EXAYARD_API_KEY=exa_test_...
```

See [Apps and keys](https://developers.exayard.com/apps-and-keys.md) for expiry, revoking and the other options.

## 3. Install the SDK

```bash
npm install @exayard/sdk
```

The SDK needs Node 20 or later. This page is for `@exayard/sdk` 0.3.0, which goes to npm with the next release.

## 4. Make your first call

```typescript
import { Exayard } from '@exayard/sdk'

// Reads EXAYARD_API_KEY from the environment.
const exa = new Exayard()

const project = await exa.projects.create({ name: 'First project' })
const projects = await exa.projects.list({})
console.log(projects.length, project)
```

There is no `organizationId` in the calls. The key works in its own company, so the API uses that company.

The same call with curl:

```bash
curl https://api.exayard.com/v1/projects \
  -H "Authorization: Bearer $EXAYARD_API_KEY"
```

Or with the CLI (`npm install -g @exayard/cli`, version 0.5.0 or later):

```bash
exayard login --api-key "$EXAYARD_API_KEY"
exayard projects list
```

No command needs `--org` with this key. See [Use the CLI](https://developers.exayard.com/guides/use-the-cli.md).

## 5. Go live

Make an app and a key in your real company the same way. That key starts with `exa_live_`. Swap it in:

```bash
export EXAYARD_API_KEY=exa_live_...
```

Nothing else changes. The same code now works in your real company.

## Handle errors

Every error is RFC 9457 `application/problem+json` with a stable `code`. The SDK throws a typed error for it:

```typescript
import { Exayard, ExayardError, RateLimitError } from '@exayard/sdk'

try {
  await exa.projects.create({ name: 'Demo' })
} catch (err) {
  if (err instanceof RateLimitError) {
    // The SDK already retried. err.retryAfter says how long to wait.
  } else if (err instanceof ExayardError && err.isInsufficientScope()) {
    console.error('The key needs another scope:', err.detail)
  }
  throw err
}
```

The SDK retries a 429, a 5xx and a dropped connection twice by default, and sends an
[`Idempotency-Key`](https://developers.exayard.com/concepts/idempotency.md) on every write so a retry never does the work twice. See
[Errors](https://developers.exayard.com/concepts/errors.md) for every code.

## Next

- [Subscribe to webhooks](https://developers.exayard.com/guides/subscribe-to-webhooks.md) to hear when a takeoff finishes.
- [Run a takeoff](https://developers.exayard.com/guides/run-a-takeoff.md).
- [End users](https://developers.exayard.com/concepts/end-users.md): tag each call with your own customer's id.
- [Pricing](https://developers.exayard.com/pricing.md): what AI work costs.
