Skip to main content
Recruiter is supported. An account that holds a LinkedIn Recruiter seat can run candidate searches, sync the talent inbox, read its hiring projects and send Recruiter InMail. Everything on this page needs that seat. Without one, every Recruiter call answers 422 recruiter_required.

What the seat gives you

Recruiter is a third surface, separate from the basic LinkedIn engine and from Sales Navigator. Its threads carry messenger_type: "recruiter", its candidates are addressed by talent_id, and its search facet ids come from a lookup of their own: none of the three id spaces are interchangeable.

How the seat is detected

The premium check stamps the seat onto the account (recruiter_seat_id). Run it with checks: ['recruiter'] to refresh just that one. Some calls need the stamped seat number, not only the seat itself. If it is missing they answer 422 recruiter_seat_unresolvable, and the premium check resolves it.

Several Recruiter contracts

A member who holds seats on several Recruiter contracts is asked by LinkedIn to pick one before Recruiter opens, and holds no seat until they do. The premium check handles the common case on its own: when only one corporate contract is on offer (or the account is already bound to one of them) it binds the browser to that contract and stamps the seat. When several corporate contracts are on offer the check does not guess, because the wrong pick binds the browser to the wrong inbox: the seat stays unstamped until someone picks. An agent lists the contracts with get_linkedin_account_my_recruiter_contracts (the corporate rows are Recruiter seats; the individual row is a Job Posting contract on the personal account) and binds one with select_linkedin_account_recruiter_contract, passing contract_id exactly as listed; the seat holder can pick it in the account’s browser instead. Either way the seat is stamped on the spot or by the next check. recruiter_contract_id on the account names the contract the seat belongs to.

The Recruiter session expires every 30 days

This is the failure everyone hits, and it is not a fault. Recruiter keeps its own session, roughly 30 days long, separate from the account’s normal LinkedIn session. The account can be perfectly healthy and still have a dead Recruiter session. When it runs out, LinkedIn asks the seat holder for their password again before Recruiter opens. The account’s recruiter_status says where it stands: active (the seat answers), signed_out (the seat needs a sign-in) or null (no Recruiter seat). It flips to signed_out on the first refused Recruiter call, and the platform also checks the session clock every 15 minutes so you hear about it before a sync runs into it. The moment it flips you get one webhook, linkedin-accounts.recruiter-signed-out, and the person who connected the account gets one email; nothing repeats until the next time, and never more than once a day per account. The webhook’s reason tells the two cases apart. session_expired and wire_401 mean LinkedIn ended a session that existed. session_unconfirmed means the seat is there but the browser has never been signed in to Recruiter (or the member is still on LinkedIn’s contract chooser): nothing was ended, and the email says “sign in to switch it on” rather than “you were signed out”. A freshly connected account with a Recruiter seat starts in exactly this state, so the first thing to do after connecting a seat holder is the sign-in below. While the seat is signed out, every Recruiter call answers 409 recruiter_reauth_required and the recruiter inbox sync waits. The error carries context.account_url, the account’s page in the app, and a plain suggestion an agent can relay. Only the seat holder can sign in again. Open the account’s page, press Sign in to Recruiter: the account’s cloud browser opens straight on Recruiter’s sign-in, you enter the LinkedIn password there and confirm. The platform restarts the browser, re-checks the seat and flips the status back to active (and sends linkedin-accounts.recruiter-signed-in). Nobody else can do it for you: not another teammate, not support, not an agent, and the platform never stores the password. Retrying the call does not help until you have signed in. recruiter_session_expires_at on the account tells you when the session will run out, so you can sign in before it does rather than after. The platform reads it from the account’s own running browser. It is null when the platform has not seen the session cookie, which is not a verdict: a browser that is still on LinkedIn’s contract chooser has no session cookie at all, and the fix there is picking a contract, which the sign-in above ends on.

InMail credits

Recruiter InMails come out of the contract’s own pool, which LinkedIn keeps apart from the Sales Navigator seat’s grant and from the Premium plan’s balance. The account carries it as recruiter_inmail_credits, what Recruiter’s Usage Overview shows as InMail credits. The premium check reads it for an active seat as part of its inmail_credits step, every 6 hours in the background or on demand with check_linkedin_account_premium_subscription and checks: ["inmail_credits"]. Null means the platform has not read it yet, never zero. A new thread on a balance known to be zero is refused before anything reaches LinkedIn (rule no_inmail_credits); a reply into an existing thread is never guarded. A signed-out seat keeps its last number until the seat holder signs in again. search_linkedin_accounts filters on the field, so recruiter_inmail_credits: {eq: 0} lists the seats that cannot open a thread until the monthly refresh.

Limits that come from LinkedIn, not from us

One InMail per candidate per 24 hours. Sending a second one answers 429 recruiter_inmail_cooldown with cooldown_ends_at. If a reply may have landed in between, refresh the thread before assuming the send failed. A per-seat search throttle. Heavy searching answers 429 recruiter_search_usage_limit. Waiting a minute clears it. Neither is a platform limit and neither is configurable here. They are LinkedIn’s, applied to the seat.