Authentication
All /v1/* endpoints require a Bearer API key.
API Keys
API keys use the plabs_ prefix and are passed in the Authorization header:
bash
curl https://persona-labsvoice-api-production.up.railway.app/v1/agents \
-H "Authorization: Bearer plabs_your_key_here"Creating Keys
bash
curl -X POST https://persona-labsvoice-api-production.up.railway.app/v1/keys \
-H "Authorization: Bearer $PH0NY_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Production Key",
"expiresInDays": 90
}'WARNING
The raw key is only returned once at creation time. Store it securely.
Listing Keys
bash
curl https://persona-labsvoice-api-production.up.railway.app/v1/keys \
-H "Authorization: Bearer $PH0NY_API_KEY"Rotating Keys
bash
curl -X POST https://persona-labsvoice-api-production.up.railway.app/v1/keys/key_id/rotate \
-H "Authorization: Bearer $PH0NY_API_KEY"Returns a new key and revokes the old one.
Revoking Keys
bash
curl -X DELETE https://persona-labsvoice-api-production.up.railway.app/v1/keys/key_id \
-H "Authorization: Bearer $PH0NY_API_KEY"BYOK (Bring Your Own Key)
Pass provider API keys as headers to use your own accounts directly. BYOK requests bypass platform credit metering.
| Header | Provider |
|---|---|
X-Provider-Key-ElevenLabs | ElevenLabs (TTS/STT) |
X-Provider-Key-OpenAI | OpenAI (LLM) |
X-Provider-Key-Anthropic | Anthropic (LLM) |
X-Provider-Key-Cartesia | Cartesia (TTS/STT) |
X-Provider-Key-Deepgram | Deepgram (STT) |
X-Provider-Key-FishAudio | Fish Audio (TTS) |
X-Provider-Key-Inworld | Inworld (TTS) |
X-Provider-Key-ResembleAI | Resemble AI (TTS) |
X-Provider-Key-Groq | Groq (LLM/STT) |
X-Provider-Key-HuggingFace | Hugging Face (TTS) |
Example:
bash
curl -X POST https://persona-labsvoice-api-production.up.railway.app/v1/synthesize \
-H "Authorization: Bearer $PH0NY_API_KEY" \
-H "X-Provider-Key-ElevenLabs: sk_your_elevenlabs_key" \
-H "Content-Type: application/json" \
-d '{"text": "Hello", "provider": "elevenlabs", "voiceId": "your_voice"}'Stored Provider Keys
You can also store provider keys server-side so they are used automatically:
bash
# Store a key
curl -X POST https://persona-labsvoice-api-production.up.railway.app/v1/provider-keys \
-H "Authorization: Bearer $PH0NY_API_KEY" \
-H "Content-Type: application/json" \
-d '{"provider": "elevenlabs", "apiKey": "sk_..."}'
# List stored keys
curl https://persona-labsvoice-api-production.up.railway.app/v1/provider-keys \
-H "Authorization: Bearer $PH0NY_API_KEY"
# Verify a key works
curl -X POST https://persona-labsvoice-api-production.up.railway.app/v1/provider-keys/elevenlabs/verify \
-H "Authorization: Bearer $PH0NY_API_KEY"
# Delete a stored key
curl -X DELETE https://persona-labsvoice-api-production.up.railway.app/v1/provider-keys/elevenlabs \
-H "Authorization: Bearer $PH0NY_API_KEY"Response Headers
Every authenticated response includes usage information:
| Header | Description |
|---|---|
X-Request-Id | Unique request identifier for debugging |
X-Usage-Current | Credits used this billing period |
X-Usage-Limit | Credit limit for your tier |
X-Usage-Remaining | Credits remaining |
X-Usage-Bypassed | true if BYOK key was used (no credits deducted) |
X-Provider-Used | Which provider handled the request |
Rate Limits
Per-key rate limiting is applied to all /v1/* routes. When you hit the limit:
429 Too Many RequestsresponseX-RateLimit-Limit— requests allowed per windowX-RateLimit-Remaining— requests left in current windowRetry-After— seconds until the window resets
Portal Authentication
The Developer Portal (/portal/*) uses session-based authentication via Better Auth (phone OTP). Portal routes are not accessible with API keys.