API Reference
Canonical reference for building automation against the TATER REST API. Covers authentication, the structured error catalog, key scoping, and ready-to-paste snippets in curl, PowerShell, and Python.
Authentication
The TATER API uses a single header for programmatic authentication:
X-API-Key: tater_<32-hex-chars>
Authorization: Bearer ... for API key auth. The
Authorization header is reserved for Entra ID JWT bearer tokens issued to the
browser app. The API explicitly rejects any non-JWT value in Authorization
with HTTP 401 and a structured error. This is by design - see
Common Errors below.
API key format:
- Prefix:
tater_ - Body: 32 lowercase hex characters (16 bytes of cryptographic randomness)
- Example:
tater_3fd88c926edd3a6f66a925de7df4cfe4
Generate keys from Manage → Connections → API Keys in the TATER app. The full key is shown once at creation time - only the prefix is stored after that and shown in the Key list. Keys are SHA-256 hashed at rest in Cosmos DB.
Org-scoped vs unbound keys
Where you generate the key determines what data it can reach:
| Key context at creation | Behavior | Org header required? |
|---|---|---|
| Org-scoped - generated while a specific org is selected in the org switcher | All API calls are auto-scoped to that organization. The key cannot read or write any other org's data even within the same tenant. | No |
| Unbound - generated while no org context is active (rare; SuperAdmin only) | For most endpoints, an unbound key against a multi-org tenant will return 400 AMBIGUOUS_ORG. Use only for tenant-wide cron jobs that loop through orgs. |
Yes - pass ?organizationId=<org-id> on each request |
organizationId through every request.
Common errors
All TATER API errors return a JSON body with error (machine code) and
message (human description). Status codes follow standard semantics.
The five auth-related cases you will see in practice:
| Status | Error code | Trigger | What to do |
|---|---|---|---|
| 401 | UNAUTHORIZED / "Missing API key" |
No X-API-Key header on the request |
Add the header |
| 401 | UNAUTHORIZED / "Invalid authorization header format" |
You sent Authorization: Bearer tater_… or similar |
Move the key value into the X-API-Key header. Do not use Authorization. |
| 401 | UNAUTHORIZED / "Invalid token" |
The key in X-API-Key is malformed, revoked, or does not exist |
Regenerate from Manage → Connections → API Keys |
| 401 | UNAUTHORIZED / "Unbound API key may not scope to a specific org" |
Unbound key tried to access an org-scoped endpoint without setup | Regenerate the key with an org selected, OR pass ?organizationId= for read-only endpoints that accept it |
| 400 | AMBIGUOUS_ORG |
Unbound key against a multi-org tenant, no organizationId hint |
Bind the key to an org, or supply ?organizationId= |
| 400 | VALIDATION_ERROR |
Auth succeeded; request body or query is malformed | Inspect message field for the specific field that failed validation |
Code examples
curl
curl -X POST "https://api.tatersecurity.com/api/scans/upload?tenantId=$TENANT_ID&organizationId=$ORG_ID" \
-H "X-API-Key: tater_3fd88c926edd3a6f66a925de7df4cfe4" \
-H "Content-Type: application/json" \
--data @scan-payload.json
PowerShell
$apiKey = 'tater_3fd88c926edd3a6f66a925de7df4cfe4'
$tenantId = '00000000-0000-0000-0000-000000000000'
$orgId = 'org-9c305e0e-cf02-4028-8ef1-edead8fdaee5'
$headers = @{
'X-API-Key' = $apiKey
'Content-Type' = 'application/json'
}
$body = Get-Content -Raw scan-payload.json
$uri = "https://api.tatersecurity.com/api/scans/upload?tenantId=$tenantId&organizationId=$orgId"
$response = Invoke-WebRequest -Uri $uri -Method POST -Headers $headers -Body $body
$response.Content | ConvertFrom-Json
Python
import requests, json
api_key = 'tater_3fd88c926edd3a6f66a925de7df4cfe4'
tenant_id = '00000000-0000-0000-0000-000000000000'
org_id = 'org-9c305e0e-cf02-4028-8ef1-edead8fdaee5'
with open('scan-payload.json') as f:
payload = json.load(f)
r = requests.post(
'https://api.tatersecurity.com/api/scans/upload',
params = {'tenantId': tenant_id, 'organizationId': org_id},
headers = {'X-API-Key': api_key},
json = payload,
timeout = 60,
)
r.raise_for_status()
print(r.json())
Key management best practices
- Per-integration key - generate a separate API key for each automation (RMM, SIEM enrichment, Power Automate flow, internal script). Revoking one will not break the others.
- Store as a secret - never check API keys into source control. Use Key Vault, Azure DevOps Library variables, GitHub Secrets, etc.
- Audit log shows usage - every API-key-authenticated write is logged with
via=apiand the key'skeyIdin the audit trail. Filter on Activity Log → Channel → API to review automated writes. - Rotate yearly - generate a new key, deploy it to the integration, verify it works, then revoke the old key from Manage → Connections → API Keys.
Related guides
- Power BI Integration - flat data endpoint at
GET /api/reports/powerbi - Power Automate Integration - custom connector +
scan.completedwebhook trigger - MCP Server Setup - Claude / Copilot agent integration via Model Context Protocol
- Settings Reference - where to manage API keys in the app
- Developer Troubleshooting - full pitfall catalog
TATER