11 min read

Vantage REST API

The Vantage REST API lets you programmatically manage workflows, execute them, retrieve results, and discover available node types. All endpoints live under /api/v1/.


Base URL

https://your-vantage-instance.com/api/v1

All requests must include an Authorization header with a valid API key.


Authentication

Every request to the v1 API must include an API key in the Authorization header using the Bearer scheme:

http
Authorization: Bearer vntg_abc123...

API keys are created from the Vantage Settings page or via the /api/v1/keys endpoint. Each key has:

PropertyDescription
nameA human-readable label for the key
scope_leveluser (only your resources) or client (all resources in your organization)
scopesPermission array: workflows:read, workflows:write, workflows:execute
expires_atOptional expiration date (ISO 8601)

Important: The full API key is shown only once when created. Store it securely — it cannot be retrieved again.

Rate Limiting

The API enforces a rate limit of 60 requests per minute per API key. If exceeded, you'll receive a 429 Too Many Requests response.

CORS

All v1 endpoints support CORS with Access-Control-Allow-Origin: *, so they can be called from browser-based applications.


Response Envelope

All successful responses follow this structure:

json
{
  "success": true,
  "data": { ... },
  "meta": {
    "request_id": "abc123xyz",
    "timestamp": "2026-04-29T12:00:00.000Z"
  }
}

Error responses:

json
{
  "success": false,
  "error": {
    "code": "WORKFLOW_NOT_FOUND",
    "message": "Workflow 42 not found"
  },
  "meta": {
    "request_id": "abc123xyz",
    "timestamp": "2026-04-29T12:00:00.000Z"
  }
}

API Key Management

Create an API Key

http
POST /api/v1/keys

Create a new API key. The full key value is returned only in this response — store it immediately.

Request Body:

json
{
  "name": "My Production Key",
  "scope_level": "user",
  "scopes": ["workflows:read", "workflows:execute"],
  "expires_at": "2027-01-01T00:00:00.000Z"
}
FieldTypeRequiredDescription
namestringHuman-readable name (max 100 chars)
scope_levelstringNo"user" (default) or "client"
scopesstring[]NoPermission array. Valid values: workflows:read, workflows:write, workflows:execute
expires_atstringNoISO 8601 expiration date

Example Response:

json
{
  "success": true,
  "key": {
    "id": 12,
    "name": "My Production Key",
    "key_prefix": "vntg_abc1",
    "scope_level": "user",
    "scopes": ["workflows:read", "workflows:execute"],
    "expires_at": "2027-01-01T00:00:00.000Z",
    "created": "2026-04-29T12:00:00.000Z"
  },
  "full_key": "vntg_abc123def456ghi789jkl012mno345"
}

List API Keys

http
GET /api/v1/keys

Returns all API keys for your account. The key value itself is never returned — only the prefix for identification.

Example Response:

json
{
  "success": true,
  "keys": [
    {
      "id": 12,
      "name": "My Production Key",
      "key_prefix": "vntg_abc1",
      "scope_level": "user",
      "scopes": ["workflows:read", "workflows:execute"],
      "is_active": true,
      "last_used_at": "2026-04-29T11:30:00.000Z",
      "expires_at": "2027-01-01T00:00:00.000Z",
      "created": "2026-04-29T12:00:00.000Z"
    }
  ]
}

Update an API Key

http
PATCH /api/v1/keys/:keyId

Update a key's name or scopes. You cannot change the key value, scope level, or hash.

Request Body:

json
{
  "name": "Renamed Key",
  "scopes": ["workflows:read", "workflows:write", "workflows:execute"]
}

Revoke an API Key

http
DELETE /api/v1/keys/:keyId

Soft-revokes a key (sets is_active = false). The key immediately stops working.

Example Response:

json
{
  "success": true,
  "revoked": true
}

Workflows

List Workflows

http
GET /api/v1/workflows

Returns all workflows visible to your API key. Results are scoped by your key's scope_level:

Query Parameters:

ParamTypeDefaultDescription
pageinteger0Page number (0-indexed)
limitinteger50Results per page (max 100)

Example Response:

