Gravity Rail API - Quick Reference
Base URL: https://api.gravityrail.com/api/v2
Authentication
# API Key
curl https://api.gravityrail.com/api/v2/w \
-H "Authorization: Bearer YOUR_API_KEY"
# OAuth Token
curl https://api.gravityrail.com/api/v2/w \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"
Essential Endpoints
Workspaces
# List workspaces
GET /w
# Get workspace
GET /w/{wid}
# Update workspace
PUT /w/{wid}
Chats & Messaging
# Create chat
POST /w/{wid}/chats
{
"channel": "web-chat",
"workflowId": 1,
"title": "Support Chat",
"assistantEnabled": true
}
# Send user message
POST /w/{wid}/chats/{chatId}/messages
{ "content": "Hello, how can I help?" }
# Send assistant message (API-initiated)
POST /w/{wid}/chats/{chatId}/send-assistant-message
{ "message": "Hello, how can I help?" }
# Get messages
GET /w/{wid}/chats/{chatId}/messages
# Update chat (assign, pause, etc.)
PUT /w/{wid}/chats/{chatId}
{
"title": "Updated Title",
"assignmentId": 42,
"paused": false
}
Data Types (CRM)
# Create data type
POST /w/{wid}/data-types
{
"name": "Customer",
"slug": "customer",
"fields": [
{
"name": "firstName",
"slug": "first_name",
"fieldType": "text",
"required": true,
"shouldIndex": true
},
{
"name": "email",
"slug": "email",
"fieldType": "email",
"shouldIndex": true
}
]
}
# Create record
# Note: {dataTypeId} is the numeric ID returned when creating the data type
POST /w/{wid}/data-types/{dataTypeId}/records
{
"fieldValues": {
"firstName": "John",
"email": "john@example.com"
},
"memberId": 123, // optional - record owner
"externalId": "CRM-001" // optional - for upsert/sync
}
# Query records
GET /w/{wid}/data-types/{dataTypeId}/records?search=John&page=1&page_size=10
# Update record
PUT /w/{wid}/data-types/{dataTypeId}/records/{recordId}
{
"fieldValues": {
"firstName": "Jane",
"email": "jane@example.com"
}
}
# Delete record
DELETE /w/{wid}/data-types/{dataTypeId}/records/{recordId}
# Upsert by external ID
POST /w/{wid}/data-types/{dataTypeId}/upsert/{externalId}
{
"fieldValues": {
"firstName": "John",
"email": "john@example.com"
}
}
# Bulk create/upsert (up to 10,000 records)
POST /w/{wid}/data-types/{dataTypeId}/records/bulk
{
"records": [
{
"fieldValues": {"firstName": "John", "email": "john@example.com"},
"externalId": "CRM-001"
},
{
"fieldValues": {"firstName": "Jane", "email": "jane@example.com"},
"externalId": "CRM-002"
}
],
"upsert": false // set true to update existing records by externalId
}
# Bulk response
{
"success": true,
"totalCount": 2,
"importedCount": 2,
"results": [
{"index": 0, "status": "created", "recordId": 123, "externalId": "CRM-001"},
{"index": 1, "status": "created", "recordId": 124, "externalId": "CRM-002"}
],
"errors": null
}
Tasks & Workflows
# Create task
POST /w/{wid}/tasks
{
"name": "Review Document",
"slug": "review-doc",
"description": "Review the submitted document",
"workflowId": 1,
"isAdmin": false
}
# Update task
PUT /w/{wid}/tasks/{taskId}
{
"name": "Review Document - Updated",
"description": "Review the document carefully"
}
# Create workflow
POST /w/{wid}/workflows
{
"name": "Customer Support",
"agentId": 2,
"defaultPhoneNumberId": 5
}
# Update workflow
PUT /w/{wid}/workflows/{workflowId}
{
"name": "Customer Support - Updated",
"agentId": 3
}
# List workflows
GET /w/{wid}/workflows
Inboxes & Email
# List inboxes
GET /w/{wid}/inboxes
# Get inbox
GET /w/{wid}/inboxes/{inboxId}
# Create inbox
POST /w/{wid}/inboxes
{ "email": "support@company.com" }
Phone & SMS
# List phone numbers
GET /w/{wid}/phone-numbers
# Get phone number
GET /w/{wid}/phone-numbers/{phoneId}
# Create phone number
POST /w/{wid}/phone-numbers
{ "number": "+1234567890" }
# Send SMS (via chat — create an SMS chat, then send a message)
POST /w/{wid}/chats
{ "channel": "phone-sms", "workflowId": 1, "memberId": 42, "phoneNumberId": 123, "title": "Outreach" }
POST /w/{wid}/chats/{chatId}/send-assistant-message
{ "message": "Hello" }
Calendar & Events
# List calendars
GET /w/{wid}/calendars
# Create event
POST /w/{wid}/calendar-events
{ "title": "Meeting", "startTime": "2024-01-15T10:00:00Z" }
# List events
GET /w/{wid}/calendar-events?startTime=...&endTime=...
Custom Toolkits
# Create toolkit
POST /w/{wid}/custom-toolkits
{
"name": "Medical Toolkit",
"slug": "medical",
"description": "Tools for medical operations"
}
# Create tool
POST /w/{wid}/custom-toolkits/{toolkitId}/tools
{
"name": "check_vitals",
"displayName": "Check Patient Vitals",
"description": "Retrieve patient vital signs",
"prompt": "You are a medical assistant...",
"chatModel": "claude-3-5-sonnet",
"inputSchema": {
"type": "object",
"properties": {
"patientId": {"type": "string"}
},
"required": ["patientId"]
}
}
# Update tool
PUT /w/{wid}/custom-toolkits/{toolkitId}/tools/{toolId}
{
"displayName": "Check Patient Vitals - v2",
"description": "Retrieve and validate patient vital signs"
}
# List tools in toolkit
GET /w/{wid}/custom-toolkits/{toolkitId}/tools
# Delete tool
DELETE /w/{wid}/custom-toolkits/{toolkitId}/tools/{toolId}
# Enable toolkit
POST /w/{wid}/custom-toolkits/{toolkitId}/enable
# Disable toolkit
POST /w/{wid}/custom-toolkits/{toolkitId}/disable
MCP Servers
# List MCP servers
GET /w/{wid}/mcp-servers
# Create MCP server
POST /w/{wid}/mcp-servers
{
"name": "External API",
"slug": "external-api",
"mcpUrl": "https://api.example.com/mcp",
"supportsDirectAuth": true,
"description": "Connect to external service"
}
# Create with OAuth
POST /w/{wid}/mcp-servers
{
"name": "Secure Service",
"slug": "secure",
"mcpUrl": "https://secure.example.com/mcp",
"supportsDirectAuth": false,
"oauthClientId": "client_id",
"oauthClientSecret": "secret"
}
# Get MCP server details
GET /w/{wid}/mcp-servers/{serverId}
# Update server
PUT /w/{wid}/mcp-servers/{serverId}
{
"name": "Updated Name",
"description": "New description"
}
# Enable server
POST /w/{wid}/mcp-servers/{serverId}/enable
# Disable server
POST /w/{wid}/mcp-servers/{serverId}/disable
# Refresh tools
POST /w/{wid}/mcp-servers/{serverId}/refresh-tools
# Delete server
DELETE /w/{wid}/mcp-servers/{serverId}
Files
# Upload file
POST /w/{wid}/files
(multipart form data)
# Get file
GET /w/{wid}/files/{fileId}
# Delete file
DELETE /w/{wid}/files/{fileId}
Event Rules (Automation)
# Create event rule
POST /w/{wid}/event-rules
{ "trigger": "email.received", "action": "execute_workflow" }
# List rules
GET /w/{wid}/event-rules
# Update rule
PUT /w/{wid}/event-rules/{ruleId}
# Delete rule
DELETE /w/{wid}/event-rules/{ruleId}
Webhooks
# Get webhook logs
GET /w/{wid}/webhook-logs
# Webhooks are created via event rules
POST /w/{wid}/event-rules
{ "trigger": "email.received", "action": "webhook", "webhookUrl": "https://..." }
Members & Roles
# List members
GET /w/{wid}/members
# Get member
GET /w/{wid}/members/{memberId}
# List roles
GET /w/{wid}/member-roles
# Create role
POST /w/{wid}/member-roles
{ "name": "Custom Role", "permissions": [...] }
Assignments
# Create assignment
POST /w/{wid}/assignments
{ "workflowId": 1, "memberId": 2 }
# List assignments
GET /w/{wid}/assignments
# Update assignment
PUT /w/{wid}/assignments/{assignmentId}
Common Response Format
{
"items": [...], // Array of resources
"total": 100, // Total count
"page": 1, // Current page
"pageSize": 10 // Items per page
}
Error Handling
4xx responses return a JSON body with a detail field:
{"detail": "Error message"}
5xx responses return:
{"detail": "An internal server error occurred"}
See Error Handling Guide for full reference.
Common Status Codes:
200: Success201: Created400: Bad Request401: Unauthorized403: Forbidden404: Not Found409: Conflict (duplicate)429: Rate Limited500: Server Error
OAuth 2.0 Flow
# 1. Redirect to authorization
https://api.gravityrail.com/api/v2/oauth/authorize?
response_type=code&
client_id=YOUR_CLIENT_ID&
redirect_uri=YOUR_REDIRECT_URI&
scope=workspace:read%20workspace:write&
state=RANDOM_STATE
# 2. User authorizes, gets redirected to redirect_uri with code
# https://yourapp.com/callback?code=AUTH_CODE&state=RANDOM_STATE
# 3. Exchange code for token
POST /oauth/token
Content-Type: application/x-www-form-urlencoded
grant_type=authorization_code&
code=AUTH_CODE&
redirect_uri=YOUR_REDIRECT_URI&
client_id=YOUR_CLIENT_ID&
client_secret=YOUR_CLIENT_SECRET
# Response:
{
"access_token": "...",
"token_type": "Bearer",
"expires_in": 3600,
"refresh_token": "..."
}
# 4. Use access token
Authorization: Bearer ACCESS_TOKEN
Webhook Events
Common event types:
email.received- New email arrivedchat.message.created- New chat messagetask.created- New task createdtask.updated- Task status changedrecord.created- New data recordrecord.updated- Record updatedrecord.deleted- Record deletedworkflow.completed- Workflow finishedworkflow.failed- Workflow errored
Webhook payload format:
{
"eventType": "email.received",
"timestamp": "2024-01-15T10:30:00Z",
"workspaceId": "550e8400-e29b-41d4-a716-446655440000",
"data": {
"id": 123,
"...": "event specific data"
}
}
Rate Limits
- Default: 100 requests per minute per API key
- Burst: Up to 10 concurrent requests
- Check headers:
X-RateLimit-Remaining,X-RateLimit-Reset
SDK/Libraries
TypeScript/Node.js (@gravity-rail/sdk):
import { GravityRailClient } from '@gravity-rail/sdk';
const apiKey = process.env.GRAVITYRAIL_API_KEY;
const baseUrl = 'https://api.gravityrail.com/api/v2';
const client = new GravityRailClient(apiKey, baseUrl);
const workspaceUuid = process.env.WORKSPACE_UUID;
// List chats
const chats = await client.getChats(workspaceUuid);
// Create a chat
const newChat = await client.createChat(workspaceUuid, {
channel: 'web-chat',
workflowId: 1,
title: 'Support Chat',
});
// Send message
const message = await client.sendChatMessage(workspaceUuid, newChat.id, 'Hello!');
// Get data records (uses numeric data type ID, not slug)
const dataTypeId = 1;
const records = await client.getDataRecords(workspaceUuid, dataTypeId);
// Create a record
const record = await client.createDataRecord(workspaceUuid, dataTypeId, {
fieldValues: {
name: 'John Doe',
email: 'john@example.com',
},
});
Python:
import requests
headers = {
'Authorization': f'Bearer {API_KEY}',
'Content-Type': 'application/json'
}
response = requests.get(
'https://api.gravityrail.com/api/v2/w',
headers=headers
)
Useful Curl Patterns
# Set variables
export API_KEY="your_api_key"
export WS="workspace_uuid"
# List with pagination
curl "https://api.gravityrail.com/api/v2/w/$WS/chats?page=1&pageSize=50" \
-H "Authorization: Bearer $API_KEY"
# Create with JSON
curl -X POST "https://api.gravityrail.com/api/v2/w/$WS/chats" \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{"workflowId": 1}'
# Upload file
curl -X POST "https://api.gravityrail.com/api/v2/w/$WS/files" \
-H "Authorization: Bearer $API_KEY" \
-F "file=@./document.pdf"
# Pretty print response
curl ... | jq .
Key Concepts
Workspace: Container for all resources (chats, tasks, data, etc.)
Member: User in workspace with assigned role and permissions
Role: Set of permissions (can be custom)
Chat: Conversation session, can be created with a workflow
Task: Work item with title, priority, assignments
Data Type: Custom CRM object (like "Customer", "Lead", etc.)
Record: Instance of a data type with field values
Workflow: Automated process triggered by events
Custom Toolkit: Set of custom tools for AI agents
MCP Server: External service connected via Model Context Protocol
Event Rule: Automation that triggers on events
Webhook: Outbound notification to your system