§ API · Authentication

Authenticate integrator API requests

Integrator endpoints are mounted under /api/nuvouch. Use x-api-key as the canonical server authentication header.

headers
required
x-api-key: $NUVOUCH_INTEGRATOR_API_KEY
content-type: application/json

# also accepted by the backend:
# Authorization: ApiKey $NUVOUCH_INTEGRATOR_API_KEY
§ API · Connection lifecycle

Inspect, list, and revoke active links

GET/api/nuvouch/v1/integrator/connections/sessions/:id
curl
check session
curl "https://api.nuvouch.com/api/nuvouch/v1/integrator/connections/sessions/conn_sess_123" \
  -H "x-api-key: $NUVOUCH_INTEGRATOR_API_KEY"
response
session envelope
{
  "session": {
    "id": "conn_sess_123",
    "sessionId": "conn_sess_123",
    "status": "accepted",
    "expiresAt": "2026-04-21T18:00:00.000Z",
    "acceptedAt": "2026-04-21T16:05:00.000Z",
    "subject": {
      "id": "cus_123",
      "label": "Ada Lovelace"
    },
    "context": {
      "key": "merchant:acct_live_001",
      "type": "merchant",
      "label": "Stripe Live Account"
    },
    "connection": {
      "id": "conn_123",
      "nuvouchUserId": "usr_nuvouch_456",
      "subject": {
        "id": "cus_123",
        "label": "Ada Lovelace"
      },
      "context": {
        "key": "merchant:acct_live_001",
        "type": "merchant",
        "label": "Stripe Live Account"
      },
      "capability": "hitl_only",
      "status": "active"
    }
  }
}
GET/api/nuvouch/v1/integrator/connections/lookup?subjectId=:subjectId&contextKey=:contextKey
curl
lookup active link
curl "https://api.nuvouch.com/api/nuvouch/v1/integrator/connections/lookup?subjectId=cus_123&contextKey=merchant:acct_live_001" \
  -H "x-api-key: $NUVOUCH_INTEGRATOR_API_KEY"
GET/api/nuvouch/v1/integrator/connections?subjectId=:subjectId&status=:status
curl
list connections
curl "https://api.nuvouch.com/api/nuvouch/v1/integrator/connections?subjectId=cus_123&status=active" \
  -H "x-api-key: $NUVOUCH_INTEGRATOR_API_KEY"
response
list envelope
{
  "items": [
    {
      "id": "conn_123",
      "nuvouchUserId": "usr_nuvouch_456",
      "subject": {
        "id": "cus_123",
        "label": "Ada Lovelace"
      },
      "context": {
        "key": "merchant:acct_live_001",
        "type": "merchant",
        "label": "Stripe Live Account"
      },
      "capability": "hitl_only",
      "status": "active",
      "lastConfirmedAt": "2026-04-21T16:05:00.000Z",
      "revokedAt": null,
      "createdAt": "2026-04-21T16:05:00.000Z",
      "updatedAt": "2026-04-21T16:05:00.000Z"
    }
  ]
}
POST/api/nuvouch/v1/integrator/connections/:id/revoke
curl
revoke connection
curl -X POST "https://api.nuvouch.com/api/nuvouch/v1/integrator/connections/conn_123/revoke" \
  -H "x-api-key: $NUVOUCH_INTEGRATOR_API_KEY"
response
revoked connection
{
  "connection": {
    "id": "conn_123",
    "nuvouchUserId": "usr_nuvouch_456",
    "subject": {
      "id": "cus_123",
      "label": "Ada Lovelace"
    },
    "context": {
      "key": "merchant:acct_live_001",
      "type": "merchant",
      "label": "Stripe Live Account"
    },
    "capability": "hitl_only",
    "status": "revoked",
    "lastConfirmedAt": "2026-04-21T16:05:00.000Z",
    "revokedAt": "2026-04-21T17:00:00.000Z",
    "createdAt": "2026-04-21T16:05:00.000Z",
    "updatedAt": "2026-04-21T17:00:00.000Z"
  }
}
§ API · Approvals

Create approval request (payment authorization flow)

POST/api/nuvouch/v1/integrator/approval-requests

Request body

FieldTypeDescription
targetUserId | targetConnectionId | targetSubjectone requiredExactly one targeting mode. New integrations should prefer targetSubject.
externalRequestIdrequiredstringYour durable business id such as payment_auth_001.
titlerequiredstringHeadline displayed to approver.
summaryrequiredstringShort context shown in request details.
requestedForrequiredstringBusiness domain label, such as Payment authorization.
actor.id / actor.namerequiredstringWho initiated the approval request in your system.
context.kind / context.title / context.reasonrequiredobjectWhat is being approved and why.
context.expiresAtrequiredISO datetimeDecision expiry timestamp.
context.referenceCoderequiredstringYour join key such as a payment intent id.
risk.levelrequiredlow | medium | highRisk emphasis and policy gating.
actionsarrayOptional explicit action labels shown to the user.
amountstringOptional human-readable amount such as $84.00.
curl
create approval
curl -X POST "https://api.nuvouch.com/api/nuvouch/v1/integrator/approval-requests" \
  -H "x-api-key: $NUVOUCH_INTEGRATOR_API_KEY" \
  -H "content-type: application/json" \
  -d '{
    "targetSubject": {
      "subjectId": "cus_123",
      "contextKey": "merchant:acct_live_001"
    },
    "externalRequestId": "payment_auth_001",
    "title": "Approve payment",
    "summary": "Stripe needs the customer to confirm a high-risk payment.",
    "requestedFor": "Payment authorization",
    "actor": {
      "id": "payments_agent_01",
      "name": "Stripe Payment Agent",
      "subtitle": "Payments risk workflow",
      "avatarLabel": "ST"
    },
    "context": {
      "kind": "digital-service",
      "title": "Card payment",
      "location": "Stripe",
      "reason": "High-risk payment requires customer confirmation",
      "expiresAt": "2026-04-21T18:00:00.000Z",
      "referenceCode": "pi_123"
    },
    "risk": {
      "level": "high",
      "summary": "Customer confirmation required before capture",
      "checks": ["3DS fallback unavailable", "Risk score above threshold"]
    },
    "actions": [
      { "label": "Approve payment", "value": "approve" },
      { "label": "Deny payment", "value": "deny" }
    ],
    "amount": "$84.00"
  }'
