# Choose a surface

Choose the Product App for work in a browser, the `lessly` CLI for scripts, MCP for your AI agent, or the REST API for your own code. They use the same platform operations and permission checks.

## Pick by the caller

**A person doing something once — use the Product App.** It is the interface you use by hand, at `https://app.lessly.com`. Signing in establishes a browser session, so there is no credential to manage. Some things start here regardless of the surface you otherwise work in: an API key is created on the product's Developer page.

**A script, or a job in CI — use the CLI.** It exists so platform operations can be scripted from a terminal or from CI. A person at a terminal signs in with `lessly auth login`, which runs a device authorization flow through a browser. A job with no human passes a product-scoped token instead — `lessly auth login --token "$LESSLY_TOKEN"` — which needs no browser and no interaction.

Two conventions make the CLI worth choosing over raw HTTP for scripting. Output is human-readable tables by default and machine-readable with `--json` or `-o json|yaml|table`. Exit codes are grouped by class, so a script can branch on the kind of failure: 2 for validation, 3 for authentication or a token problem, 4 for not found or forbidden. Note that operations which change something ask for confirmation, and in a non-interactive shell that failure is immediate unless you pass `--yes`.

**An AI agent — use the MCP endpoint.** The agent connects its MCP client to `https://mcp.lessly.com`, calls `tools/list`, and gets exactly the operations the authenticated identity may use on the active product, each with a JSON Schema for its arguments. Interactive clients authenticate with the OAuth 2.1 authorization code flow; headless ones paste a static API key into the client configuration as a bearer credential. Read-only tools are annotated as such, so a careful client can treat anything unannotated as a mutation.

**Your own application code — use the REST API.** `https://api.lessly.com`, versioned under `v1`, with a bearer credential on every request: a short-lived session token, or a long-lived API key starting with `lsk_dev_`. Choose it when you are calling from a language runtime rather than a shell, or when you need control over the HTTP request itself — such as naming the product with the `X-Product-Id` header.

## The credential usually decides

If you already know how the caller will authenticate, the surface follows:

| The caller has | Surface |
| --- | --- |
| A browser and a person to sign in | Product App |
| A product-scoped token in an environment variable | CLI |
| An MCP client config | MCP endpoint |
| A bearer token in an HTTP request | REST API |

Whichever you pick, the credential travels with the request; see [REST API and API keys](/interfaces/api-and-keys) for how keys are created, scoped and revoked. If a piece of code should not hold a long-lived credential, trade the key for a short-lived token with `POST /auth/api/v1/api-keys/exchange`.

## Mixing them is normal

Nothing binds a workflow to one surface. Create the key by hand in the Product App, hand it to CI for the CLI, paste it into an agent's MCP client — it is the same platform underneath, and the same permission checks apply to each call.

## Next steps

- [Find your way around the Product App](/interfaces/web-app): the routes, the product slug, the session.
- [Run Lessly from a terminal](/interfaces/cli): install, sign in, branch on the exit code.
- [Connect an agent to Lessly](/interfaces/mcp): add the server, authenticate, call a tool.
- [Call the REST API with an API key](/interfaces/api-and-keys): create the key, use it, revoke it.
