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 --version

Sign in

curviate login

login 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 me

curviate doctor

doctor answers one question: can this machine call the API right now?

curviate doctor --json

It 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.

ExitMeaning
0Every check passed (including zero connected accounts).
2Usage error before any check ran, most often a malformed --base-url.
3No credential resolved, or the resolved credential was rejected.
5The credential is valid but the workspace has no active seat.
7The 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.

FlagTypeDefaultDescription
--api-keystringnoneAPI key. Visible in ps and shell history: prefer CURVIATE_API_KEY.
--profilestringnoneNamed profile to use from the config file.
--accountstringnoneAccount ID for account-scoped commands. Optional when exactly one account is connected; required with --preview.
--base-urlstringnoneOverride the API base URL.
--timeoutstringnoneRequest timeout in milliseconds.
--jsonbooleanfalseEmit JSON output (automatic when stdout is not a TTY).
--fieldsstringnoneComma-separated dot-path projection, for example id,name.
--limitstringnoneMaximum items per page.
--cursorstringnonePagination cursor (opaque token from a previous response).
--allbooleanfalseStream all pages as NDJSON.
--max-pagesstringnoneMaximum number of pages to fetch when --all is used. Refused (exit 2) without --all.
--page-delaystring400Milliseconds between pages under --all (0 disables). Refused (exit 2) without --all.
--previewbooleanfalsePrint the request the CLI would send, without calling the API.
--verbosebooleanfalseDeeper fields on the few commands that hide some by default.
--betabooleanfalseAllow 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 under Settings › API & Webhooks. 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.

CodeMeaningExample error codes
0Success.
1Unexpected or server-side failure. Also the fallback for an unrecognised error code.INTERNAL, PLATFORM_NOT_IMPLEMENTED
2Bad request or bad usage: an invalid argument, a missing required flag, a rejected payload.INVALID_REQUEST, PAYLOAD_TOO_LARGE, UNSUPPORTED_MEDIA_TYPE
3Not authenticated. The API key is missing, malformed, or rejected.UNAUTHORIZED
4Not found. The id does not exist, or is not owned by this key.ACCOUNT_NOT_FOUND, RESOURCE_NOT_FOUND, SEAT_NOT_FOUND
5The account is not on an active seat, or its LinkedIn lacks the required subscription.NO_ACTIVE_SEAT, LINKEDIN_FEATURE_NOT_SUBSCRIBED
6Rate limited. Back off and retry.RATE_LIMIT_TENANT, RATE_LIMIT_ACCOUNT, LINKEDIN_RATE_LIMITED
7Upstream platform failure. Usually transient.PLATFORM_ERROR, LINKEDIN_SERVICE_UNAVAILABLE
8The 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
9A connect checkpoint needs attention.CHECKPOINT_EXPIRED, CHECKPOINT_INVALID_CODE
10The action is no longer permitted on that object.MESSAGE_WINDOW_EXPIRED, RECIPIENT_UNREACHABLE
11Billing. A payment or subscription problem blocks the call.PAYMENT_REQUIRED, SEAT_CANCELLED
12Not an error. A connect flow needs the next human step, so run the checkpoint or poll the session.
13A 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

Next steps

  • Account: connect a LinkedIn account and read its acc_... id.
  • Messaging: read an inbox and send a message.
  • Errors: the full error-code list and what to retry.