Unipile MCP · Hosted Auth
Unipile Hosted Auth: connect your users' accounts with a coding agent
Your users link their own LinkedIn, WhatsApp, email or calendar account on a page Unipile hosts. Your app creates a link, redirects, and receives an account ID. With the Unipile MCP server, Codex, Cursor, Claude Code or Gemini CLI reads the auth link contract and writes the route, the callback and the storage in your stack. Part of the Unipile MCP server.
POST /v2/auth/link
redirect_uri and state
Reconnect with account_id
No credentials in your code
One route, one callback, one account ID stored. 7-day free trial, no credit card.
Your agent · crm-app
Unipile MCP connected
Implement Unipile Hosted Auth in this React and Fastify app: a server route that creates the auth link, a callback that reads account_id and state, and persistence on the workspace.
Read endpointPOST /v2/auth/linkschema loaded
Added POST /api/accounts/connect (creates the link with providers, expires_on, redirect_uri and a signed state) and GET /auth/callback, which reads account_id, provider and state from the query and stores the account on the workspace.
Now add a Reconnect button next to each account that shows as disconnected.
Run requestPOST /v2/auth/link201 · link
Describe the next feature…
The job
What you are trying to do
Let each user of your product connect their own accounts, without your code ever seeing a password or a token, and get back the account ID every later request needs. Each provider has its own login, two-factor step and consent screen. Hosted Auth puts all of that on one page Unipile serves, and the agent wires the three pieces your app owns.
Without it
Login forms, tokens, provider quirks
You build a login form per provider and store tokens you did not want to hold.
Two-factor prompts and consent screens break the flow differently on each provider.
The account ID ends up guessed from the redirect, and lost when the user closes the tab.
With the Unipile MCP server
The result in your application
A Connect button that opens the hosted wizard, and a callback route that stores the account ID on the workspace.
A Reconnect button that reuses the same endpoint with the stored account ID.
The flow validated with the mock provider on your Development application before a real account is linked.
Prompt, steps, code
Give your agent the prompt
Two prompts, each with the Unipile endpoints the agent reads and runs and what lands in your project. Paths are complete, on the API base URL
https://api.unipile.com, with your scoped key in the X-API-KEY header.Implement Unipile Hosted Auth in this React and Fastify application: a server route that creates the auth link, a callback route that reads account_id and state, and persistence of the account_id on the current workspace.
Read endpointPOST /v2/auth/linkschema loaded
Run requestPOST /v2/auth/link201 · link
Added
POST /api/accounts/connect in Fastify: it calls the auth link endpoint with providers, an expires_on fifteen minutes ahead in ISO 8601 UTC, the redirect_uri of the callback and a signed state carrying the workspace ID. The React Settings page opens the returned link. GET /auth/callback reads account_id, provider and state from the query and stores the account. Tested with providers: "mock" on the Development app.A link created server-side, a callback that stores the account ID
The link is created on your server with your scoped key; the browser only receives the hosted URL. When the user is done, Unipile redirects to your
redirect_uri with account_id, provider and your state in the query string. The agent reads these three fields from the contract, not from memory, and writes the callback accordingly.Endpoints the agent uses
POST/v2/auth/linkGET/v2/accounts/{account_id}GET/v2/accounts/
Common mistake: Creating the auth link from the browser. The key would leak; the frontend only opens the link your server returns.
Auth link reference
Add a Reconnect button next to each connected account: call the Unipile auth link endpoint in re-authentication mode with the stored account_id, and handle the callback the same way as the first connection.
Read endpointPOST /v2/auth/linkre-authenticate branch
Run requestGET /v2/accounts/{account_id}status: disconnected
Added
POST /api/accounts/:id/reconnect: same endpoint, same redirect_uri, but the body carries account_id instead of providers. The Settings page shows the button when the account status is not running, and the existing callback handles the return. Verified by disconnecting the mock account on the Development app.Same endpoint, one field changes
A reconnect link takes
account_id and no providers; a first connection takes providers and no account_id. The contract says the entire account is refreshed and every configured product restarts, so the agent triggers it from the account status and keeps one callback for both flows.Endpoints the agent uses
POST/v2/auth/linkGET/v2/accounts/{account_id}POST/v2/auth/checkpoint
Common mistake: Sending both providers and account_id. The body is one branch or the other, never both.
Trigger it from account.status.disconnected
Payload
The request body, both branches, and the response
Verbatim from the v2 contract the agent reads through the server. Three fields are required for a first connection, and the response is a single link.
1Link a new accountproviders, expires_on and redirect_uri are required. state is echoed back in the redirect and in the account.add event. account_scope_id assigns the account to a Scope.POST https://api.unipile.com/v2/auth/link{ "providers": "*", "expires_on": "2026-10-01T12:00:00.000Z", "redirect_uri": "https://app.example.com/auth/callback", "state": "ws_42.signed", "account_scope_id": "scope_…" }
2Re-authenticate an existing accountaccount_id replaces providers. The whole account is refreshed and every configured product restarts.POST https://api.unipile.com/v2/auth/link{ "account_id": "acc_…", "expires_on": "2026-10-01T12:00:00.000Z", "redirect_uri": "https://app.example.com/auth/callback" }
3Response and returnThe response is a HostedAuthLink. After the wizard, the redirect carries account_id, provider and state; the account.add webhook carries the same state.{ "object": "HostedAuthLink", "link": "https://auth.unipile.com/…" }GET https://app.example.com/auth/callback?account_id=acc_…&provider=linkedin&state=ws_42.signed
Development to production
Test on a Development application first
Your Unipile dashboard separates a Development application from Production. Give the agent a scoped key from Development and use the mock provider: the whole flow, no real account.
1Run the flow with providers: "mock"Link created server-side, callback read, account ID stored.
2Reconnect the test accountDisconnect it, open the reconnect link, status back to running.
3Confirm account.add, then switch the keyThe webhook carries the same state as the redirect; only then use Production.
crm-app · DevelopmentUsed by your agent
Scopedev-tests · 2 accounts
Key
scoped Account API keyAccountsLinkedIn test account, Gmail test mailbox
Webhooks1 endpoint · message events
crm-app · ProductionUntouched
Scopeone per workspace
Key
scoped keys, in your backend onlyAccountsyour users' own accounts, via Hosted Auth
Troubleshooting
Common errors and what they mean
The four mistakes that stop a Hosted Auth integration, and the fix for each. Most of them come from copying a v1 example.
notify_url or success_redirect_url in the body
The request is rejected, or the callback never fires.
FixThese are v1 fields. The v2 body takes redirect_uri and state; notifications go through a webhook endpoint subscribed to account.add and account.reconnect.
expires_on rejected
Validation error on the date.
FixThe field expects an ISO 8601 UTC datetime, YYYY-MM-DDTHH:MM:SS.sssZ. A Unix timestamp or a local date is refused.
Both branches in one body
Validation error on providers or account_id.
FixA first connection takes providers and no account_id; a reconnect takes account_id and no providers. Send one branch.
The account ID never arrives
The user closed the tab before the redirect.
FixThe redirect is a convenience. The source of truth is the account.add event on your webhook endpoint, which carries the same state. Store from the event, confirm from the redirect.
Hosted Auth FAQ
What Hosted Auth is, which endpoint creates the link, how you know the user finished, how to reconnect, and which providers the wizard can show.
A page hosted by Unipile where your user authenticates with their provider. You create a link with
POST /v2/auth/link, redirect the user to it, and get back an account_id. Credentials and tokens never pass through your code.POST https://api.unipile.com/v2/auth/link, with the X-API-KEY header and a body carrying providers, expires_on and redirect_uri. There is no /v2/hosted/accounts/link path in v2.Two channels. The
redirect_uri receives account_id, provider and state as query parameters. The account.add webhook event carries the same state. Use the webhook as the source of truth and the redirect for the user experience.Same endpoint, with
account_id instead of providers. The contract says the entire account is refreshed and all configured products restart. Trigger the flow from the account.status.disconnected event or from the account status.providers accepts *, a family filter such as *:EMAILS, *:MESSAGING, *:CALENDAR or *:SOCIAL, or a list among linkedin, whatsapp, google, outlook, imap, telegram and instagram. Use mock to test the flow.
Instagram