Skip to main content
POST
/
api
/
unipile
/
refresh
Refresh a Unipile account's premium status
curl --request POST \
  --url https://app.puffle.ai/api/unipile/refresh \
  --header 'Authorization: Bearer <token>' \
  --header 'Content-Type: application/json' \
  --data '
{
  "accountId": "3c90c3cc-0d44-4b50-8888-8dd25736052a"
}
'
{
  "success": true,
  "is_premium": true,
  "has_sales_navigator": true,
  "weekly_connection_limit": 100,
  "weekly_message_limit": 150,
  "changed": {
    "is_premium": false,
    "has_sales_navigator": true
  }
}

Overview

Cheap, idempotent, no OAuth round-trip. The route fetches the account payload from Unipile and writes these fields back to unipile_accounts:
  • name, profile_url
  • is_premium, has_sales_navigator
  • weekly_connection_limit (100 premium / 80 free)
  • weekly_message_limit (150 premium / 100 free)
The changed object in the response is a per-field diff versus the prior row — useful for deciding whether to notify the user.

AI agent notes

Use this (not reconnectUnipileAccount) when:
  • The user tells you they just added Sales Navigator / Premium — we just need to re-read the flags, not re-auth.
  • You want to pick up new weekly limits before launching a LinkedIn campaign.
Use reconnectUnipileAccount instead when:
  • The account is in disconnected or credentials_required — refresh cannot restore broken cookies.
  • changed.has_sales_navigator comes back false but the user insists the upgrade happened — Unipile may need a fresh cookie capture.
Chains with: searchUnipile (Sales Navigator flag determines which search API is used), any LinkedIn campaign launch.Idempotent. Safe to call repeatedly — both Unipile-side reads and DB writes are trivial. Still, don’t poll this endpoint; Unipile account state changes are infrequent.

Authorizations

Authorization
string
header
required

Bearer authentication header of the form Bearer <token>, where <token> is your auth token.

Body

application/json
accountId
string<uuid>
required

Supabase UUID of the unipile_accounts row. Must be owned by the authenticated user.

Pattern: ^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$

Response

Account refreshed. Response reflects the post-refresh state of the row.

success
enum<boolean>
required
Available options:
true
is_premium
boolean
required

True if the LinkedIn account has any premium feature or a premiumId.

has_sales_navigator
boolean
required

True if the account has the sales_navigator premium feature.

weekly_connection_limit
integer
required

Weekly connection-request cap after refresh. Premium accounts get 100, free get 80.

Required range: 0 < x <= 9007199254740991
weekly_message_limit
integer
required

Weekly message cap after refresh. Premium accounts get 150, free get 100.

Required range: 0 < x <= 9007199254740991
changed
object
required

Per-field diff versus the previously stored row. Both false means nothing changed.