API reference

Build against the authorization plane.

Greene Comply sits ahead of your payment rails. Before your agent spends, it calls our API. We approve, deny, or hold the request against the policy you set. Your rail only executes what we approve.

01

Overview

Greene Comply sits ahead of your payment rails. Before your agent spends, it calls our API. We approve, deny, or hold the request against the policy you set. Your rail only executes what we approve.

Base URL: https://api.greenecomply.com/v1

All responses are JSON. All timestamps are ISO 8601. All amounts are in the smallest currency unit (cents for USD).

02

Authentication

All requests require a Bearer token in the Authorization header. Tokens are scoped per agent and generated from the dashboard or via API.

http
Authorization: Bearer gc_live_xxxxxxxxxxxx

Tokens are stored as SHA-256 hashes server-side. We never store the raw token. Sandbox tokens begin with gc_test_, live tokens begin with gc_live_.

03

Authorization Checks

POST /v1/authorize

This is the core endpoint. Your agent calls this before every spend. We evaluate identity, policy, and counterparty in milliseconds and return a signed decision.

Request body

agent_idrequired
stringThe registered agent making the spend.
amountrequired
numberAmount in cents (smallest currency unit).
currencyrequired
stringISO 4217 currency code, e.g. "usd".
vendorrequired
stringCounterparty name or domain.
category
stringSpend category, e.g. "saas", "compute", "travel".
metadata
objectArbitrary key-value pairs, stored on the audit log.

Response fields

decision
"approved" | "denied" | "held"The outcome of policy evaluation.
decision_id
stringUnique ID for this decision — reference in your audit log.
authorization_token
stringSigned token; present only on approved decisions. Pass to your rail.
reason
stringPresent on denied and held decisions.
policy_applied
stringID of the policy that was evaluated.
timestamp
ISO 8601Server time of the decision.

cURL

bash
curl -X POST https://api.greenecomply.com/v1/authorize \
  -H "Authorization: Bearer $GREENE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "agent_id": "agt_8f2k9d",
    "amount": 4500,
    "currency": "usd",
    "vendor": "openai.com",
    "category": "compute",
    "metadata": { "request_id": "req_a1b2c3" }
  }'

Node.js (fetch)

typescriptauthorize.ts
import { fetch } from 'undici'

const res = await fetch('https://api.greenecomply.com/v1/authorize', {
  method: 'POST',
  headers: {
    'Authorization': `Bearer ${process.env.GREENE_API_KEY}`,
    'Content-Type':  'application/json',
  },
  body: JSON.stringify({
    agent_id: 'agt_8f2k9d',
    amount:   4500,
    currency: 'usd',
    vendor:   'openai.com',
    category: 'compute',
    metadata: { request_id: 'req_a1b2c3' },
  }),
})

const decision = await res.json()
if (decision.decision !== 'approved') {
  throw new Error(`Spend blocked: ${decision.reason}`)
}

// Pass decision.authorization_token to your payment rail
await chargeStripe({ token: decision.authorization_token })
Approved
json
{
  "decision":              "approved",
  "decision_id":           "dec_01HXY2K5R3P7M9N4Q6S8T2V1W3",
  "authorization_token":   "gca_eyJhbGciOiJFUzI1NiJ9...",
  "policy_applied":        "pol_default_compute",
  "timestamp":             "2026-05-05T14:22:09.418Z"
}
Denied
json
{
  "decision":      "denied",
  "decision_id":   "dec_01HXY2K9V8C1L4P2R5T7W9Y3Z1",
  "reason":        "Vendor not on allowlist for this agent.",
  "policy_applied":"pol_default_compute",
  "timestamp":     "2026-05-05T14:22:09.418Z"
}
Only calls that return HTTP 200 are billable. Errors, 4xx, and sandbox calls are never counted toward usage.
04

Agents

Manage the agents that can authorize spend on your account.

POST/v1/agentsRegister a new agent
GET/v1/agentsList all agents (paginated)
GET/v1/agents/:idRetrieve a single agent
PATCH/v1/agents/:idUpdate agent
DELETE/v1/agents/:idDeactivate agent

Agent object

id
stringStable identifier. Begins with "agt_".
name
stringHuman-readable label shown in the dashboard.
policy_id
stringPolicy currently bound to this agent.
status
"active" | "frozen" | "deactivated"Authorization availability.
kyc_status
stringIdentity verification state for the human owner.
created_at
ISO 8601When the agent was registered.
metadata
objectArbitrary key-value pairs you set on create or update.

Register an agent

http
POST /v1/agents
Authorization: Bearer $GREENE_API_KEY
Content-Type:  application/json

{
  "name":      "Research crawler",
  "policy_id": "pol_default_compute",
  "metadata":  { "team": "growth" }
}

