Recruiter

Requires the Recruiter add-on. These commands call Recruiter-specific endpoints on the account. If the account does not have the add-on active, the platform returns a TIER_NOT_ACTIVE error (exit 5). The CLI does not pre-check — the error comes back from the API on the first call.

The recruiter commands are a project-centric rebuild in 0.15.0: messaging, profile lookup, people search, hiring-project management, pipeline tracking, project-scoped job postings, talent-pool search, candidate saving, and applicant/résumé lookup all key off a Recruiter project (a hiring project — proj_…), not a bare job id. All commands are account-scoped and require --account.

Changed in 0.15.0: recruiter sync, recruiter add-applicant, recruiter reject-applicant, and recruiter job checkpoint are removed with no replacement. recruiter add-candidate is replaced by recruiter save-candidate <project_id> --stage-id <id> --candidate-id <id> (full body reshape). recruiter job applicants is replaced by the project-scoped recruiter applicants <project_id> --channel-id <id>. Applicant detail/résumé (recruiter applicant) is now project-scoped: <project_id> <applicant_id>, not a bare applicant id. recruiter message new is now a JSON-only request (attachments ride as base64, no multipart) and requires --subject and --signature. New: recruiter search <url>, recruiter projects, recruiter project (get/update), recruiter pipeline, recruiter project-job (get/create/budget/update), recruiter talent-search, recruiter job close.

recruiter message new

Start a new Recruiter conversation. --to takes a verbatim provider ID (AE… format) — it is not resolved via URL or slug normalization. --subject and --signature are both required. --voice and --video are unique to Recruiter and Sales Navigator messaging (max 7 MiB each).

# Start a new Recruiter conversation (write, --preview accepted)
curviate recruiter message new \
  --to <recruiter_provider_id> \
  --subject "<subject>" \
  --signature "<sender signature>" \
  "<message text>" \
  [--attach <file>…] \
  [--voice <audio-file>] \
  [--video <video-file>] \
  --account <account_id>

recruiter profile

The <identifier> argument accepts a LinkedIn profile URL, a public slug, or a native id — the CLI normalizes automatically.

# Get a Recruiter profile (read)
curviate recruiter profile <identifier> --account <account_id>

recruiter search

# Run a pasted Recruiter search, talent-pool, or applicant URL directly (POST, paginated)
curviate recruiter search "<url>" [--limit <n>] [--cursor <token>] [--all] [--max-pages <n>] --account <account_id>
# Search Recruiter members (POST, paginated)
# Named flags: --keywords, --locale, --employment-type, --function, --profile-language
# Escape hatch: --filters '<json>' | --filters-file <path> | --filters -
curviate recruiter search people \
  [--keywords <k>] \
  [--locale <code>] \
  [--employment-type <ids>] \
  [--function <ids>] \
  [--profile-language <codes>] \
  [--filters '<json>'] \
  [--filters-file <path>] \
  [--limit <n>] [--cursor <token>] [--all] [--max-pages <n>] \
  --account <account_id>

For the full Recruiter filter surface, pass a JSON body via --filters. See the API reference for the complete filter field set. Named flags merge over the --filters base body. There is no recruiter search companies command.

# Resolve Recruiter filter parameter IDs (POST — source-scoped)
# --source: APPLICANTS | PIPELINE (both require --project-id) | SEARCH | JOB_POSTING | JOBS
# --type's valid set depends on --source (e.g. SKILL/LOCATION/JOB_TITLE for APPLICANTS, CONTRACT/SEAT/LOCATION for JOBS)
curviate recruiter search parameters \
  --source <SOURCE> \
  --type <TYPE> \
  [--keywords <k>] \
  [--project-id <project_id>] \
  [--stage-id <stage_id>] \
  --account <account_id>

--project-id is required when --source is APPLICANTS or PIPELINE. --stage-id is only meaningful with --source PIPELINE.

recruiter projects and project

# List Recruiter hiring projects (paginated read)
curviate recruiter projects [--limit <n>] [--cursor <token>] [--all] [--max-pages <n>] --account <account_id>
# Get a single hiring project by ID (read)
curviate recruiter project <project_id> --account <account_id>
# Edit a hiring project's config (write, --preview accepted). All fields optional — omitted fields are left unchanged.
curviate recruiter project update <project_id> \
  [--name <name>] \
  [--visibility <PRIVATE|PUBLIC>] \
  [--description <text>] \
  [--company-id <id>|--company-name <name>] \
  [--job-title-id <id>|--job-title <name>] \
  [--location <location_parameter_id>] \
  [--seniority-level <INTERNSHIP|ENTRY_LEVEL|ASSOCIATE|MID_SENIOR_LEVEL|DIRECTOR|EXECUTIVE|NOT_APPLICABLE>] \
  --account <account_id>

