# Get a project key

Every event is sent with a project key. This guide creates an account and a property, then finds its key.

## Prerequisites

- An email address and permission to create an account. An agent must ask the person before creating an account or a property for them.
- For the API route: `curl`, or any HTTP client.

## In the dashboard

1. Open [analytics.specvista.com/signup](https://analytics.specvista.com/signup). Enter first name, last name, email and a password of at least 8 characters, then choose **Create account**. You land on the dashboard. Last name is optional.
2. Choose **Properties** in the sidebar, then **New property**.
3. Enter a **Name**. For a website, enter its **Domain**, for example `example.com`, without `https://`. Pick the **Type**: Website, Mobile, Backend or Other.
4. Choose **Create and get script**. The property appears in the list with its key, which starts with `sa_live_`, and a **Copy** button. **Show script** reveals the website snippet with the key filled in.

Expected result: the property is listed and its key is visible.

## With the API

The person runs the sign-in in their own terminal, so the password never reaches an agent's transcript or the shell history. Each command prompts for the email and password and stores the token in `SA_TOKEN` for that terminal session.

macOS and Linux, with Node.js 18 or later:

```bash
printf "Email: "; read -r SA_EMAIL; printf "Password: "; stty -echo; read -r SA_PASSWORD; stty echo; echo
export SA_TOKEN=$(SA_EMAIL="$SA_EMAIL" SA_PASSWORD="$SA_PASSWORD" node -e '
fetch("https://analyticsapi.specvista.com/api/v1/auth/login", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ email: process.env.SA_EMAIL, password: process.env.SA_PASSWORD }) })
  .then(async (res) => { const body = await res.json(); if (!res.ok) { console.error(body.code, body.message); process.exit(1); } console.log(body.user.token); })')
unset SA_PASSWORD
```

Windows PowerShell:

```powershell
$credential = Get-Credential -Message "Specvista Analytics"
$body = @{ email = $credential.UserName; password = $credential.GetNetworkCredential().Password } | ConvertTo-Json
$env:SA_TOKEN = (Invoke-RestMethod -Method Post -Uri https://analyticsapi.specvista.com/api/v1/auth/login -ContentType "application/json" -Body $body).user.token
```

Expected result: `SA_TOKEN` is set. On a wrong email or password, the macOS command prints `invalid_credentials` and PowerShell shows a 401 error; `SA_TOKEN` stays empty. Sign-in returns status 201, not 200.

Create a property. `type` is `web`, `mobile`, `backend` or `other`, and defaults to `web`:

```bash
curl -s https://analyticsapi.specvista.com/api/v1/projects \
  -H "Authorization: Bearer $SA_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"name":"My shop","domain":"example.com","type":"web"}'
```

Expected result: status 201 and a project object with `id` and `apiKey`. List existing properties and their keys with `GET /api/v1/projects`.

## Which type to pick

| Type | Use it for | Notes |
|---|---|---|
| `web` | A website using the browser script | Set `domain` to allow tracking without a key in the page |
| `mobile` | A React Native or Expo app | |
| `backend` | A server sending events | Only backend keys can call `POST /forget` |
| `other` | Anything else | |

## Keep keys safe

- A web key is visible in the page source by design. Anyone with it can send events to that property, never read reports.
- Keep backend keys out of source control. Read them from an environment variable such as `SA_API_KEY`.
- A mobile key ships inside the app, so anyone who unpacks the app can read it. Inject it at build time, for example with `EXPO_PUBLIC_SA_API_KEY`, rather than committing it.
- **Rotate API key** on the Properties page, or `POST /api/v1/projects/{id}/rotate-key`, issues a new key and stops the old one at once. Ask the person first: every place still using the old key stops sending.

## Common errors

| Error code | Meaning | Fix |
|---|---|---|
| `email_taken` | The email already has an account | Sign in instead |
| `password_too_short` | Fewer than 8 characters | Use a longer password |
| `invalid_credentials` | Wrong email or password | Check both. There is no self-serve password reset yet |
| `project_name_required` | The name was missing or blank | Send a non-empty `name` |
| `missing_token`, `invalid_token` | No bearer token, or it expired after 90 days | Sign in again |

Every error is listed in [Errors](https://analytics.specvista.com/docs/errors.md).

## Confirm success

`GET /api/v1/projects` with the bearer token returns the property, or the property shows on the Properties page.
