Pass-through integration for local government · records are never stored System status1-559-251-7767Sentra familySign in
SentraBridgeIntegration platform
DevelopersOpenAPI 3.1.0 · API version 1.0

API reference

The 41 endpoints SentraBridge supports, grouped by area. Each one shows the least role a token needs, its limit, a request you can paste and a real answer.

Answers hold settings, counts, record IDs and redacted errors, never record contents. Addresses not listed here are internal to the web app and can change without notice. Examples use $SENTRABRIDGE_URL (https://app.sentrabridge.com) and $SENTRABRIDGE_TOKEN.

Identity

Who the token is, and the session a write call needs.

GET /v1/me

Who am I. The token's person, its workspace and the role it is acting with. user.role is the lower of the person's role and the token's limit. A good first call to check a token.

  • Minimum roleAny role
  • Rate limitNo fixed limit
Request: Who am I
curl -s "$SENTRABRIDGE_URL/v1/me" \
  -H "Authorization: Bearer $SENTRABRIDGE_TOKEN"

200 The person, the workspace and the role in use.

Example answer (application/json, real, shortened)
Answer: Who am I
{
  "auth": "local",
  "user": {
    "id": 3,
    "name": "Alex Rivera",
    "email": "[email protected]",
    "platform_admin": false,
    "must_change_password": false,
    "role": "admin",
    "mfa_enabled": false,
    "mfa_setup_required": false,
    "mfa_clerk_required": false,
    "signed_in_with": "password",
    "departments": null
  },
  "workspace": {
    "id": "01m74hqe1m08znmjtembcq6sf7",
    "name": "City of Demo",
    "timezone": "America/Los_Angeles",
    "status": "active",
    "alert_emails": [],
    "alert_on": "failed",
    "status_page": true,
    "slug": "city-of-demo",
    "require_mfa": false,
    "departments": [],
    "ai_enabled": true,
    "ai_records": false,
    "ai_available": true
  },
  "workspaces": [
    {
      "id": "01m74hqe1m08znmjtembcq6sf7",
      "name": "City of Demo",
      "status": "active",
      "role": "admin"
    },
    {
      "id": "01m75mava07vbsmk78aa8vnyhm",
      "name": "City of Demo (Test)",
      "status": "active",
      "role": "admin"
    }
  ],
  "version": "0.2.0"
}
Errors
  • 401 The API token is missing, wrong, expired or revoked.

GET /v1/auth/csrf

Start a session for write calls. Sets two cookies: a session cookie and XSRF-TOKEN. Calls that change something (POST, PATCH) must send both cookies back, plus the URL-decoded XSRF-TOKEN value in an X-XSRF-TOKEN header, next to the bearer token. Read calls need only the token. The session lasts two hours; on a 419 answer, call this again.

  • Minimum roleNo token
  • Rate limitNo fixed limit
Request: Start a session for write calls
curl -s "$SENTRABRIDGE_URL/v1/auth/csrf" \
  -c cookies.txt

204 No body. The cookies are in the Set-Cookie headers.

Flows

List, read, describe, move as YAML, run, and turn flows on or off.

GET /v1/flows

List flows. Every flow in the workspace, most recently changed first: name, trigger, schedule, on or off, and the last run. Not paged: all flows are returned.

  • Minimum roleViewer
  • Rate limitNo fixed limit
Request: List flows
curl -s "$SENTRABRIDGE_URL/v1/flows" \
  -H "Authorization: Bearer $SENTRABRIDGE_TOKEN"

200 All flows.

Example answer (application/json, real, shortened)
Answer: List flows
{
  "data": [
    {
      "id": "01m75v8y18hknat4d18ahm7m1a",
      "name": "New pothole requests become Scheduler visits",
      "description": "Every 15 minutes, takes new or changed pothole requests from Sentra 311 and creates a visit for the street repair crew in Sentra Scheduler.",
      "enabled": false,
      "trigger": "trigger.schedule",
      "schedule": "*/15 * * * *",
      "steps": 5,
      "connectors": [
        "01m74hqe33cy19f80c393jnpz7",
        "01m74hqe33cy19f80c393jnpz8"
      ],
      "next_run_at": null,
      "last_run_at": "2026-11-11T21:46:12+00:00",
      "last_status": "ok",
      "version": 1,
      "template": "311-potholes-to-scheduler",
      "updated_at": "2026-11-11T21:46:12+00:00",
      "last_success_at": "2026-11-11T21:46:11+00:00",
      "department": null
    },
    {
      "id": "01m761r01x3qf1macy3wfkp3k1",
      "name": "Post severe weather alerts on the city website",
      "description": "Every 15 minutes, takes severe or extreme National Weather Service alerts for your state and posts them as website alerts in Sentra CMS.",
      "enabled": false,
      "trigger": "trigger.schedule",
      "schedule": "*/15 * * * *",
      "steps": 5,
      "connectors": [
        "01m74mfya73ey4wz1snyrtapfc",
        "01m74hqe35wmejccfkdanf375r"
      ],
      "next_run_at": null,
      "last_run_at": null,
      "last_status": null,
      "version": 2,
      "template": "nws-alerts-to-cms",
      "updated_at": "2026-11-11T19:36:01+00:00",
      "last_success_at": null,
      "department": null
    }
  ]
}
Errors
  • 401 The API token is missing, wrong, expired or revoked.
  • 403 The token's role is below viewer, or the caller's address is not allowed.

GET /v1/flows/{id}

Get a flow. One flow with its steps and wires (graph), anything that would stop it running (problems) and its notifications. Step settings are included; saved secrets are named in secrets_saved, never returned. For a webhook flow, webhook_url is its private address: treat it like a password.

  • Minimum roleViewer
  • Rate limitNo fixed limit
Parameters of Get a flow
NameInTypeRequiredWhat it is
idpathstringYesFlow ID.
Request: Get a flow
curl -s "$SENTRABRIDGE_URL/v1/flows/$FLOW_ID" \
  -H "Authorization: Bearer $SENTRABRIDGE_TOKEN"

200 The flow.

Example answer (application/json, real, shortened)
Answer: Get a flow
{
  "data": {
    "id": "01m75v8y18hknat4d18ahm7m1a",
    "name": "New pothole requests become Scheduler visits",
    "description": "Every 15 minutes, takes new or changed pothole requests from Sentra 311 and creates a visit for the street repair crew in Sentra Scheduler.",
    "enabled": false,
    "trigger": "trigger.schedule",
    "schedule": "*/15 * * * *",
    "steps": 5,
    "connectors": [
      "01m74hqe33cy19f80c393jnpz7",
      "01m74hqe33cy19f80c393jnpz8"
    ],
    "next_run_at": null,
    "last_run_at": "2026-11-11T21:46:12+00:00",
    "last_status": "ok",
    "version": 1,
    "template": "311-potholes-to-scheduler",
    "updated_at": "2026-11-11T21:46:12+00:00",
    "last_success_at": "2026-11-11T21:46:11+00:00",
    "department": null,
    "graph": {
      "nodes": [
        {
          "id": "start",
          "type": "trigger.schedule",
          "position": {
            "x": 40,
            "y": 160
          },
          "data": {
            "label": "Every 15 minutes",
            "config": {
              "cron": "*/15 * * * *"
            },
            "note": ""
          }
        },
        {
          "id": "read",
          "type": "source.read",
          "position": {
            "x": 300,
            "y": 160
          },
          "data": {
            "label": "Changed 311 requests",
            "config": {
              "connection_id": "01m74hqe33cy19f80c393jnpz7",
              "resource": "requests",
              "only_changed": true,
              "max_records": 500
            },
            "note": ""
          }
        }
      ],
      "edges": [
        {
          "id": "start-read",
          "source": "start",
          "target": "read",
          "sourceHandle": null
        },
        {
          "id": "read-pothole",
          "source": "read",
          "target": "pothole",
          "sourceHandle": null
        }
      ]
    },
    "webhook_url": null,
    "problems": [],
    "secrets_saved": [],
    "public_status": false,
    "notify": {
      "on": [],
      "emails": []
    }
  }
}
Errors
  • 401 The API token is missing, wrong, expired or revoked.
  • 403 The token's role is below viewer, or the caller's address is not allowed.
  • 404 Nothing with that ID in this workspace.

PATCH /v1/flows/{id}

Turn a flow on or off, or rename it. Send only what should change. Turning a flow on is refused with 422 while it has problems, or when the workspace requires passing tests and they do not pass. The change is written to the activity log. The web app also sends graph here; its format is not part of the supported API, so change steps with YAML import instead.

  • Minimum roleBuilder
  • Rate limitNo fixed limit
Parameters of Turn a flow on or off, or rename it
NameInTypeRequiredWhat it is
idpathstringYesFlow ID.
JSON body of Turn a flow on or off, or rename it
FieldTypeRequiredWhat it is
enabledbooleanNotrue turns the flow on, false turns it off.
namestringNoNew name, up to 120 characters.
descriptionstringNoNew description, up to 1,000 characters.
Request: Turn a flow on or off, or rename it
curl -s -X PATCH "$SENTRABRIDGE_URL/v1/flows/$FLOW_ID" \
  -H "Authorization: Bearer $SENTRABRIDGE_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"enabled": true}'

200 The flow after the change.

Example answer (application/json, real, shortened)
Answer: Turn a flow on or off, or rename it
{
  "data": {
    "id": "01m769behch8x1ym13ssqct3xv",
    "name": "Data quality alert (sub-flow)",
    "description": "A reusable sub-flow: other flows hand it the records that failed their checks, and it emails the data team a summary with a CSV attached.",
    "enabled": true,
    "trigger": "trigger.manual",
    "schedule": null,
    "steps": 3,
    "connectors": [],
    "next_run_at": null,
    "last_run_at": null,
    "last_status": null,
    "version": 1,
    "template": "data-quality-alert",
    "updated_at": "2026-11-11T21:48:47+00:00",
    "last_success_at": null,
    "department": null,
    "graph": {
      "nodes": [
        {
          "id": "t",
          "type": "trigger.manual",
          "position": {
            "x": 40,
            "y": 160
          },
          "data": {
            "label": "Records from another flow",
            "config": [],
            "note": ""
          }
        },
        {
          "id": "lim",
          "type": "transform.limit",
          "position": {
            "x": 330,
            "y": 160
          },
          "data": {
            "label": "First 500",
            "config": {
              "count": 500
            },
            "note": ""
          }
        }
      ],
      "edges": [
        {
          "id": "t-lim-out",
          "source": "t",
          "target": "lim",
          "sourceHandle": null
        },
        {
          "id": "lim-mail-out",
          "source": "lim",
          "target": "mail",
          "sourceHandle": null
        }
      ]
    },
    "webhook_url": null,
    "problems": [],
    "secrets_saved": [],
    "public_status": false,
    "notify": {
      "on": [],
      "emails": []
    }
  }
}
Errors
  • 401 The API token is missing, wrong, expired or revoked.
  • 403 The token's role is below builder, or the caller's address is not allowed.
  • 404 Nothing with that ID in this workspace.
  • 422 The flow cannot be turned on yet. problems lists what to fix, or tests_required is true.

GET /v1/flows/{id}/describe

Describe a flow in plain English. What starts the flow, what each step does and which systems it reads and writes, written from its settings. No AI is used and no records are read.

  • Minimum roleViewer
  • Rate limitNo fixed limit
Parameters of Describe a flow in plain English
NameInTypeRequiredWhat it is
idpathstringYesFlow ID.
Request: Describe a flow in plain English
curl -s "$SENTRABRIDGE_URL/v1/flows/$FLOW_ID/describe" \
  -H "Authorization: Bearer $SENTRABRIDGE_TOKEN"

200 A summary, the systems involved and one sentence per step.

Example answer (application/json, real, shortened)
Answer: Describe a flow in plain English
{
  "summary": "Every 15 minutes, takes new or changed pothole requests from Sentra 311 and creates a visit for the street repair crew in Sentra Scheduler. It works with Sentra 311 (sandbox) and Sentra Scheduler (sandbox). It has 5 steps, 1 of them sending or writing somewhere. It is off.",
  "trigger": "Starts every 15 minutes (America/Los_Angeles).",
  "systems": [
    "Sentra 311 (sandbox)",
    "Sentra Scheduler (sandbox)"
  ],
  "steps": [
    {
      "id": "start",
      "label": "Every 15 minutes",
      "type": "trigger.schedule",
      "step": "On a schedule",
      "text": "Starts every 15 minutes (America/Los_Angeles).",
      "after": [
        "Changed 311 requests"
      ]
    },
    {
      "id": "read",
      "label": "Changed 311 requests",
      "type": "source.read",
      "step": "Get records",
      "text": "Reads service requests from Sentra 311 (sandbox), only the ones that changed since the last good run, up to 500 at a time.",
      "after": [
        "Open potholes"
      ]
    }
  ],
  "text": "New pothole requests become Scheduler visits\n\nEvery 15 minutes, takes new or changed pothole requests from Sentra 311 and creates a visit for the street repair crew in Sentra Scheduler. It works with Sentra 311 (sandbox) and Sentra Scheduler (sandbox). It has 5 steps, 1 of them sending or writing somewhere. It is off.\n\n1. Every 15 minutes (On a schedule): Starts every 15 minutes (America/Los_Angeles).\n2. Changed 311 requests (Get records): Reads service requests from Sentra 311 (sandbox), only the ones that changed since the last good run, up to 500 at a time.\n3. Open potholes (Filter): Keeps …"
}
Errors
  • 401 The API token is missing, wrong, expired or revoked.
  • 403 The token's role is below viewer, or the caller's address is not allowed.
  • 404 Nothing with that ID in this workspace.

GET /v1/flows/{id}/export

Export a flow as YAML. The whole flow as a SentraBridge flow file, for version control or moving between workspaces. Connections appear by name, never their keys. Saved secrets are left out. Tests are included.

  • Minimum roleViewer
  • Rate limitNo fixed limit
Parameters of Export a flow as YAML
NameInTypeRequiredWhat it is
idpathstringYesFlow ID.
Request: Export a flow as YAML
curl -s "$SENTRABRIDGE_URL/v1/flows/$FLOW_ID/export" \
  -H "Authorization: Bearer $SENTRABRIDGE_TOKEN"

200 The flow file.

Example answer (application/yaml, real, shortened)
Answer: Export a flow as YAML
# SentraBridge flow. Connections are named, never their keys: import matches them in the target client.
sentrabridge: 1
name: 'Copy 311 requests into the city database, with map points'
description: 'Every 15 minutes, upserts new and changed Sentra 311 requests into a PostGIS table, with a map point built from latitude and longitude.'
exported: '2026-11-11T21:48:46+00:00'
connections:
  sentra_311_sandbox:
    connector: sentra311
    name: 'Sentra 311 (sandbox)'
  city_database_sandbox:
    connector: postgres
    name: 'City database (sandbox)'
steps:
  -
    id: start
    type: trigger.schedule
    label: 'Every 15 minutes'
    at:
      - 40
      - 160
    settings:
      cron: '*/15 * * * *'
  -
    id: read
…
Errors
  • 401 The API token is missing, wrong, expired or revoked.
  • 403 The token's role is below viewer, or the caller's address is not allowed.
  • 404 Nothing with that ID in this workspace.

POST /v1/flows/import

Import a flow from YAML. Makes a new flow from a flow file. It is always created turned off. Connections are matched by connector and name in this workspace; notes says what was matched or made. Importing the same file twice makes two flows.

  • Minimum roleBuilder
  • Rate limitNo fixed limit
JSON body of Import a flow from YAML
FieldTypeRequiredWhat it is
yamlstringYesThe flow file, starting with "sentrabridge: 1". Up to 1 MB.
Request: Import a flow from YAML
curl -s -X POST "$SENTRABRIDGE_URL/v1/flows/import" \
  -H "Authorization: Bearer $SENTRABRIDGE_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"yaml": "sentrabridge: 1\nname: '\''Nightly permit export'\''\nsteps:\n  - {id: start, type: trigger.manual, label: '\''Run by hand'\'', at: [40, 160]}\n"}'

201 The new flow and import notes.

Example answer (application/json, real, shortened)
Answer: Import a flow from YAML
{
  "data": {
    "id": "01m769bjp928n7vqvkaezxh05w",
    "name": "API reference sample",
    "description": "Every 15 minutes, upserts new and changed Sentra 311 requests into a PostGIS table, with a map point built from latitude and longitude.",
    "enabled": false,
    "trigger": "trigger.schedule",
    "schedule": "*/15 * * * *",
    "steps": 4,
    "connectors": [
      "01m74hqe33cy19f80c393jnpz7",
      "01m74knwpc7xd4424q3ybrqf3b"
    ],
    "next_run_at": null,
    "last_run_at": null,
    "last_status": null,
    "version": 1,
    "template": null,
    "updated_at": "2026-11-11T21:48:51+00:00",
    "last_success_at": null,
    "department": null,
    "graph": {
      "nodes": [
        {
          "id": "start",
          "type": "trigger.schedule",
          "position": {
            "x": 40,
            "y": 160
          },
          "data": {
            "label": "Every 15 minutes",
            "config": {
              "cron": "*/15 * * * *"
            },
            "note": ""
          }
        },
        {
          "id": "read",
          "type": "source.read",
          "position": {
            "x": 300,
            "y": 160
          },
          "data": {
            "label": "Changed 311 requests",
            "config": {
              "resource": "requests",
              "only_changed": true,
              "connection_id": "01m74hqe33cy19f80c393jnpz7"
            },
            "note": ""
          }
        }
      ],
      "edges": [
        {
          "id": "start-read-out",
          "source": "start",
          "target": "read",
          "sourceHandle": null
        },
        {
          "id": "read-map-out",
          "source": "read",
          "target": "map",
          "sourceHandle": null
        }
      ]
    },
    "webhook_url": null,
    "problems": [],
    "secrets_saved": [],
    "public_status": false,
    "notify": {
      "on": [],
      "emails": []
    }
  },
  "notes": [
    "Added 1 test(s)."
  ]
}
Errors
  • 401 The API token is missing, wrong, expired or revoked.
  • 403 The token's role is below builder, or the caller's address is not allowed.
  • 422 The file is not a valid flow file. message says why.

POST /v1/flows/{id}/run

Run a flow now. Starts the flow by hand, whether it is on or off, and answers at once with the new run in queued state. Poll "Get a run" until status is ok, partial or failed.

  • Minimum roleBuilder
  • Rate limit30 a minute per person
Parameters of Run a flow now
NameInTypeRequiredWhat it is
idpathstringYesFlow ID.
Request: Run a flow now
curl -s -X POST "$SENTRABRIDGE_URL/v1/flows/$FLOW_ID/run" \
  -H "Authorization: Bearer $SENTRABRIDGE_TOKEN"

202 The run that was started.

Example answer (application/json, real, shortened)
Answer: Run a flow now
{
  "data": {
    "id": "01m769ben0mnkzwcdmyjy6aqsv",
    "flow_id": "01m769behch8x1ym13ssqct3xv",
    "flow_name": "Data quality alert (sub-flow)",
    "flow_version": 1,
    "trigger": "manual",
    "status": null,
    "replay_of": null,
    "replay_count": 0,
    "created_at": "2026-11-11T21:48:47+00:00",
    "started_at": null,
    "finished_at": null,
    "duration_ms": null,
    "records_in": null,
    "records_out": null,
    "records_failed": null,
    "error": null
  }
}
Errors
  • 401 The API token is missing, wrong, expired or revoked.
  • 403 The token's role is below builder, or the caller's address is not allowed.
  • 404 Nothing with that ID in this workspace.
  • 422 The flow has problems and cannot run. problems lists them.
  • 429 More than 30 calls in a minute. See the Retry-After header.

GET /v1/flows/{id}/runs

List a flow's runs. The flow's 50 most recent runs, newest first.

  • Minimum roleViewer
  • Rate limitNo fixed limit
Parameters of List a flow's runs
NameInTypeRequiredWhat it is
idpathstringYesFlow ID.
Request: List a flow's runs
curl -s "$SENTRABRIDGE_URL/v1/flows/$FLOW_ID/runs" \
  -H "Authorization: Bearer $SENTRABRIDGE_TOKEN"

200 Up to 50 runs.

Example answer (application/json, real, shortened)
Answer: List a flow's runs
{
  "data": [
    {
      "id": "01m75tbvcqvmw773q9fgb66h96",
      "flow_id": "01m74ksfj3gg6fvx6yvsv2g3w9",
      "flow_name": "Copy 311 requests into the city database, with map points",
      "flow_version": 1,
      "trigger": "manual",
      "status": "ok",
      "replay_of": null,
      "replay_count": 0,
      "created_at": "2026-11-11T17:26:51+00:00",
      "started_at": "2026-11-11T17:26:52+00:00",
      "finished_at": "2026-11-11T17:26:52+00:00",
      "duration_ms": 99,
      "records_in": 41,
      "records_out": 41,
      "records_failed": 0,
      "error": null
    },
    {
      "id": "01m74kssqx334fnx1tvs6mmt5j",
      "flow_id": "01m74ksfj3gg6fvx6yvsv2g3w9",
      "flow_name": "Copy 311 requests into the city database, with map points",
      "flow_version": 1,
      "trigger": "manual",
      "status": "ok",
      "replay_of": null,
      "replay_count": 0,
      "created_at": "2026-11-11T06:12:54+00:00",
      "started_at": "2026-11-11T06:12:54+00:00",
      "finished_at": "2026-11-11T06:12:54+00:00",
      "duration_ms": 95,
      "records_in": 40,
      "records_out": 40,
      "records_failed": 0,
      "error": null
    }
  ]
}
Errors
  • 401 The API token is missing, wrong, expired or revoked.
  • 403 The token's role is below viewer, or the caller's address is not allowed.
  • 404 Nothing with that ID in this workspace.

Flow tests

Saved tests run in dry mode: made-up records in, nothing written or sent.

GET /v1/flows/{id}/tests

List a flow's tests. The saved tests of a flow, with their made-up input records, expectations and last result. Test records are made up by the person who wrote the test; they are not records from a city system.

  • Minimum roleViewer
  • Rate limitNo fixed limit
Parameters of List a flow's tests
NameInTypeRequiredWhat it is
idpathstringYesFlow ID.
Request: List a flow's tests
curl -s "$SENTRABRIDGE_URL/v1/flows/$FLOW_ID/tests" \
  -H "Authorization: Bearer $SENTRABRIDGE_TOKEN"

200 The tests, plus what the designer needs to edit them.

Example answer (application/json, real, shortened)
Answer: List a flow's tests
{
  "data": [
    {
      "id": "01m769bjpb8xkzb9gjmq4gekb5",
      "name": "From preview",
      "reads": "mocked",
      "input": {
        "start_at": "read",
        "format": "json",
        "text": "[\n    {\n        \"description\": \"Cgivmq sals vowt (LM-2957)\",\n        \"address\": \"890 Mhlz Dpxk, Hnfu Hsea\",\n        \"source\": \"cyzahskc\",\n        \"external_ref\": \"CS-8320\",\n        \"id\": \"39904s\",\n        \"created_at\": \"2026-11-25T07:13:40+00:00\",\n        \"updated_at\": \"2026-11-25T07:13:40+00:00\",\n        \"number\": \"GBK-82269\",\n        \"status\": \"wkyc\"\n    },\n    {\n        \"id\": \"0622\",\n        \"number\": \"ZHG-26141\",\n        \"status\": \"itznqt\",\n        \"priority\": \"dwnsie\",\n        \"category\": \"Jpmo fxhx\",\n        \"category_id\": \"1\",\n        \"department\": \"Dowwu\",\n        \"assignee\": \"Lmlc Z\",…"
      },
      "records": 5,
      "mocks": {},
      "expectations": [
        {
          "type": "count",
          "node_id": "map",
          "op": "eq",
          "value": 5,
          "output": "out"
        },
        {
          "type": "count",
          "node_id": "write",
          "op": "eq",
          "value": 5,
          "output": "out"
        }
      ],
      "has_snapshot": true,
      "snapshot": {
        "write": [
          {
            "request_id": "39904s",
            "number": "GBK-82269",
            "category": null,
            "department": null,
            "status": "wkyc",
            "address": "890 Mhlz Dpxk, Hnfu Hsea",
            "description": "Cgivmq sals vowt (LM-2957)",
            "created_at": "2026-11-25T07:13:40+00:00",
            "updated_at": "2026-11-25T07:13:40+00:00",
            "lat": null,
            "lng": null
          },
          {
            "request_id": "0622",
            "number": "ZHG-26141",
            "category": "Jpmo fxhx",
            "department": "Dowwu",
            "status": "itznqt",
            "address": "132 Dkxxqjsoqy Kpi, Dgon Cxgt",
            "description": "Amah yonh pndfquoi jhbm sgk gxqarn.",
            "created_at": "2026-11-24T10:36:39+00:00",
            "updated_at": "2026-11-25T05:36:39+00:00",
            "lat": 18.5259,
            "lng": -540.6357
          }
        ]
      },
      "last_status": null,
      "last_passed": null,
      "last_failed": null,
      "last_run_at": null,
      "updated_at": "2026-11-11T21:48:51+00:00"
    }
  ],
  "tests_on_save": false,
  "require_passing_tests": false,
  "default_start": "read",
  "condition_fields": [],
  "mockable": [
    {
      "node_id": "read",
      "label": "Changed 311 requests",
      "type": "source.read",
      "kind": "records"
    }
  ],
  "outputs": {
    "start": {
      "out": "out"
    },
    "read": {
      "out": "out"
    },
    "map": {
      "out": "out"
    },
    "write": {
      "out": "out"
    }
  }
}
Errors
  • 401 The API token is missing, wrong, expired or revoked.
  • 403 The token's role is below viewer, or the caller's address is not allowed.
  • 404 Nothing with that ID in this workspace.

POST /v1/flows/{id}/tests/run

Run all of a flow's tests. Runs every saved test in dry mode: nothing is read from live sources unless the test says so, and nothing is written, sent or emailed. Answers with pass or fail per test and per expectation. Good for a deployment pipeline.

  • Minimum roleBuilder
  • Rate limit60 a minute per person
Parameters of Run all of a flow's tests
NameInTypeRequiredWhat it is
idpathstringYesFlow ID.
Request: Run all of a flow's tests
curl -s -X POST "$SENTRABRIDGE_URL/v1/flows/$FLOW_ID/tests/run" \
  -H "Authorization: Bearer $SENTRABRIDGE_TOKEN"

200 Totals and one result per test. status is passing, failing or none.

Example answer (application/json, real, shortened)
Answer: Run all of a flow's tests
{
  "total": 1,
  "passed": 1,
  "failed": 0,
  "status": "passing",
  "tests": [
    {
      "test_id": "01m769bjpb8xkzb9gjmq4gekb5",
      "name": "From preview",
      "status": "passed",
      "passed": 5,
      "failed": 0,
      "duration_ms": 1,
      "results": [
        {
          "type": "count",
          "label": "Name fields like the columns out = 5",
          "pass": true,
          "message": "Got 5.",
          "diff": {
            "expected": 5,
            "actual": 5
          }
        },
        {
          "type": "count",
          "label": "Upsert into service_requests out = 5",
          "pass": true,
          "message": "Got 5.",
          "diff": {
            "expected": 5,
            "actual": 5
          }
        }
      ],
      "run_id": 15,
      "flow_status": "ok",
      "steps": [
        {
          "node_id": "start",
          "label": "Every 15 minutes",
          "type": "trigger.schedule",
          "status": "ok",
          "records_in": 0,
          "records_out": 1,
          "outputs": {
            "out": 1
          },
          "error": null,
          "note": null,
          "would_send_count": 0,
          "would_send": []
        },
        {
          "node_id": "read",
          "label": "Changed 311 requests",
          "type": "source.read",
          "status": "ok",
          "records_in": 1,
          "records_out": 5,
          "outputs": {
            "out": 5
          },
          "error": null,
          "note": "5 test record(s) handed in here.",
          "would_send_count": 0,
          "would_send": []
        }
      ],
      "output": {
        "write": [
          {
            "request_id": "39904s",
            "number": "GBK-82269",
            "category": null,
            "department": null,
            "status": "wkyc",
            "address": "890 Mhlz Dpxk, Hnfu Hsea",
            "description": "Cgivmq sals vowt (LM-2957)",
            "created_at": "2026-11-25T07:13:40+00:00",
            "updated_at": "2026-11-25T07:13:40+00:00",
            "lat": null,
            "lng": null
          },
          {
            "request_id": "0622",
            "number": "ZHG-26141",
            "category": "Jpmo fxhx",
            "department": "Dowwu",
            "status": "itznqt",
            "address": "132 Dkxxqjsoqy Kpi, Dgon Cxgt",
            "description": "Amah yonh pndfquoi jhbm sgk gxqarn.",
            "created_at": "2026-11-24T10:36:39+00:00",
            "updated_at": "2026-11-25T05:36:39+00:00",
            "lat": 18.5259,
            "lng": -540.6357
          }
        ]
      }
    }
  ]
}
Errors
  • 401 The API token is missing, wrong, expired or revoked.
  • 403 The token's role is below builder, or the caller's address is not allowed.
  • 404 Nothing with that ID in this workspace.
  • 429 More than 60 calls in a minute. See the Retry-After header.

POST /v1/flows/{id}/tests/{test}/run

Run one test. Runs a single saved test in dry mode.

  • Minimum roleBuilder
  • Rate limit60 a minute per person
Parameters of Run one test
NameInTypeRequiredWhat it is
idpathstringYesFlow ID.
testpathstringYesTest ID from "List a flow's tests".
Request: Run one test
curl -s -X POST "$SENTRABRIDGE_URL/v1/flows/$FLOW_ID/tests/$TEST_ID/run" \
  -H "Authorization: Bearer $SENTRABRIDGE_TOKEN"

200 The result of that test.

Example answer (application/json, real, shortened)
Answer: Run one test
{
  "test_id": "01m769bjpb8xkzb9gjmq4gekb5",
  "name": "From preview",
  "status": "passed",
  "passed": 5,
  "failed": 0,
  "duration_ms": 1,
  "results": [
    {
      "type": "count",
      "label": "Name fields like the columns out = 5",
      "pass": true,
      "message": "Got 5.",
      "diff": {
        "expected": 5,
        "actual": 5
      }
    },
    {
      "type": "count",
      "label": "Upsert into service_requests out = 5",
      "pass": true,
      "message": "Got 5.",
      "diff": {
        "expected": 5,
        "actual": 5
      }
    }
  ],
  "run_id": 16,
  "flow_status": "ok",
  "steps": [
    {
      "node_id": "start",
      "label": "Every 15 minutes",
      "type": "trigger.schedule",
      "status": "ok",
      "records_in": 0,
      "records_out": 1,
      "outputs": {
        "out": 1
      },
      "error": null,
      "note": null,
      "would_send_count": 0,
      "would_send": []
    },
    {
      "node_id": "read",
      "label": "Changed 311 requests",
      "type": "source.read",
      "status": "ok",
      "records_in": 1,
      "records_out": 5,
      "outputs": {
        "out": 5
      },
      "error": null,
      "note": "5 test record(s) handed in here.",
      "would_send_count": 0,
      "would_send": []
    }
  ],
  "output": {
    "write": [
      {
        "request_id": "39904s",
        "number": "GBK-82269",
        "category": null,
        "department": null,
        "status": "wkyc",
        "address": "890 Mhlz Dpxk, Hnfu Hsea",
        "description": "Cgivmq sals vowt (LM-2957)",
        "created_at": "2026-11-25T07:13:40+00:00",
        "updated_at": "2026-11-25T07:13:40+00:00",
        "lat": null,
        "lng": null
      },
      {
        "request_id": "0622",
        "number": "ZHG-26141",
        "category": "Jpmo fxhx",
        "department": "Dowwu",
        "status": "itznqt",
        "address": "132 Dkxxqjsoqy Kpi, Dgon Cxgt",
        "description": "Amah yonh pndfquoi jhbm sgk gxqarn.",
        "created_at": "2026-11-24T10:36:39+00:00",
        "updated_at": "2026-11-25T05:36:39+00:00",
        "lat": 18.5259,
        "lng": -540.6357
      }
    ]
  }
}
Errors
  • 401 The API token is missing, wrong, expired or revoked.
  • 403 The token's role is below builder, or the caller's address is not allowed.
  • 404 Nothing with that ID in this workspace.
  • 429 More than 60 calls in a minute. See the Retry-After header.

Runs

Run history, one run step by step, replaying failed records, and tracing a record ID.

GET /v1/runs

List runs. The workspace's 200 most recent runs, newest first. Filter to reach older ones. Each run has counts in, out and failed, timing and a redacted error.

  • Minimum roleViewer
  • Rate limitNo fixed limit
Parameters of List runs
NameInTypeRequiredWhat it is
statusquerystring · one of queued, running, ok, partial, failed, waitingNoOnly runs in this state.
flow_idquerystringNoOnly runs of this flow.
Request: List runs
curl -s "$SENTRABRIDGE_URL/v1/runs?status=failed" \
  -H "Authorization: Bearer $SENTRABRIDGE_TOKEN"

200 Up to 200 runs.

Example answer (application/json, real, shortened)
Answer: List runs
{
  "data": [
    {
      "id": "01m7696pwp3b42x4zxxkqh6ntp",
      "flow_id": "01m75v8y18hknat4d18ahm7m1a",
      "flow_name": "New pothole requests become Scheduler visits",
      "flow_version": 1,
      "trigger": "manual",
      "status": "ok",
      "replay_of": null,
      "replay_count": 0,
      "created_at": "2026-11-11T21:46:11+00:00",
      "started_at": "2026-11-11T21:46:11+00:00",
      "finished_at": "2026-11-11T21:46:12+00:00",
      "duration_ms": 37,
      "records_in": 0,
      "records_out": 0,
      "records_failed": 0,
      "error": null
    },
    {
      "id": "01m768zpfvdv44tnbt25drnr54",
      "flow_id": "01m75v8y18hknat4d18ahm7m1a",
      "flow_name": "New pothole requests become Scheduler visits",
      "flow_version": 1,
      "trigger": "manual",
      "status": "ok",
      "replay_of": null,
      "replay_count": 0,
      "created_at": "2026-11-11T21:42:21+00:00",
      "started_at": "2026-11-11T21:42:22+00:00",
      "finished_at": "2026-11-11T21:42:22+00:00",
      "duration_ms": 117,
      "records_in": 41,
      "records_out": 4,
      "records_failed": 0,
      "error": null
    }
  ]
}
Errors
  • 401 The API token is missing, wrong, expired or revoked.
  • 403 The token's role is below viewer, or the caller's address is not allowed.

GET /v1/runs/{id}

Get a run. One run step by step: counts, the record IDs that moved (source and, once written, target), and failures with their record ID and error. Record contents are not kept, so they are not here.

  • Minimum roleViewer
  • Rate limitNo fixed limit
Parameters of Get a run
NameInTypeRequiredWhat it is
idpathstringYesRun ID.
Request: Get a run
curl -s "$SENTRABRIDGE_URL/v1/runs/$RUN_ID" \
  -H "Authorization: Bearer $SENTRABRIDGE_TOKEN"

200 The run with its steps.

Example answer (application/json, real, shortened)
Answer: Get a run
{
  "data": {
    "id": "01m768zpfvdv44tnbt25drnr54",
    "flow_id": "01m75v8y18hknat4d18ahm7m1a",
    "flow_name": "New pothole requests become Scheduler visits",
    "flow_version": 1,
    "trigger": "manual",
    "status": "ok",
    "replay_of": null,
    "replay_count": 0,
    "created_at": "2026-11-11T21:42:21+00:00",
    "started_at": "2026-11-11T21:42:22+00:00",
    "finished_at": "2026-11-11T21:42:22+00:00",
    "duration_ms": 117,
    "records_in": 41,
    "records_out": 4,
    "records_failed": 0,
    "error": null,
    "steps": [
      {
        "node_id": "start",
        "type": "trigger.schedule",
        "label": "Every 15 minutes",
        "status": "ok",
        "records_in": 0,
        "records_out": 1,
        "records_failed": 0,
        "http_calls": 0,
        "duration_ms": 0,
        "record_ids": [],
        "failures": [],
        "error": null,
        "totals": null
      },
      {
        "node_id": "read",
        "type": "source.read",
        "label": "Changed 311 requests",
        "status": "ok",
        "records_in": 1,
        "records_out": 41,
        "records_failed": 0,
        "http_calls": 1,
        "duration_ms": 32,
        "record_ids": [
          {
            "source": "10411g"
          },
          {
            "source": "5040"
          }
        ],
        "failures": [],
        "error": null,
        "totals": null
      }
    ],
    "replayable_ids": []
  }
}
Errors
  • 401 The API token is missing, wrong, expired or revoked.
  • 403 The token's role is below viewer, or the caller's address is not allowed.
  • 404 Nothing with that ID in this workspace.

POST /v1/runs/{id}/replay

Replay failed records. Reads the failed records again from their source, by ID, and sends them through the flow as a new run. With no body, every failed record of the run is replayed.

  • Minimum roleBuilder
  • Rate limitNo fixed limit
Parameters of Replay failed records
NameInTypeRequiredWhat it is
idpathstringYesRun ID.
JSON body of Replay failed records
FieldTypeRequiredWhat it is
idsarrayNoRecord IDs to replay (up to 500). Default: every failed record of the run.
Request: Replay failed records
curl -s -X POST "$SENTRABRIDGE_URL/v1/runs/$RUN_ID/replay" \
  -H "Authorization: Bearer $SENTRABRIDGE_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"ids": ["REQ-1001", "REQ-1002"]}'

202 The new run.

Example answer (application/json, real, shortened)
Answer: Replay failed records
{
  "data": {
    "id": "01m769bjmpvfwac9ksw2arqp8w",
    "flow_id": "01m769behch8x1ym13ssqct3xv",
    "flow_name": "Data quality alert (sub-flow)",
    "flow_version": 1,
    "trigger": "replay",
    "status": null,
    "replay_of": "01m769ben0mnkzwcdmyjy6aqsv",
    "replay_count": 1,
    "created_at": "2026-11-11T21:48:51+00:00",
    "started_at": null,
    "finished_at": null,
    "duration_ms": null,
    "records_in": null,
    "records_out": null,
    "records_failed": null,
    "error": null
  }
}
Errors
  • 401 The API token is missing, wrong, expired or revoked.
  • 403 The token's role is below builder, or the caller's address is not allowed.
  • 404 Nothing with that ID in this workspace.
  • 422 The run has no failed records with IDs.

GET /v1/trace

Trace a record. Follows one record ID (a permit number, a request ID) through every run that read, sent or failed it, and shows what it became in the next system. Up to 200 hops, newest first.

  • Minimum roleViewer
  • Rate limit60 a minute per person
Parameters of Trace a record
NameInTypeRequiredWhat it is
idquerystringYesThe record's ID in any connected system.
Request: Trace a record
curl -s "$SENTRABRIDGE_URL/v1/trace?id=REQ-1001" \
  -H "Authorization: Bearer $SENTRABRIDGE_TOKEN"

200 The hops, and how many flows and runs were involved.

Example answer (application/json, real, shortened)
Answer: Trace a record
{
  "id": "10411g",
  "hops": [
    {
      "what": "read",
      "source": "10411g",
      "target": null,
      "error": null,
      "step": "Changed 311 requests",
      "type": "source.read",
      "run_id": "01m768zpfvdv44tnbt25drnr54",
      "run_status": "ok",
      "trigger": "manual",
      "flow_id": "01m75v8y18hknat4d18ahm7m1a",
      "flow_name": "New pothole requests become Scheduler visits",
      "at": "2026-11-11T21:42:21+00:00"
    },
    {
      "what": "read",
      "source": "10411g",
      "target": null,
      "error": null,
      "step": "Changed 311 requests",
      "type": "source.read",
      "run_id": "01m75twwnd39jj708g6g25r6sf",
      "run_status": "ok",
      "trigger": "manual",
      "flow_id": "01m75tw3hvy8n0vc7naawnazrf",
      "flow_name": "New pothole requests become Scheduler visits",
      "at": "2026-11-11T17:36:09+00:00"
    }
  ],
  "flows": 7,
  "runs": 11
}
Errors
  • 401 The API token is missing, wrong, expired or revoked.
  • 403 The token's role is below viewer, or the caller's address is not allowed.
  • 429 More than 60 calls in a minute. See the Retry-After header.

Monitoring

Health of the workspace: success rates, slow steps and data-health issues.

GET /v1/monitoring

Workspace health. Runs per day, totals and success rate, results per flow, flows failing right now, the slowest steps and connections that need attention.

  • Minimum roleViewer
  • Rate limitNo fixed limit
Parameters of Workspace health
NameInTypeRequiredWhat it is
daysqueryinteger · one of 7, 14, 30, 90NoHow many days to look back. Default 14.
Request: Workspace health
curl -s "$SENTRABRIDGE_URL/v1/monitoring?days=7" \
  -H "Authorization: Bearer $SENTRABRIDGE_TOKEN"

200 Health over the chosen days.

Example answer (application/json, real, shortened)
Answer: Workspace health
{
  "days": 7,
  "timezone": "America/Los_Angeles",
  "daily": [
    {
      "date": "2026-11-05",
      "ok": 0,
      "partial": 0,
      "failed": 0,
      "records": 0
    },
    {
      "date": "2026-11-06",
      "ok": 0,
      "partial": 0,
      "failed": 0,
      "records": 0
    }
  ],
  "totals": {
    "runs": 51,
    "ok": 51,
    "partial": 0,
    "failed": 0,
    "success_rate": 100,
    "records": 667,
    "records_failed": 0,
    "avg_ms": 147,
    "p95_ms": 454,
    "running": 0
  },
  "flows": [
    {
      "id": "01m74hqe3jjn4tpavrv5j4hp84",
      "name": "New pothole requests become Scheduler visits",
      "enabled": false,
      "runs": 11,
      "ok": 11,
      "partial": 0,
      "failed": 0,
      "success_rate": 100,
      "avg_ms": 55,
      "records": 20,
      "last_status": "ok",
      "last_run_at": "2026-11-11T17:33:34+00:00",
      "last_failure_at": null,
      "last_error": null
    },
    {
      "id": "01m75ma90qyvtfemtpz47d802s",
      "name": "Open data: building permits API",
      "enabled": true,
      "runs": 8,
      "ok": 8,
      "partial": 0,
      "failed": 0,
      "success_rate": 100,
      "avg_ms": 32,
      "records": 224,
      "last_status": "ok",
      "last_run_at": "2026-11-11T17:50:59+00:00",
      "last_failure_at": null,
      "last_error": null
    }
  ],
  "failing_now": [],
  "slow_steps": [
    {
      "flow_id": "01m75ktv3qm550vqn6qjwpcmvg",
      "flow_name": "EnerGov issued permits to ArcGIS",
      "step": "Add to the map layer",
      "type": "destination.write",
      "runs": 1,
      "avg_ms": 833,
      "max_ms": 833,
      "calls": 9
    },
    {
      "flow_id": "01m75ktt4de0ghzf72k83sb3c9",
      "flow_name": "Meter reads from AMI to utility billing with zero-read check",
      "step": "Load the read",
      "type": "destination.write",
      "runs": 1,
      "avg_ms": 466,
      "max_ms": 466,
      "calls": 20
    }
  ],
  "connections": [
    {
      "id": "01m74hqe33cy19f80c393jnpz7",
      "name": "Sentra 311 (sandbox)",
      "issue": "Never tested",
      "error": null,
      "tested_at": null
    },
    {
      "id": "01m74hqe33cy19f80c393jnpz8",
      "name": "Sentra Scheduler (sandbox)",
      "issue": "Never tested",
      "error": null,
      "tested_at": null
    }
  ]
}
Errors
  • 401 The API token is missing, wrong, expired or revoked.
  • 403 The token's role is below viewer, or the caller's address is not allowed.

GET /v1/health/issues

Data-health issues. Open data-health issues (no records, volume change, run late, stale data, failure rate) and the last 10 that cleared.

  • Minimum roleViewer
  • Rate limitNo fixed limit
Request: Data-health issues
curl -s "$SENTRABRIDGE_URL/v1/health/issues" \
  -H "Authorization: Bearer $SENTRABRIDGE_TOKEN"

200 Active and recently cleared issues.

Example answer (application/json, real, shortened)
Answer: Data-health issues
{
  "active": [
    {
      "id": 2,
      "flow_id": "01m74hqe3jjn4tpavrv5j4hp84",
      "flow": "New pothole requests become Scheduler visits",
      "rule": "no_records",
      "title": "No records read",
      "message": "The last run finished but read no records. Check the source system and the flow's filters.",
      "status": "active",
      "started_at": "2026-11-11T17:18:10+00:00",
      "cleared_at": null,
      "sent": []
    },
    {
      "id": 1,
      "flow_id": "01m74hqe3jjn4tpavrv5j4hp84",
      "flow": "New pothole requests become Scheduler visits",
      "rule": "volume",
      "title": "Volume changed",
      "message": "The last run read 0 records, 100% below the average of 8.2 over the last 5 runs (limit 20%).",
      "status": "active",
      "started_at": "2026-11-11T15:34:00+00:00",
      "cleared_at": null,
      "sent": []
    }
  ],
  "recent": []
}
Errors
  • 401 The API token is missing, wrong, expired or revoked.
  • 403 The token's role is below viewer, or the caller's address is not allowed.

Connections

Connected systems and their last test. Credentials are never returned.

GET /v1/connections

List connections. Connected systems: connector, address, how they sign in, the result of the last test and which flows use them. has_credentials and credential_fields say what is saved; the credentials themselves are never returned.

  • Minimum roleViewer
  • Rate limitNo fixed limit
Request: List connections
curl -s "$SENTRABRIDGE_URL/v1/connections" \
  -H "Authorization: Bearer $SENTRABRIDGE_TOKEN"

200 All connections.

Example answer (application/json, real, shortened)
Answer: List connections
{
  "data": [
    {
      "id": "01m74k6h1paacjet4mez9974j8",
      "name": "Accela Civic Platform",
      "connector": "accela",
      "connector_name": "Accela Civic Platform",
      "kind": "vendor",
      "base_url": "https://system.example.gov/v4",
      "auth_type": "oauth2_client",
      "auth_config": {},
      "default_headers": {
        "x-accela-agency": "",
        "x-accela-environment": "PROD"
      },
      "has_credentials": false,
      "credential_fields": [],
      "status": "untested",
      "last_tested_at": null,
      "last_error": null,
      "sandbox": false,
      "is_database": false,
      "department": null,
      "is_mcp": false,
      "is_files": false,
      "relay_id": null,
      "used_by": [
        {
          "id": "01m74k6h1qjx1g0d9wc838410v",
          "name": "311 code-enforcement requests become Accela records"
        },
        {
          "id": "01m74q1bcnfc4vf0dr9rd1mn6q",
          "name": "Closed Accela records close their 311 requests"
        }
      ]
    },
    {
      "id": "01m74qmz62e9qbpv00yse14w5d",
      "name": "Backup bucket (sandbox)",
      "connector": "s3",
      "connector_name": "Amazon S3 / S3-compatible",
      "kind": "file",
      "base_url": "s3://city-backups",
      "auth_type": "s3",
      "auth_config": {
        "endpoint": "https://system.example.gov",
        "region": "us-east-1",
        "bucket": "city-backups",
        "access_key": "EXAMPLE"
      },
      "default_headers": {},
      "has_credentials": true,
      "credential_fields": [
        "secret_key"
      ],
      "status": "ok",
      "last_tested_at": "2026-11-11T17:50:59+00:00",
      "last_error": null,
      "sandbox": true,
      "is_database": false,
      "department": null,
      "is_mcp": false,
      "is_files": true,
      "relay_id": null,
      "used_by": [
        {
          "id": "01m74qnpe5hs1vtafrrec21j62",
          "name": "Nightly backup: Sentra 311 requests to S3"
        },
        {
          "id": "01m74qnwnyf7n1ns4xnwnjsq58",
          "name": "Nightly backup: a database table to CSV in S3"
        }
      ]
    }
  ]
}
Errors
  • 401 The API token is missing, wrong, expired or revoked.
  • 403 The token's role is below viewer, or the caller's address is not allowed.

POST /v1/connections/{id}/test

Test a connection. Signs in to the system and reads something small. The answer is always 200: look at ok. The result is saved on the connection.

  • Minimum roleAdmin
  • Rate limit30 a minute per person
Parameters of Test a connection
NameInTypeRequiredWhat it is
idpathstringYesConnection ID.
Request: Test a connection
curl -s -X POST "$SENTRABRIDGE_URL/v1/connections/$CONNECTION_ID/test" \
  -H "Authorization: Bearer $SENTRABRIDGE_TOKEN"

200 Whether it worked, a plain message, how long it took and the connection.

Example answer (application/json, real, shortened)
Answer: Test a connection
{
  "ok": true,
  "message": "Signed in to bucket city-backups. 0 files at the top of the bucket.",
  "ms": 9,
  "data": {
    "id": "01m74qmz62e9qbpv00yse14w5d",
    "name": "Backup bucket (sandbox)",
    "connector": "s3",
    "connector_name": "Amazon S3 / S3-compatible",
    "kind": "file",
    "base_url": "s3://city-backups",
    "auth_type": "s3",
    "auth_config": {
      "endpoint": "https://system.example.gov",
      "region": "us-east-1",
      "bucket": "city-backups",
      "access_key": "EXAMPLE"
    },
    "default_headers": {},
    "has_credentials": true,
    "credential_fields": [
      "secret_key"
    ],
    "status": "ok",
    "last_tested_at": "2026-11-11T21:48:51+00:00",
    "last_error": null,
    "sandbox": true,
    "is_database": false,
    "department": null,
    "is_mcp": false,
    "is_files": true,
    "relay_id": null
  }
}
Errors
  • 401 The API token is missing, wrong, expired or revoked.
  • 403 The token's role is below admin, or the caller's address is not allowed.
  • 404 Nothing with that ID in this workspace.
  • 429 More than 30 calls in a minute. See the Retry-After header.

Approvals

Requests waiting for a person, and deciding them.

GET /v1/approvals

List approvals. The 200 most recent approval requests, newest first, and how many are waiting. Requests hold record IDs, not record contents.

  • Minimum roleViewer
  • Rate limitNo fixed limit
Parameters of List approvals
NameInTypeRequiredWhat it is
statusquerystring · one of pendingNoSend pending for only the requests still waiting.
Request: List approvals
curl -s "$SENTRABRIDGE_URL/v1/approvals?status=pending" \
  -H "Authorization: Bearer $SENTRABRIDGE_TOKEN"

200 Approval requests and the pending count.

Example answer (application/json, real, shortened)
Answer: List approvals
{
  "data": [
    {
      "id": "01m74qgpw7kc7jjs998pfjavjs",
      "title": "Publish 2 agendas to the website",
      "status": "approved",
      "flow_id": "01m74qgp2wzbenx034zhvc6ye0",
      "flow_name": "Publish agendas on the website after the clerk approves",
      "step": "Clerk approves",
      "run_id": "01m74qgp6xcjma40d75fd8gqe6",
      "continued_run_id": "01m74qgvmt0eaj5r8x0t8rv4zz",
      "count": 2,
      "record_ids": [
        "45",
        "43"
      ],
      "approved_ids": [
        "45",
        "43"
      ],
      "approvers": [
        "[email protected]"
      ],
      "decided_by": "SentraBridge admin",
      "decided_at": "2026-11-11T07:17:55+00:00",
      "reason": null,
      "expires_at": "2026-11-13T07:17:50+00:00",
      "created_at": "2026-11-11T07:17:50+00:00",
      "can_decide": false
    }
  ],
  "pending": 0
}
Errors
  • 401 The API token is missing, wrong, expired or revoked.
  • 403 The token's role is below viewer, or the caller's address is not allowed.

GET /v1/approvals/{id}

Get an approval. One approval request. can_decide says whether this token's person may decide it.

  • Minimum roleViewer
  • Rate limitNo fixed limit
Parameters of Get an approval
NameInTypeRequiredWhat it is
idpathstringYesApproval ID.
Request: Get an approval
curl -s "$SENTRABRIDGE_URL/v1/approvals/$APPROVAL_ID" \
  -H "Authorization: Bearer $SENTRABRIDGE_TOKEN"

200 The approval request.

Example answer (application/json, real, shortened)
Answer: Get an approval
{
  "data": {
    "id": "01m74qgpw7kc7jjs998pfjavjs",
    "title": "Publish 2 agendas to the website",
    "status": "approved",
    "flow_id": "01m74qgp2wzbenx034zhvc6ye0",
    "flow_name": "Publish agendas on the website after the clerk approves",
    "step": "Clerk approves",
    "run_id": "01m74qgp6xcjma40d75fd8gqe6",
    "continued_run_id": "01m74qgvmt0eaj5r8x0t8rv4zz",
    "count": 2,
    "record_ids": [
      "45",
      "43"
    ],
    "approved_ids": [
      "45",
      "43"
    ],
    "approvers": [
      "[email protected]"
    ],
    "decided_by": "SentraBridge admin",
    "decided_at": "2026-11-11T07:17:55+00:00",
    "reason": null,
    "expires_at": "2026-11-13T07:17:50+00:00",
    "created_at": "2026-11-11T07:17:50+00:00",
    "can_decide": false
  }
}
Errors
  • 401 The API token is missing, wrong, expired or revoked.
  • 403 The token's role is below viewer, or the caller's address is not allowed.
  • 404 Nothing with that ID in this workspace.

POST /v1/approvals/{id}/decide

Approve or reject. Decides a waiting request. Any role can call it, but only the people named as approvers, or an admin, are allowed to decide. Approving continues the flow for the approved records as a new run (continued_run_id).

  • Minimum roleViewer
  • Rate limitNo fixed limit
Parameters of Approve or reject
NameInTypeRequiredWhat it is
idpathstringYesApproval ID.
JSON body of Approve or reject
FieldTypeRequiredWhat it is
decisionstring · one of approve, rejectYesWhat to do.
idsarrayNoApprove only these record IDs. Default: all of them.
reasonstringNoOptional note, up to 500 characters.
Request: Approve or reject
curl -s -X POST "$SENTRABRIDGE_URL/v1/approvals/$APPROVAL_ID/decide" \
  -H "Authorization: Bearer $SENTRABRIDGE_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"decision": "approve", "reason": "Checked against the agenda packet."}'

200 The request after the decision.

Example answer (application/json, real, shortened)
Answer: Approve or reject
{
  "data": {
    "id": "01m74qgpw7kc7jjs998pfjavjs",
    "title": "Publish 2 agendas to the website",
    "status": "approved",
    "flow_id": "01m74qgp2wzbenx034zhvc6ye0",
    "flow_name": "Publish agendas on the website after the clerk approves",
    "step": "Clerk approves",
    "run_id": "01m74qgp6xcjma40d75fd8gqe6",
    "continued_run_id": "01m74qgvmt0eaj5r8x0t8rv4zz",
    "count": 2,
    "record_ids": [
      "45",
      "43"
    ],
    "approved_ids": [
      "45",
      "43"
    ],
    "approvers": [
      "[email protected]"
    ],
    "decided_by": "SentraBridge admin",
    "decided_at": "2026-11-11T07:17:55+00:00",
    "reason": null,
    "expires_at": "2026-11-13T07:17:50+00:00",
    "created_at": "2026-11-11T07:17:50+00:00",
    "can_decide": false
  }
}
Errors
  • 401 The API token is missing, wrong, expired or revoked.
  • 403 This person is not an approver or an admin.
  • 404 Nothing with that ID in this workspace.
  • 409 The request was already approved, rejected or expired.

Templates

Ready-made flows, and making a flow from one.

GET /v1/templates

List templates. Ready-made flows: built-in ones, and ones SentraBridge staff shared (their key starts with shared:).

  • Minimum roleViewer
  • Rate limitNo fixed limit
Request: List templates
curl -s "$SENTRABRIDGE_URL/v1/templates" \
  -H "Authorization: Bearer $SENTRABRIDGE_TOKEN"

200 All templates.

Example answer (application/json, real, shortened)
Answer: List templates
{
  "data": [
    {
      "key": "311-potholes-to-scheduler",
      "name": "New pothole requests become Scheduler visits",
      "description": "Every 15 minutes, takes new or changed pothole requests from Sentra 311 and creates a visit for the street repair crew in Sentra Scheduler.",
      "category": "Work orders",
      "connectors": [
        "sentra311",
        "sentrascheduler"
      ],
      "trigger": "trigger.schedule",
      "steps": 5
    },
    {
      "key": "311-to-accela-code-cases",
      "name": "311 code-enforcement requests become Accela records",
      "description": "When Sentra 311 sends request.created, code-enforcement requests become new Accela records. Everything else is ignored.",
      "category": "Permitting",
      "connectors": [
        "sentra311",
        "accela"
      ],
      "trigger": "trigger.webhook",
      "steps": 4
    }
  ]
}
Errors
  • 401 The API token is missing, wrong, expired or revoked.
  • 403 The token's role is below viewer, or the caller's address is not allowed.

POST /v1/templates/{key}/use

Make a flow from a template. Makes a new flow, turned off, from a built-in template. It uses this workspace's connection for each connector the template needs, and makes an empty or sandbox connection where there is none. Shared templates (shared: keys) are not available here.

  • Minimum roleBuilder
  • Rate limitNo fixed limit
Parameters of Make a flow from a template
NameInTypeRequiredWhat it is
keypathstringYesTemplate key from "List templates", for example 311-potholes-to-scheduler.
Request: Make a flow from a template
curl -s -X POST "$SENTRABRIDGE_URL/v1/templates/311-potholes-to-scheduler/use" \
  -H "Authorization: Bearer $SENTRABRIDGE_TOKEN"

201 The new flow.

Example answer (application/json, real, shortened)
Answer: Make a flow from a template
{
  "data": {
    "id": "01m769behch8x1ym13ssqct3xv",
    "name": "Data quality alert (sub-flow)",
    "description": "A reusable sub-flow: other flows hand it the records that failed their checks, and it emails the data team a summary with a CSV attached.",
    "enabled": null,
    "trigger": "trigger.manual",
    "schedule": null,
    "steps": 3,
    "connectors": [],
    "next_run_at": null,
    "last_run_at": null,
    "last_status": null,
    "version": 1,
    "template": "data-quality-alert",
    "updated_at": "2026-11-11T21:48:47+00:00",
    "last_success_at": null,
    "department": null,
    "graph": {
      "nodes": [
        {
          "id": "t",
          "type": "trigger.manual",
          "position": {
            "x": 40,
            "y": 160
          },
          "data": {
            "label": "Records from another flow",
            "config": [],
            "note": ""
          }
        },
        {
          "id": "lim",
          "type": "transform.limit",
          "position": {
            "x": 330,
            "y": 160
          },
          "data": {
            "label": "First 500",
            "config": {
              "count": 500
            },
            "note": ""
          }
        }
      ],
      "edges": [
        {
          "id": "t-lim-out",
          "source": "t",
          "target": "lim",
          "sourceHandle": null
        },
        {
          "id": "lim-mail-out",
          "source": "lim",
          "target": "mail",
          "sourceHandle": null
        }
      ]
    },
    "webhook_url": null,
    "problems": [],
    "secrets_saved": [],
    "public_status": false,
    "notify": {
      "on": [],
      "emails": []
    }
  }
}
Errors
  • 401 The API token is missing, wrong, expired or revoked.
  • 403 The token's role is below builder, or the caller's address is not allowed.
  • 404 No built-in template has that key.

Audit and usage

The activity log as a file, and this month's usage against the plan.

GET /v1/activity/export

Export the activity log. Streams the workspace activity log (who did what, when, with tamper-check hashes) or the AI and MCP call log, as CSV or NDJSON. The whole range is sent in one answer. Each export is itself written to the log.

  • Minimum roleAdmin
  • Rate limit30 a minute per person
Parameters of Export the activity log
NameInTypeRequiredWhat it is
formatquerystring · one of csv, ndjsonNoFile format. Default csv.
scopequerystring · one of activity, callsNoactivity (default) or calls for the AI and MCP call log.
fromquerystringNoFirst day, YYYY-MM-DD, in the workspace time zone.
toquerystringNoLast day, YYYY-MM-DD, in the workspace time zone.
actionquerystringNoOnly this action, or a prefix such as flow. (scope activity).
kindquerystring · one of ai, mcpNoOnly AI or only MCP calls (scope calls).
Request: Export the activity log
curl -s "$SENTRABRIDGE_URL/v1/activity/export?format=csv&from=2026-01-01" \
  -H "Authorization: Bearer $SENTRABRIDGE_TOKEN"

200 The log as a file.

Example answer (text/csv, real, shortened)
Answer: Export the activity log
id,at,workspace_id,workspace,action,summary,who,email,subject_type,subject_id,ip,meta,prev_hash,hash
1,2026-11-11T06:20:05+00:00,01m74hqe1m08znmjtembcq6sf7,"City of Demo",user.signed_in,[email protected],"SentraBridge admin",[email protected],User,1,203.0.113.10,,000000000000…,ee41d37ccf9c…
2,2026-11-11T06:24:09+00:00,01m74hqe1m08znmjtembcq6sf7,"City of Demo",user.signed_in,[email protected],"Pedro Braz",[email protected],User,2,203.0.113.10,,ee41d37ccf9c…,8fa3f5496b4b…
…
Errors
  • 401 The API token is missing, wrong, expired or revoked.
  • 403 The token's role is below admin, or the caller's address is not allowed.
  • 429 More than 30 calls in a minute. See the Retry-After header.

GET /v1/usage

Usage this month. This month's meters (runs, records read and written, active flows, connections, Data API, AI and MCP calls) against the plan, and the last 12 months. Plan amounts are null when the plan is not shown to the client.

  • Minimum roleAdmin
  • Rate limitNo fixed limit
Request: Usage this month
curl -s "$SENTRABRIDGE_URL/v1/usage" \
  -H "Authorization: Bearer $SENTRABRIDGE_TOKEN"

200 Meters, history and plan.

Example answer (application/json, real, shortened)
Answer: Usage this month
{
  "month": "2026-11",
  "meters": [
    {
      "key": "runs",
      "label": "Runs",
      "unit": "runs",
      "used": 63,
      "included": 2000,
      "percent": 3,
      "hard": false
    },
    {
      "key": "records_read",
      "label": "Records read",
      "unit": "records",
      "used": 1293,
      "included": null,
      "percent": null,
      "hard": false
    }
  ],
  "labels": {
    "runs": "Runs",
    "records_read": "Records read",
    "records_written": "Records written",
    "active_flows": "Active flows",
    "connections": "Connections",
    "relays": "Relays",
    "data_api_calls": "Data API calls",
    "ai_calls": "AI calls",
    "mcp_calls": "MCP calls"
  },
  "history": [
    {
      "month": "2025-12",
      "runs": 0,
      "records_read": 0,
      "records_written": 0,
      "active_flows": 0,
      "connections": 0,
      "relays": 0,
      "data_api_calls": 0,
      "ai_calls": 0,
      "mcp_calls": 0
    },
    {
      "month": "2026-01",
      "runs": 0,
      "records_read": 0,
      "records_written": 0,
      "active_flows": 0,
      "connections": 0,
      "relays": 0,
      "data_api_calls": 0,
      "ai_calls": 0,
      "mcp_calls": 0
    }
  ],
  "plan": {
    "name": "Demo city (draft)",
    "cycle": "monthly",
    "starts_on": "2026-11-01",
    "visible": true
  },
  "estimate": {
    "lines": [
      {
        "kind": "base",
        "label": "Demo city (draft) plan, monthly",
        "quantity": 1,
        "unit_cents": 150000,
        "amount_cents": 150000
      }
    ],
    "total_cents": 150000
  },
  "banner": [],
  "updated_at": "2026-11-11T17:59:48+00:00"
}
Errors
  • 401 The API token is missing, wrong, expired or revoked.
  • 403 The token's role is below admin, or the caller's address is not allowed.

Data API

Read-only flows published as JSON endpoints. Each call runs the flow live; records are not stored.

GET /public/data/{workspace}/{flow}

Read a published data API. Runs a read-only flow that starts with "When someone asks for data" and answers with its records. The records are read live for this call and are not stored (a flow can turn on a short encrypted cache). Flows marked public need no key; others need a data key (sbd_…) made on the flow, sent as a bearer token or in X-API-Key. The flow's own query parameters are listed in its OpenAPI document.

  • Minimum roleData key, or none if public
  • Rate limit600 a minute per calling address
Parameters of Read a published data API
NameInTypeRequiredWhat it is
workspacepathstringYesThe workspace's short name, for example city-of-demo.
flowpathstringYesThe address name set on the flow, for example permits.
limitqueryintegerNoRecords per page. The flow sets the default (100) and the most allowed (up to 5,000).
offsetqueryintegerNoRecords to skip. Use meta.next_offset or follow links.next.
Request: Read a published data API
curl -s "$SENTRABRIDGE_URL/public/data/city-of-demo/permits?limit=100"

200 A page of records, with meta and links.next. Headers: X-Total-Count, X-Run-Id, X-Cache.

Example answer (application/json, real, shortened)
Answer: Read a published data API
{
  "data": [
    {
      "id": 1,
      "permit_number": "BLD-2026-0001",
      "permit_type": "New single-family",
      "status": "issued",
      "address": "137 Oak Ave, Demo City",
      "applicant": "B. Chen",
      "issued_on": "2026-11-08",
      "valuation": 6375,
      "updated_at": "2026-11-11 05:07:15.494113+00",
      "geom": {
        "type": "Point",
        "coordinates": [
          -119.7991,
          36.7298
        ]
      }
    },
    {
      "id": 2,
      "permit_number": "BLD-2026-0002",
      "permit_type": "Commercial tenant improvement",
      "status": "in review",
      "address": "174 Elm St, Demo City",
      "applicant": "C. Okafor",
      "issued_on": "2026-11-05",
      "valuation": 7750,
      "updated_at": "2026-11-11 04:07:15.494113+00",
      "geom": {
        "type": "Point",
        "coordinates": [
          -119.7951,
          36.7338
        ]
      }
    }
  ],
  "meta": {
    "total": 30,
    "limit": 2,
    "offset": 0,
    "next_offset": 2
  },
  "links": {
    "next": "https://app.sentrabridge.example/public/data/city-of-demo/permits?limit=2&offset=2"
  }
}
Errors
  • 401 A key is needed, or the key is not valid for this data API.
  • 409 The data API is turned off, or its address is used by more than one flow.
  • 429 Over the flow's limit per caller (60 a minute unless the flow says otherwise). See Retry-After.
  • 502 The source could not be read. The message carries a run ID.

GET /public/data/{workspace}/{flow}/openapi.json

OpenAPI for one data API. An OpenAPI 3 document for one published data API: its parameters and the fields its records have. Same key rules as the data itself.

  • Minimum roleData key, or none if public
  • Rate limit600 a minute per calling address
Parameters of OpenAPI for one data API
NameInTypeRequiredWhat it is
workspacepathstringYesThe workspace's short name.
flowpathstringYesThe address name set on the flow.
Request: OpenAPI for one data API
curl -s "$SENTRABRIDGE_URL/public/data/city-of-demo/permits/openapi.json"

200 An OpenAPI 3 document.

Example answer (application/json, real, shortened)
Answer: OpenAPI for one data API
{
  "openapi": "3.0.3",
  "info": {
    "title": "Open data: building permits API",
    "version": "1",
    "description": "Publishes the permits table as a read-only JSON API for the open data portal.\n\nPublished by City of Demo with SentraBridge. Each request reads the data live from its sources; SentraBridge doesn't keep a copy."
  },
  "servers": [
    {
      "url": "https://app.sentrabridge.example"
    }
  ],
  "paths": "…"
}
Errors
  • 429 More than 600 calls in a minute. See the Retry-After header.

Webhooks

Send an event into a flow at its private address.

POST /hooks/{token}

Send an event into a flow. POST JSON to a flow's private address (shown on its "When a system calls in" step). The flow runs inside the request and the message is dropped afterwards: it is never queued or stored. If the flow checks signatures, sign the body as its step says. The flow may also limit which addresses can call.

  • Minimum roleNo token: private address
  • Rate limit120 a minute per calling address
Parameters of Send an event into a flow
NameInTypeRequiredWhat it is
tokenpathstringYesThe private part of the flow's address.

Body: Any JSON object. The flow says where the records are inside it.

Request: Send an event into a flow
curl -s -X POST "$SENTRABRIDGE_URL/hooks/$PRIVATE_ADDRESS" \
  -H "X-Signature: sha256=$SIGNATURE" \
  -H "Content-Type: application/json" \
  -d '{"id": "REQ-1001", "status": "open"}'

200 The run that handled the message, with counts.

Example answer (application/json, real, shortened)
Answer: Send an event into a flow
{
  "run_id": "01m769bjym26wdm4ej2rw2k7wn",
  "status": "ok",
  "records": 1,
  "sent": 0
}
Errors
  • 401 The signature check failed.
  • 403 The calling address is not on the flow's list.
  • 404 Unknown address.
  • 409 The flow is turned off.
  • 422 The body was not JSON, or was empty.
  • 429 More than 120 calls in a minute. See the Retry-After header.
  • 502 The flow ran and failed. The body still carries the run ID.

Status

Platform status, feeds and status updates. Public, no token.

GET /public/platform-status

Platform status. Whether SentraBridge itself is working: five components checked live, 90 days of uptime, open incidents and planned maintenance. Open to any origin. Cached for 30 seconds. It never includes anything about a client.

  • Minimum roleNo token
  • Rate limit240 a minute per calling address
Request: Platform status
curl -s "$SENTRABRIDGE_URL/public/platform-status"

200 Overall status, components, uptime and notices.

Example answer (application/json, real, shortened)
Answer: Platform status
{
  "status": "operational",
  "label": "All systems operational",
  "updated_at": "2026-11-11T21:48:51+00:00",
  "components": [
    {
      "key": "app",
      "label": "Web app and sign-in",
      "status": "operational"
    },
    {
      "key": "api",
      "label": "API, webhooks and MCP",
      "status": "operational"
    }
  ],
  "uptime": {
    "app": {
      "days": [
        null,
        null
      ],
      "percent": 100
    },
    "api": {
      "days": [
        null,
        null
      ],
      "percent": 100
    },
    "schedules": {
      "days": [
        null,
        null
      ],
      "percent": 100
    },
    "live": {
      "days": [
        null,
        null
      ],
      "percent": 100
    },
    "queue": {
      "days": [
        null,
        null
      ],
      "percent": 100
    }
  },
  "incidents": [],
  "upcoming": []
}
Errors
  • 429 More than 240 calls in a minute. See the Retry-After header.

GET /public/status/{slug}

A workspace's public status page. For workspaces that turned their status page on: the state and 30-day history of the flows they chose to show. Names, states and counts of runs only.

  • Minimum roleNo token
  • Rate limit120 a minute per calling address
Parameters of A workspace's public status page
NameInTypeRequiredWhat it is
slugpathstringYesThe workspace's short name.
Request: A workspace's public status page
curl -s "$SENTRABRIDGE_URL/public/status/city-of-demo"

200 Overall state and one entry per published flow.

Example answer (application/json, real, shortened)
Answer: A workspace's public status page
{
  "name": "City of Demo",
  "timezone": "America/Los_Angeles",
  "overall": "paused",
  "flows": [
    {
      "name": "Copy 311 requests into the city database, with map points",
      "description": "Every 15 minutes, upserts new and changed Sentra 311 requests into a PostGIS table, with a map point built from latitude and longitude.",
      "state": "paused",
      "last_success_at": "2026-11-11T17:26:51+00:00",
      "uptime": 100,
      "days": [
        {
          "date": "2026-10-13",
          "ok": 0,
          "partial": 0,
          "failed": 0
        },
        {
          "date": "2026-10-14",
          "ok": 0,
          "partial": 0,
          "failed": 0
        }
      ]
    },
    {
      "name": "File CivicCA agendas and minutes in Laserfiche",
      "description": "File CivicCA agendas and minutes in Laserfiche",
      "state": "paused",
      "last_success_at": "2026-11-11T06:48:59+00:00",
      "uptime": 100,
      "days": [
        {
          "date": "2026-10-13",
          "ok": 0,
          "partial": 0,
          "failed": 0
        },
        {
          "date": "2026-10-14",
          "ok": 0,
          "partial": 0,
          "failed": 0
        }
      ]
    }
  ],
  "updated_at": "2026-11-11T21:48:51+00:00"
}
Errors
  • 404 No workspace with that name has a status page.
  • 429 More than 120 calls in a minute. See the Retry-After header.

GET /public/status/feed.atom

Status feed (Atom). Incidents and planned maintenance as an Atom feed. Cached for 5 minutes.

  • Minimum roleNo token
  • Rate limit120 a minute per calling address
Request: Status feed (Atom)
curl -s "$SENTRABRIDGE_URL/public/status/feed.atom"

200 An Atom feed.

Example answer (application/atom+xml, real, shortened)
Answer: Status feed (Atom)
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom"><title>SentraBridge status</title><subtitle>Incidents and planned maintenance on the SentraBridge platform</subtitle><id>tag:app.sentrabridge.example,2026:status</id><updated>2026-11-11T21:48:51+00:00</updated><link rel="alternate" type="text/html" href="https://app.sentrabridge.example/status/"/><link rel="self" type="application/atom+xml" href="https://app.sentrabridge.example/public/status/feed.atom"/><author><name>SentraBridge</name></author></feed>
…
Errors
  • 429 More than 120 calls in a minute. See the Retry-After header.

GET /public/status/feed.rss

Status feed (RSS). The same notices as an RSS 2.0 feed.

  • Minimum roleNo token
  • Rate limit120 a minute per calling address
Request: Status feed (RSS)
curl -s "$SENTRABRIDGE_URL/public/status/feed.rss"

200 An RSS feed.

Example answer (application/rss+xml, real, shortened)
Answer: Status feed (RSS)
<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>SentraBridge status</title><link>https://app.sentrabridge.example/status/</link><description>Incidents and planned maintenance on the SentraBridge platform</description><language>en-us</language><lastBuildDate>Wed, 11 Nov 2026 21:48:51 +0000</lastBuildDate><atom:link href="https://app.sentrabridge.example/public/status/feed.rss" rel="self" type="application/rss+xml"/></channel></rss>
…
Errors
  • 429 More than 120 calls in a minute. See the Retry-After header.

GET /public/status/maintenance.ics

Maintenance calendar (iCal). Planned maintenance windows as a calendar you can subscribe to.

  • Minimum roleNo token
  • Rate limit120 a minute per calling address
Request: Maintenance calendar (iCal)
curl -s "$SENTRABRIDGE_URL/public/status/maintenance.ics"

200 An iCalendar file.

Example answer (text/calendar, real, shortened)
Answer: Maintenance calendar (iCal)
BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//SentraBridge//Status//EN
CALSCALE:GREGORIAN
METHOD:PUBLISH
X-WR-CALNAME:SentraBridge planned maintenance
X-PUBLISHED-TTL:PT1H
REFRESH-INTERVAL;VALUE=DURATION:PT1H
END:VCALENDAR
…
Errors
  • 429 More than 120 calls in a minute. See the Retry-After header.

GET /public/status/subscribe

Ways to get status updates. The channels on offer (email, text when set up, webhook) and the components you can follow.

  • Minimum roleNo token
  • Rate limit60 a minute per calling address
Request: Ways to get status updates
curl -s "$SENTRABRIDGE_URL/public/status/subscribe"

200 Channels and components.

Example answer (application/json, real, shortened)
Answer: Ways to get status updates
{
  "channels": [
    "email",
    "webhook"
  ],
  "components": [
    {
      "key": "app",
      "label": "Web app and sign-in"
    },
    {
      "key": "api",
      "label": "API, webhooks and MCP"
    }
  ]
}
Errors
  • 429 More than 60 calls in a minute. See the Retry-After header.

POST /public/status/subscribe

Subscribe to status updates. Email: a confirmation link is sent. Webhook: SentraBridge first POSTs a signed subscription.verify message with a challenge; your endpoint must answer 2xx with the challenge in its body. The signing secret is shown once in the answer. Limited to 20 tries an hour per network.

  • Minimum roleNo token
  • Rate limit10 a minute per calling address
JSON body of Subscribe to status updates
FieldTypeRequiredWhat it is
channelstring · one of email, sms, webhookNoHow to be told. Default email.
emailstringNoFor channel email.
phonestringNoFor channel sms.
urlstringNoFor channel webhook: a public https address.
secretstringNoOptional signing secret of your own, 16 to 200 characters. One is made if left out.
componentsarrayNoOnly these components (keys from "Ways to get status updates"). Default: everything.
Request: Subscribe to status updates
curl -s -X POST "$SENTRABRIDGE_URL/public/status/subscribe" \
  -H "Content-Type: application/json" \
  -d '{"channel": "webhook", "url": "https://ops.example.gov/hooks/sentrabridge-status", "components": ["api", "schedules"]}'

202 Email and text: a message saying a confirmation is on its way. A verified webhook answers 201 instead, with message, secret (shown once) and unsubscribe_url.

Example answer (application/json, real, shortened)
Answer: Subscribe to status updates
{
  "message": "Too Many Attempts."
}
Errors
  • 422 Something is missing, or the webhook address could not be verified.
  • 429 Too many tries.

MCP

SentraBridge as a Model Context Protocol server for AI assistants.

POST /mcp

MCP server. SentraBridge as a Model Context Protocol server (streamable HTTP, JSON answers, no event stream). Send JSON-RPC 2.0: initialize, ping, tools/list, tools/call. Signs in with an API token only. Each tool needs a least role; a tool the token's role cannot use answers with isError. Every tool call is written to the activity log and the MCP call log. No session or X-XSRF-TOKEN is needed here.

  • Minimum roleAny role
  • Rate limit120 a minute per person
JSON body of MCP server
FieldTypeRequiredWhat it is
jsonrpcstringYesAlways "2.0".
idintegerNoYour request number. Leave it out for notifications.
methodstring · one of initialize, ping, tools/list, tools/callYesThe MCP method.
paramsobjectNoFor tools/call: name and arguments.
Request: MCP server
curl -s -X POST "$SENTRABRIDGE_URL/mcp" \
  -H "Authorization: Bearer $SENTRABRIDGE_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc": "2.0", "id": 1, "method": "tools/call", "params": {"name": "list_flows", "arguments": {}}}'

