Skip to main content

Documentation Index

Fetch the complete documentation index at: https://spendguard.mintlify.app/llms.txt

Use this file to discover all available pages before exploring further.

Endpoint

POST /v1/checks
Authentication: Required (X-API-Key header) This is the core endpoint. Your agent calls this before executing any financial action.

Request Body

FieldTypeRequiredDescription
agent_idstringYesID of the agent making the request
policy_idstringYesPolicy to evaluate against
action_typestringNo*One of: refund, credit, discount, spend. *Required unless reason_text is provided.
amountnumberYesDollar amount of the action (>= 0)
currencystringYesISO 4217 currency code (exactly 3 characters, e.g., “USD”)
counterpartystringYesCustomer ID, vendor ID, or counterparty identifier
payment_methodstringNoPayment method (e.g., “card”, “ach”, “wire”, “crypto”)
merchant_or_vendorstringNoMerchant or vendor identifier
reason_textstringNo*Why this action is being taken. *Required if action_type is omitted — the intent classifier resolves it.
idempotency_keystringNoUnique key for safe retries (24-hour window)
metadataobjectNoAdditional context for rule evaluation

Common Metadata Fields

KeyTypeUsed By
days_since_purchaseintegerrefund_age_limit rule
discount_percentnumberdiscount_cap rule
countrystringgeography_block rule
categorystringblocked_categories rule
Either action_type or reason_text must be provided. If both are missing, the API returns a 422 validation error.

Example Request

curl -X POST https://spendguardapi.com/v1/checks \
  -H "Content-Type: application/json" \
  -H "X-API-Key: $SPENDGUARD_API_KEY" \
  -d '{
    "agent_id": "support-agent-v1",
    "policy_id": "my_refund_policy",
    "action_type": "refund",
    "amount": 300.00,
    "currency": "USD",
    "counterparty": "customer_789",
    "metadata": {
      "days_since_purchase": 5
    }
  }'

Response — 200 OK

{
  "check_id": "chk_a1b2c3d4e5f6",
  "decision": "escalate",
  "confidence": "high",
  "reason_code": "escalation_threshold_exceeded",
  "message": "Refund of $300.00 exceeds the escalation threshold of $200.00.",
  "violated_rule_id": "r2",
  "violated_rule_description": "Escalate refunds over $200",
  "policy_version": 1,
  "next_step": "Route to human approval before proceeding.",
  "latency_ms": 11,
  "timestamp": "2026-04-03T12:00:00Z"
}

Response Fields

FieldTypeDescription
check_idstringUnique check identifier (chk_...)
decisionstringallow, block, or escalate
confidencestringhigh, medium, or low
reason_codestring or nullMachine-readable reason (null on allow)
messagestring or nullHuman-readable explanation
violated_rule_idstring or nullWhich rule triggered (null on allow)
violated_rule_descriptionstring or nullDescription of the violated rule
policy_versionintegerWhich policy version was evaluated
next_stepstring or nullRecommended next action for the agent
latency_msintegerProcessing time in milliseconds
timestampstringDecision timestamp (UTC ISO 8601)

Processing Flow

  1. Load the policy (latest version)
  2. If action_type is missing, resolve it via the intent classifier using reason_text
  3. Check for idempotency key hit (return cached response if found)
  4. Run duplicate guard (block if fingerprint matches within window)
  5. Evaluate all rules in the policy
  6. Log the decision to the immutable audit trail
  7. If block or escalate, log to violations table
  8. Return the response

Idempotency

Include an idempotency_key for safe retries:
{
  "agent_id": "support-agent-v1",
  "policy_id": "my_refund_policy",
  "action_type": "refund",
  "amount": 300.00,
  "currency": "USD",
  "counterparty": "customer_789",
  "idempotency_key": "refund-customer789-20260403"
}
If the same idempotency_key is sent again within 24 hours, SpendGuard returns the original response without re-running rules or creating new audit records.

Error Responses

StatusCodeWhen
401unauthorizedMissing or invalid API key
404policy_not_foundPolicy ID does not exist
422validation_errorMissing required fields, or both action_type and reason_text are absent
429rate_limit_exceededToo many requests
500internal_errorServer error