Quick Start
From an API key to a connected LinkedIn account, a first read, a first webhook and a first write tried without sending it.
This page takes you from an API key to a connected LinkedIn account, a first read, a first webhook and a first write tried without sending it. Every example uses shell variables: replace them with your own values.
1. Set Your Key#
Direct authenticates every API call with the X-API-KEY header. See Authentication And Accounts for how to get a key.
export DIRECT_API_KEY="your-api-key"
export DIRECT="https://direct.lempile.com/api/v1"Check it:
curl -sS "$DIRECT/accounts" -H "X-API-KEY: $DIRECT_API_KEY"{
"object": "AccountList",
"items": [],
"cursor": null,
"total_count": 0,
"status_counts": { "OK": 0, "CONNECTING": 0, "CREDENTIALS": 0, "STOPPED": 0, "ERROR": 0 }
}The list holds your workspace's accounts only. A missing, wrong or revoked key answers 401 with "type": "errors/missing_credentials".
2. Connect A LinkedIn Account#
Ask for a hosted auth link, then send the person who owns the LinkedIn account to its url. They sign in to LinkedIn on Lempile's page, in a real browser (security checks and codes included), and come back to your success_redirect_url.
curl -sS -X POST "$DIRECT/hosted/accounts/link" \
-H "X-API-KEY: $DIRECT_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"type": "create",
"api_url": "https://direct.lempile.com",
"providers": ["LINKEDIN"],
"expiresOn": "2026-11-01T12:00:00.000Z",
"name": "user_42",
"success_redirect_url": "https://app.example.com/linkedin/connected",
"failure_redirect_url": "https://app.example.com/linkedin/failed",
"notify_url": "https://app.example.com/hooks/direct-connected?secret=your-own-secret"
}'{
"object": "HostedAuthUrl",
"url": "https://direct.lempile.com/connect/<token>"
}When the account works, Direct POSTs your notify_url:
{ "status": "CREATION_SUCCESS", "account_id": "<account_id>", "name": "user_42" }Keep account_id: every other call names it.
export ACCOUNT_ID="<account_id>"
curl -sS "$DIRECT/accounts/$ACCOUNT_ID" -H "X-API-KEY: $DIRECT_API_KEY"The account is ready when sources[0].status is OK.
3. First Read#
curl -sS "$DIRECT/users/me?account_id=$ACCOUNT_ID" \
-H "X-API-KEY: $DIRECT_API_KEY"{
"object": "AccountOwnerProfile",
"provider": "LINKEDIN",
"provider_id": "ACoAAAbcdefghijklmnop",
"first_name": "Ada",
"last_name": "Sender",
"public_identifier": "ada-sender",
"public_profile_url": "https://www.linkedin.com/in/ada-sender/",
"premium": true
}(Shortened.) Then the inbox:
curl -sS "$DIRECT/chats?account_id=$ACCOUNT_ID&limit=20" \
-H "X-API-KEY: $DIRECT_API_KEY"4. First Webhook#
Register a URL for new messages. Put your own secret in a header: Direct sends it with every delivery, and you check it.
curl -sS -X POST "$DIRECT/webhooks" \
-H "X-API-KEY: $DIRECT_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"request_url": "https://app.example.com/hooks/linkedin-messages",
"source": "messaging",
"name": "messages",
"headers": [{ "key": "x-webhook-secret", "value": "your-own-secret" }]
}'{ "object": "WebhookCreated", "webhook_id": "<webhook_id>" }Send the account a LinkedIn message from another account. Within seconds, your URL receives a message_received event. Answer any 2xx. See Webhooks for the payload and the timing.
5. First Write, Not Sent#
Every write takes ?dry_run=true: Direct answers the exact LinkedIn call it would make, and sends nothing.
export CHAT_ID="<a chat id from GET /chats>"
curl -sS -X POST "$DIRECT/chats/$CHAT_ID/messages?dry_run=true" \
-H "X-API-KEY: $DIRECT_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "account_id": "'"$ACCOUNT_ID"'", "text": "Thanks, Tuesday works for me." }'{
"object": "DryRun",
"route": "chats.message",
"method": "POST",
"path": "/voyager/api/voyagerMessagingDashMessengerMessages?action=createMessage",
"body": { "message": { "body": { "attributes": [], "text": "Thanks, Tuesday works for me." } } },
"status": 201
}(Shortened.) To send it for real, drop dry_run and add an Idempotency-Key header, so a retry never sends it twice:
curl -sS -X POST "$DIRECT/chats/$CHAT_ID/messages" \
-H "X-API-KEY: $DIRECT_API_KEY" \
-H "Idempotency-Key: reply-42" \
-H "Content-Type: application/json" \
-d '{ "account_id": "'"$ACCOUNT_ID"'", "text": "Thanks, Tuesday works for me." }'{ "object": "MessageSent", "message_id": "<message_id>", "id": "<message_id>" }An account whose writes aren't on yet answers 403 with title Writes off (errors/insufficient_permissions). Dry runs work either way.
Next#
- Errors And Limits: what each error means and how to retry.
- Chats And Messages: files, InMail, ids.
- Migrating From Unipile: moving an existing Unipile integration.
Was this page helpful?