# 201 Created
{
  "id":         "agt_8f2k9d",
  "name":       "Research crawler",
  "policy_id":  "pol_default_compute",
  "status":     "active",
  "kyc_status": "pending",
  "created_at": "2026-05-05T14:18:02.044Z",
  "metadata":   { "team": "growth" }
}

List agents

http
GET /v1/agents?limit=20
Authorization: Bearer $GREENE_API_KEY

# 200 OK
{
  "data": [
    {
      "id":         "agt_8f2k9d",
      "name":       "Research crawler",
      "policy_id":  "pol_default_compute",
      "status":     "active",
      "kyc_status": "verified",
      "created_at": "2026-05-05T14:18:02.044Z",
      "metadata":   { "team": "growth" }
    }
  ],
  "has_more": false,
  "next_cursor": null
}
05

Policies

Policies are the rules every authorization is checked against. Bind one policy to one or many agents.

POST/v1/policiesCreate policy
GET/v1/policiesList policies
GET/v1/policies/:idRetrieve policy
PATCH/v1/policies/:idUpdate policy
DELETE/v1/policies/:idDelete policy

Policy object

name
stringDisplay name for the policy.
budget_monthly
numberCents. Rolling monthly cap across all approved spend.
budget_single_max
numberCents. Hard ceiling on a single transaction.
vendor_allowlist
string[]Vendors permitted without further checks.
vendor_denylist
string[]Vendors that always deny, regardless of amount.
require_approval_above
numberCents. Holds for human review above this amount.
categories_allowed
string[]Spend categories permitted by this policy.
active
booleanInactive policies are skipped at evaluation.
06

Audit Logs

GET /v1/audit-logs

Returns paginated append-only records. Every authorization decision, freeze, override, and approval is captured.

Query parameters

agent_id
stringFilter by agent.
decision
"approved" | "denied" | "held"Filter by outcome.
from
ISO 8601Lower-bound timestamp (inclusive).
to
ISO 8601Upper-bound timestamp (exclusive).
limit
numberMax 100. Default 50.
cursor
stringPagination cursor returned by the previous response.

Export: pass Accept: text/csv for CSV export or Accept: application/json for JSON (default).

07

Webhooks

Greene Comply emits signed webhook events for key state changes. Configure delivery URLs in the dashboard or via API.

Events

authorize.approvedA POST /v1/authorize call returned approved.
authorize.deniedA POST /v1/authorize call returned denied.
authorize.heldA request requires human approval and is queued.
agent.frozenAn agent has been frozen — no further spend possible.
approval.completedA held request has been resolved (approved or denied).

Payload shape

json
{
  "event":     "authorize.denied",
  "data":      { /* event-specific payload */ },
  "timestamp": "2025-05-01T12:00:00Z",
  "signature": "sha256=..."
}

Verify signatures (Node.js)

Verify signatures using HMAC-SHA256 with your webhook secret. Always read the raw request body — JSON re-serialization will invalidate the signature.

typescriptverify-greene.ts
import crypto from 'node:crypto'

export function verifyGreeneSignature(
  rawBody: string,
  signatureHeader: string, // value of "X-Greene-Signature"
  secret: string,
): boolean {
  // Header format: "sha256=<hex>"
  const expected = signatureHeader.replace(/^sha256=/, '')
  const computed = crypto
    .createHmac('sha256', secret)
    .update(rawBody, 'utf8')
    .digest('hex')

  // Timing-safe comparison guards against signature-extraction side channels.
  return (
    expected.length === computed.length &&
    crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(computed))
  )
}
08

Errors

Error responses follow a consistent shape. The HTTP status reflects the class of error; the code field is the precise machine-readable cause.

json
{
  "error": {
    "code":    "budget_exceeded",
    "message": "Monthly budget limit reached for this agent.",
    "param":   "amount"
  }
}

Error codes

unauthorizedMissing or invalid bearer token.
policy_deniedA policy rule rejected the request.
agent_frozenThe agent is frozen and cannot transact.
budget_exceededMonthly cap or single-transaction max reached.
invalid_requestA required field is missing or malformed.
rate_limitedToo many requests for this plan in the current window.
not_foundThe referenced resource does not exist.
09

Rate Limits

PlanLimit
Sandbox100 req/min
Starter500 req/min
Growth2,000 req/min
EnterpriseCustom

Headers returned on every response: X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset.

On 429, retry after the value in X-RateLimit-Reset.

10

API Pricing

Usage is tracked via Stripe Billing Meters. Every successful call to POST /v1/authorize counts as one authorization check. Stripe aggregates usage across the month and invoices on your billing cycle. Only HTTP 200 responses are counted — errors, 4xx, and sandbox calls are never billed.

PlanIncluded checks/moOverage rate
SandboxUnlimitedFree forever
Starter10,000$0.0015 per check
Growth100,000$0.0008 per check
EnterpriseCustomVolume pricing
You can view real-time usage and projected monthly costs in your dashboard. Overages are invoiced automatically at the end of your billing cycle via Stripe.
View plans