json
{
  "success": true,
  "data": {
    "workflows": [
      {
        "id": 42,
        "title": "Daily Sales Report",
        "description": "Pulls Stripe data and generates a summary",
        "is_active": true,
        "created": "2026-03-15T09:00:00.000Z",
        "modified": "2026-04-28T14:30:00.000Z",
        "node_count": 5,
        "edge_count": 4
      }
    ],
    "total": 1,
    "page": 0,
    "limit": 50
  },
  "meta": {
    "request_id": "req_abc123",
    "timestamp": "2026-04-29T12:00:00.000Z"
  }
}

Get a Workflow

http
GET /api/v1/workflows/:workflowId

Returns a single workflow with its full graph (nodes and edges).

Example Response:

json
{
  "success": true,
  "data": {
    "id": 42,
    "title": "Daily Sales Report",
    "description": "Pulls Stripe data and generates a summary",
    "is_active": true,
    "created": "2026-03-15T09:00:00.000Z",
    "modified": "2026-04-28T14:30:00.000Z",
    "nodes": [
      {
        "id": 101,
        "node_type": "stripe/listCharges",
        "node_role": "getter",
        "label": "List Charges",
        "config": {
          "limit": 100,
          "status": "succeeded"
        }
      },
      {
        "id": 102,
        "node_type": "queryoperators/computedColumn",
        "node_role": "setter",
        "label": "Calculate Revenue",
        "config": {
          "column_name": "revenue_usd",
          "expression": "amount / 100"
        }
      },
      {
        "id": 103,
        "node_type": "termination/dashboardOutput",
        "node_role": "terminator",
        "label": "Output to Dashboard",
        "config": {}
      }
    ],
    "edges": [
      {
        "id": 201,
        "source_node_id": 101,
        "target_node_id": 102,
        "source_key": "output1",
        "target_key": "input1"
      },
      {
        "id": 202,
        "source_node_id": 102,
        "target_node_id": 103,
        "source_key": "output1",
        "target_key": "input1"
      }
    ]
  },
  "meta": {
    "request_id": "req_def456",
    "timestamp": "2026-04-29T12:00:00.000Z"
  }
}

Create a Workflow

http
POST /api/v1/workflows

Request Body:

json
{
  "title": "New Sales Pipeline",
  "description": "Automated Stripe charge processing",
  "nodes": [
    {
      "node_type": "stripe/listCharges",
      "node_role": "getter",
      "label": "List Charges",
      "config": { "limit": 50 }
    },
    {
      "node_type": "termination/dashboardOutput",
      "node_role": "terminator",
      "label": "Dashboard Output",
      "config": {}
    }
  ],
  "edges": [
    {
      "source_node_index": 0,
      "target_node_index": 1,
      "source_key": "output1",
      "target_key": "input1"
    }
  ]
}
FieldTypeRequiredDescription
titlestringWorkflow name (max 255 chars)
descriptionstringNoDescription text
nodesarrayNoArray of node definitions
edgesarrayNoArray of edge definitions (uses source_node_index / target_node_index to reference nodes by array position)

Note: Edge indices are 0-based references to the nodes array position, not database IDs. The API resolves them to actual node IDs automatically.

Node Roles:

RoleDescription
getterFetches data from a source (integration, database, API)
setterTransforms, filters, or enriches data
terminatorOutputs the final result (dashboard, email, export, etc.)

Every workflow must have at least one terminator node.

Update a Workflow

http
PATCH /api/v1/workflows/:workflowId

Update metadata, or replace the entire node/edge graph by including nodes in the body.

Metadata-only update:

json
{
  "title": "Updated Title",
  "description": "New description",
  "is_active": false
}

Full graph replacement:

json
{
  "title": "Updated Pipeline",
  "nodes": [
    { "node_type": "stripe/listCharges", "node_role": "getter", "label": "Charges", "config": {} },
    { "node_type": "queryoperators/aggregation", "node_role": "setter", "label": "Sum Revenue", "config": {} },
    { "node_type": "termination/dashboardOutput", "node_role": "terminator", "label": "Output", "config": {} }
  ],
  "edges": [
    { "source_node_index": 0, "target_node_index": 1 },
    { "source_node_index": 1, "target_node_index": 2 }
  ]
}

When nodes is included, the existing graph is atomically replaced — all previous nodes and edges are deleted and recreated.

The response includes a node_id_map that maps your 0-based node indices to the new database IDs:

json
{
  "node_id_map": { "0": 301, "1": 302, "2": 303 }
}

