# Timix.AI agent sign-up

This file describes how an AI assistant opens a Timix.AI account for a person. It is for AI agents and for the people who build them. It describes the sign-up protocol and nothing else.

Canonical copy: https://timix.ai/auth.md

## Summary

- Two calls: start (the person's email address) and verify (the code the person received by email).
- The person reads one email and gives the code in it to the assistant. That is their whole part.
- The result is a new Timix.AI account, an organization that the person owns, and a limited API key for the assistant.
- It opens new accounts only. An email address that already has an account never receives a code (see "If the person already has an account").

## What the person does

1. They ask the assistant to open a Timix.AI account.
2. Timix.AI emails them a sign-up code. The email says what the assistant will get, and that giving the code to the assistant opens the account and means they agree to the Terms of Service (https://timix.ai/terms) and the Privacy Policy (https://timix.ai/privacy).
3. They give the code to the assistant. The code has 8 digits, is written like `1234-5678`, is valid for 10 minutes and works once.

The calls contain no field for accepting the terms. The person accepts by giving the code themselves.

## Call 1: start

```http
POST https://api.timix.ai/api/integration/v1/agent/signup
Content-Type: application/json

{
  "email": "dana@acme.co",
  "language": "en",
  "agent": { "name": "Claude Code", "model": "claude-opus-5-5", "purpose": "track client hours" }
}
```

| Field | Required | Rules |
|---|---|---|
| `email` | yes | The person's address, at most 254 characters. |
| `language` | no | `en` or `he`: the language of the email, of `messageForUser` and of the new organization's starter structure. Default `en`. |
| `agent.name` | yes | 1 to 40 characters from `A-Z a-z 0-9 space . _ -`. It names the key: `Agent: <name>`. |
| `agent.model` | no | At most 100 characters. Logged, never emailed. |
| `agent.purpose` | no | At most 100 characters. Logged, never emailed. |

The request must carry no credentials. A request with an API key or a sign-in token is refused with `403 forbidden`: a key never creates an account.

The answer is always `202 Accepted`, with the same body and timing whether or not the address already has an account, so it reveals nothing about accounts:

```json
{
  "challenge": "ch1.…",
  "expiresAt": "2026-11-08T10:10:00Z",
  "codeFormat": "8 digits, e.g. 1234-5678",
  "messageForUser": "Check dana@acme.co for an email from Timix.AI. If it contains a sign-up code, give me the code. …",
  "termsUrl": "https://timix.ai/terms",
  "privacyUrl": "https://timix.ai/privacy",
  "verifyUrl": "https://api.timix.ai/api/integration/v1/agent/signup/verify"
}
```

`challenge` is an opaque token: send it back unchanged in call 2. `messageForUser` is the text for the person (see the rules below).

## Call 2: verify

```http
POST https://api.timix.ai/api/integration/v1/agent/signup/verify
Content-Type: application/json

{
  "challenge": "ch1.…",
  "code": "4821-7730",
  "firstName": "Dana",
  "lastName": "Levi",
  "organizationName": "Acme",
  "timeZone": "Asia/Jerusalem",
  "country": "IL",
  "currency": "ILS"
}
```

| Field | Required | Rules |
|---|---|---|
| `challenge` | yes | The token from call 1. It is valid for 10 minutes. |
| `code` | yes | The 8-digit code the person gives you. Spaces and dashes are ignored. |
| `firstName` | yes | The person's first name. |
| `organizationName` | yes | 2 to 50 characters after trimming. |
| `lastName`, `timeZone`, `country`, `currency` | no | The web app's defaults apply when they are left out. |

The email address always comes from the challenge, so it cannot be changed here. The answer is `201 Created`:

```json
{
  "apiKey": "tmx_…",
  "key": { "id": "…", "name": "Agent: Claude Code", "scopes": ["read", "write"], "restricted": true, "expiresAt": "2027-02-06T23:59:59Z" },
  "organization": { "id": "og_…", "name": "Acme", "trialEndsAt": "2027-02-06" },
  "user": { "id": "ag…", "email": "dana@acme.co" },
  "endpoints": { "rest": "https://api.timix.ai/api/integration/v1", "mcp": "https://api.timix.ai/api/integration/v1/mcp" },
  "web": { "url": "https://app.timix.ai", "firstSignIn": "Choose 'Forgot password?' with this email to set a password." },
  "storageHint": "Store apiKey as a secret (e.g. TIMIX_API_KEY). It is shown once and cannot be recovered."
}
```

`apiKey` is shown once and cannot be recovered.

## The key

| | |
|---|---|
| Name | `Agent: <agent name>`. The prefix is reserved: only this sign-up creates such a key. |
| Can | View, add and edit time entries, customers and projects, over the MCP server (https://api.timix.ai/api/integration/v1/mcp) and the REST API (https://api.timix.ai/api/integration/v1). |
| Cannot | Delete anything, invite users, send email to other people, issue invoices, or open financial reports and their exports (they answer `403`). Sensitive financial and contact data is redacted in MCP results. It cannot create other keys. |
| Rate | 120 requests per minute. |
| Lifetime | 90 days, to the end of the day. It is not renewed. |
| Revoke | The person can revoke it at any time on the API Keys page of the web app (https://app.timix.ai/api-keys), where it carries an Agent badge. |

Send the key as `X-Api-Key: <key>` or as `Authorization: Bearer <key>`.

The person owns the new organization, which starts on the 90-day free trial and then continues on the Free plan. To use Timix.AI in a browser they open https://app.timix.ai, choose "Forgot password?" and set a password with the same email address.

## If the person already has an account

An address that already has an account gets an email saying so, with no code. No code exists for that address, so call 2 cannot succeed. The person signs in at https://app.timix.ai and creates a key on the API Keys page (owners and admins can create keys).

## Errors

Errors use one JSON shape, `{ "error": { "code": "…", "message": "…", "details": [ { "field": "…", "message": "…" } ] } }`, with these codes:

| HTTP | `code` | When | What the agent does |
|---|---|---|---|
| 403 | `agent_signup_disabled` | Agent sign-up is switched off. | Sends the person to https://app.timix.ai. |
| 403 | `forbidden` | The request carried credentials. | Sends it again with no Authorization or X-Api-Key header. |
| 422 | `validation_error` | The body is invalid; `details` names the fields. | Fixes the body. |
| 422 | `email_not_allowed` | A disposable domain, or an address that cannot be used. | Asks the person for another address. |
| 429 | `rate_limit_exceeded` | A limit on the address, the domain or the caller's IP address; `Retry-After` is set. | Waits. |
| 503 | `signup_unavailable` | The daily limit is reached, or email delivery is down; `Retry-After` is set. | Retries later, or sends the person to https://app.timix.ai. |
| 422 | `invalid_code` | The code is wrong. | Asks the person to read the code again. |
| 422 | `challenge_expired` | More than 10 minutes have passed. | Starts over with call 1. |
| 429 | `too_many_attempts` | 5 wrong codes on this challenge, or 10 an hour on this address. | Without `Retry-After`, this challenge is locked: starts over with call 1 at once. With `Retry-After`, the address's hour is spent: waits that long (at most an hour). |
| 409 | `challenge_used` | This challenge already created the account. | The person signs in on the web and creates a key there. |
| 409 | `account_exists` | An account appeared in the meantime by another route. | The person signs in on the web. |
| 500 | `internal_error` | A server error. | Sends call 2 again with the same challenge and code: it resumes where it stopped. |

## What Timix.AI expects of an agent

1. Start only when the user asked for a Timix.AI account.
2. Show `messageForUser` to the user exactly as it is.
3. Never guess or try codes. Only the person can read the code, and wrong codes count against the attempt limits.
4. Never state that the user accepted the terms. They accept by giving the code.
5. Store the key as a secret, for example as `TIMIX_API_KEY`. It is shown once.

## Web sign-up

The person can always sign up without an assistant at https://app.timix.ai.
