Authentication
Every request to the Schedulala API must include a valid API key. Keys are scoped to your account and control what resources you can access.
API Key Format
Schedulala issues two types of API keys, distinguished by their prefix:
| Type | Prefix | Purpose |
|---|---|---|
| Production | sk_live_ | Publishes to real social media platforms |
| Test / Sandbox | sk_test_ | Simulates the full flow without publishing (see Sandbox Mode) |
A full key looks like sk_live_abc123xyz789... or sk_test_abc123xyz789.... Keys can be generated via the dashboard or entirely from the terminal (see below).
Getting an API Key
There are three ways to get an API key. The device flow is terminal-first — it opens a browser once so you can sign in and approve the code.
Option A: Device Flow (recommended for agents)
The device authorization flow follows the same pattern as the GitHub CLI. Perfect for AI agents and terminal workflows.
# Step 1: Start device authorizationcurl -X POST https://schedulala.com/api/v1/auth/device \-H "Content-Type: application/json" \-d '{"email": "you@example.com"}'# Response:# {# "success": true,# "device_code": "dev_abc123...",# "user_code": "SCHD-7X9K-M3QP",# "verification_url": "https://schedulala.com/developers/verify",# "message": "Check your email or visit the URL and enter code: SCHD-7X9K-M3QP",# "expires_in": 900,# "interval": 5# }# Step 2: Open the verification URL, sign in to your Schedulala# account, and enter the code to approve the device.# Step 3: Poll for your API keycurl -X POST https://schedulala.com/api/v1/auth/device/token \-H "Content-Type: application/json" \-d '{"device_code": "dev_abc123..."}'# Response (after verification):# {# "success": true,# "status": "complete",# "key_id": "...",# "key_prefix": "...",# "plan": "...",# "api_key": "sk_live_...",# "message": "Save this key — it won't be shown again."# }
Option B: Email registration
Provide your email and, if it's a new account, we'll email you a free API key. Existing accounts get sign-in instructions instead — for security, a key is never returned in the response body.
curl -X POST https://schedulala.com/api/v1/auth/register \-H "Content-Type: application/json" \-d '{"email": "you@example.com"}'# New account: check your email for the API key.# Existing account: sign in at schedulala.com or run: schedulala init
Option C: Dashboard
Sign in at schedulala.com and navigate to Settings → Developer API.
Key Management via API
Once you have your first API key, you can manage all keys from the terminal:
# List your API keyscurl https://schedulala.com/api/v1/auth/keys \-H "Authorization: Bearer sk_live_..."# Create a new keycurl -X POST https://schedulala.com/api/v1/auth/keys \-H "Authorization: Bearer sk_live_..." \-H "Content-Type: application/json" \-d '{"name": "CI/CD Key", "permissions": {"posts": true, "analytics": false}}'# Rotate a key (revoke old, create new)curl -X POST https://schedulala.com/api/v1/auth/keys/KEY_ID/rotate \-H "Authorization: Bearer sk_live_..."# Revoke a keycurl -X DELETE https://schedulala.com/api/v1/auth/keys/KEY_ID \-H "Authorization: Bearer sk_live_..."
Making Authenticated Requests
Include your API key in the Authorization header as a Bearer token on every request:
curl https://schedulala.com/api/v1/accounts \-H "Authorization: Bearer sk_live_abc123xyz789..."
How Authentication Works
When your request reaches the API, the authentication middleware performs the following checks in order:
Verify key format
Must start with sk_live_ or sk_test_
Hash and lookup
The key is hashed and matched against stored keys in the database
Check active status
The key must have isActive: true — revoked keys are rejected
Verify expiration
If an expiresAt date is set on the key, it must not have passed
IP whitelist validation
If an IP whitelist is configured, the request's IP must be on the list
Update usage stats
Request count and last-used timestamp are recorded for the key
If any check fails, the API returns a 401 Unauthorized response with an error message describing what went wrong.
API Key Permissions
Each API key is scoped to specific permissions. You can configure these when creating or editing a key in your dashboard.
| Permission | Access |
|---|---|
posts | Create, read, update, and delete posts |
accounts | List and manage connected social accounts |
analytics | Read post and account analytics (premium plans only) |
webhooks | Create and manage webhook endpoints |
Tip: Follow the principle of least privilege. Only grant the permissions your integration actually needs. For example, if your app only reads analytics, don't include the posts permission.
Rate Limits
Each API key has rate limits based on your plan. All paid plans include a 7-day free trial when you subscribe.
| Plan | Requests / Minute | Posts / Month | Connected Accounts |
|---|---|---|---|
| Free | 30 | 4 | 2 |
| Personal ($29/mo) | 120 | Unlimited | 10 |
| Team ($49/mo) | 120 | Unlimited | 25 |
| Agency ($99/mo) | 120 | Unlimited | 100 |
For full details on rate limits, headers, and handling 429 errors, see the Rate Limits page.
Security Best Practices
Warning: Never expose your API keys in client-side code, public repositories, or browser JavaScript. Anyone with your key can make requests on your behalf.
Use environment variables
Store your API key in an environment variable instead of hardcoding it in your source code.
// .envSCHEDULALA_API_KEY=sk_live_abc123xyz789...// your-app.jsconst response = await fetch('https://schedulala.com/api/v1/accounts', {headers: {'Authorization': `Bearer ${process.env.SCHEDULALA_API_KEY}`}});
Rotate keys regularly
Generate new API keys periodically and revoke old ones. You can have multiple active keys at once, which allows you to rotate without downtime — create a new key, update your integration, then revoke the old key.
Use IP whitelisting
If your integration runs from known IP addresses (e.g., a dedicated server), configure an IP whitelist on your API key. Requests from any other IP will be rejected, even with a valid key.
Use test keys for development
Always use sk_test_ keys during development and testing. They use the same API but won't publish real posts. See the Sandbox Mode page for details.