Skip to content
Docs

Migrating From Unipile

Moving a Unipile integration to Direct: base URL, key, account ids, chat ids, webhooks, hosted auth and fallback.

Direct answers Unipile's LinkedIn routes with Unipile's paths, fields, status codes and error types. Moving a Unipile integration is mostly configuration, plus a few points below.

1. Base URL And Key#

Unipile Direct
Base URL https://<your-dsn>/api/v1 https://direct.lempile.com/api/v1
Key header X-API-KEY: <unipile key> X-API-KEY: <Direct key> (one per workspace, made in Lempile's dashboard)

Paths stay the same: GET /users/me, GET /chats, POST /chats/{chat_id}/messages…

If your code checks hostnames (for example that a hosted auth link starts with https://account.unipile.com/, or that the API host ends in unipile.com), accept direct.lempile.com too.

2. Account IDs#

Direct's account ids are Lempile account ids. A Unipile account id doesn't exist here.

  • Connect each LinkedIn account through Direct's hosted auth link (or have Lempile connect it), then store the new id. GET /accounts lists them; connection_params.im.id is the member's provider id, the same as on Unipile, so you can match accounts by it.
  • Every account starts with writes off. Ask Lempile to turn writes on per account, and use ?dry_run=true meanwhile.

3. Chat And Message IDs#

  • A chat id is LinkedIn's own conversation id (2-…) and a message id LinkedIn's own message id, answered URL-safe (- and _, no =). They are not Unipile's ids: chat and message ids stored from Unipile don't resolve. Read the chats from Direct to map them (match on the other attendee's provider id and the latest message's time).
  • Every inbox call names its account: GET /chats/{chat_id}?account_id=, GET /chats/{chat_id}/messages?account_id=, GET /messages/{message_id}?account_id=, and account_id in the body of POST /chats/{chat_id}/messages. Unipile finds the account from the chat id; Direct can't.
  • Profile provider ids (ACo…) and posts' social_id (urn:li:activity:…) are LinkedIn's own, as on Unipile, so stored ones keep working. Comment and invitation ids are LinkedIn's numbers; read them from Direct.

4. Webhooks#

  • Register your webhooks again with POST /webhooks on Direct: webhooks set in Unipile's dashboard don't move. Same bodies, same payloads.
  • Messaging events come in real time from LinkedIn's own live connection, with polling as the backstop; new_relation from polling, 30 to 60 minutes after the connection. See Webhooks.
  • message_received, message_read, message_reaction, message_edited, message_deleted, new_relation and the account status events are sent. message_delivered is accepted but never sent.
  • Deliveries carry the headers you registered and are not signed: authenticate them with a secret header, as with Unipile.

5. Hosted Auth#

  • POST /hosted/accounts/link takes Unipile's body and answers Unipile's HostedAuthUrl (200). The url is on direct.lempile.com.
  • providers takes Unipile's forms ("LINKEDIN", ["LINKEDIN"], "*", "*:MESSAGING") and must take LinkedIn; a reconnect link needs none.
  • A new account joins your key's workspace; a reconnect link can only name your workspace's accounts.
  • notify_url receives exactly {status, account_id, name} (CREATION_SUCCESS or RECONNECTED), as on Unipile.
  • Unipile's options disabled_features, disabled_options, proxy, sync_limit, google_scopes, microsoft_scopes and single_use are ignored. The link lasts 24 hours at most.
  • Native authentication (POST /accounts with credentials or cookies), checkpoints (POST /accounts/checkpoint) and PATCH /accounts/{id} answer 501: accounts connect only through Lempile's real-browser sign-in.

6. Errors And Fallback#

  • Error bodies are Unipile's {title, detail, type, status}; types and statuses follow Unipile's.
  • Anything Direct doesn't do answers 501 errors/feature_not_implemented. A client that keeps Unipile for some accounts or features can fall back to Unipile on 501. For a write, fall back only on 501 (or 403 Writes off, or 404 Account not found): any other answer may mean the write went out.
  • 429 errors/too_many_requests comes with retry_after and a Retry-After header: Direct's limits are per account (1,500 LinkedIn calls and 150 writes a day). See Errors And Limits.
  • A missing account_id answers 400 errors/missing_parameters, a parameter of the wrong type 400 errors/invalid_parameters.

7. What You Gain#

  • ?dry_run=true on every write: the exact LinkedIn call, not sent.
  • Idempotency-Key on writes: the same key never writes twice, so retries are safe.
  • DELETE /posts/{post_id}/comments/{comment_id} and DELETE /posts/reaction, which Unipile doesn't have.
  • Every call goes out from the account's own browser session and its own proxy.

8. Checklist#

  1. Get a Direct key for your workspace; set the base URL and the key.
  2. Connect the accounts through hosted auth; store the new account ids.
  3. Add account_id to every inbox call that lacked it.
  4. Re-read chats from Direct; don't reuse Unipile's chat and message ids.
  5. Register the webhooks on Direct; authenticate them with a header secret.
  6. Accept direct.lempile.com wherever your code checks Unipile's hostnames.
  7. Try every write with ?dry_run=true, then ask Lempile to turn writes on.
  8. Handle 501 (fall back or skip) and 429 (wait retry_after).
  9. Check the routes you use against Unipile Compatibility.

Was this page helpful?