recruiter pipeline

List the candidates in a project's pipeline.

# List candidates in a project's pipeline (paginated read, POST-as-list)
# --sort-by: LAST_MODIFIED | ALPHABETICAL
# --spotlights: comma-separated — OPEN_TO_WORK, ACTIVE_TALENT, MISSED_CANDIDATES
curviate recruiter pipeline <project_id> \
  [--keywords <k>] \
  [--stage-id <stage_id>] \
  [--sort-by <LAST_MODIFIED|ALPHABETICAL>] \
  [--spotlights <tags>] \
  [--limit <n>] [--cursor <token>] [--all] [--max-pages <n>] \
  --account <account_id>

recruiter project-job

The job posting attached to a hiring project — at most one per project. This is distinct from recruiter job below, which operates outside any specific project (creating one, or reading any public posting).

# Get the single job posting attached to a project (read; 404 when none is attached)
curviate recruiter project-job get <project_id> --account <account_id>
# Create a job-posting draft attached to an existing project (write, --preview accepted)
# Same body-flag set as `recruiter job create` below, minus --project-name
curviate recruiter project-job create <project_id> \
  --job-title <title>|--job-title-id <id> \
  --company-id <id>|--company-name <name> \
  --workplace-type <ON_SITE|HYBRID|REMOTE> \
  --location <location_parameter_id> \
  --employment-status <FULL_TIME|PART_TIME|CONTRACT|TEMPORARY|OTHER|VOLUNTEER|INTERNSHIP> \
  --seniority-level <level> \
  --description "<full job description, min 200 chars>" \
  --apply-method <linkedin|external> \
  [--industry <ids, 1-3>] \
  [--job-function <ids, 1-3>] \
  [--notification-email <email>] \
  [--website-url <url>] \
  --account <account_id>
 
# Or supply the full body as JSON, optionally overriding scalar fields
curviate recruiter project-job create <project_id> --body-file job.json --account <account_id>
cat job.json | curviate recruiter project-job create <project_id> --body - --account <account_id>
# Get pricing to publish a project's job posting (read)
curviate recruiter project-job budget <project_id> <job_id> --account <account_id>
# Apply a partial update to a project's job posting (write, --preview accepted)
# Same flag set as project-job create — every flag optional
curviate recruiter project-job update <project_id> <job_id> [--job-title <t>] [--description <d>] […] --account <account_id>

recruiter talent-search

Search a project's talent pool. --channel-id (the project's RECRUITER_SEARCH talent-pool channel ID) is required.

# Search a project's talent pool (paginated read)
curviate recruiter talent-search <project_id> --channel-id <channel_id> [--keywords <k>] [--filters '<json>'] [--filters-file <path>] [--limit <n>] [--cursor <token>] [--all] [--max-pages <n>] --account <account_id>

recruiter save-candidate

Save a candidate to a project's pipeline at a given stage. Replaces the pre-0.15.0 recruiter add-candidate.

# Save a candidate into a project's pipeline (write, bodyless-style, --preview accepted)
curviate recruiter save-candidate <project_id> --stage-id <stage_id> --candidate-id <candidate_id> --account <account_id>

recruiter applicants and applicant

recruiter applicants lists applicants in a project's talent pool — project-scoped, not job-scoped. --channel-id (the project's JOB_POSTING talent-pool channel ID) is required.

# List applicants in a project's talent pool (paginated read)
curviate recruiter applicants <project_id> --channel-id <channel_id> [--limit <n>] [--cursor <token>] [--all] [--max-pages <n>] --account <account_id>
# Get a single applicant by ID (read, project-scoped)
curviate recruiter applicant <project_id> <applicant_id> --account <account_id>
# Download an applicant's résumé as binary (--preview not accepted)
# -o writes the bytes to a file; omit to stream to stdout
curviate recruiter applicant resume <project_id> <applicant_id> [-o <output-file>] --account <account_id>

recruiter jobs and job

recruiter jobs lists your Recruiter job postings across projects. recruiter job operates outside any specific project — create opens a brand-new hiring project for the job; get reads any public posting via the Recruiter lens (not only your own); publish and close are project-scoped (they take both <project_id> and <job_id>).

