Joyful Docs

API

Build integrations and automate workflows. Pro feature.

Getting started

The Joyful API lets you manage publications, newsletters, subscribers, and more programmatically.

  1. Go to Settings → API Keys
  2. Click Create API Key and give it a name
  3. 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

MethodEndpointDescription
GET/api/publicationsList all publications
POST/api/publicationsCreate a publication
GET/api/publications/:idGet a publication
PUT/api/publications/:idUpdate a publication
DELETE/api/publications/:idDelete a publication

Newsletters

MethodEndpointDescription
GET/api/newslettersList all newsletters
POST/api/newslettersCreate a newsletter
GET/api/newsletters/:idGet a newsletter
PUT/api/newsletters/:idUpdate a newsletter
DELETE/api/newsletters/:idDelete a newsletter

Subscribers

MethodEndpointDescription
GET/api/subscribersList all subscribers
POST/api/subscribersAdd a subscriber
GET/api/subscribers/:idGet a subscriber
PUT/api/subscribers/:idUpdate a subscriber
DELETE/api/subscribers/:idRemove a subscriber

Templates

MethodEndpointDescription
GET/api/templatesList all templates
POST/api/templatesCreate a template
GET/api/templates/:idGet a template
DELETE/api/templates/:idDelete a template

Stats

MethodEndpointDescription
GET/api/statsOverall statistics
GET/api/stats/:newsletterIdStats 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"
}