Credentials
Credentials in Scheduler0 provide secure authentication for API access. They consist of API keys and secrets that allow applications and users to authenticate with the Scheduler0 API and manage their scheduled jobs.
Overview
Credentials are essential for accessing the Scheduler0 API. They provide secure authentication mechanisms that ensure only authorized users and applications can create, modify, or delete jobs, projects, and executors.
After sign up a default credential is created in your account. There should be at least one credential for your account.
Authentication Methods
Scheduler0 supports two authentication methods:
-
API Key + Secret Authentication (Default for managed service)
- Used for all standard API operations
- Requires
X-API-KeyandX-Secret-Keyheaders - Most endpoints also require
X-Account-IDheader
-
Basic Authentication (Self-hosting only)
- Only available for users self-hosting Scheduler0
- Used for system-level operations (accounts, features, async tasks management)
- Requires username and password from Scheduler0 configuration
- Requires
X-Peerheader with value 'cmd' or 'peer' - Note: This authentication method is not available for managed service users
Credential Structure
Most credential responses (list, get, update) look like this:
{
"id": 1,
"accountId": 123,
"archived": false,
"apiKey": "1234567890abcdef",
"dateCreated": "2024-01-15T10:30:00Z",
"dateModified": null,
"dateDeleted": null,
"createdBy": "user123",
"deletedBy": null,
"expiresAt": "2024-04-14T10:30:00Z",
"scopes": ["read", "write", "execute"]
}
The create response (201) also includes plaintextSecret:
{
"id": 1,
"accountId": 123,
"archived": false,
"apiKey": "1234567890abcdef",
"plaintextSecret": "abc123...",
"dateCreated": "2024-01-15T10:30:00Z",
"expiresAt": "2024-04-14T10:30:00Z",
"scopes": ["read", "write", "execute"]
}
plaintextSecret is returned once only at creation time. The server stores only the AES-GCM encrypted form and cannot return the plaintext again. Save it in your secret manager immediately.
Fields
- id: Unique identifier for the credential
- accountId: ID of the account that owns this credential
- archived: Whether the credential is archived (disabled)
- apiKey: Stable plaintext identifier used in the
X-API-Keyrequest header - plaintextSecret: (create response only) The raw secret you must send as
X-Secret-Keyon every request. Never stored by the server in plaintext. - dateCreated: Timestamp when the credential was created
- dateModified: Timestamp when the credential was last modified
- dateDeleted: Timestamp when the credential was deleted
- createdBy: Identifier of the user who created the credential
- deletedBy: Identifier of the user who deleted the credential
- expiresAt: Server-set expiry timestamp. User credentials expire 90 days after creation; system/seed credentials may have a
nullexpiry. - scopes: Array of scopes (
read,write,execute) gating which routes this credential may call. Always returned by the API and required when creating new credentials.
Expiry
Every user-created credential is server-set to expire 90 days after creation. The expiry is not user-overridable and is returned in the expiresAt field of every credential response.
- Requests authenticated with an expired credential are rejected with
401 credential expired. - A periodic background sweep (running on the Raft leader) auto-archives credentials whose
expiresAthas passed, so you do not have to clean them up manually. - System/bootstrap credentials created during installation have
expiresAt = nulland never expire — they are intended for self-hosting administrative work and should not be used for application traffic.
To detect expiry on the client side, compare expiresAt to the current time and rotate well before the deadline. The CLI exposes a one-shot rotation helper (see Rotating Credentials).
Scopes
Every credential carries a scopes array containing one or more of:
| Scope | Allows |
|---|---|
read | GET on jobs, projects, credentials, executors, executions/*, async-tasks/{id}, features, and account/ai-settings. Also GET /local-executors/{id}/jobs (local executor job pull). |
write | POST/PUT/DELETE on jobs, projects, credentials, executors, and account/ai-settings. Also POST /local-executors (register a local executor). |
execute | POST /prompt, POST /executions/cleanup-old-logs, and POST /local-executors/{id}/executions (batch-report local execution results). |
Healthcheck (GET /healthcheck) is always allowed regardless of scope. Self-hosting endpoints (/accounts/*, /cluster/*, peer handshake) use Basic/peer auth and bypass the scope check entirely.
If a request authenticates successfully but the credential lacks the required scope, the API responds with 403 credential missing required scope: <scope>.
Setting Scopes via the API
Scopes are required when creating a credential. The server rejects empty arrays or unknown values with 400.
curl -X POST "https://api.scheduler0.com/v1/credentials" \
-H "Content-Type: application/json" \
-H "X-API-Key: YOUR_API_KEY" \
-H "X-Secret-Key: YOUR_API_SECRET" \
-H "X-Account-ID: YOUR_ACCOUNT_ID" \
-d '{
"createdBy": "user123",
"scopes": ["read", "write"]
}'
Setting Scopes via the Web UI
When you click Create New Credential in the Scheduler0 dashboard, the slide-over panel exposes three checkboxes (Read, Write, Execute) — all selected by default. Uncheck the ones the credential should not have. The dashboard also shows the 90-day rotation policy inline so you can plan rotations before submitting.
Creating Credentials
Through the Web Interface
- Navigate to the Credentials section in your Scheduler0 dashboard
- Click "Create New Credential"
- Choose the scopes (Read / Write / Execute) the credential should carry
- Submit the form — the server creates the credential with a 90-day
expiresAt - A one-time banner appears with the
apiKeyandplaintextSecret. Copy both values to your secret manager before dismissing the banner — the secret cannot be retrieved again.
Using Credentials
Scheduler0 uses X-API-Key and X-Secret-Key headers for authentication. Include both headers in your API requests:
curl -X GET "https://api.scheduler0.com/v1/projects" \
-H "X-API-Key: your_api_key" \
-H "X-Secret-Key: your_secret_key"
Scheduler0 uses X-API-Key and X-Secret-Key headers for authentication. Include both headers in your API requests:
curl -X GET "https://api.scheduler0.com/v1/projects" \
-H "X-API-Key: your_api_key" \
-H "X-Secret-Key: your_secret_key"
package main
import (
"fmt"
"github.com/scheduler0/scheduler0-go-client"
)
func main() {
client, err := scheduler0_go_client.NewClient(
"https://api.scheduler0.com",
"v1",
scheduler0_go_client.WithAPIKey("your_api_key"),
scheduler0_go_client.WithAPISecret("your_secret_key"),
scheduler0_go_client.WithAccountID("your_account_id"),
)
if err != nil {
panic(err)
}
// Use the client to make API calls
projects, err := client.ListProjects(10, 0, "date_created", "desc")
if err != nil {
panic(err)
}
fmt.Printf("Found %d projects\n", len(projects.Data.Projects))
}
Node.js Client
const Scheduler0Client = require('@scheduler0/node-client');
const client = new Scheduler0Client({
apiKey: 'your_api_key',
apiSecret: 'your_saved_plaintext_secret', // the plaintextSecret from credential creation
baseURL: 'https://api.scheduler0.com/v1'
});
// Use the client
client.projects.list()
.then(projects => {
console.log(`Found ${projects.data.projects.length} projects`);
})
.catch(error => {
console.error('Error:', error);
});
Managing Credentials
Rotating Credentials (Expiry)
Because every credential carries a fixed 90-day expiresAt, you must replace them before they expire to avoid service interruption. Create a new credential with the same scopes, roll out the new key/secret to your clients, then archive the old one:
# 1. Create a replacement credential — save the returned apiKey and plaintextSecret immediately
scheduler0 credentials create --created-by "user123" --scopes "read,write,execute"
# 2. Update your clients with the new apiKey and plaintextSecret.
# Use apiKey as X-API-Key and plaintextSecret as X-Secret-Key in every request.
# 3. Archive the old credential
scheduler0 credentials archive <old-credential-id> --archived-by "user123"
Or via the API:
# Create a new credential
curl -X POST "https://api.scheduler0.com/v1/credentials" \
-H "X-API-Key: YOUR_API_KEY" \
-H "X-Secret-Key: YOUR_API_SECRET" \
-H "X-Account-ID: YOUR_ACCOUNT_ID" \
-d '{"createdBy":"user123","scopes":["read","write","execute"]}'
# Archive the old one
curl -X POST "https://api.scheduler0.com/v1/credentials/{id}/archive" \
-H "X-API-Key: YOUR_API_KEY" \
-H "X-Secret-Key: YOUR_API_SECRET" \
-H "X-Account-ID: YOUR_ACCOUNT_ID" \
-d '{"archivedBy":"user123"}'
The new credential's plaintextSecret is returned once at creation time and is never stored. Save it in your secret manager immediately.
Rotating the Server's Secret Key (Self-Hosting Only)
If the server's SecretKey (the AES-GCM key used to encrypt stored api_secret values) is compromised and you need to replace it, use the dedicated key-rotation flow:
How it works
api_keyis a stable plaintext identifier. Clients always send it as-is.api_secretis stored AES-GCM encrypted with the currentSecretKey. Clients always send the plaintext secret they received at credential creation time.- Validation decrypts the stored secret before comparing — so re-encrypting all secrets with a new key (rotation) does not break any existing client.
Operator sequence
-
Update
SecretKeyin your secrets source (file / SSM / Secrets Manager / env var), leaving the server running with the old key cached. -
Run the CLI command (requires basic auth —
AuthUsername/AuthPassword):scheduler0 credentials rotate-secretOr call the API endpoint directly:
curl -X POST "https://your-host/api/v1/credentials/rotate-secret" \
-u "YOUR_AUTH_USERNAME:YOUR_AUTH_PASSWORD" \
-H "X-Peer: cmd" -
The server:
- Writes the old key to a savepoint file (
.scheduler0.rotation). - Reloads the new key from the secrets source.
- Re-encrypts all active, non-expired credentials in batches of 100.
- Deletes the savepoint on completion.
- Writes the old key to a savepoint file (
-
The response includes
{"success":true,"data":{"rotated":<count>}}.
Resumability: If the process is interrupted (server restart, network error), re-run the command. The server reads the old key from the savepoint and continues from where it left off.
Secret-key rotation is a self-hosting only operation. It is authenticated via Basic Auth (AuthUsername/AuthPassword) and requires the X-Peer header — the CLI and official SDKs set this automatically when using the basic-auth client.
Archiving Credentials
You can archive credentials to disable them without deleting them:
curl -X POST "https://api.scheduler0.com/v1/credentials/1/archive" \
-H "Content-Type: application/json" \
-H "X-API-Key: YOUR_API_KEY" \
-H "X-Secret-Key: YOUR_API_SECRET" \
-H "X-Account-ID: YOUR_ACCOUNT_ID" \
-d '{
"archivedBy": "user123"
}'
Note: Archived credentials cannot be used for authentication but are retained in the system for audit purposes.
Listing Credentials
Retrieve credentials with pagination and sorting:
curl -X GET "https://api.scheduler0.com/v1/credentials?limit=10&offset=0&orderBy=date_created&orderByDirection=desc" \
-H "X-API-Key: YOUR_API_KEY" \
-H "X-Secret-Key: YOUR_API_SECRET" \
-H "X-Account-ID: YOUR_ACCOUNT_ID"
Query Parameters:
- limit (required): Maximum number of results (1-100, default: 10)
- offset (required): Number of results to skip (default: 0)
- orderBy (optional): Field to sort by (
date_created,date_modified,created_by,modified_by,deleted_by) - orderByDirection (optional): Sort direction (
asc,desc). Default:desc
Troubleshooting
Common Issues
- Invalid Credentials: Double-check API key and secret
- Archived Credentials: Ensure credentials are not archived
401 credential expired: The credential is past its 90-dayexpiresAt. Create a new credential, roll out the new key/secret, then archive the old one (see Rotating Credentials above).403 credential missing required scope: <scope>: The credential lacks the scope required by the requested route. Check the Scopes table above and either retry from a credential that has the right scope or rotate to a new credential with the necessary scopes.- Network Issues: Verify network connectivity and firewall settings
- Rate Limiting: Implement proper rate limiting in your application
API Reference
For complete API documentation, see the Scheduler0 API Reference.