# List Recruiter job postings (paginated read)
curviate recruiter jobs [--limit <n>] [--cursor <token>] [--all] [--max-pages <n>] --account <account_id>
# Create a Recruiter job-posting draft, opening a brand-new hiring project (write, --preview accepted)
# --project-name is required; same body flags as `recruiter project-job create`
curviate recruiter job create \
  --project-name "<hiring project name>" \
  --job-title <title>|--job-title-id <id> \
  --company-id <id>|--company-name <name> \
  --workplace-type <ON_SITE|HYBRID|REMOTE> \
  --location <location_parameter_id> \
  --employment-status <FULL_TIME|PART_TIME|CONTRACT|TEMPORARY|OTHER|VOLUNTEER|INTERNSHIP> \
  --seniority-level <level> \
  --description "<full job description, min 200 chars>" \
  --apply-method <linkedin|external> \
  [--industry <ids, 1-3>] \
  [--job-function <ids, 1-3>] \
  [--notification-email <email>] \
  [--website-url <url>] \
  --account <account_id>
# Get a job posting via the Recruiter lens — any public posting, not only your own (read)
curviate recruiter job get <job_id> --account <account_id>
# Publish a project's job-posting draft (write, --preview accepted)
# --mode is required; PROMOTED/PROMOTED_PLUS spend real money and require the full --budget-* triple
curviate recruiter job publish <project_id> <job_id> --mode <FREE|PROMOTED|PROMOTED_PLUS> [--budget-currency <ISO-4217>] [--budget-amount <n>] [--budget-scope <DAILY|TOTAL>] --account <account_id>
# Stop a project's job posting from accepting applications (write, bodyless, --preview accepted)
# Irreversible once the posting is LISTED
curviate recruiter job close <project_id> <job_id> --account <account_id>

Examples

Search for Recruiter candidates

curviate recruiter search people \
  --keywords "machine learning" \
  --employment-type FULL_TIME \
  --account acc_YOUR_ACCOUNT_ID

Create a hiring project and its job in one step

curviate recruiter job create \
  --project-name "Senior ML Engineer Hire" \
  --job-title "Senior ML Engineer" \
  --company-id 1234567 \
  --workplace-type REMOTE \
  --location 106967730 \
  --employment-status FULL_TIME \
  --seniority-level MID_SENIOR_LEVEL \
  --description "We're looking for a Senior ML Engineer to join our platform team..." \
  --apply-method linkedin \
  --notification-email hiring@acme.com \
  --account acc_YOUR_ACCOUNT_ID
# => { "object": "recruiter_job_posting_created", "project_id": "proj_YOUR_PROJECT_ID", "job_id": "job_YOUR_JOB_ID" }

Publish the project's job

curviate recruiter job publish proj_YOUR_PROJECT_ID job_YOUR_JOB_ID --mode FREE --account acc_YOUR_ACCOUNT_ID

Save a candidate to the pipeline

curviate recruiter save-candidate proj_YOUR_PROJECT_ID \
  --stage-id stage_UNCONTACTED \
  --candidate-id RECRUITER_USER_ID \
  --account acc_YOUR_ACCOUNT_ID

List and browse the pipeline

curviate recruiter pipeline proj_YOUR_PROJECT_ID --sort-by LAST_MODIFIED --account acc_YOUR_ACCOUNT_ID

List applicants and download a résumé

curviate recruiter applicants proj_YOUR_PROJECT_ID --channel-id ch_YOUR_CHANNEL_ID --account acc_YOUR_ACCOUNT_ID
 
curviate recruiter applicant resume proj_YOUR_PROJECT_ID app_YOUR_APPLICANT_ID -o resume.pdf --account acc_YOUR_ACCOUNT_ID

Send a Recruiter message with a video

curviate recruiter message new \
  --to RECRUITER_PROVIDER_ID \
  --subject "Quick intro" \
  --signature "Alex, Talent Team" \
  "Hi, I wanted to share a quick video introduction." \
  --video ./intro.mp4 \
  --account acc_YOUR_ACCOUNT_ID
COMPANY · LEGAL

Privacy Policy

Redmer Holding GmbHLast updated July 25, 2026

Who we are

Curviate is operated by Redmer Holding GmbH ("Curviate", "we", "us"), a German GmbH registered at Amtsgericht Bonn, HRB 29957, registered address Hostertstraße 16, 53332 Bornheim, Germany. Full company details are on our Imprint. We haven't appointed a statutory Data Protection Officer, since our processing doesn't reach the scale or sensitivity that requires one. Privacy questions go to privacy@curviate.com.

The two roles we play

When you create an account and use Curviate, we process your own data (identity, billing, API keys, connector authorizations). For that data, we are the controller.

When you use Curviate to act on your own connected LinkedIn account, viewing profiles, sending messages, managing engagement, that content and those contacts belong to that account and its people. You are the controller of that data; we are the processor, acting only on your instructions, under the Data Processing Agreement between us. If one of your contacts has a question about being reached through Curviate, you're who they should contact first; email privacy@curviate.com if you need help routing it.

