# Quickstart

Five minutes, no OAuth, no registration.

## 1. Make a personal access token

In init.Tasks: **Settings → account → encryption & devices → api keys → new key**. Pick the scopes you need and an expiry.

You will see the key exactly once. It looks like this:

```text
itk_7mQ2xLp9Va4Nk1Zr8Ts6Ye3Wu0Bd5Mg2Hj7Cq4Ln1Xv8
```

// It carries your encryption key. Treat it like a password manager entry, not like an API key you paste into a chat.

## 2. Check it works

```bash
curl -s https://api.inittasks.com/v1/me \
  -H "Authorization: Bearer $INITTASKS_TOKEN"
```

```json
{
  "sub": "8Kd2mQ...",
  "scopes": ["todos:read", "todos:write"],
  "grant": { "id": "gr_4f2a", "kind": "pat", "clientId": null },
  "webhooks": { "disabled": 0 }
}
```

## 3. Create a to-do

```bash
curl -s https://api.inittasks.com/v1/todos \
  -X POST \
  -H "Authorization: Bearer $INITTASKS_TOKEN" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{"title":"buy milk","whenDate":"2026-09-16","tags":["errands"]}'
```

The title is encrypted on the way in and decrypted on the way out. `errands` is created if it does not exist — you do not have to pre-register a vocabulary.

## 4. Read it back

```bash
curl -s "https://api.inittasks.com/v1/todos?limit=5" \
  -H "Authorization: Bearer $INITTASKS_TOKEN"
```

```json
{
  "data": [{ "id": "8E4F2A1B", "title": "buy milk", "whenDate": "2026-09-16", "tags": ["errands"] }],
  "next_cursor": null
}
```

## Retrying safely

This is the part most integrations get wrong, so it is worth doing properly from the start.

A write that times out may still have succeeded. Retrying it without an `Idempotency-Key` creates a second to-do. With one, the server replays the original response instead.

```bash
#!/usr/bin/env bash
# One key per logical operation — generated ONCE, reused by every retry.
KEY=$(uuidgen)

for attempt in 1 2 3 4 5; do
  response=$(curl -s -w '\n%{http_code}' https://api.inittasks.com/v1/todos \
    -X POST \
    -H "Authorization: Bearer $INITTASKS_TOKEN" \
    -H "Content-Type: application/json" \
    -H "Idempotency-Key: $KEY" \
    -d '{"title":"buy milk"}')

  status=$(printf '%s' "$response" | tail -n1)
  body=$(printf '%s' "$response" | sed '$d')

  case "$status" in
    2*) printf '%s\n' "$body"; exit 0 ;;
    429|5*)
      # Back off. `Retry-After` is on 429s; this doubles from one second.
      sleep $(( 2 ** (attempt - 1) ))
      ;;
    *) printf 'giving up: %s\n' "$body" >&2; exit 1 ;;
  esac
done
```

Three rules behind it:

1. **Generate the key once, outside the loop.** A key generated per attempt defeats the whole mechanism — that is the actual bug this example exists to prevent.
2. **Retry only on 429 and 5xx.** A `validation_failed` will fail identically forever.
3. **Reuse the key with the *same body*.** A different body under the same key is a [conflict](/errors/conflict), on purpose: it means two different operations were given the same name.

## Next

- Scopes and OAuth: [authentication](/authentication)
- What the server can and cannot see: [encryption](/encryption)
- Every route: [reference](/reference)