Delete a Workflow

http
DELETE /api/v1/workflows/:workflowId

Permanently deletes a workflow and all its nodes, edges, and schedules.

Returns 204 No Content on success.


Workflow Execution

Execute a Workflow

http
POST /api/v1/workflows/:workflowId/execute

Runs a workflow and returns the results. Execution happens synchronously — the response is returned when the workflow completes.

Request Body (optional):

json
{
  "params": {
    "start_date": "2026-04-01",
    "end_date": "2026-04-30"
  }
}
FieldTypeDescription
paramsobjectKey-value parameters passed to the workflow's input nodes

Example Response:

json
{
  "success": true,
  "data": {
    "workflow_id": 42,
    "status": "completed",
    "execution_time_ms": 2340,
    "result_id": "dataRef:wf42_1714392000_abc123",
    "rows": [
      { "charge_id": "ch_1abc", "amount": 4999, "currency": "usd", "revenue_usd": 49.99 },
      { "charge_id": "ch_2def", "amount": 2500, "currency": "usd", "revenue_usd": 25.00 }
    ],
    "total_rows": 2,
    "schema": {
      "charge_id": "string",
      "amount": "number",
      "currency": "string",
      "revenue_usd": "number"
    }
  },
  "meta": {
    "request_id": "req_exec_789",
    "timestamp": "2026-04-29T12:00:02.340Z"
  }
}

Use the result_id to paginate through large result sets without re-executing:

Validate a Workflow

http
POST /api/v1/workflows/:workflowId/validate

Checks whether a workflow graph is valid without executing it. Returns validation errors if any nodes are misconfigured or edges are invalid.

Example Response (valid):

json
{
  "success": true,
  "data": {
    "valid": true,
    "warnings": []
  }
}

Example Response (invalid):

json
{
  "success": true,
  "data": {
    "valid": false,
    "errors": [
      { "node_id": 102, "message": "Missing required config field: column_name" },
      { "node_id": null, "message": "No terminator node found in workflow" }
    ]
  }
}

Execution Data

Get Execution Results

http
GET /api/v1/workflows/:workflowId/data/:resultId

Paginate through previously executed workflow results using the result_id from an execute response.

Query Parameters:

ParamTypeDefaultDescription
pageinteger0Page number (0-indexed)
limitinteger100Rows per page (max 1000)

Example Response:

json
{
  "success": true,
  "data": {
    "rows": [
      { "charge_id": "ch_1abc", "amount": 4999, "currency": "usd" },
      { "charge_id": "ch_2def", "amount": 2500, "currency": "usd" }
    ],
    "total_rows": 248,
    "schema": {
      "charge_id": "string",
      "amount": "number",
      "currency": "string"
    },
    "page": 0,
    "limit": 100,
    "has_more": true,
    "next_page_url": "/api/v1/workflows/42/data/dataRef:wf42_abc123?page=1&limit=100"
  }
}

Note: Execution results are stored temporarily and may expire. If a DATA_EXPIRED error is returned, re-execute the workflow.


Node Types

List Available Node Types

http
GET /api/v1/node-types

Returns all available workflow node types with their categories, roles, and configuration requirements.

Query Parameters:

ParamTypeDescription
categorystringFilter by category name (case-insensitive, partial match)
rolestringFilter by node role: getter, setter, terminator

Example Request:

http
GET /api/v1/node-types?category=stripe&role=getter

Example Response:

json
{
  "success": true,
  "data": {
    "categories": [
      { "id": 15, "name": "Stripe", "node_count": 8 }
    ],
    "node_types": [
      {
        "node_type": "stripe/listCharges",
        "category": "Stripe",
        "label": "List Charges",
        "node_role": "getter",
        "description": "Retrieve a list of charges from Stripe",
        "inputs": ["input1"],
        "outputs": ["output1"],
        "requires_credential": true
      },
      {
        "node_type": "stripe/getBalance",
        "category": "Stripe",
        "label": "Get Balance",
        "node_role": "getter",
        "description": "Retrieve the current Stripe account balance",
        "inputs": ["input1"],
        "outputs": ["output1"],
        "requires_credential": true
      }
    ],
    "total": 2
  }
}

Error Codes

