API Reference
ReleaseRay provides a REST API for programmatic access to all features. This guide covers authentication, endpoints, rate limits, and code examples.
Overview
Base URL: https://app.releaseray.com/api
Authentication: API keys or OAuth (coming soon)
Format: JSON
Rate Limits: 100 requests per minute per API key
Authentication
API Keys
🔜 Coming in v2.0.0 (April 2026) - API key management is currently in development. This documentation represents the planned functionality.
Generate an API key from your dashboard:
- Go to Settings → API Keys
- Click "Generate New Key"
- Give it a name (e.g., "CI/CD Pipeline")
- Copy the key (you won't see it again)
Using API Keys
Include your API key in the Authorization header:
curl https://app.releaseray.com/api/drafts \
-H "Authorization: Bearer YOUR_API_KEY"
Key Security
- ✅ Store securely: Use environment variables, never commit to git
- ✅ Rotate regularly: Generate new keys every 6 months
- ✅ Limit scope: Create separate keys for different purposes
- ❌ Never share: Each team member should have their own key
Rate Limits
Limits
- 100 requests per minute per API key
- 1000 requests per hour per API key
- 10,000 requests per day per organization
Headers
Check your rate limit status in response headers:
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 87
X-RateLimit-Reset: 1699021234
Exceeding Limits
If you exceed rate limits, you'll receive:
{
"error": "Rate limit exceeded",
"message": "Limit: 100 requests per minute. Try again in 42 seconds.",
"retryAfter": 42
}
Response code: 429 Too Many Requests
Endpoints
Drafts
List Drafts
Get all drafts for a release range.
GET /api/drafts?releaseRangeId={rangeId}
Query Parameters:
releaseRangeId(required): Release range IDpersona(optional): Filter by persona (engineer,internal,customer)
Response:
{
"drafts": [
{
"id": "draft_abc123",
"releaseRangeId": "range_xyz789",
"persona": "engineer",
"bodyMd": "## Features\n- Added OAuth2 support...",
"flags": {
"highlights": ["OAuth2 PKCE", "Performance improvement"],
"contributors": ["johndoe", "janedoe"]
},
"createdAt": "2025-11-03T14:32:00Z",
"updatedAt": "2025-11-03T14:35:00Z"
}
]
}
Get Draft
Get a specific draft by ID.
GET /api/drafts/{draftId}
Response:
{
"id": "draft_abc123",
"releaseRangeId": "range_xyz789",
"persona": "engineer",
"bodyMd": "## Features\n- Added OAuth2 support...",
"flags": {
"highlights": ["OAuth2 PKCE"],
"upgradeInstructions": "Run `npm install @auth/core@latest`",
"contributors": ["johndoe"]
},
"createdAt": "2025-11-03T14:32:00Z",
"updatedAt": "2025-11-03T14:35:00Z"
}
Generate Draft
Generate a new draft for a release range.
POST /api/drafts/{rangeId}/generate
Content-Type: application/json
{
"persona": "engineer"
}
Body Parameters:
persona(required):engineer,internal, orcustomer
Response:
{
"id": "draft_abc123",
"status": "processing",
"estimatedTime": 30
}
Note: Draft generation is async. Poll the draft endpoint to check status.
Update Draft
Edit a draft (manual changes).
PATCH /api/drafts/{draftId}
Content-Type: application/json
{
"bodyMd": "## Features\n- Added OAuth2 PKCE support (updated)"
}
Response:
{
"id": "draft_abc123",
"bodyMd": "## Features\n- Added OAuth2 PKCE support (updated)",
"updatedAt": "2025-11-03T15:00:00Z"
}
Release Ranges
List Release Ranges
Get all release ranges for a repository.
GET /api/ranges?repoId={repoId}
Query Parameters:
repoId(required): Repository IDlimit(optional): Number of results (default: 20)offset(optional): Pagination offset (default: 0)
Response:
{
"ranges": [
{
"id": "range_xyz789",
"repoId": "repo_123",
"fromTag": "v1.0.0",
"toTag": "v1.1.0",
"compareUrl": "https://github.com/owner/repo/compare/v1.0.0...v1.1.0",
"createdAt": "2025-11-03T10:00:00Z"
}
],
"total": 45,
"hasMore": true
}
Get Release Range
Get a specific release range.
GET /api/ranges/{rangeId}
Response:
{
"id": "range_xyz789",
"repoId": "repo_123",
"fromTag": "v1.0.0",
"toTag": "v1.1.0",
"compareUrl": "https://github.com/owner/repo/compare/v1.0.0...v1.1.0",
"prCount": 23,
"issueCount": 12,
"createdAt": "2025-11-03T10:00:00Z"
}
Create Release Range
Create a new release range.
POST /api/ranges
Content-Type: application/json
{
"repoId": "repo_123",
"fromTag": "v1.1.0",
"toTag": "v1.2.0"
}
Response:
{
"id": "range_xyz789",
"repoId": "repo_123",
"fromTag": "v1.1.0",
"toTag": "v1.2.0",
"compareUrl": "https://github.com/owner/repo/compare/v1.1.0...v1.2.0",
"createdAt": "2025-11-03T16:00:00Z"
}
Publishing
Publish Draft
Publish a draft to one or more channels.
POST /api/publish
Content-Type: application/json
{
"draftId": "draft_abc123",
"channel": "github",
"draft": false
}
Body Parameters:
draftId(required): Draft ID to publishchannel(required):github,intercom,hosted,slack,teamsdraft(optional): Publish as draft (GitHub only, default: false)
Response:
{
"id": "pub_def456",
"status": "completed",
"url": "https://github.com/owner/repo/releases/tag/v1.2.0",
"publishedAt": "2025-11-03T16:30:00Z"
}
Repositories
List Repositories
Get all connected repositories.
GET /api/repos
Response:
{
"repos": [
{
"id": "repo_123",
"orgId": "org_456",
"githubRepoId": 789012,
"fullName": "acme/myapp",
"defaultBranch": "main",
"createdAt": "2025-10-01T08:00:00Z"
}
]
}
Get Repository Tags
Get all Git tags for a repository.
GET /api/repos/{repoId}/tags
Response:
{
"tags": [
{
"name": "v1.2.0",
"sha": "abc123def456",
"date": "2025-11-03T10:00:00Z"
},
{
"name": "v1.1.0",
"sha": "def456ghi789",
"date": "2025-10-15T14:00:00Z"
}
]
}
Statistics
Get Organization Stats
Get usage statistics for your organization.
GET /api/stats
Response:
{
"currentMonth": "2025-11",
"activeRepos": 5,
"draftsGenerated": 42,
"publishedReleases": 38,
"apiCalls": 1234,
"billingTier": "growth",
"usagePercentage": 75
}
Error Handling
Error Response Format
All errors follow this format:
{
"error": "Error type",
"message": "Human-readable description",
"details": {
"field": "Additional context"
}
}
HTTP Status Codes
200 OK- Success201 Created- Resource created400 Bad Request- Invalid request401 Unauthorized- Missing or invalid API key403 Forbidden- Insufficient permissions404 Not Found- Resource not found429 Too Many Requests- Rate limit exceeded500 Internal Server Error- Server error
Common Errors
Invalid API Key:
{
"error": "Unauthorized",
"message": "Invalid API key. Generate a new key in Settings → API Keys."
}
Rate Limit Exceeded:
{
"error": "Rate limit exceeded",
"message": "Limit: 100 requests per minute. Try again in 42 seconds.",
"retryAfter": 42
}
Resource Not Found:
{
"error": "Not found",
"message": "Draft draft_abc123 not found or you don't have access."
}
Code Examples
Node.js
const RELEASERAY_API_KEY = process.env.RELEASERAY_API_KEY;
const BASE_URL = "https://app.releaseray.com/api";
async function generateDraft(rangeId, persona) {
const response = await fetch(`${BASE_URL}/drafts/${rangeId}/generate`, {
method: "POST",
headers: {
Authorization: `Bearer ${RELEASERAY_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({ persona }),
});
if (!response.ok) {
const error = await response.json();
throw new Error(error.message);
}
return await response.json();
}
// Usage
const draft = await generateDraft("range_xyz789", "engineer");
console.log("Draft generated:", draft.id);
Python
import os
import requests
RELEASERAY_API_KEY = os.getenv('RELEASERAY_API_KEY')
BASE_URL = 'https://app.releaseray.com/api'
def generate_draft(range_id, persona):
response = requests.post(
f'{BASE_URL}/drafts/{range_id}/generate',
headers={
'Authorization': f'Bearer {RELEASERAY_API_KEY}',
'Content-Type': 'application/json',
},
json={'persona': persona}
)
response.raise_for_status()
return response.json()
# Usage
draft = generate_draft('range_xyz789', 'engineer')
print(f'Draft generated: {draft["id"]}')
cURL
# Generate draft
curl -X POST https://app.releaseray.com/api/drafts/range_xyz789/generate \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"persona": "engineer"}'
# Get draft
curl https://app.releaseray.com/api/drafts/draft_abc123 \
-H "Authorization: Bearer YOUR_API_KEY"
# Publish to GitHub
curl -X POST https://app.releaseray.com/api/publish \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"draftId": "draft_abc123",
"channel": "github",
"draft": false
}'
Webhooks (Outgoing)
Coming soon: Configure webhooks to receive events when drafts are generated or published.
Event types:
draft.generated- Draft generation completeddraft.published- Draft published to a channelrange.created- New release range created
Webhook payload:
{
"event": "draft.generated",
"timestamp": "2025-11-03T16:00:00Z",
"data": {
"draftId": "draft_abc123",
"persona": "engineer",
"releaseRangeId": "range_xyz789"
}
}
Pagination
List endpoints support pagination:
GET /api/ranges?repoId=repo_123&limit=20&offset=40
Parameters:
limit- Number of results per page (max: 100, default: 20)offset- Number of results to skip (default: 0)
Response includes:
{
"ranges": [...],
"total": 150,
"hasMore": true,
"nextOffset": 60
}
Filtering & Sorting
Filtering
Filter results with query parameters:
GET /api/drafts?releaseRangeId=range_xyz&persona=engineer
Sorting
Sort results with sort and order:
GET /api/ranges?sort=createdAt&order=desc
Sort fields: createdAt, updatedAt, name
Order: asc, desc
SDKs
Official SDKs
We provide official SDKs for:
- ✅ Node.js/TypeScript -
npm install @releaseray/sdk - 🔜 Python - Coming Q1 2026
- 🔜 Go - Coming Q1 2026
Node.js SDK
npm install @releaseray/sdk
import { ReleaseRay } from "@releaseray/sdk";
const client = new ReleaseRay({
apiKey: process.env.RELEASERAY_API_KEY,
});
// Generate draft
const draft = await client.drafts.generate("range_xyz789", {
persona: "engineer",
});
// Publish to GitHub
await client.publish({
draftId: draft.id,
channel: "github",
});
Best Practices
API Key Management
✅ Do:
- Store API keys in environment variables
- Use different keys for dev/staging/production
- Rotate keys every 6 months
- Delete unused keys immediately
❌ Don't:
- Commit API keys to git
- Share keys between team members
- Use production keys in development
- Store keys in plaintext files
Rate Limiting
✅ Do:
- Implement exponential backoff for retries
- Cache responses when appropriate
- Use bulk endpoints when available
- Monitor rate limit headers
❌ Don't:
- Retry immediately on 429 errors
- Poll endpoints more than once per second
- Make parallel requests for the same data
- Ignore rate limit warnings
Error Handling
✅ Do:
- Check HTTP status codes
- Parse error messages
- Log errors for debugging
- Retry on 5xx errors
❌ Don't:
- Assume all requests succeed
- Ignore error details
- Retry on 4xx errors (except 429)
- Continue on 401/403 errors
Testing
Sandbox Environment
Coming soon: Sandbox API for testing without affecting production data.
Test Mode
Use X-Test-Mode: true header to simulate API calls:
curl https://app.releaseray.com/api/drafts/range_xyz/generate \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "X-Test-Mode: true" \
-H "Content-Type: application/json" \
-d '{"persona": "engineer"}'
Test mode:
- ✅ Validates requests
- ✅ Returns mock responses
- ❌ Doesn't consume API credits
- ❌ Doesn't create actual resources
Changelog
Version 1.0 (Current)
- Initial API release
- Drafts CRUD operations
- Release ranges management
- Publishing endpoints
- Statistics endpoint
Upcoming
- Outgoing webhooks
- Bulk operations
- Advanced filtering
- Custom persona API
- GraphQL endpoint
Support
Need Help?
- Documentation: Full docs
- Email: support@releaseray.com
- Status: status.releaseray.com
Questions about the API? We're here to help!
Report Issues
Found a bug in the API?
- Email api@releaseray.com with:
- Request/response examples
- Expected vs actual behavior
- Timestamp of issue
- We'll investigate within 24 hours
- Critical issues resolved within 4 hours
Related Documentation
- Getting Started - Initial setup
- Webhooks - Incoming GitHub webhooks
- Integrations - Publishing channels
- Dashboard - Using the web UI