This is the default path in the quickstart and the one the
setup-slideless marketplace skill uses. If you already have a key from the dashboard, slideless login --api-key cko_... is still available.When to use OTP
| Situation | Use |
|---|---|
| First-time setup on a new machine, new CI runner, or an agent with no prior state | slideless auth signup-request then signup-complete |
| Existing account, no local API key (or the key is bad) | slideless auth login-request then login-complete |
You already copied a cko_... from the dashboard | slideless login --api-key cko_... |
cko_ key is saved to ~/.config/slideless/config.json and set as the active profile — so slideless share, slideless list, etc. work immediately after.
Signup
Minimal (email + code)
"My Organization". You can rename it later from the dashboard.
With company details
Everything beyond--email + --code is optional and mapped straight onto the new organization document.
JSON output
~/.config/slideless/config.json; it is not echoed to stdout in the JSON response.
Login
Use this when the email already has a Slideless account but the current machine has no valid key.login-complete mints a fresh cko_ key scoped to your existing organization and saves it as a new profile. Previous keys stay valid (you can revoke them from the dashboard if you want).
Options (signup-complete & login-complete)
| Flag | Applies to | Default |
|---|---|---|
--profile-name <name> | both | Auto-derived from the org name |
--key-name <name> | both | "CLI default key" |
--key-expires-in <days> | both | No expiration (1–365 accepted) |
--base-url <url> | all four | Production |
--json | all four | Human output |
| Flag | Default |
|---|---|
--company <name> | "My Organization" |
--description <text> | — |
--brand-primary <hex> | — |
--brand-secondary <hex> | — |
--brand-accent <hex> | — |
--tone <text> | — |
--logo <path> | — |
Rate limits
- Resend cooldown: 30 seconds between OTP requests for the same email.
- Abuse caps: 20 OTP requests per email per hour; 60 per IP per hour.
- Code lifetime: 10 minutes.
- Brute-force lockout: after 5 bad codes, the server deletes the record and makes you request a fresh one.
Error codes
Every failure returns this shape (both in--json output and in the structured log of the human renderer):
nextAction field is designed to be acted on programmatically. For example:
| Code | HTTP | Meaning | nextAction |
|---|---|---|---|
EMAIL_REQUIRED / EMAIL_INVALID | 400 | Missing or malformed --email | Pass --email <valid@email> |
OTP_RESEND_COOLDOWN | 429 | Hit the 30-second cooldown | Wait details.retryInSeconds, retry |
EMAIL_RATE_LIMITED / IP_RATE_LIMITED | 429 | 20/hour per email or 60/hour per IP exceeded | Wait up to an hour |
USER_ALREADY_HAS_ORGANIZATION | 409 | Signup for an email that already has an org | Switch to login-request |
USER_NOT_FOUND | 404 | Login for an email with no account | Switch to signup-request |
USER_HAS_NO_ORGANIZATION | 409 | Login for an account that somehow has no org | Switch to signup-request |
OTP_NOT_FOUND | 404 | No pending code (never sent, or already consumed + expired) | Run the matching -request first |
OTP_EXPIRED | 410 | Code older than 10 minutes | Request a fresh code |
OTP_INVALID | 400 | Wrong 6 digits | Re-read the email; details.attemptsRemaining shows what’s left |
OTP_ALREADY_USED | 409 | Code consumed in an earlier call | Request a fresh code |
OTP_LOCKED_OUT | 429 | 5 bad attempts on the same code | Request a fresh code |
OTP_PURPOSE_MISMATCH | 409 | Signup code used for login or vice versa | Run the matching -request |
COMPANY_NAME_TOO_LONG | 400 | --company over 100 chars | Shorten or omit |
BRAND_COLOR_INVALID | 400 | Non-hex brand color | Use a 6-digit hex (#1a2b3c) |
LOGO_TOO_LARGE / LOGO_INVALID_FORMAT / LOGO_DECODE_FAILED | 400 | Logo fails size/format/decode validation | Use a PNG/JPEG/WebP/SVG under 2 MB |
INVALID_EXPIRES_IN_DAYS | 400 | --key-expires-in outside 1–365 | Omit or pick a valid value |
INTERNAL | 500 | Backend error | Retry in a few seconds |
What’s saved locally
After a successfulsignup-complete or login-complete:
- The raw
cko_key, its prefix, scopes,keyName, org id/name, andcreatedAtare written to~/.config/slideless/config.json(mode0600) as a new profile. - That profile is marked active.
- Subsequent commands (
slideless share,slideless whoami,slideless list, …) pick it up automatically.
Single-organization rule
A Slideless account has exactly one organization. Two consequences:signup-requestrefuses (USER_ALREADY_HAS_ORGANIZATION) if the email already owns one. The returnednextActiontells you to switch tologin-request.- Re-running
signup-completeafter an org exists would try to create a second one; the backend blocks it at both the endpoint and thecreateOrganizationlevel.
See also
- Quickstart — the full five-minute path that uses this.
cli/commands— compact syntax reference for the four subcommands.- HTTP API: CLI auth endpoints — the underlying
POST /cliRequestSignupOtp//cliCompleteSignup//cliRequestLoginOtp//cliCompleteLogin.