CodeHTTP StatusDescription
UNAUTHORIZED401Missing or invalid API key
FORBIDDEN403API key lacks the required scope
RATE_LIMITED429Exceeded 60 requests/minute
INVALID_INPUT400Request body validation failed
INVALID_BODY400Request body is not valid JSON
WORKFLOW_NOT_FOUND404Workflow doesn't exist or isn't accessible
DATA_EXPIRED404Execution results have expired
USER_NOT_FOUND404Authenticated user not found
SERVICE_UNAVAILABLE503Backend service (e.g. data store) unavailable
INTERNAL_ERROR500Unexpected server error

Quick Start

1. Create an API Key

bash
curl -X POST https://your-instance.com/api/v1/keys \
  -H "Content-Type: application/json" \
  -H "Cookie: your-session-cookie" \
  -d '{
    "name": "My First Key",
    "scope_level": "user",
    "scopes": ["workflows:read", "workflows:write", "workflows:execute"]
  }'

Save the full_key from the response — you'll need it for all subsequent requests.

2. List Your Workflows

bash
curl https://your-instance.com/api/v1/workflows \
  -H "Authorization: Bearer vntg_your_key_here"

3. Execute a Workflow

bash
curl -X POST https://your-instance.com/api/v1/workflows/42/execute \
  -H "Authorization: Bearer vntg_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{ "params": { "date_range": "last_30_days" } }'

4. Paginate Results

bash
curl "https://your-instance.com/api/v1/workflows/42/data/dataRef:wf42_abc123?page=1&limit=50" \
  -H "Authorization: Bearer vntg_your_key_here"

5. Discover Node Types

bash
curl "https://your-instance.com/api/v1/node-types?category=slack" \
  -H "Authorization: Bearer vntg_your_key_here"

SDK Examples

JavaScript / Node.js

javascript
const VANTAGE_API = 'https://your-instance.com/api/v1';
const API_KEY = 'vntg_your_key_here';

const headers = {
  'Authorization': `Bearer ${API_KEY}`,
  'Content-Type': 'application/json',
};

// List workflows
const workflows = await fetch(`${VANTAGE_API}/workflows`, { headers })
  .then(r => r.json());

// Execute a workflow
const result = await fetch(`${VANTAGE_API}/workflows/42/execute`, {
  method: 'POST',
  headers,
  body: JSON.stringify({ params: { limit: 100 } }),
}).then(r => r.json());

console.log(`Completed in ${result.data.execution_time_ms}ms`);
console.log(`${result.data.total_rows} rows returned`);

Python

python
import requests

API_BASE = "https://your-instance.com/api/v1"
API_KEY = "vntg_your_key_here"
headers = {"Authorization": f"Bearer {API_KEY}"}

# List workflows
workflows = requests.get(f"{API_BASE}/workflows", headers=headers).json()

# Execute a workflow
result = requests.post(
    f"{API_BASE}/workflows/42/execute",
    headers=headers,
    json={"params": {"date_range": "last_30_days"}}
).json()

# Paginate through results
result_id = result["data"]["result_id"]
page = 0
all_rows = []

while True:
    data = requests.get(
        f"{API_BASE}/workflows/42/data/{result_id}?page={page}&limit=100",
        headers=headers
    ).json()
    all_rows.extend(data["data"]["rows"])
    if not data["data"]["has_more"]:
        break
    page += 1

print(f"Total rows: {len(all_rows)}")

cURL — Create a Workflow via API

bash
curl -X POST https://your-instance.com/api/v1/workflows \
  -H "Authorization: Bearer vntg_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{
    "title": "Slack Alert Pipeline",
    "description": "Monitors Stripe charges and sends Slack alerts for high-value transactions",
    "nodes": [
      {
        "node_type": "stripe/listCharges",
        "node_role": "getter",
        "label": "Get Recent Charges",
        "config": { "limit": 50, "status": "succeeded" }
      },
      {
        "node_type": "queryoperators/filter",
        "node_role": "setter",
        "label": "High Value Only",
        "config": { "field": "amount", "operator": "gt", "value": 10000 }
      },
      {
        "node_type": "slack/sendMessage",
        "node_role": "terminator",
        "label": "Alert Sales Team",
        "config": { "channel": "#sales-alerts" }
      }
    ],
    "edges": [
      { "source_node_index": 0, "target_node_index": 1 },
      { "source_node_index": 1, "target_node_index": 2 }
    ]
  }'