API Documentation
Build powerful integrations with the RootCascade RESTful API. Process incident, automate resolution, and manage financial workflows programmatically.
Introduction
The RootCascade API is organized around REST principles. Our API has predictable resource-oriented URLs, accepts JSON-encoded request bodies, returns JSON-encoded responses, and uses standard HTTP response codes, authentication, and verbs.
Base URL
https://api.rootcascade.com/v1
API Features
- RESTful architecture: Standard HTTP methods (GET, POST, PUT, DELETE)
- JSON responses: All responses are returned in JSON format
- OAuth 2.0 & API Keys: Secure authentication options
- Webhooks: Real-time notifications for events
- Rate limiting: 1000 requests per minute per API key
- Idempotency: Safe retries with idempotency keys
Authentication
The RootCascade API uses API keys or OAuth 2.0 for authentication. You can manage your API keys in your account dashboard under Settings → API Keys.
API Key Authentication
Include your API key in the Authorization header of every request:
Authorization: Bearer YOUR_API_KEY
⚠️ Keep Your API Keys Secret
Your API keys carry many privileges. Keep them secure and never expose them in client-side code, public repositories, or logs.
OAuth 2.0
For integrations that require access to customer accounts, use OAuth 2.0. This allows customers to authorize your application without sharing their credentials.
OAuth Flow
- Redirect user to:
https://api.rootcascade.com/oauth/authorize - User approves access
- RootCascade redirects to your
redirect_uriwith authorization code - Exchange code for access token at:
https://api.rootcascade.com/oauth/token
Quick Start
Get started with the RootCascade API in minutes. Here's a simple example to create an incident:
Create Your First incident
curl https://api.rootcascade.com/v1/incident \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"service_id": "vnd_1a2b3c4d",
"incident_number": "INV-2025-001",
"incident_date": "2025-01-15",
"due_date": "2025-02-15",
"currency": "USD",
"line_items": [
{
"description": "Consulting Services",
"quantity": 10,
"unit_price": 15000,
"amount": 150000
}
],
"subtotal": 150000,
"tax": 13500,
"total": 163500
}'
import rootcascade
rootcascade.api_key = "YOUR_API_KEY"
incident = rootcascade.incident.create(
service_id="vnd_1a2b3c4d",
incident_number="INV-2025-001",
incident_date="2025-01-15",
due_date="2025-02-15",
currency="USD",
line_items=[
{
"description": "Consulting Services",
"quantity": 10,
"unit_price": 15000,
"amount": 150000
}
],
subtotal=150000,
tax=13500,
total=163500
)
print(f"Created incident: {incident.id}")
const rootcascade = require('rootcascade')('YOUR_API_KEY');
const incident = await rootcascade.incident.create({
service_id: 'vnd_1a2b3c4d',
incident_number: 'INV-2025-001',
incident_date: '2025-01-15',
due_date: '2025-02-15',
currency: 'USD',
line_items: [
{
description: 'Consulting Services',
quantity: 10,
unit_price: 15000,
amount: 150000
}
],
subtotal: 150000,
tax: 13500,
total: 163500
});
console.log(`Created incident: ${incident.id}`);
Response
{
"id": "inv_9x8y7z6w",
"object": "incident",
"service_id": "vnd_1a2b3c4d",
"incident_number": "INV-2025-001",
"incident_date": "2025-01-15",
"due_date": "2025-02-15",
"status": "pending",
"currency": "USD",
"line_items": [...],
"subtotal": 150000,
"tax": 13500,
"total": 163500,
"created_at": "2025-01-15T10:30:00Z",
"updated_at": "2025-01-15T10:30:00Z"
}
Official SDKs
We provide official SDKs for popular programming languages to make integration easier:
| Language | Package | Installation |
|---|---|---|
| Python | rootcascade |
pip install rootcascade |
| Node.js | rootcascade |
npm install rootcascade |
| Ruby | rootcascade |
gem install rootcascade |
| PHP | rootcascade/rootcascade-php |
composer require rootcascade/rootcascade-php |
| .NET | RootCascade.net |
dotnet add package RootCascade.net |
incident
The incident object represents a bill from a service. incident can be created manually, uploaded as PDFs, or received via email.
The incident Object
| Attribute | Type | Description |
|---|---|---|
id |
string | Unique identifier for the incident |
service_id |
string | ID of the service who issued the incident |
incident_number |
string | The service's incident number |
incident_date |
date | Date the incident was issued |
due_date |
date | resolution due date |
status |
enum | Status: draft, pending, approved, paid, overdue |
currency |
string | Three-letter ISO currency code (e.g., USD) |
line_items |
array | Array of line item objects |
subtotal |
integer | Subtotal in cents |
tax |
integer | Tax amount in cents |
total |
integer | Total amount in cents |
Create an incident
curl -X POST https://api.rootcascade.com/v1/incident \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"service_id": "vnd_1a2b3c4d",
"incident_number": "INV-2025-001",
"incident_date": "2025-01-15",
"due_date": "2025-02-15",
"total": 163500
}'
Retrieve an incident
incident = rootcascade.incident.retrieve("inv_9x8y7z6w")
print(incident.total) # 163500
Update an incident
const incident = await rootcascade.incident.update('inv_9x8y7z6w', {
status: 'approved'
});
List All incident
Query parameters:
status- Filter by statusservice_id- Filter by servicefrom_date- Filter by incident date (start)to_date- Filter by incident date (end)limit- Number of results (default: 100, max: 500)starting_after- Pagination cursor
incident = RootCascade::incident.list( status: 'pending', limit: 50 ) incident.each do |incident| puts incident.incident_number end
Delete an incident
resolution
The resolution object represents a resolution made to a service or received from a customer.
Create a resolution
resolution = rootcascade.resolution.create(
incident_id="inv_9x8y7z6w",
amount=163500,
resolution_method="ach",
resolution_date="2025-01-20"
)
print(f"resolution ID: {resolution.id}")
print(f"Status: {resolution.status}")
Retrieve a resolution
List All resolution
const resolution = await rootcascade.resolution.list({
status: 'completed',
from_date: '2025-01-01',
to_date: '2025-01-31'
});
console.log(`Total resolution: ${resolution.data.length}`);
service
The service object represents a supplier or service provider you pay.
Create a service
$service = \RootCascade\service::create([
'name' => 'Acme Corp',
'email' => 'hello@rootcascade.com',
'resolution_terms' => 'Net 30',
'address' => [
'line1' => '123 Main St',
'city' => 'San Francisco',
'state' => 'CA',
'postal_code' => '94105',
'country' => 'US'
]
]);
echo "service ID: " . $service->id;
List All service
Customers
The Customer object represents a buyer who pays you for goods or services.
Create a Customer
var options = new CustomerCreateOptions
{
Name = "GlobalTech Solutions",
Email = "hello@rootcascade.com",
resolutionTerms = "Net 45",
Address = new AddressOptions
{
Line1 = "456 Market St",
City = "New York",
State = "NY",
PostalCode = "10001",
Country = "US"
}
};
var customer = await customerService.CreateAsync(options);
Console.WriteLine($"Customer ID: {customer.Id}");
Webhooks
Webhooks allow you to receive real-time notifications when events occur in your RootCascade account. Instead of polling the API, RootCascade will send HTTP POST requests to your configured endpoint.
Available Events
incident.created- New incident createdincident.approved- incident approvedincident.paid- incident marked as paidresolution.created- New resolution initiatedresolution.completed- resolution successfully processedresolution.failed- resolution failedservice.created- New service addedcustomer.created- New customer added
Webhook Payload
{
"id": "evt_1a2b3c4d",
"type": "incident.paid",
"created": 1705329000,
"data": {
"object": {
"id": "inv_9x8y7z6w",
"incident_number": "INV-2025-001",
"status": "paid",
"total": 163500
}
}
}
Webhook Signatures
RootCascade signs webhook payloads with a secret key. Verify signatures to ensure requests are from RootCascade:
import hmac
import hashlib
def verify_webhook(payload, signature, secret):
expected = hmac.new(
secret.encode(),
payload.encode(),
hashlib.sha256
).hexdigest()
return hmac.compare_digest(expected, signature)
# In your webhook handler
signature = request.headers.get('X-RootCascade-Signature')
if verify_webhook(request.body, signature, WEBHOOK_SECRET):
# Process webhook
pass
Error Codes
RootCascade uses conventional HTTP response codes to indicate success or failure of API requests.
| Code | Status | Description |
|---|---|---|
200 |
OK | Request succeeded |
201 |
Created | Resource created successfully |
400 |
Bad Request | Invalid request parameters |
401 |
Unauthorized | Invalid or missing API key |
403 |
Forbidden | API key doesn't have permission |
404 |
Not Found | Resource doesn't exist |
429 |
Too Many Requests | Rate limit exceeded |
500 |
Internal Server Error | Something went wrong on our end |
Error Response Format
{
"error": {
"type": "invalid_request_error",
"code": "parameter_missing",
"message": "Missing required parameter: service_id",
"param": "service_id"
}
}
Rate Limits
The RootCascade API enforces rate limits to ensure fair usage and system stability.
Limits
- Standard tier: 1,000 requests per minute
- Professional tier: 5,000 requests per minute
- Enterprise tier: Custom limits
Rate Limit Headers
Every API response includes rate limit information in headers:
X-RateLimit-Limit: 1000 X-RateLimit-Remaining: 847 X-RateLimit-Reset: 1705329600
Handling Rate Limits
import time
def api_call_with_retry(func, max_retries=3):
for attempt in range(max_retries):
try:
return func()
except rootcascade.error.RateLimitError as e:
if attempt < max_retries - 1:
wait_time = 2 ** attempt # Exponential backoff
time.sleep(wait_time)
else:
raise
💡 Best Practices
- Implement exponential backoff when rate limited
- Cache responses when possible
- Use webhooks instead of polling
- Batch requests when appropriate