---
title: "Reducto Authentication"
description: "How agents discover, obtain, use, and revoke Reducto API credentials."
canonical: "https://reducto.ai/auth.md"
---

# Reducto Authentication

Reducto supports direct HTTP signup for a new user at a new company. It grants the standard 15,000 free credits and an API key. The human supplies an email, their name, a verification code, and explicit agreement to the terms. No CLI or browser cookies are needed.

Existing users, existing companies, SSO accounts, organization joining, and lost-key recovery use [Studio](https://studio.reducto.ai/). Never create another account to work around these restrictions.

## 1. Check for a saved key

Use the approved secret store or process environment; do not print its contents. If REDUCTO_API_KEY exists, check it with GET https://platform.reducto.ai/jobs?limit=1 and Authorization: Bearer $REDUCTO_API_KEY. A 200 response means setup is done. Invalid saved keys go to Studio for recovery, not a new signup. Retry service failures without creating an account.

## 2. Request a verification code

If there is no key, ask for the human's email and POST JSON (Content-Type: application/json) to https://accounts.reducto.ai/api/agent/accounts:

```json
{"email":"ada@example.com"}
```

A 200 response is:

```json
{"signup_token":"<opaque 43-character token>","expires_at":"2026-09-07T14:10:00.000Z","resend_after":60,"terms_url":"https://reducto.ai/terms","privacy_url":"https://reducto.ai/privacy"}
```

Keep signup_token private. Codes last 10 minutes and permit five incorrect attempts. To resend, wait at least resend_after seconds and repeat this POST; the previous token/code pair stops working. Limits are five sends per email per hour and ten per IP per hour. A lost start response requires a new request after the cooldown; do not guess a token.

## 3. Gather the remaining inputs, then ask the human once

Fill in what you can before asking:

- **Code:** if you can read the human's inbox (a connected mail tool, an accessible mailbox, etc.), fetch the six-digit Reducto code yourself instead of asking the human to check email.
- **Name:** if the first and last name are already known from memory, the environment, or prior conversation, use them. Never invent a name.

Then ask the human for whatever is still missing plus terms agreement, together: “Do you agree to [Reducto's terms](https://reducto.ai/terms) and acknowledge the [privacy policy](https://reducto.ai/privacy)? Agreeing authorizes me to create the account and receive an API key on your behalf.” Add the code, name, and first document to the question only if you could not obtain them.

Terms agreement always requires an explicit answer from the human, even when every other input was obtained automatically. Do not infer consent from the code being available, prior sessions, or silence. Do not upload the document until signup succeeds.

## 4. Verify and wait for the key

POST JSON to https://accounts.reducto.ai/api/agent/accounts/verify:

```json
{"signup_token":"<saved token>","code":"012345","first_name":"Ada","last_name":"Lovelace","terms_accepted":true}
```

Keep the code a string, including leading zeros. Send terms_accepted: true only after the human explicitly agrees.

Provisioning returns HTTP 202, a Retry-After header, and:

```json
{"status":"provisioning","retry_after":5}
```

Wait retry_after seconds, then repeat the **same verification request** (same token, code, name, and consent). Do not restart signup. Network errors and HTTP 503 also retry this same request, respecting Retry-After. The completed HTTP 200 response is:

```json
{"api_key":"<secret>","api_key_id":"<key ID>","org_id":"<organization ID>","credits_granted":15000,"expires_at":"2027-09-07T14:01:00.000Z","studio_url":"https://studio.reducto.ai"}
```

Handle this response privately: do not print it into the conversation or terminal logs. Save api_key securely as REDUCTO_API_KEY using the project's approved secret manager or protected, ignored local configuration. Never commit it or put it in a URL. SDKs read the process environment, not .env files automatically.

The key expires after one year. The same verification request can retrieve the identical response for 10 minutes after key creation if delivery was lost. After that, use Studio; signup does not rotate or recover keys. Tell the human their account is ready without displaying the key. Explain that no password was set; the signup code only verified their email. They can sign into Studio using a magic link via “Email me a sign-in link”. Setting a password is optional via “Set a password” on the login screen.

## 5. Process the first document

Check GET https://platform.reducto.ai/jobs?limit=1 with the saved bearer key. For a local document, POST multipart form field file to https://platform.reducto.ai/upload; keep the returned file_id. POST https://platform.reducto.ai/parse with that ID:

```json
{"input":"<file_id from upload>"}
```

Both requests use Authorization: Bearer $REDUCTO_API_KEY. A public/presigned document URL can also be the input. Read [the developer guide](https://docs.reducto.ai/agent-guide.md) for current parse options and response shapes. Share the output and the returned studio_link with the human, not the credential. They can later sign into Studio using normal passwordless email login.

## Signup errors

All signup responses are JSON with Cache-Control: no-store. Errors include error.code and a human-readable error.message. Show the message and error.field (when present) in the agent's terminal so the human can correct the input there. For example, an email-policy rejection includes {"error":{"code":"signup_restricted","field":"email","message":"This email is not eligible for agent signup. Enter a different email address."}}. Only studio_required includes studio_url and requires browser continuation. Retryable responses also include retry_after seconds and Retry-After.

| HTTP | error.code | Agent action |
| --- | --- | --- |
| 400 | invalid_input | Show the field and message; ask for corrected input. If error.restart_required is true, user creation was rejected: correct the fields and start a new code request after the cooldown. Otherwise retry the request, preserving any already accepted verification data. |
| 400 | invalid_code | Ask the human to check the code. Never guess. |
| 410 | verification_expired | The token/code expired, was superseded, or exhausted five attempts. Request a new code after the cooldown. |
| 403 | signup_restricted | Show the email-policy message in the terminal and ask for a different email. Retry signup with that email; do not bypass restrictions. |
| 409 | studio_required | Stop automated signup and show the human error.message with studio_url. They can sign in or select Join or Request access for a listed organization in Studio. This also covers uncertain provisioning or expired key delivery. |
| 429 | rate_limited | Wait Retry-After seconds before retrying. |
| 503 | temporarily_unavailable | Retry the same request after Retry-After; for an interrupted initial code request, respect the resend cooldown. |

No balance, payment, organization-joining, or key-recovery API is part of signup. Revoke or replace keys in Studio's API Keys page. Full signup schema: [Accounts OpenAPI](https://accounts.reducto.ai/api/agent/openapi.json).
