API
Build integrations and automate workflows. Pro feature.
Getting started
The Joyful API lets you manage publications, newsletters, subscribers, and more programmatically.
- Go to Settings → API Keys
- Click Create API Key and give it a name
- Copy the key immediately — you won't see it again
Authentication
All requests require a Bearer token in the Authorization header:
curl -H "Authorization: Bearer jf_your_api_key" \
https://joyful.to/api/publications API keys start with jf_ and provide full access to your account.
Keep your keys secure. Don't expose them in client-side code or public repositories.
Rate limits
Each API key is limited to 1,000 requests per hour. Rate limit info is included in response headers:
X-RateLimit-Limit: 1000
X-RateLimit-Remaining: 999
X-RateLimit-Reset: 1702425600 If you exceed the limit, you'll get a 429 Too Many Requests response.
Endpoints
Publications
| Method | Endpoint | Description |
|---|---|---|
GET | /api/publications | List all publications |
POST | /api/publications | Create a publication |
GET | /api/publications/:id | Get a publication |
PUT | /api/publications/:id | Update a publication |
DELETE | /api/publications/:id | Delete a publication |
Newsletters
| Method | Endpoint | Description |
|---|---|---|
GET | /api/newsletters | List all newsletters |
POST | /api/newsletters | Create a newsletter |
GET | /api/newsletters/:id | Get a newsletter |
PUT | /api/newsletters/:id | Update a newsletter |
DELETE | /api/newsletters/:id | Delete a newsletter |
Subscribers
| Method | Endpoint | Description |
|---|---|---|
GET | /api/subscribers | List all subscribers |
POST | /api/subscribers | Add a subscriber |
GET | /api/subscribers/:id | Get a subscriber |
PUT | /api/subscribers/:id | Update a subscriber |
DELETE | /api/subscribers/:id | Remove a subscriber |
Templates
| Method | Endpoint | Description |
|---|---|---|
GET | /api/templates | List all templates |
POST | /api/templates | Create a template |
GET | /api/templates/:id | Get a template |
DELETE | /api/templates/:id | Delete a template |
Stats
| Method | Endpoint | Description |
|---|---|---|
GET | /api/stats | Overall statistics |
GET | /api/stats/:newsletterId | Stats for a newsletter |
Examples
JavaScript
const API_KEY = 'jf_your_api_key';
// List all subscribers
const response = await fetch('https://joyful.to/api/subscribers', {
headers: {
'Authorization': `Bearer ${API_KEY}`
}
});
const data = await response.json();
console.log(data.subscribers);
// Add a subscriber
const newSubscriber = await fetch('https://joyful.to/api/subscribers', {
method: 'POST',
headers: {
'Authorization': `Bearer ${API_KEY}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
email: 'reader@example.com',
firstName: 'Jane',
publicationId: 'pub_abc123'
})
}); Python
import requests
API_KEY = 'jf_your_api_key'
BASE_URL = 'https://joyful.to/api'
headers = {
'Authorization': f'Bearer {API_KEY}',
'Content-Type': 'application/json'
}
# List all subscribers
response = requests.get(f'{BASE_URL}/subscribers', headers=headers)
subscribers = response.json()['subscribers']
# Add a subscriber
new_subscriber = requests.post(
f'{BASE_URL}/subscribers',
headers=headers,
json={
'email': 'reader@example.com',
'firstName': 'Jane',
'publicationId': 'pub_abc123'
}
) Responses
All responses are JSON. Success responses contain the requested data:
{
"publications": [
{
"id": "pub_abc123",
"name": "My Newsletter",
"slug": "my-newsletter"
}
]
} Errors include a message:
{
"error": "Rate limit exceeded"
}