Authentication
Every API request requires an API key. This page explains how to create keys, how scopes work, and how to keep your keys secure.
Creating an API key
- Go to the API Guide page in the dashboard
- Make sure the Public API is enabled (toggle in Stream Settings)
- Click Create Key
- Give it a label (e.g. "Website integration", "Podcast sync")
- Select the scopes you need
- Optionally set an expiry date
- Copy the key immediately — it's only shown once
The full API key is only displayed once at creation time. If you lose it, you'll need to revoke the key and create a new one.
Using your API key
Include your API key in the X-API-Key header with every request:
curl -H "X-API-Key: apk_your-key-here" \
https://api.autopod.xyz/v1/station
Examples in different languages
JavaScript (fetch)
const response = await fetch('https://api.autopod.xyz/v1/episodes', {
headers: {
'X-API-Key': 'apk_your-key-here'
}
});
const data = await response.json();
Python (requests)
import requests
response = requests.get(
'https://api.autopod.xyz/v1/episodes',
headers={'X-API-Key': 'apk_your-key-here'}
)
data = response.json()
PHP (cURL)
$ch = curl_init('https://api.autopod.xyz/v1/episodes');
curl_setopt($ch, CURLOPT_HTTPHEADER, ['X-API-Key: apk_your-key-here']);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = json_decode(curl_exec($ch));
Scopes
Each API key has a set of scopes that control exactly which endpoints it can access. This lets you create keys with only the permissions they need — for example, a key for your website only needs read scopes, while a key for your podcast publishing tool needs write access to episodes.
Available scopes
| Scope | Access | Endpoints |
|---|---|---|
station:read | Read | GET /v1/station |
episodes:read | Read | GET /v1/episodes, GET /v1/episodes/{id} |
episodes:write | Write | POST /v1/episodes, POST /v1/episodes/upload, PUT /v1/episodes/{id}, DELETE /v1/episodes/{id} |
episodes:generate | Write | POST /v1/episodes/generate |
shows:read | Read | GET /v1/shows, GET /v1/shows/{id} |
shows:write | Write | POST /v1/shows, PUT /v1/shows/{id}, DELETE /v1/shows/{id} |
schedule:read | Read | GET /v1/schedule |
schedule:write | Write | PUT /v1/schedule, DELETE /v1/schedule |
now_playing:read | Read | GET /v1/now-playing |
search:read | Read | GET /v1/search |
Scope presets
When creating a key, the dashboard offers two quick presets:
- All Read — all six read scopes (station, episodes, shows, schedule, now playing, search)
- All Read + Write — all ten scopes including write and generate
You can also select individual scopes for fine-grained control.
How scopes are checked
Every endpoint requires a specific scope. If your key doesn't have the required scope, the request returns 403 Forbidden:
{
"message": "This API key does not have the 'episodes:read' scope."
}
Write scopes are additive — having episodes:write lets you create and modify episodes, but you also need episodes:read if you want to list or fetch them.
Multiple keys per stream
You can create up to 10 API keys per stream. This lets you use separate keys for different integrations:
| Key | Scopes | Use case |
|---|---|---|
| Website key | All read scopes | Display episodes and schedule on your site |
| Podcast sync | episodes:read, episodes:write | Automated episode publishing |
| Schedule bot | schedule:read, schedule:write | External scheduling tool |
| Analytics | episodes:read, shows:read | Reporting dashboard |
Each key has its own label, scopes, and optional expiry date. You can revoke any key without affecting the others.
Key expiry
Keys can optionally have an expiry date. After the expiry date, the key stops working and requests return 403 Forbidden. Expired keys are still visible in the dashboard (highlighted in red) and can be revoked to clean them up.
Keys without an expiry date never expire — revoke them manually when they're no longer needed.
Master kill switch
The Enable Public API toggle in Stream Settings acts as a master switch. When it's off, all API keys for that stream are disabled, regardless of their individual scopes or expiry. Turn it back on and they resume working.
Authentication errors
Missing API key
If you don't include the X-API-Key header:
HTTP 401 Unauthorized
{
"message": "Missing X-API-Key header"
}
Invalid or expired API key
If the key doesn't exist, has been revoked, or has expired:
HTTP 403 Forbidden
{
"message": "Invalid or disabled API key"
}
Missing scope
If the key is valid but doesn't have the required scope for the endpoint:
HTTP 403 Forbidden
{
"message": "This API key does not have the 'schedule:read' scope."
}
Security best practices
- Use the narrowest scopes possible. A key that only needs to read episodes shouldn't have write access to shows.
- Don't expose keys in client-side code. If you're building a website, make API calls from your server, not from the browser.
- Set expiry dates for temporary integrations. If a key is only needed for a one-off import, set it to expire after a few days.
- Revoke unused keys. If an integration is decommissioned, revoke its key from the API Guide page.
- Use separate keys for separate systems. If one key is compromised, you can revoke it without disrupting other integrations.
- Use HTTPS. Always use
https://api.autopod.xyz— the API rejects plain HTTP connections.
Idempotency (for write operations)
When creating resources, you can include an X-Idempotency-Key header to prevent duplicate operations. If a request with the same idempotency key is received within 24 hours, the API returns the original response instead of creating a duplicate.
curl -X POST \
-H "X-API-Key: apk_your-key-here" \
-H "X-Idempotency-Key: unique-request-id-123" \
-H "Content-Type: application/json" \
-d '{"title": "My Episode", "show_id": 15, "audio_url": "https://example.com/audio.mp3"}' \
https://api.autopod.xyz/v1/episodes
This is useful when retrying failed requests — if the first request actually succeeded but you didn't get the response (e.g., network timeout), the retry returns the same result without creating a duplicate episode.
Idempotency keys are scoped per stream and expire after 24 hours.