Skip to main content

curviate-inbox

Read and send LinkedIn messages with the Curviate CLI. Covers `inbox` (list, get, messages, search, mark-read), `inboxes` (personal and company-page discovery), `message` (new, send, get, edit, delete, react, attachment, InMail), replying as a company page, retrieval mode (`--mode`/`--max-age`) on the two inbox reads, and `webhook` for delivery of message events. Use when triaging conversations, reading a thread, sending or replying to a DM or InMail, or wiring event delivery.

Jump to install

Source facts

Repository
davila7/claude-code-templates
Last source activity
September 17, 2026 at 17:49
Detected SKILL.md language
English
Stars
30,896
Forks
3,522

Install options

The review-first prompt is selected by default. You can switch to a direct command or download a local copy.

Review the source files

Read SKILL.md and any companion files shown by SkillsMP before deciding whether to install.

Showing SKILL.md

SKILL.md
Source instructions · Read-only preview
name
curviate-inbox
description
Read and send LinkedIn messages with the Curviate CLI. Covers `inbox` (list, get, messages, search, mark-read), `inboxes` (personal and company-page discovery), `message` (new, send, get, edit, delete, react, attachment, InMail), replying as a company page, retrieval mode (`--mode`/`--max-age`) on the two inbox reads, and `webhook` for delivery of message events. Use when triaging conversations, reading a thread, sending or replying to a DM or InMail, or wiring event delivery.
version
0.1.0
author
Curviate
license
MIT
tags
["LinkedIn","CLI","Agents","Sales","Recruiting","Outreach"]
repository
https://github.com/Curviate/curviate-plugin
# Curviate: inbox and messaging Messaging is the highest-consequence surface here: every send lands in a real person's inbox and cannot be unsent. Preview first, always. Command surface established against CLI `0.33.0`. ## Before any command ```bash npm install -g @curviate/cli && curviate --version # needs Node 18 or newer curviate login --api-key <key> # or export CURVIATE_API_KEY curviate account list --json # the acc_id for --account ``` - **Credentials resolve flag > environment > stored profile** (`CURVIATE_API_KEY`, `CURVIATE_BASE_URL`, `CURVIATE_ACCOUNT`). - **`--profile <name>` picks the stored credential set; `--account <acc_id>` picks which connected LinkedIn account sends this message.** On a multi-account tenant, getting this wrong sends from the wrong person. Name the account explicitly on every write. - **`--preview` before every send.** It renders the resolved request (recipient, text, acting account) without sending. On a read command it is refused with exit `2`. - **`--json` on anything you parse**; **`--fields a,b,c`** to project (a message carries 22 fields); **`--verbose`** when a slim response looks suspiciously empty. - **Put global flags at the end of the command.** - **Branch on the exit code, never on prose.** See the table at the end. ### Text input Message text is a positional argument, and `-` reads stdin. **Use a quoted heredoc**: the quoted delimiter disables every shell expansion, so apostrophes, accents, `$` and backticks survive intact. An unquoted heredoc has produced an empty message that went out blank. ```bash cat <<'EOF' | curviate message send "<chat_id>" - --preview Hi Thomas, thanks for connecting. I saw the work you shared last week. EOF ``` ## Retrieval mode: `--mode` and `--max-age` Exactly four reads decide between a stored copy and a live LinkedIn call: `profile me`, `profile <id>`, `inbox get` and `inbox messages`. Two of them are here. | `--mode` | Behaviour | |---|---| | `auto` (default) | A stored copy while it is fresh, otherwise fetch. | | `live` | Always fetch from LinkedIn. | | `refill` | A stored copy at any age; fetch only when nothing is stored. | | `cache_only` | Never fetch. A store miss is refused, not fetched. | `--max-age <seconds>` (0 to 31536000) overrides those presets in both directions; `--max-age 0` is the same as `--mode live`. Every response carries `source: store | live` plus `observed_at` under `--json`, and a `provenance:` line on stderr in human mode. Read `source` rather than assuming. - **`cache_only` with `--max-age` is a usage error, exit `2`**, raised before any network call. `cache_only` never reaches LinkedIn at any age, so a freshness threshold cannot change its answer. Drop `--max-age`, or use `--mode refill`. - **`cache_only` on a store miss is exit `14` (`NOT_STORED`)**: the chat may exist perfectly well on LinkedIn, this API just holds no copy. It is not "not found" (`4`), so re-checking the chat id is the wrong move, and it is not retryable as sent. Re-read with `refill`, `auto` or `live`. - **`inbox messages`: one bare `--mode live` page restarts the chat walk and leaves it unservable by `cache_only` afterwards.** A listing is served from the store only over a *closed* walk. `inbox messages --all` walks to `cursor: null` and closes it. When you need a chat to be `cache_only`-servable later, reach for `--all` rather than a single live page. - **Every other command refuses the flags outright rather than ignoring them**: `unknown flag --mode`, exit `2`. ## Reading: `inbox` | Command | What it does | Confidence | |---|---|---| | `curviate inbox list` | Conversations, newest activity first, 20 by default. `--unread` / `--no-unread` filter by read state; `--inbox <folder>` selects `primary` (default), `inmail`, `archived`, `spam`, `jobs` or `starred`. | proven | | `curviate inbox get <chat_id>` | One chat's detail including `last_message` (full text and sender), the cheap triage read. Accepts `--mode`/`--max-age`. | proven | | `curviate inbox messages <chat_id>` | The messages in one chat. Full `text` per message; `is_sender` (0 or 1) says who sent each. `--before`/`--after` take ISO-8601 UTC with a `Z` suffix. Accepts `--mode`/`--max-age`. | proven | | `curviate inbox search "<query>"` | Free-text search of the account's own inbox: participant names and message content. | proven | | `curviate inbox mark-read <chat_id>` | Mark a chat read. | proven | **Listing chats does not mark anything read**, so triage freely. A chat item already carries the counterpart's identity: `user_id` (the `ACoAA…` member id), an embedded `user{}` (`id`, `type`, `display_name`, `profile_url`, `public_picture_url`), and `name`, the chat's own display name, which is populated on direct messages. Escalate to `curviate profile <user_id>` only for what `user{}` does not carry: headline, network distance, the full profile. ### Traps - **`--limit` on `inbox list` and `inbox messages` is validated client-side to 1-25** (default 20). Outside that range the command exits `2`. - **Neither `inbox list` nor `inbox search` reliably answers "does a chat with X exist".** A single `inbox list --limit 25` call has repeatedly omitted a chat created seconds earlier, across candidates, not a one-off race. `inbox search` has a different defect: its result set is ranked and capped rather than exhaustive, so a common first name can omit an exact match that a rarer name finds immediately. When the answer matters, walk `inbox list` by `--cursor` to exhaustion (or a generous `--max-pages`) rather than trusting one page or the search. - **Inbox threads carry no vanity slug.** `user.profile_url` is built from the member id and `public_identifier` is absent even under `--verbose`. Join inbox-driven flows on the member id. - **`inbox list` has no date-range flags.** `--before`/`--after` exist on `inbox messages` only, and filter messages within one chat. Filter a chat list client-side on `last_message_timestamp`. - **A very recent send or delete can take minutes to appear in `inbox messages`** (LinkedIn-side indexing). `message get <chat_id> <message_id>` reflects it immediately, use that to confirm a send, not a re-list. ## Discovering inboxes: `inboxes` | Command | What it does | Confidence | |---|---|---| | `curviate inboxes list` | Every inbox the account can act in: its own, plus the company pages it administers. `--kind personal\|company` and `--company-id <id>` narrow it. Beta. | proven | | `curviate inboxes chats <inbox_id>` | One inbox's conversations. Each chat id is send-ready. Beta. | proven | **A `COMPANY_…` chat id sends as that page, with no extra flag.** Pass it to `message send` and the message goes out from the page rather than from you; the output confirms with `Sent as <name> (company page)`. Company inboxes are reply-only: they cannot start a conversation. The page's own admin inbox has a second, richer surface under `company` (see `curviate-profile`). ## Sending: `message` | Command | What it does | Confidence | |---|---|---| | `curviate message new --to <recipient> "<text>"` | Start a new chat. `--to` takes a profile URL, a bare slug or a member id, and resolves it for you. `--attach <file>` is repeatable. | proven | | `curviate message send <chat_id> "<text>"` | Reply in an existing chat. A `COMPANY_` chat id sends as that page. | proven | | `curviate message get <chat_id> <message_id>` | One message. Reflects a very recent send immediately, unlike the thread listing. | proven | | `curviate message edit <chat_id> <message_id> "<text>"` | Edit a message within LinkedIn's allowed window. | proven | | `curviate message delete <chat_id> <message_id>` | Delete a message. | proven | | `curviate message react <chat_id> <message_id> <emoji>` | Add an emoji reaction to a message. | proven | | `curviate message attachment <chat_id> <message_id> <attachment_id>` | Download an attachment. | proven | | `curviate message inmail --to <recipient> --subject "<subject>" "<text>"` | Send an InMail. Both `--to` and `--subject` are required. Consumes an InMail credit. | proven | | `curviate message inmail-balance` | Remaining InMail credits. Check before a run that depends on them. | proven | **Chat ids** look like `CLASSIC_2-MzJmZTg1…` for a personal chat and `COMPANY_<id>_2-…` for a page. **There is no idempotency key and no server-side de-duplication.** A send that times out may already have landed. Re-read the thread (`inbox messages`, or `message get` for the id you just wrote) before re-issuing anything. ## Event delivery: `webhook` Message and account events arrive by webhook rather than by polling. | Command | What it does | Confidence | |---|---|---| | `curviate webhook create --source <s> --request-url <https url> --account-ids <ids>` | Register an endpoint. `--source` is `messaging`, `user` or `account_status`. Also `--name`, `--events`, `--data`, `--no-enabled`. | proven | | `curviate webhook list` | Registered webhooks. | proven | | `curviate webhook events` | The canonical event catalogue, read it before subscribing to a name. | proven | | `curviate webhook get <id>` | One webhook. | proven | | `curviate webhook update <id>` | Update in place. `--request-url`, `--name`, `--enabled`, `--events`, `--data`, `--account-ids`. The source is immutable. | proven | | `curviate webhook delete <id>` | Remove a subscription permanently. | proven | | `curviate webhook verify --secret <s> --header <sig> --body <json\|file\|->` | Verify a delivery signature offline, no network call. `--max-age-secs` rejects a replay older than the given age (default 300). | proven | Verify the signature on every delivery before acting on its body. ## Full command surface <!-- generated: command surface, CLI 0.33.0 --> Read from the CLI's own `--help` at version 0.33.0. Descriptions, traps and confidence tags elsewhere in this skill are hand-written and carry the version they were established against. Every command below that takes flags at all also accepts `--json`. | Command | Arguments | Flags | |---|---|---| | `curviate inbox list` | *(none)* | `--api-key`, `--profile`, `--account`, `--base-url`, `--timeout`, `--fields`, `--limit`, `--cursor`, `--all`, `--max-pages`, `--page-delay`, `--preview`, `--verbose`, `--beta`, `--unread`, `--inbox` | | `curviate inbox get` | `CHATID` | `--api-key`, `--profile`, `--account`, `--base-url`, `--timeout`, `--fields`, `--preview`, `--verbose`, `--beta`, `--mode`, `--max-age` | | `curviate inbox mark-read` | `CHATID` | `--api-key`, `--profile`, `--account`, `--base-url`, `--timeout`, `--fields`, `--preview`, `--verbose`, `--beta` | | `curviate inbox messages` | `CHATID` | `--api-key`, `--profile`, `--account`, `--base-url`, `--timeout`, `--fields`, `--limit`, `--cursor`, `--all`, `--max-pages`, `--page-delay`, `--preview`, `--verbose`, `--beta`, `--mode`, `--max-age`, `--before`, `--after` | | `curviate inbox search` | `QUERY` | `--api-key`, `--profile`, `--account`, `--base-url`, `--timeout`, `--fields`, `--limit`, `--cursor`, `--all`, `--max-pages`, `--page-delay`, `--preview`, `--verbose`, `--beta` | | `curviate inboxes list` | *(none)* | `--api-key`, `--profile`, `--account`, `--base-url`, `--timeout`, `--fields`, `--preview`, `--verbose`, `--beta`, `--kind`, `--company-id` |
View on GitHub
This SKILL.md is very large, so SkillsMP previews the first section here. View on GitHub