ApprovalMatrix
REST API

Integrate approval workflows into any system

Connect your ERP, HR platform, or ticketing system to route approvals through your existing matrix — without changing your core systems.

REST

JSON API

60/min

Rate limit

v1

Stable API

How it works

Four steps from zero to live approval routing in your system.

1

Get an API key

Create a key from your settings panel. Scope it to requests:write and requests:read.

2

Map your employees

Each member has an externalRef — your system's employee ID. Use it as submitterRef in requests.

3

Submit requests

POST to /v1/requests with your metadata. The platform finds the matching approval matrix automatically.

4

Poll or webhook

Check status with GET /v1/requests/:id. Webhooks coming soon for real-time push notifications.

API Reference

All endpoints are under https://api.yourapp.com and return JSON.

POST /v1/requests Submit a new approval request

Headers

Authorization: Bearer apx_live_YOUR_KEY
Content-Type: application/json

Request body

{
  "submitterRef": "EMP-1042",
  "requestType": "purchase_order",
  "title": "Office Supplies Q3",
  "amount": 4500,
  "currency": "USD",
  "metadata": {
    "department": "Engineering",
    "poNumber": "PO-9871"
  }
}

Response 201 Created

{
  "requestId": "req_abc123",
  "status": "pending",
  "matrixId": "mat_xyz789",
  "createdAt": "2025-01-15T10:30:00Z"
}
Field Type Required
submitterRefstringYes
requestTypestringYes
titlestringYes
amountnumberNo
currencystringNo
metadataobjectNo

Code examples

# Submit a new approval request
curl -X POST https://api.yourapp.com/v1/requests \
  -H "Authorization: Bearer apx_live_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{"submitterRef":"EMP-1042","requestType":"purchase_order","title":"Office Supplies Q3","amount":4500}'
// Submit a new approval request
const res = await fetch('https://api.yourapp.com/v1/requests', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer apx_live_YOUR_KEY',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    submitterRef: 'EMP-1042',
    requestType: 'purchase_order',
    title: 'Office Supplies Q3',
    amount: 4500,
  }),
});
const { requestId, status } = await res.json();
import requests

resp = requests.post(
    'https://api.yourapp.com/v1/requests',
    headers={'Authorization': 'Bearer apx_live_YOUR_KEY'},
    json={
        'submitterRef': 'EMP-1042',
        'requestType': 'purchase_order',
        'title': 'Office Supplies Q3',
        'amount': 4500,
    }
)
data = resp.json()
GET /v1/requests/:requestId Get current status of a request

Headers

Authorization: Bearer apx_live_YOUR_KEY

Path parameters

Param Description
requestIdThe ID returned when the request was created (e.g. req_abc123)

Status values

pending in_progress approved rejected cancelled

Response 200 OK

{
  "requestId": "req_abc123",
  "status": "approved",
  "title": "Office Supplies Q3",
  "submitterRef": "EMP-1042",
  "currentStage": null,
  "totalStages": 2,
  "decisions": [
    {
      "stage": 1,
      "decidedBy": "Jane Smith",
      "decision": "approved",
      "decidedAt": "2025-01-15T11:00:00Z"
    },
    {
      "stage": 2,
      "decidedBy": "Bob Lee",
      "decision": "approved",
      "decidedAt": "2025-01-15T14:22:00Z"
    }
  ]
}

Code examples

curl https://api.yourapp.com/v1/requests/req_abc123 \
  -H "Authorization: Bearer apx_live_YOUR_KEY"
const res = await fetch('https://api.yourapp.com/v1/requests/req_abc123', {
  headers: { 'Authorization': 'Bearer apx_live_YOUR_KEY' },
});
const request = await res.json();
import requests

resp = requests.get(
    'https://api.yourapp.com/v1/requests/req_abc123',
    headers={'Authorization': 'Bearer apx_live_YOUR_KEY'},
)
data = resp.json()
POST /v1/requests/test Dry-run Validate payload without creating a request

Integration testing endpoint

Accepts the same payload as POST /v1/requests. Validates your data, resolves the matching approval matrix, and returns what a real request would look like — without creating anything or notifying any approvers.

Request body

Same fields as POST /v1/requests.

Response 200 OK

{
  "requestId": null,
  "status": "pending",
  "matrixId": "mat_xyz789",
  "matrixName": "Engineering PO Matrix",
  "dryRun": true,
  "createdAt": null
}

Code examples

# Dry-run: validate without creating
curl -X POST https://api.yourapp.com/v1/requests/test \
  -H "Authorization: Bearer apx_live_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{"submitterRef":"EMP-1042","requestType":"purchase_order","title":"Office Supplies Q3","amount":4500}'
// Dry-run: validate without creating
const res = await fetch('https://api.yourapp.com/v1/requests/test', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer apx_live_YOUR_KEY',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    submitterRef: 'EMP-1042',
    requestType: 'purchase_order',
    title: 'Office Supplies Q3',
    amount: 4500,
  }),
});
const { matrixName, dryRun } = await res.json();
# Dry-run: validate without creating
import requests

resp = requests.post(
    'https://api.yourapp.com/v1/requests/test',
    headers={'Authorization': 'Bearer apx_live_YOUR_KEY'},
    json={
        'submitterRef': 'EMP-1042',
        'requestType': 'purchase_order',
        'title': 'Office Supplies Q3',
        'amount': 4500,
    }
)
data = resp.json()  # data['dryRun'] == True

Authentication & Security

Everything you need to know about keeping your integration secure.

API key format

All keys start with apx_live_ followed by a 32-character cryptographically random string.

Authorization header

Send your key in every request as Authorization: Bearer apx_live_.... Query-string auth is not supported.

Tenant isolation

Keys are strictly scoped to your tenant. A key cannot read or write data belonging to any other organization — ever.

Rate limiting

60 requests per minute per API key. Exceeding the limit returns HTTP 429 Too Many Requests with a Retry-After header.

Instant revocation

Revoke any key immediately from your settings panel. Revoked keys become invalid within milliseconds — no propagation delay.

Never commit keys

Do not hardcode keys in source code or commit them to version control. Always load keys from environment variables or a secrets manager.

Recommended: load from environment

# .env (never commit this file)
APPROVALMATRIX_API_KEY=apx_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

# Node.js
const apiKey = process.env.APPROVALMATRIX_API_KEY;

# Python
import os
api_key = os.environ["APPROVALMATRIX_API_KEY"]

Ready to integrate?

Create your account and generate your first API key in minutes.