{"openapi":"3.1.0","info":{"title":"Curviate API","version":"1.0.0","description":"Agent-native LinkedIn infrastructure."},"servers":[{"url":"https://api.curviate.com","description":"Production"},{"url":"https://api.staging.curviate.com","description":"Staging"},{"url":"http://api.localhost:3000","description":"Local dev (host-mode)"}],"tags":[{"name":"Users","description":"Look up and manage professional-network user profiles, retrieve a profile, update your own, list connections, list the pages the account administers, check InMail credit balance, and endorse a skill; plus the connected account's own insights: premium subscription entitlements, performance analytics, profile visitors, and Social Selling Index."},{"name":"Following","description":"Follow and unfollow professional-network users, and list a user's followers or who they follow."},{"name":"Companies: Profile","x-displayName":"Profile","description":"Look up a company profile and its employees, posts, jobs, followers, and the connections invitable to follow it."},{"name":"Companies: Inbox","x-displayName":"Inbox","description":"Read, search, and reply in a company page's admin message inbox: list conversations, retrieve one, read a thread's messages, filter by topic or unread, and reply to a conversation as the page."},{"name":"Groups","description":"List the groups a member belongs to, look up a group's detail, and browse or search a group's members."},{"name":"Search","description":"Search for people, companies, posts, jobs, groups, and services across the professional network."},{"name":"Messaging","description":"Send messages, manage conversations, track message threads with connections, and search your inbox."},{"name":"Feed","description":"Read the connected account's home feed as agent-actionable posts, ranked or reverse-chronological."},{"name":"Notifications","description":"Read the connected account's notifications, and delete or mute a notification card."},{"name":"Comments","description":"Comment on posts and manage comments, comment on a post, reply to a comment, update or delete a comment, list a user's comments and a comment's replies, and list, add, or remove comment reactions."},{"name":"Invites","description":"Send, list, withdraw, accept, and decline connect-requests on the professional network."},{"name":"Jobs","description":"Retrieve a public job posting's full detail by id."},{"name":"Posts","description":"Read, publish, and delete posts, and react to them: get a post, list a user's posts (your own or another's), create or delete a post, list and add reactions, list a user's reactions, and remove a reaction; and save posts for later: list your saved posts, save a post, and unsave one. Commenting lives in the Comments group."},{"name":"Drafts","description":"Prepare posts before publishing: create, edit, list, move between accounts and delete Drafts with their media, publish one now, and list the publish records of posts published through Curviate."},{"name":"Recruiter: User Profile","x-displayName":"User Profile","description":"Look up a Recruiter-enriched member profile."},{"name":"Recruiter: Messaging","x-displayName":"Messaging","description":"Start Recruiter InMail conversations."},{"name":"Recruiter: Search","x-displayName":"Search","description":"Resolve filter parameters and search people, the talent pool, or a pasted search URL."},{"name":"Recruiter: Projects","x-displayName":"Projects","description":"Manage hiring projects and their candidate pipeline."},{"name":"Recruiter: Jobs","x-displayName":"Jobs","description":"Manage the full job-posting lifecycle and review talent-pool applicants."},{"name":"Sales Navigator: Messaging","x-displayName":"Messaging","description":"Start Sales Navigator InMail conversations."},{"name":"Sales Navigator: User Profile","x-displayName":"User Profile","description":"Look up a Sales Navigator-enriched member profile."},{"name":"Sales Navigator: Lists","x-displayName":"Lists","description":"Manage saved account and lead lists, list, browse, and save into them."},{"name":"Sales Navigator: Search","x-displayName":"Search","description":"Resolve filter parameters and search people, companies, or a pasted search URL."},{"name":"Accounts","description":"Manage connected professional network accounts, list, inspect, update, and disconnect."},{"name":"Auth","description":"Connect and re-authenticate professional network accounts, hosted links, direct credential/cookie sign-in, verification checkpoints, and connect-session status."},{"name":"Webhooks","description":"Register and manage webhooks that deliver real-time account events, and read the events an account received in the last 24 hours whether or not any webhook was subscribed to them."},{"name":"Safety","description":"Read and configure an account's safety limits: per-budget-row ceilings and bands, counting windows, enforcement posture, the activity window, warm-up state and character caps. Every number is seeded configuration and every one of them is settable."},{"name":"Seats","description":"Buy or manage the seats a workspace's subscription holds: add seats, and schedule or revert a seat's cancellation. Use GET /v1/accounts/seats to find a free seat to connect an account into."}],"x-tagGroups":[{"name":"Users","tags":["Users"]},{"name":"Following","tags":["Following"]},{"name":"Companies","tags":["Companies: Profile","Companies: Inbox"]},{"name":"Groups","tags":["Groups"]},{"name":"Search","tags":["Search"]},{"name":"Messaging","tags":["Messaging"]},{"name":"Feed","tags":["Feed"]},{"name":"Notifications","tags":["Notifications"]},{"name":"Comments","tags":["Comments"]},{"name":"Invites","tags":["Invites"]},{"name":"Jobs","tags":["Jobs"]},{"name":"Posts","tags":["Posts"]},{"name":"Drafts","tags":["Drafts"]},{"name":"Recruiter","tags":["Recruiter: User Profile","Recruiter: Messaging","Recruiter: Search","Recruiter: Projects","Recruiter: Jobs"]},{"name":"Sales Navigator","tags":["Sales Navigator: Messaging","Sales Navigator: User Profile","Sales Navigator: Lists","Sales Navigator: Search"]},{"name":"Accounts","tags":["Accounts"]},{"name":"Auth","tags":["Auth"]},{"name":"Webhooks","tags":["Webhooks"]},{"name":"Safety","tags":["Safety"]},{"name":"Seats","tags":["Seats"]}],"components":{"schemas":{"Error":{"type":"object","description":"Structured error envelope. Every non-2xx response uses this shape.","required":["code","message","user_fixable","retry_likely_to_succeed"],"properties":{"code":{"type":"string","description":"Stable machine-readable error code (e.g. ACCOUNT_NOT_FOUND)."},"message":{"type":"string","description":"Human-readable explanation. Safe to surface to an end user."},"retry_hint":{"type":"object","nullable":true,"description":"How to retry, when retrying may help.","properties":{"kind":{"type":"string","enum":["delay","backoff","never"]},"delay_ms":{"type":"number","description":"Suggested wait before retry, in milliseconds."}}},"user_fixable":{"type":"boolean","description":"True when the caller can resolve this by changing the request."},"retry_likely_to_succeed":{"type":"boolean","description":"True when an identical retry is likely to succeed."},"row":{"type":"string","nullable":true,"description":"Present on a PLATFORM_RATE_LIMIT raised because one account-safety budget row is paused: LinkedIn refused a recent call on that row, so this one was refused locally without reaching LinkedIn. Names the paused row (for example profile_views, connection_requests_no_note). The pause is scoped to this row on this account; every other row keeps working. Absent on every other rate limit. Also present on BUDGET_EXHAUSTED, where it names the row that hit its CEILING rather than one LinkedIn paused: read the code to tell the two apart, because the recovery differs. Null on a BUDGET_EXHAUSTED whose reason is activity_window and whose action spends no budget of its own, because there is no row to name; hint.parameter still names the setting to change. Never null on a rate limit."},"reset_at":{"type":"string","nullable":true,"description":"Present on BUDGET_EXHAUSTED: the instant the refusal lifts, as an absolute instant rather than a duration, so it stays true however long you hold it. It is the window roll on a ceiling refusal and the next window open on an activity-window one. It is null in the two cases where no clock frees the account: the pending_invites gauge, whose backlog falls when invitations are accepted or withdrawn, and an InMail credit exhaustion (row inmail), which LinkedIn regrants on a schedule this product cannot read."},"hint":{"type":"object","description":"Present on BUDGET_EXHAUSTED: the exact setting to change, as a field rather than as prose. parameter is addressable on PATCH /v1/{account_id}/safety-policy, so an agent can decide between waiting until reset_at, escalating to a human, and reconfiguring, without parsing the message.","properties":{"parameter":{"type":"string","description":"The settable parameter, for example profile_views.ceiling or posture."},"message":{"type":"string","description":"One paragraph naming the condition and what changing that parameter would do."}},"required":["parameter","message"]},"reason":{"type":"string","enum":["ceiling","activity_window"],"description":"Present on BUDGET_EXHAUSTED: which rule refused. ceiling means the row's configured limit is spent, and you wait until reset_at or raise it. activity_window means the account is outside the hours it works in, and reset_at is when the window next opens. The two need different fixes, so branch on this rather than on the message; hint.parameter already names the right setting for each."},"blocked":{"type":"boolean","description":"Present on BUDGET_EXHAUSTED, always true: the action did not happen and spent nothing. The same payload with blocked false rides the SUCCESS body of an account on the default warn posture, under safety_warning, and is otherwise field-identical, so one branch of your code handles both postures and moving an account to enforce is not a breaking change."},"retry_after":{"type":"integer","description":"Present alongside row: whole seconds until that row is usable again. This response carries no Retry-After header and no delay retry_hint, deliberately: a paused row can be paused for an hour, and a client that sleeps that inside the call hangs. Do not retry this row before the wait elapses; switch to other work instead. Seconds, not milliseconds."},"unresolved":{"type":"array","description":"Present when a structured search filter value matched several filter options and one has to be picked (422 FILTER_CANDIDATES_REQUIRED). One entry per offending value, so a single retry can fix them all. A value that matched no option at all is not listed here and is not an error: it is sent on as an id and reported in notices[] on the 200.","items":{"type":"object","properties":{"field":{"type":"string","description":"The request body field the value came from. Dotted for nested filters, for example author.company."},"value":{"type":"string","description":"The value exactly as you sent it."},"candidates":{"type":"array","description":"The filter options this value matched. Pick one and re-send its id.","items":{"type":"object","properties":{"id":{"type":"string","description":"The filter id to send instead of the display name."},"name":{"type":"string","description":"Human-readable label for this option."}}}}}}},"portal_url":{"type":"string","nullable":true,"description":"Present on PAYMENT_REQUIRED and ACCOUNT_DISPUTED: the self-service page where the tenant resolves the payment problem, so an agent can hand a human one link. Null when no portal session could be opened; fall back to the dashboard."},"attempts_remaining":{"type":"integer","description":"Present on CHECKPOINT_INVALID_CODE: how many more verification codes the checkpoint accepts before it locks. Stop and ask the account owner for a fresh code when it reaches zero, rather than guessing."},"challenge_type":{"type