200 A JSON-RPC result. Notifications answer 202 with no body.

Example answer (application/json, real, shortened)
Answer: MCP server
{
  "jsonrpc": "2.0",
  "id": 3,
  "result": {
    "content": [
      {
        "type": "text",
        "text": "(the same data as structuredContent, as text)"
      }
    ],
    "structuredContent": {
      "data": [
        {
          "id": "01m769bjwj9bnvmyggg6rp5kcn",
          "name": "API reference webhook sample",
          "description": null,
          "enabled": false,
          "trigger": "trigger.webhook",
          "schedule": null,
          "steps": 2,
          "connectors": [],
          "next_run_at": null,
          "last_run_at": "2026-11-11T21:48:51+00:00",
          "last_status": "ok",
          "version": 1,
          "template": null,
          "updated_at": "2026-11-11T21:48:51+00:00",
          "last_success_at": null,
          "department": null
        },
        {
          "id": "01m769bjp928n7vqvkaezxh05w",
          "name": "API reference sample",
          "description": "Every 15 minutes, upserts new and changed Sentra 311 requests into a PostGIS table, with a map point built from latitude and longitude.",
          "enabled": false,
          "trigger": "trigger.schedule",
          "schedule": "*/15 * * * *",
          "steps": 4,
          "connectors": [
            "01m74hqe33cy19f80c393jnpz7",
            "01m74knwpc7xd4424q3ybrqf3b"
          ],
          "next_run_at": null,
          "last_run_at": null,
          "last_status": null,
          "version": 1,
          "template": null,
          "updated_at": "2026-11-11T21:48:51+00:00",
          "last_success_at": null,
          "department": null
        }
      ]
    },
    "isError": false
  }
}
Errors
  • 401 No valid API token was sent.
  • 429 More than 120 calls in a minute. See the Retry-After header.

Reference

This document, and addresses for firewalls.

GET /public/openapi.json

This document. The OpenAPI 3.1 description of the supported API, with this server's address filled in.

  • Minimum roleNo token
  • Rate limit120 a minute per calling address
Request: This document
curl -s "$SENTRABRIDGE_URL/public/openapi.json"

200 An OpenAPI 3.1 document.

Errors
  • 429 More than 120 calls in a minute. See the Retry-After header.

GET /public/egress-ips

Outbound addresses. The addresses SentraBridge calls out from, for your firewall's allow list. Not secret.

  • Minimum roleNo token
  • Rate limit60 a minute per calling address
Request: Outbound addresses
curl -s "$SENTRABRIDGE_URL/public/egress-ips"

200 A list of addresses and a note.

Example answer (application/json, real, shortened)
Answer: Outbound addresses
{
  "ips": [],
  "note": "This SentraBridge has no fixed outbound addresses listed. If it runs on your own network (self-hosted), it calls out from that server's address. Otherwise ask SentraBridge support for the relay address to allow."
}
Errors
  • 429 More than 60 calls in a minute. See the Retry-After header.