Skip to content

REST API

In addition to the GraphQL API, the Manager provides REST endpoints for specific operations, primarily for machine user authentication and backend registration.

Base URL

https://manager.example.com/api

Authentication

REST endpoints use the same authentication methods as GraphQL:

Bearer Token:

http
Authorization: Bearer <token>

Basic Authentication:

http
Authorization: Basic <base64(username:password)>

Endpoints

Validate Machine User

Validates machine user credentials. Used internally by the Proxy for authentication.

Endpoint:

http
POST /api/validate-machine-user

Authentication: None required (internal use)

Request Body:

json
{
  "username": "machine-user-name",
  "token": "bearer-token-or-password"
}

Response (Success):

json
{
  "valid": true,
  "tenantId": "tenant-uuid",
  "machineUserId": "machine-user-uuid"
}

Response (Invalid):

json
{
  "valid": false,
  "error": "Invalid credentials"
}

Example:

bash
curl -X POST https://manager.example.com/api/validate-machine-user \
  -H "Content-Type: application/json" \
  -d '{
    "username": "payment-service",
    "token": "muser_abc123..."
  }'

Check Machine User Auth

Verifies the current machine user authentication status.

Endpoint:

http
GET /api/machine/check

Authentication: Bearer Token (Machine User) - Required

Response:

json
{
  "authenticated": true,
  "machineUserId": "machine-user-uuid",
  "tenantId": "tenant-uuid"
}

Example:

bash
curl -X GET https://manager.example.com/api/machine/check \
  -H "Authorization: Bearer muser_abc123..."

Register Backend

Registers a backend service to receive trigger execution callbacks.

Endpoint:

http
POST /api/machine/register-backend

Authentication: Bearer Token (Machine User) - Required

Request Body:

json
{
  "name": "Payment Service",
  "callbackUrl": "https://payment.example.com/triggers/callback",
  "description": "Handles payment processing triggers"
}

Response:

json
{
  "id": "backend-uuid",
  "name": "Payment Service",
  "callbackUrl": "https://payment.example.com/triggers/callback",
  "machineUserId": "machine-user-uuid",
  "createdAt": "2025-12-01T10:00:00Z"
}

Example:

bash
curl -X POST https://manager.example.com/api/machine/register-backend \
  -H "Authorization: Bearer muser_abc123..." \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Payment Service",
    "callbackUrl": "https://payment.example.com/triggers/callback",
    "description": "Handles payment processing triggers"
  }'

Error Responses

All REST endpoints return standard HTTP status codes:

Success Codes

  • 200 OK - Request successful
  • 201 Created - Resource created successfully

Client Error Codes

  • 400 Bad Request - Invalid request format or parameters
  • 401 Unauthorized - Missing or invalid authentication
  • 403 Forbidden - Insufficient permissions
  • 404 Not Found - Resource not found

Server Error Codes

  • 500 Internal Server Error - Server-side error occurred

Error Response Format

json
{
  "error": "Error message",
  "code": "ERROR_CODE",
  "status": 400
}

Example Error:

json
{
  "error": "Invalid machine user credentials",
  "code": "INVALID_CREDENTIALS",
  "status": 401
}

Usage Patterns

Machine User Registration Flow

bash
#!/bin/bash

# 1. Create machine user (via GraphQL)
RESPONSE=$(curl -X POST https://manager.example.com/query \
  -H "Authorization: Bearer $USER_PAT" \
  -H "Content-Type: application/json" \
  -d '{
    "query": "mutation { createMachineUserWithCredentials(tenantId: \"'$TENANT_ID'\", input: { name: \"Backend Service\", username: \"backend\", hashedKey: \"__GENERATE_TOKEN__\", enabled: true }) { generatedToken machineUser { id } } }"
  }')

MACHINE_TOKEN=$(echo $RESPONSE | jq -r '.data.createMachineUserWithCredentials.generatedToken')

# 2. Verify authentication
curl -X GET https://manager.example.com/api/machine/check \
  -H "Authorization: Bearer $MACHINE_TOKEN"

# 3. Register backend for triggers
curl -X POST https://manager.example.com/api/machine/register-backend \
  -H "Authorization: Bearer $MACHINE_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Backend Service",
    "callbackUrl": "https://backend.example.com/triggers/callback"
  }'

Health Check Integration

Use the check endpoint for health monitoring:

javascript
// Health check endpoint
app.get("/health", async (req, res) => {
  try {
    const response = await fetch(
      "https://manager.example.com/api/machine/check",
      {
        headers: {
          Authorization: `Bearer ${process.env.MACHINE_TOKEN}`,
        },
      }
    );

    if (response.ok) {
      const data = await response.json();
      res.json({
        status: "healthy",
        authenticated: data.authenticated,
      });
    } else {
      res.status(503).json({ status: "unhealthy" });
    }
  } catch (error) {
    res.status(503).json({
      status: "unhealthy",
      error: error.message,
    });
  }
});

