Gvnr Approval API
The Approval API from Gvnr — 2 operation(s) for approval.
Operations 2
POST
/v1/approval/request
Create an approval request — returns approval_id, approval_url, expires_at
#
The Approval API from Gvnr — 2 operation(s) for approval.
Every API here is available over the APIs.io API and to AI agents over MCP.
One button, every client — Claude, Cursor, VS Code and the rest.
https://apis.io/mcp
find_apisBrowse and filter every API in the catalog.get_api_artifactsOne API's artifacts, grouped by type.get_openapiThe primary OpenAPI for this API.find_similar_apisAPIs that look like this one.apis_io_searchSTART HERE — APIs, providers and tags for one query, each with its total.resolveTurn a domain, URL or GitHub org into the provider it belongs to.find_cohortsEvery scored population of providers in the catalog.curl "https://apis.io/api/v1/apis/gvnr-dev:gvnr-dev-approval-api"
curl "https://apis.io/api/v1/apis?limit=25"
Calls without X-API-Key need no key. Calls with it need a paid plan — get a key.
Free tier, no form to fill in. Signing in shares your email address with us — we store it to create your key and to recognise you if you sign in with another provider. See our Privacy Policy and Terms.
A second provider on the same verified email joins the account you already have.
openapi: 3.2.0
info:
title: Gvnr Approval API
version: 1.8.1
description: Budget & cost control for AI agents — per-agent spend caps, rate limits, idempotency, post-call reconciliation, and human approval bridges, enforced before each call.
servers:
- url: https://gvnr.dev
tags:
- name: Approval
paths:
/v1/approval/request:
post:
summary: Create an approval request — returns approval_id, approval_url, expires_at
security:
- bearerAuth: []
requestBody:
content:
application/json:
schema:
type: object
required:
- agent_id
- action_summary
properties:
agent_id:
type: string
maxLength: 128
action_summary:
type: string
maxLength: 280
description: Human-readable description of what needs approval
ttl_seconds:
type: integer
minimum: 1
maximum: 604800
description: How long the approver has to decide (default 600s, max 7 days)
channels:
type: array
items:
type: string
enum:
- email
- telegram
- sms
description: Notification channels (default ["email"]; telegram/sms accepted in schema but rejected with channel_not_implemented in V1)
responses:
'200':
description: Approval created; notification dispatched per channel
content:
application/json:
schema:
type: object
required:
- approval_id
- approval_url
- expires_at
- notification
properties:
approval_id:
type: string
description: Opaque ID; pass to GET /v1/approval/check/{approval_id} to poll
approval_url:
type: string
format: uri
description: Mobile-first approval page URL to send to the human
expires_at:
type: integer
description: Unix ms when the approval window closes
notification:
type: object
required:
- email
properties:
email:
type: string
description: 'Dispatch status: "sent" | "no_address" | "skipped_no_key" | "failed"'
error:
type: string
description: Failure detail when status="failed"
'429':
description: Rate limited (30 request_approval calls per minute per account)
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
default:
description: Error (invalid_agent_id, invalid_action_summary, invalid_ttl_seconds, invalid_channels, channel_not_implemented, notification_email_unset)
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
tags:
- Approval
operationId: postV1ApprovalRequest
x-operation-id-source: derived
/v1/approval/check/{approval_id}:
get:
summary: Poll the status of an approval request
security:
- bearerAuth: []
parameters:
- name: approval_id
in: path
required: true
schema:
type: string
responses:
'200':
description: Current approval state
content:
application/json:
schema:
type: object
required:
- approval_id
- decision
- agent_id
- action_summary
- created_at
- expires_at
properties:
approval_id:
type: string
decision:
type: string
enum:
- pending
- approved
- denied
- timeout
agent_id:
type: string
action_summary:
type: string
created_at:
type: integer
description: Unix ms
expires_at:
type: integer
description: Unix ms
responder:
type: string
description: Present when decision is approved or denied
decided_at:
type: integer
description: Unix ms when the human decided (approved/denied only)
'404':
description: approval_not_found (wrong account, wrong id, or storage TTL elapsed past grace window)
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
default:
description: Error
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
tags:
- Approval
operationId: getV1ApprovalCheckByApprovalId
x-operation-id-source: derived
components:
schemas:
ErrorResponse:
type: object
required:
- error
properties:
error:
type: string
description: Stable machine-readable error code (e.g. "invalid_params", "rate_limited", "not_found")
required:
type: array
items:
type: string
description: Names/descriptors of required fields when error is "invalid_params"
hint:
type: string
description: Human-readable guidance for resolving the error
detail:
type: string
description: Additional context for the error
valid:
type: array
items:
type: string
description: Allowed values when input was rejected as out-of-set
valid_channels:
type: array
items:
type: string
description: Allowed notification channels (for approval requests)
retryable:
type: boolean
description: Whether retrying the same request can succeed. false = fix input / auth / config first, or terminal. Omitted when retryability is already implied by required/valid (fix the input) or retry_after_ms (wait, then retry).
retry_after_ms:
type: integer
description: Milliseconds to wait before retrying — present on rate_limited (429). Matches the runtime rate_check field.
limit:
type: string
description: Description of the limit that was hit
securitySchemes:
bearerAuth:
type: http
scheme: bearer
description: API key from POST /v1/account