What we collect, and why

DataWhy
Account identity (name, email, sign-in method)Create and secure your account
Your LinkedIn credentialsOperate the actions you request
LinkedIn content returned by an API callFulfil that specific request, nothing more
API keys and connector (OAuth) authorizationsAuthenticate your API, CLI, MCP, or SDK requests
Billing detailsCharge you correctly and meet our tax obligations
Usage and security logsKeep the service reliable and abuse-free
Support messagesRespond to you
Website analytics, only if you opt inUnderstand how the site is used

We rely on our contract with you, our legitimate interest in running and securing the service, our legal obligations (tax law, for example), and, for analytics, your consent. We never sell your data or use it to train models.

Where it's processed, and who else touches it

Our infrastructure runs in the EU. Hosting: Railway. Database and auth: Supabase, Ireland. Email: Resend. Payments: Stripe. Network security: a DDoS-protection provider sits in front of our app and never sees or stores request content. LinkedIn connectivity: a third-party infrastructure provider that lets us execute LinkedIn actions on your behalf. Error tracking: Sentry, Frankfurt. Product analytics: PostHog, Frankfurt. Uptime monitoring: Better Stack.

We give the current, named list of every provider above, plus our Data Processing Agreement, to any customer who asks: security@curviate.com.

Outside the EU

All customer LinkedIn data, account data, and telemetry are processed and stored exclusively in EU regions of our sub-processors. A few providers we rely on (Stripe and Sentry, for example) are headquartered outside the EU/EEA; where that applies, it's covered by their own GDPR safeguards, typically the EU Standard Contractual Clauses.

How long we keep it

DataRetention
Account and workspace dataWhile your account is active
Closed accountRecoverable for 7 days, then deleted on day 8
LinkedIn credentialsUntil you disconnect that account
LinkedIn contentNot stored; any transient cache clears within 1 hour, never indexed, never used for training
API keysUntil you revoke or rotate them
Connector (OAuth) authorizationsAccess token ~1 hour; refresh token up to ~12 months, or until you revoke it, whichever comes first
Billing recordsAs required by German tax law, currently up to 10 years
LogsA short operational window; metadata only, never message content

The 12-month figure above is a server-side credential for a connected AI agent or app. It is not a cookie and doesn't touch your browser session; see Cookies below for that. You can see and revoke every connector from Authorized applications in your dashboard at any time.

Cookies

We keep cookies to a minimum, and ask before anything beyond the essentials runs.

Strictly necessary, no consent needed:

NamePurposeExpiry
cc_cookieRemembers your cookie choice12 months
curviate-themeRemembers light/dark mode (local storage, not a cookie)Persistent
sb-*-auth-tokenKeeps you signed inWhile active; cleared on sign-out

Analytics, only if you accept:

NamePurposeExpiry
_gaGoogle Analytics: distinguishes visitors2 years
_gidGoogle Analytics: distinguishes visitors24 hours
_ga_<container id>Google Analytics: persists session state2 years

No advertising cookies, ever. Accept and reject are equally easy, and you can change your mind any time via Cookie Preferences in the footer; we won't ask again for 12 months unless something material changes. Our LinkedIn connect flow and OAuth authorization screen never set anything beyond the essentials, so no banner appears there.

Connecting an AI agent or app

Curviate is built for AI agents and automated clients as much as for people. If you connect an app like Claude, or your own code, via an API key or an OAuth connector, it can act on your workspace within the access you gave it. What it does with anything it receives back, including what it sends to its own AI model, is between you and that provider; review its practices before connecting it. Review and revoke any connection any time from your dashboard.

Your rights

You can access, correct, delete, restrict, or object to your data, port it elsewhere, and withdraw consent at any time: email privacy@curviate.com. Closing your account starts the 7-day recoverable window above. We don't make automated decisions about you that have a legal or similarly significant effect. You can also complain to a supervisory authority; ours is the Landesbeauftragte für Datenschutz und Informationsfreiheit Nordrhein-Westfalen (LDI NRW), www.ldi.nrw.de, though you're free to complain to the one in your own country instead.

Keeping it secure

Credentials are encrypted and never logged, returned, or shared. LinkedIn actions run through native, humanized flows; full detail is on our Security & Compliance page. If a breach puts your rights at risk, we'll notify the authorities and you, as GDPR requires. Curviate isn't directed at, or offered to, anyone under 16.

Changes

We'll update this page when our practices change, and reset the cookie prompt if the change is material.

Contact