LeadPanther API LLM Guide
Status: initial public guide for current API v1 behavior. Last updated: 2026-05-25.
Purpose
This guide is for LLMs, agents, and code-generation tools that help users call the LeadPanther API. Follow these rules exactly. Do not infer endpoints, hosts, scopes, or account behavior from common SaaS API patterns.
Non-Negotiable Rules
- Use only this current API v1 base URL:
https://app.leadpanther.ai/api/v1
- Do not use this host as the app API base URL:
https://api.leadpanther.ai/v1
-
Do not guess endpoint names. Use only documented paths under
https://app.leadpanther.ai/api/v1. -
If the user says they are posting for a client, use:
/clients/{clientId}/posts
Do not use /posts for agency-client work.
- If the user says they are managing lead magnets for a client, use:
/clients/{clientId}/lead-magnets
Do not use /lead-magnets for agency-client work.
- If the user says they are reading leads or activity for a client, use:
/clients/{clientId}/leads
/clients/{clientId}/activity
Do not use direct /leads or /activity routes for agency-client work.
- If a call returns
403, check both:
- the API key scope
- the agency-client grant
-
Do not use Supabase REST, Supabase storage URLs, service-role keys, key hashes, internal database IDs, or private operational docs unless the user explicitly asks for internal implementation work and has authorization.
-
Never place API keys in browser code, frontend bundles, mobile apps, public repositories, generated docs, screenshots, or logs.
-
Treat
leads:readandactivity:readas sensitive scopes. They can expose personal data, message/comment content, LinkedIn profile URLs, platform identifiers, and intent metadata.
Current API Surface
Use only these current API v1 routes.
| Task | Direct-user path | Agency-client path | Scope |
|---|---|---|---|
| API metadata | GET /api/v1 | n/a | none |
| Current API subject | GET /api/v1/me | n/a | valid API key |
| List clients | GET /api/v1/clients | n/a | clients:read |
| Get client | GET /api/v1/clients/{clientId} | n/a | clients:read |
| List posts | GET /api/v1/posts | GET /api/v1/clients/{clientId}/posts | posts:read |
| Create post | POST /api/v1/posts | POST /api/v1/clients/{clientId}/posts | posts:write |
| Get post | GET /api/v1/posts/{id} | GET /api/v1/clients/{clientId}/posts/{id} | posts:read |
| Update post | PATCH /api/v1/posts/{id} | PATCH /api/v1/clients/{clientId}/posts/{id} | posts:write |
| Delete post | DELETE /api/v1/posts/{id} | DELETE /api/v1/clients/{clientId}/posts/{id} | posts:write |
| Get post engagement | GET /api/v1/posts/{id}/engagement | GET /api/v1/clients/{clientId}/posts/{id}/engagement | analytics:read |
| List lead magnets | GET /api/v1/lead-magnets | GET /api/v1/clients/{clientId}/lead-magnets | lead_magnets:read |
| Create lead magnet | POST /api/v1/lead-magnets | POST /api/v1/clients/{clientId}/lead-magnets | lead_magnets:write |
| Get lead magnet | GET /api/v1/lead-magnets/{id} | GET /api/v1/clients/{clientId}/lead-magnets/{id} | lead_magnets:read |
| Update lead magnet | PATCH /api/v1/lead-magnets/{id} | PATCH /api/v1/clients/{clientId}/lead-magnets/{id} | lead_magnets:write |
| Archive lead magnet | DELETE /api/v1/lead-magnets/{id} | DELETE /api/v1/clients/{clientId}/lead-magnets/{id} | lead_magnets:write |
| Lead magnet analytics | GET /api/v1/lead-magnets/{id}/analytics | GET /api/v1/clients/{clientId}/lead-magnets/{id}/analytics | analytics:read |
| Create media upload URL | POST /api/v1/media/upload-url | POST /api/v1/clients/{clientId}/media/upload-url | media:write |
| Delete media | DELETE /api/v1/media | DELETE /api/v1/clients/{clientId}/media | media:write |
| List leads | GET /api/v1/leads | GET /api/v1/clients/{clientId}/leads | leads:read |
| List activity | GET /api/v1/activity | GET /api/v1/clients/{clientId}/activity | activity:read |
When constructing a URL from the table, do not duplicate /api/v1. For example:
https://app.leadpanther.ai/api/v1/me
https://app.leadpanther.ai/api/v1/clients/00000000-0000-4000-8000-000000000001/posts
Unsupported Guessed Routes
Do not generate calls to these routes unless future docs explicitly add them:
/accounts
/users
/lists
/campaigns
/organizations
/team
/workspaces
/lead-magnet-posts
/webhooks
Unsupported guessed endpoints may return 404, method_not_allowed, or other invalid path behavior.
Account Model
Direct-user routes operate on the API key owner's account.
Agency-client routes operate on a target client account and require an active agency-client grant:
/api/v1/clients/{clientId}/...
The public clientId currently refers to the client account user_id returned by GET /clients. Do not expose or request private implementation identifiers such as account table IDs, API key IDs, privileged backend data, key hashes, or production database IDs.
Use placeholder IDs in examples:
00000000-0000-4000-8000-000000000001
00000000-0000-4000-8000-000000000002
00000000-0000-4000-8000-000000000003
Authentication Pattern
Use a server-side bearer token:
curl -sS \
-H "Authorization: Bearer $LEADPANTHER_API_KEY" \
"https://app.leadpanther.ai/api/v1/me"
Use environment variables in generated code:
LEADPANTHER_API_KEY=lp_live_REDACTED
Do not hard-code a key. Do not invent a key. Do not ask users to paste real keys into prompts.
Request ID Pattern
For troubleshooting examples, include X-Request-Id:
curl -sS \
-H "Authorization: Bearer $LEADPANTHER_API_KEY" \
-H "X-Request-Id: req_example_001" \
"https://app.leadpanther.ai/api/v1/me"
Tell users to provide the response request_id to LeadPanther support when reporting an API issue.
Response Envelopes
Success responses use:
{
"data": {},
"request_id": "req_000000000000000000000000"
}
List responses use:
{
"data": [],
"pagination": {
"limit": 50,
"offset": 0,
"has_more": false
},
"request_id": "req_000000000000000000000000"
}
Error responses use:
{
"error": {
"code": "bad_request",
"message": "Invalid payload."
},
"request_id": "req_000000000000000000000000"
}
Do not assume field-level validation details are available. Current validation errors may be general.
Pagination Rules
All list endpoints use limit and offset unless a specific endpoint documents otherwise. Default limit is generally 50; maximum is generally 100.
Good:
GET /api/v1/leads?limit=50&offset=0
Bad:
GET /api/v1/leads?page=1&page_size=50
Do not invent cursor pagination.
Privacy and Redaction Rules
Use anonymized values in all generated examples:
Client AExample Agency00000000-0000-4000-8000-00000000000100000000-0000-4000-8000-00000000000200000000-0000-4000-8000-000000000003person@example.comREDACTED_MESSAGE_CONTENTREDACTED_PLATFORM_MESSAGE_IDREDACTED_SIGNED_UPLOAD_URLREDACTED_UPLOAD_TOKEN
Never include:
- real customer names
- real customer emails
- real API keys
- real production UUIDs
- real lead message text
- real LinkedIn message IDs, chat IDs, or comment IDs
- service-role keys
- key hashes
- Supabase REST examples for public API use
leads:read can return personal data. activity:read can return message/comment content and platform identifiers. Public examples are redacted and do not represent the full sensitivity of production data.
Safe Example: Direct User Lists Posts
curl -sS \
-H "Authorization: Bearer $LEADPANTHER_API_KEY" \
"https://app.leadpanther.ai/api/v1/posts?limit=10&offset=0"
Required scope: posts:read.
Safe Example: Agency Lists Client Posts
curl -sS \
-H "Authorization: Bearer $LEADPANTHER_API_KEY" \
"https://app.leadpanther.ai/api/v1/clients/00000000-0000-4000-8000-000000000001/posts?limit=10&offset=0"
Required scope: posts:read.
Also required: active agency-client grant for 00000000-0000-4000-8000-000000000001.
Safe Example: Agency Creates Client Post
curl -sS \
-X POST \
-H "Authorization: Bearer $LEADPANTHER_API_KEY" \
-H "Content-Type: application/json" \
"https://app.leadpanther.ai/api/v1/clients/00000000-0000-4000-8000-000000000001/posts" \
-d '{
"text": "Public-safe LinkedIn post copy.",
"status": "draft",
"scheduled_at": null,
"theme_id": null,
"template_id": null,
"images": [],
"document_url": null,
"notes": "Example internal note."
}'
Required scope: posts:write.
Safe Example: List Leads With Privacy Warning
curl -sS \
-H "Authorization: Bearer $LEADPANTHER_API_KEY" \
"https://app.leadpanther.ai/api/v1/clients/00000000-0000-4000-8000-000000000001/leads?limit=50&offset=0"
Required scope: leads:read.
Warn the user that this response can contain personal data, including names, LinkedIn profile URLs, submitted emails, work emails, personal emails, sources, intent signals, qualification status, and timestamps.
Safe Example: List Activity With Privacy Warning
curl -sS \
-H "Authorization: Bearer $LEADPANTHER_API_KEY" \
"https://app.leadpanther.ai/api/v1/clients/00000000-0000-4000-8000-000000000001/activity?limit=50&offset=0"
Required scope: activity:read.
Warn the user that this response can contain message/comment content, author information, LinkedIn profile URLs, source metadata, message IDs, chat IDs, comment IDs, and intent metadata.
Current vs Planned Boundaries
Current:
- API v1 base URL is
https://app.leadpanther.ai/api/v1. - API keys are provisioned privately for now.
- API keys are bearer tokens and must stay server-side.
- Current list pagination is
limitandoffset. - Agency client work uses
/clients/{clientId}/.... /lead-magnet-postsis not currently implemented.
Planned or not currently guaranteed:
- Published rate limits are not yet a public contract.
- Idempotency keys are planned, not currently guaranteed.
- Webhook endpoints are planned, not currently available.
- SDKs are planned or future, not currently available.
webhooks:writemay appear as a scope, but no public v1 webhook route is currently implemented.- OpenAPI and generated SDK contracts may be added later, but do not invent them now.
Troubleshooting Decision Tree
For 401 unauthorized:
- Check the bearer token header.
- Check that the key is active.
- Keep the key server-side.
For 403 forbidden:
- Check the endpoint's required scope.
- If agency-client work is involved, check the active agency-client grant.
- Confirm the route is nested under
/clients/{clientId}/....
For 404 not_found:
- Check the base URL.
- Check the path against the documented endpoint list.
- Do not switch to guessed routes.
- For agency work, verify the client ID through an authorized workflow.
For 400 bad_request:
- Check JSON syntax.
- Check required fields.
- Check query parameters.
- Check current payload rules for posts, lead magnets, media, leads, or activity.
For 409 conflict:
- Check resource state. Published or publishing posts have update and delete restrictions.
For 500 internal_error:
- Retry later if appropriate.
- Capture the response
request_id. - Do not expose sensitive request or response data when reporting the issue.