response
201 created
{
  "approvalRequest": {
    "id": "req_2f5cd6dbb6784b9ab2f7",
    "externalRequestId": "payment_auth_001",
    "targetUserId": "usr_nuvouch_456",
    "status": "pending",
    "title": "Approve payment",
    "summary": "Stripe needs the customer to confirm a high-risk payment.",
    "requestedFor": "Payment authorization",
    "amount": "$84.00",
    "createdAt": "2026-04-21T16:00:00.000Z",
    "decisionMethod": null,
    "decisionNote": null,
    "decisionDecidedAt": null,
    "cancelledAt": null,
    "context": {
      "kind": "digital-service",
      "title": "Card payment",
      "location": "Stripe",
      "reason": "High-risk payment requires customer confirmation",
      "expiresAt": "2026-04-21T18:00:00.000Z",
      "referenceCode": "pi_123"
    },
    "risk": {
      "level": "high",
      "summary": "Customer confirmation required before capture",
      "checks": ["3DS fallback unavailable", "Risk score above threshold"]
    },
    "actions": [
      { "label": "Approve payment", "value": "approve" },
      { "label": "Deny payment", "value": "deny" }
    ]
  }
}
§ API · Idempotency

Retry approval creation without creating duplicates

Approval creation deduplicates by (integrator, externalRequestId). Treat externalRequestId as the durable identity for the approval request you are trying to create.

  • Reuse the same externalRequestId on network retries, worker recovery, or queue replays.
  • If create returns DUPLICATE_EXTERNAL_ID, fetch by external_id instead of creating a new request.
  • Do not mint a fresh external id just because the first HTTP attempt had an uncertain outcome.
error-body.json
duplicate external id
{
  "error": {
    "code": "DUPLICATE_EXTERNAL_ID",
    "message": "Duplicate external request id payment_auth_001"
  }
}
§ API · Reads

Read approval request state for support and reconciliation

GET/api/nuvouch/v1/integrator/approval-requests/:id
curl
by id
curl "https://api.nuvouch.com/api/nuvouch/v1/integrator/approval-requests/req_2f5cd6dbb6784b9ab2f7" \
  -H "x-api-key: $NUVOUCH_INTEGRATOR_API_KEY"
GET/api/nuvouch/v1/integrator/approval-requests?external_id=:externalId
curl
by external id
curl "https://api.nuvouch.com/api/nuvouch/v1/integrator/approval-requests?external_id=payment_auth_001" \
  -H "x-api-key: $NUVOUCH_INTEGRATOR_API_KEY"
response
approved example
{
  "approvalRequest": {
    "id": "req_2f5cd6dbb6784b9ab2f7",
    "externalRequestId": "payment_auth_001",
    "status": "approved",
    "title": "Approve payment",
    "amount": "$84.00",
    "decisionMethod": "biometric",
    "decisionNote": "Approved from trusted device",
    "decisionDecidedAt": "2026-04-21T16:14:11.000Z"
  }
}
§ API · Lifecycle

Cancel pending request

POST/api/nuvouch/v1/integrator/approval-requests/:id/cancel
curl
cancel
curl -X POST "https://api.nuvouch.com/api/nuvouch/v1/integrator/approval-requests/req_2f5cd6dbb6784b9ab2f7/cancel" \
  -H "x-api-key: $NUVOUCH_INTEGRATOR_API_KEY"

Cancel works only while request is pending. Terminal states (approved, denied, expired, cancelled) return an error.

§ API · Errors

Stable error codes

FieldTypeDescription
API_KEY_REQUIRED401Integrator authentication header was missing.
INTEGRATOR_KEY_UNBOUND403API key exists but is not bound to an integrator.
INTEGRATOR_INACTIVE403Integrator is inactive or not provisioned.
INTEGRATOR_CALLBACK_NOT_CONFIGURED409Callback URL must be configured before creating connection sessions.
REQUEST_NOT_FOUND404Unknown approval request id or external id.
REQUEST_ALREADY_TERMINAL409Cannot cancel or mutate a completed request.
DUPLICATE_EXTERNAL_ID409This integrator has already used that externalRequestId.
CONNECTION_ALREADY_LINKED409The requested subject/context tuple already has an active link.
CONNECTION_NOT_FOUND404Unknown connection id or no active lookup match for the subject tuple.
CONNECTION_SESSION_NOT_FOUND404Unknown connection session id.
CONNECTION_SESSION_EXPIRED409Connection session or challenge expired before acceptance.
CONNECTION_CONFLICT409Session or challenge state conflicts with the attempted action.
UNLINKED_TARGET409No active connection exists for the supplied targetSubject or targetConnectionId.
RATE_LIMIT_EXCEEDED429Endpoint-specific rate limit hit. Respect Retry-After and retry later.
VALIDATION_FAILED400Input body or query shape failed validation.
FORBIDDEN403Caller is authenticated but does not have permission for that resource.
UNKNOWN_USER404targetUserId refers to a Nuvouch user that does not exist.
error-body.json
{
  "error": {
    "code": "RATE_LIMIT_EXCEEDED",
    "message": "Too many approval status reads. Retry after 42 seconds."
  }
}