Setup & Doctor
The curviate CLI is a scriptable terminal client for Curviate. JSON output when piped, stable exit codes, cursor pagination, and a preview flag on every write. Node.js 18 or later is required. Prefer to let your coding agent do it? Paste Set up https://curviate.com/INSTALL.md into it, as in the Quickstart.
Install
npm install -g @curviate/cli
curviate --versionSign in
curviate loginlogin prompts for the API key from your Curviate dashboard and masks it; nothing is echoed or logged. In CI or any non-interactive shell, set CURVIATE_API_KEY instead: the environment variable wins over a saved profile. curviate setup is the guided alternative: it opens your dashboard in a browser, you approve and read back a short code, and it saves the key for you (curviate setup --json, then printf '%s' "$CODE" | curviate setup --code -).
First commands
Connect a LinkedIn account in the dashboard, then point the CLI at it once:
curviate account list
curviate config set-account acc_YOUR_ACCOUNT_ID
curviate profile mecurviate doctor
doctor answers one question: can this machine call the API right now?
curviate doctor --jsonIt reports the CLI version, the config path, profile and base URL, where the credential came from (never its value), the workspace, whether the API accepts the credential, and every connected account. Run login or setup first: with no credential, doctor reports the API as unreachable. Zero connected accounts is a pass.
| Exit | Meaning |
|---|---|
0 | Every check passed (including zero connected accounts). |
2 | Usage error before any check ran, most often a malformed --base-url. |
3 | No credential resolved, or the resolved credential was rejected. |
5 | The credential is valid but the workspace has no active seat. |
7 | The API could not be reached. |
The credential check is a real API call, so any API exit code can surface. Branch on the exit code, never on the message text.
Global flags
Every command that makes an API request accepts these.
| Flag | Type | Default | Description |
|---|---|---|---|
--api-key | string | none | API key. Visible in ps and shell history: prefer CURVIATE_API_KEY. |
--profile | string | none | Named profile to use from the config file. |
--account | string | none | Account ID for account-scoped commands. Optional when exactly one account is connected; required with --preview. |
--base-url | string | none | Override the API base URL. |
--timeout | string | none | Request timeout in milliseconds. |
--json | boolean | false | Emit JSON output (automatic when stdout is not a TTY). |
--fields | string | none | Comma-separated dot-path projection, for example id,name. |
--limit | string | none | Maximum items per page. |
--cursor | string | none | Pagination cursor (opaque token from a previous response). |
--all | boolean | false | Stream all pages as NDJSON. |
--max-pages | string | none | Maximum number of pages to fetch when --all is used. Refused (exit 2) without --all. |
--page-delay | string | 400 | Milliseconds between pages under --all (0 disables). Refused (exit 2) without --all. |
--preview | boolean | false | Print the request the CLI would send, without calling the API. |
--verbose | boolean | false | Deeper fields on the few commands that hide some by default. |
--beta | boolean | false | Allow a beta operation for this call only (--beta=false to refuse). Without it, a beta operation exits 5 with BETA_NOT_ENABLED unless beta is enabled in Settings. Persists nothing. |
--preview is accepted by write commands only; a read refuses it (exit 2). It renders the request your arguments produce and sends nothing. It is not a validation check: a clean preview can still fail live (missing target, disconnected account, rate limit). To know whether a target exists, read it first.
Local commands (login, config ..., webhook verify) accept only the flags they act on, plus --json; any other flag exits 2.
Exit codes
Every command exits with a code derived from the error class, so a script can branch without parsing output.
| Code | Meaning | Example error codes |
|---|---|---|
0 | Success. | |
1 | Unexpected or server-side failure. Also the fallback for an unrecognised error code. | INTERNAL, PLATFORM_NOT_IMPLEMENTED |
2 | Bad request or bad usage: an invalid argument, a missing required flag, a rejected payload. | INVALID_REQUEST, PAYLOAD_TOO_LARGE, UNSUPPORTED_MEDIA_TYPE |
3 | Not authenticated. The API key is missing, malformed, or rejected. | UNAUTHORIZED |
4 | Not found. The id does not exist, or is not owned by this key. | ACCOUNT_NOT_FOUND, RESOURCE_NOT_FOUND, SEAT_NOT_FOUND |
5 | The account is not on an active seat, or its LinkedIn lacks the required subscription. | NO_ACTIVE_SEAT, LINKEDIN_FEATURE_NOT_SUBSCRIBED |
6 | Rate limited. Back off and retry. | RATE_LIMIT_TENANT, RATE_LIMIT_ACCOUNT, LINKEDIN_RATE_LIMITED |
7 | Upstream platform failure. Usually transient. | PLATFORM_ERROR, LINKEDIN_SERVICE_UNAVAILABLE |
8 | The account cannot perform the action right now: restricted, needs re-auth, or the action conflicts with existing state. | ACCOUNT_RESTRICTED, REAUTH_REQUIRED, CONNECTION_REQUEST_CONFLICT |
9 | A connect checkpoint needs attention. | CHECKPOINT_EXPIRED, CHECKPOINT_INVALID_CODE |
10 | The action is no longer permitted on that object. | MESSAGE_WINDOW_EXPIRED, RECIPIENT_UNREACHABLE |
11 | Billing. A payment or subscription problem blocks the call. | PAYMENT_REQUIRED, SEAT_CANCELLED |
12 | Not an error. A connect flow needs the next human step, so run the checkpoint or poll the session. | |
13 | A safety limit you set is spent, or the account is outside its working hours. Not exit 6: nothing reached LinkedIn, so backing off is the wrong recovery; see Safety settings. | BUDGET_EXHAUSTED |
curviate account list --json
case $? in
0) echo "ok" ;;
3) echo "check CURVIATE_API_KEY" ;;
6) echo "rate limited, backing off"; sleep 30 ;;
13) echo "safety ceiling spent; raise it or wait for resetAt" ;;
*) echo "failed" ;;
esac