Skip to main content

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: Success
  • 201: Created
  • 400: Bad Request
  • 401: Unauthorized
  • 403: Forbidden
  • 404: Not Found
  • 409: Conflict (duplicate)
  • 429: Rate Limited
  • 500: 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 arrived
  • chat.message.created - New chat message
  • task.created - New task created
  • task.updated - Task status changed
  • record.created - New data record
  • record.updated - Record updated
  • record.deleted - Record deleted
  • workflow.completed - Workflow finished
  • workflow.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