# Quickstart — Push your first message in 5 minutes

You will:

1. Sign up at the portal.
2. Mint a system token.
3. POST a single test message with `curl`.
4. See it appear in the portal's Messages view.

If you already have an account, skip to step 2.

![Sequence overview: sign up, mint token, POST, see message](screenshots/quickstart-overview.png)

## 1. Sign up

Visit [`https://activitylog.com/portal/`](https://activitylog.com/portal/) and click **Sign up**.

You'll be asked for:

- Display name
- Email
- Password (≥ 12 characters)

On submit you land on the **Dashboard** with a new tenant already created for you. The tenant is your top-level container for systems, users, and tokens — see [`10-setup-account-tenant.md`](./10-setup-account-tenant.md) for the full account model.

![Sign-up form](screenshots/portal-signup.png)

> Don't have a portal URL yet? Use the staging environment at `https://activitylog.betawebserver.com/portal/` while the production DNS is being cut over.

## 2. Mint a system token

A **system** is the logical source of activity (your backend, your worker, your iPhone app). A **token** is the credential that source uses to POST messages.

1. In the portal sidebar click **Systems**.
2. Click **New System**.
3. Give it a name like `my-backend` and **Save**.
4. On the new system's detail page click **New Token**.
5. The token (starts with `al_`) is displayed **once** — copy it now.

![Systems list with New System button](screenshots/portal-systems-list.png)
![Token reveal dialog](screenshots/portal-systems-token-reveal.png)

> Store the token in your secret manager (Azure Key Vault, 1Password, AWS Secrets Manager). If you lose it you cannot recover it — you can only revoke and mint a new one.

## 3. Push a test message

Replace `al_REPLACE_WITH_YOUR_TOKEN` with the token you just copied.

```bash
curl -X POST https://api.activitylog.com/api/v1/messages \
  -H "Authorization: Bearer al_REPLACE_WITH_YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "stream":   "events",
    "level":    "info",
    "type":     "smoke.test",
    "body":     { "hello": "world" },
    "tags":     ["quickstart"]
  }'
```

Expected response (HTTP 201):

```json
{
  "id":         "01JT8KMBN4VK0000000000000",
  "ingestedAt": "2026-05-20T14:21:03.123Z"
}
```

If you get **401 Unauthorized**: the token is wrong or has been revoked. Revisit step 2.
If you get **429 Too Many Requests**: you're hitting the Free-tier burst cap. Wait the `Retry-After` seconds and try again.

## 4. See it in the portal

In the portal sidebar click **Messages**. Your `smoke.test` event should be at the top of the list within a second or two.

Click the row to see the full detail — body, tags, metadata, timestamps.

![Messages list with the new message highlighted](screenshots/portal-messages-list-first.png)
![Message detail panel](screenshots/portal-message-detail.png)

That's it. You're ingesting.

## Where to go next

| Goal | Doc |
|---|---|
| Send batches instead of one-at-a-time | [`50-ingest-native.md`](./50-ingest-native.md#batch) |
| Add metadata for filtering (`?meta.partner=acme`) | [`50-ingest-native.md`](./50-ingest-native.md#metadata) |
| Track long-running jobs with duration messages | [`50-ingest-native.md`](./50-ingest-native.md#duration) |
| Wire OpenTelemetry instead | [`51-ingest-otlp.md`](./51-ingest-otlp.md) |
| Invite a teammate | [`30-invites-and-team.md`](./30-invites-and-team.md) |
| Pull in Microsoft Teams / Outlook / Entra / SharePoint | [`70-integrations-m365.md`](./70-integrations-m365.md) |

## Troubleshooting

**My token starts with `alw_`, not `al_`.**
That's a webhook URL token — for `POST /webhooks/{token}` (Event Grid, ADO Service Hooks, etc.). For native `POST /messages` you want an `al_` token. See [`53-ingest-webhooks.md`](./53-ingest-webhooks.md) for the webhook flow.

**The message I sent doesn't appear in Messages.**
Make sure you're looking at the same tenant. The portal's tenant selector is top-right. Also check the **Systems** page — if the system you minted the token under is filtered out, the messages won't render. Clear filters.

**I want to use a base URL other than `api.activitylog.com`.**
Staging is `https://activitylog-api.betawebserver.com`. Self-hosted? You don't — ActivityLog is currently SaaS-only.