Best Practices

Error Handling

Always handle errors gracefully:

javascript
async function validateMachineUser(username, token) {
  try {
    const response = await fetch(
      "https://manager.example.com/api/validate-machine-user",
      {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ username, token }),
      }
    );

    if (!response.ok) {
      throw new Error(`HTTP ${response.status}: ${response.statusText}`);
    }

    const data = await response.json();
    return data.valid;
  } catch (error) {
    console.error("Validation failed:", error);
    return false;
  }
}

Retry Logic

Implement retries for transient failures:

python
import requests
from requests.adapters import HTTPAdapter
from requests.packages.urllib3.util.retry import Retry

def create_session_with_retries():
    session = requests.Session()

    retry = Retry(
        total=3,
        backoff_factor=1,
        status_forcelist=[500, 502, 503, 504]
    )

    adapter = HTTPAdapter(max_retries=retry)
    session.mount('http://', adapter)
    session.mount('https://', adapter)

    return session

# Use the session
session = create_session_with_retries()
response = session.get(
    'https://manager.example.com/api/machine/check',
    headers={'Authorization': f'Bearer {token}'}
)

Timeout Configuration

Set appropriate timeouts:

javascript
const response = await fetch("https://manager.example.com/api/machine/check", {
  headers: { Authorization: `Bearer ${token}` },
  signal: AbortSignal.timeout(5000), // 5 second timeout
});

Migration from GraphQL

While the GraphQL API provides comprehensive functionality, REST endpoints are provided for specific use cases:

Use REST when:

  • Implementing Proxy authentication
  • Simple machine user validation needed
  • Backend registration for triggers
  • Lightweight health checks

Use GraphQL when:

  • Managing complex resources
  • Querying related data
  • Batch operations
  • Type-safe API interactions

API Client Examples

Node.js

javascript
class ManagerRestClient {
  constructor(baseUrl, token) {
    this.baseUrl = baseUrl;
    this.token = token;
  }

  async checkAuth() {
    const response = await fetch(`${this.baseUrl}/api/machine/check`, {
      headers: { Authorization: `Bearer ${this.token}` },
    });
    return response.json();
  }

  async registerBackend(name, callbackUrl, description) {
    const response = await fetch(
      `${this.baseUrl}/api/machine/register-backend`,
      {
        method: "POST",
        headers: {
          Authorization: `Bearer ${this.token}`,
          "Content-Type": "application/json",
        },
        body: JSON.stringify({ name, callbackUrl, description }),
      }
    );
    return response.json();
  }
}

// Usage
const client = new ManagerRestClient("https://manager.example.com", token);
await client.checkAuth();

Python

python
import requests

class ManagerRestClient:
    def __init__(self, base_url, token):
        self.base_url = base_url
        self.token = token
        self.headers = {'Authorization': f'Bearer {token}'}

    def check_auth(self):
        response = requests.get(
            f'{self.base_url}/api/machine/check',
            headers=self.headers
        )
        return response.json()

    def register_backend(self, name, callback_url, description=''):
        response = requests.post(
            f'{self.base_url}/api/machine/register-backend',
            headers={**self.headers, 'Content-Type': 'application/json'},
            json={
                'name': name,
                'callbackUrl': callback_url,
                'description': description
            }
        )
        return response.json()

# Usage
client = ManagerRestClient('https://manager.example.com', token)
client.check_auth()

Go

go
package main

import (
    "bytes"
    "encoding/json"
    "net/http"
)

type ManagerRestClient struct {
    BaseURL string
    Token   string
    Client  *http.Client
}

func (c *ManagerRestClient) CheckAuth() (map[string]interface{}, error) {
    req, _ := http.NewRequest("GET", c.BaseURL+"/api/machine/check", nil)
    req.Header.Set("Authorization", "Bearer "+c.Token)

    resp, err := c.Client.Do(req)
    if err != nil {
        return nil, err
    }
    defer resp.Body.Close()

    var result map[string]interface{}
    json.NewDecoder(resp.Body).Decode(&result)
    return result, nil
}

func (c *ManagerRestClient) RegisterBackend(name, callbackURL, description string) (map[string]interface{}, error) {
    body := map[string]string{
        "name":        name,
        "callbackUrl": callbackURL,
        "description": description,
    }

    jsonBody, _ := json.Marshal(body)
    req, _ := http.NewRequest("POST", c.BaseURL+"/api/machine/register-backend", bytes.NewBuffer(jsonBody))
    req.Header.Set("Authorization", "Bearer "+c.Token)
    req.Header.Set("Content-Type", "application/json")

    resp, err := c.Client.Do(req)
    if err != nil {
        return nil, err
    }
    defer resp.Body.Close()

    var result map[string]interface{}
    json.NewDecoder(resp.Body).Decode(&result)
    return result, nil
}

See Also