POST /v1/actions
The core action proxy. Every call your agent makes to a connected SaaS platform flows through this endpoint.
Most agents call this indirectly via the MCP
use_platformtool. Direct invocation is only needed when building a custom MCP server or integrating from a non-MCP host.
Request
POST /v1/actions HTTP/1.1
Host: api.agentvalet.ai
Authorization: Bearer <agent-rs256-jwt>
Content-Type: application/json{
"platform": "slack",
"endpoint": "/api/chat.postMessage",
"method": "POST",
"scope": "slack:write",
"data": { "channel": "#general", "text": "Hello" },
"headers": {}
}| Field | Type | Required | Notes |
|---|---|---|---|
platform | string | yes | Platform id from list_platforms (e.g. slack, gmail, stripe) |
endpoint | string | yes | The SaaS endpoint path. Validated by the SSRF guard — no private/loopback addresses |
method | string | yes | GET / POST / PUT / PATCH / DELETE |
scope | string | yes | The scope the agent claims for this call. Must be granted in the dashboard permission matrix |
data | object | no | Request payload forwarded to the SaaS |
headers | object | no | Extra headers forwarded to the SaaS |
Success — 200 OK
The upstream response wrapped in a discovery envelope:
{
"status": 200,
"data": { "ok": true, "channel": "C123", "ts": "1715000000.000100" },
"_links": [
{ "capability": "audit.query", "endpoint": "GET /v1/audit" },
{ "capability": "agent.permissions", "endpoint": "GET /v1/agent/permissions" }
]
}If the org has PII redaction beta enabled and the agent has a per-platform
visibility map, the data body is rewritten before the response is
returned. The audit row records pii_detected, pii_categories,
pii_redacted, and pii_record_count. See PII redaction.
Pending approval — 202 Accepted
When the scope is marked require_approval in the permission matrix:
{
"status": "pending_approval",
"approval_id": "01HKZ7...",
"message": "Owner approval required"
}Your agent should poll GET /v1/approvals/:id until
status is approved (with result populated) or denied /
expired. The MCP use_platform tool does this long-poll for you for
up to 50 seconds; after that it returns the 202 envelope and your
agent should explain the wait to the user.
Approvals expire 24 hours from creation. The owner can be notified via push (mobile), email (delegates), and the dashboard inbox.
Error codes
All errors follow the common envelope. The error
identifier is stable.
| Status | error | Cause | Fix |
|---|---|---|---|
| 400 | invalid_jwt | JWT malformed or missing required claim | Check agent_id, owner_id, iat, exp claims |
| 400 | secrets_in_params | Request body matched the secrets scanner (AWS key, Slack token, etc.) | Don’t embed credentials in data; use the platform’s own auth mechanism |
| 400 | endpoint_blocked | SSRF guard rejected the endpoint (private/loopback) | Use the platform’s public API endpoint |
| 401 | Missing Bearer token | No Authorization: Bearer header | Add the header |
| 401 | Invalid JWT | Signature verification failed against the agent’s public key | The agent’s private key doesn’t match the registered public key — re-register or rotate |
| 401 | Unknown agent | agent_id claim doesn’t match any row | Confirm the agent exists in the dashboard and isn’t soft-deleted |
| 402 | plan_inactive | Org plan is past_due or cancelled | Update billing |
| 403 | Permission denied (with reason: scope_not_granted or similar) | The scope isn’t in the agent’s permission matrix | Grant the scope in Agents → permissions |
| 403 | AuthZEN policy denied | A policy decision from the AuthZEN evaluator denied the call | Inspect the audit row’s metadata.authzen_reason |
| 502 | Upstream request failed (with detail: "Response could not be safely returned") | PII redaction failed closed — Presidio returned an error and the org has the beta flag on | See troubleshooting: PII fail-closed 502 |
| 502 | Upstream request failed (with the platform error in detail) | The SaaS returned 5xx or the call timed out | Check the upstream platform status; the proxy retried per its policy |
Audit
Every call writes one row to audit_log with:
action= the requested scoperesult=allowed/denied/pending_approval/errormetadata.response_statusfrom the upstreampii_*columns if PII redaction ran- Forensic columns (
ip_address,user_agent,geo_country, etc.) if your org has forensic capture enabled