Skip to content
LogoLogo

Nava Guardian API reference

Developer Preview

Nava Guardian integrations use Nava Service to submit a structured proposed action and read its policy verdict.

Authentication

Send one agent API key header on both operations:

x-api-key: <agent-api-key>

Do not also send a bearer token. For least privilege, use an agent key with verdicts:create:own. The status route requires authentication and confirms that the caller owns the transaction.

Never send the key in a URL, persist it in request metadata, or log it.

POST /transactions

Submit a canonical action for policy evaluation. Agent keys default to policy routing, but clients should send arbiter: "policy" explicitly.

Request body

FieldTypeRequiredDescription
escrowAddressstringYesThe agent's registered wallet for the proposed chain.
promptstringYesNon-empty human-readable description of the action.
proposedTxobjectYesCanonical structured action. Must include protocol and chainId, plus the venue-specific action/signing fields.
metadataobjectNoNon-action context. Do not include secrets.
contextLogsobjectNoAdditional non-sensitive debugging context.
executionSignaturestringNoExecution signature for flows that require it.
arbiterpolicyNoSelects Nava Guardian policy evaluation. Set it explicitly to policy.
{
  "escrowAddress": "0x1111111111111111111111111111111111111111",
  "prompt": "Swap a placeholder amount using the configured policy.",
  "proposedTx": {
    "protocol": "uniswap",
    "chainId": 11155111,
    "to": "0x2222222222222222222222222222222222222222",
    "data": "0x",
    "value": "0x0"
  },
  "metadata": {
    "environment": "test"
  },
  "arbiter": "policy"
}

The addresses and action data are placeholders. Replace them before use. Agent keys cannot use the pre-encrypted request shape.

201 response

The response is the created transaction record. The integration-critical field is requestHash:

FieldTypeDescription
idstringService transaction identifier.
requestHashstringHash-bound request identifier used by the status route.
descriptionstringUser-facing description derived from prompt.
statusstringTransaction lifecycle state; not the Guardian verdict.
Other transaction fieldsvariesThe service can return additional stored transaction fields.
{
  "id": "11111111-2222-3333-4444-555555555555",
  "requestHash": "0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
  "description": "Swap a placeholder amount using the configured policy.",
  "status": "PENDING"
}

Reject a successful HTTP response that lacks a non-empty string requestHash.

GET /transactions/:requestHash/approval-status

Read the request's approval envelope and Nava Guardian verdict.

Path parameter

ParameterTypeRequiredDescription
requestHashstringYesThe exact value returned by POST /transactions.

Response envelope

FieldTypeDescription
verdictverdict or nullGuardian policy verdict when present. It may be absent or null before one is available.

Verdict object

FieldTypeDescription
schemaVersion1Literal verdict schema version.
outcomeenumAuthoritative state: pending, approved, or rejected.
reasonCodeenumTop-level machine-readable reason. Must agree with the outcome.
humanReasonstringHuman-readable explanation.
triggeringPolicyFieldstring or nullDotted path to the policy field responsible for a rejection, when applicable.
checkscheck[]Per-check results.
evidenceobjectdecodedAction, concrete observations, and source references.
policyVersioninteger or nullPolicy version evaluated; may be null while pending or before policy resolution.
latencyMsnon-negative integerEvaluation latency.
dataFreshnessobjectOverall and per-source freshness.
trustobjectTrust level and optional notes.
redactionobjectWhether fields were redacted and which fields.
usdNotionalnon-negative number or nullAction notional when applicable.
timestampISO 8601 stringVerdict timestamp.

Check results

Each checks[] item contains a checkId, status, optional failure code, human-readable reason, and optional triggering policy field. The table below is the complete implemented and in-review check contract. See Policy checks for human-readable behavior and applicability.

checkIdHuman-readable checkAvailabilityFailure code
venueVenueAvailablevenue_not_allowed
chainNetworkAvailablechain_not_allowed
contract_selectorContract and functionAvailablecontract_or_selector_not_allowed
assetAssetAvailableasset_not_in_universe
recipientRecipientAvailablerecipient_not_allowed
sideTrade sideAvailableside_not_allowed
slippage_guardSlippage protectionAvailableno_slippage_guard
execution_price_boundExecution price boundAvailableno_execution_price_bound
leverageLeverageAvailableleverage_cap_exceeded
sanctionsSanctionsAvailablesanctioned_address
sink_recipientSink recipientAvailablesink_recipient
per_tx_capPer-transaction USD capIn reviewper_tx_cap_exceeded or data_unavailable
checks[].statusMeaning
passedThe check ran and the action satisfied it.
failedThe check ran and rejected the action.
not_checkedThe check did not apply or its optional policy constraint was not configured.

Other enum values

FieldValues
outcomepending, approved, rejected
reasonCodeallowed, pending, decode_failure, data_unavailable, and the failure codes listed in the check table above
dataFreshness.overallfresh, cached, mixed
dataFreshness.sources[].statusfresh, cached
trust.levelhigh, medium, low

An approved verdict must use reasonCode: "allowed"; a pending verdict must use reasonCode: "pending"; and a rejected verdict must use a violation code. Except for cross-cutting decode_failure and data_unavailable, a rejected reason code must match a failed check.

Approved response

{
  "verdict": {
    "schemaVersion": 1,
    "outcome": "approved",
    "reasonCode": "allowed",
    "humanReason": "The action satisfies the configured policy.",
    "triggeringPolicyField": null,
    "checks": [
      {
        "checkId": "venue",
        "status": "passed",
        "code": null,
        "humanReason": "The venue is configured.",
        "triggeringPolicyField": null
      }
    ],
    "evidence": {
      "decodedAction": {
        "protocol": "uniswap",
        "chainId": 11155111
      },
      "observations": {},
      "sources": []
    },
    "policyVersion": 3,
    "latencyMs": 42,
    "dataFreshness": {
      "overall": "fresh",
      "sources": []
    },
    "trust": {
      "level": "high",
      "notes": null
    },
    "redaction": {
      "redacted": false,
      "fields": []
    },
    "usdNotional": null,
    "timestamp": "2026-07-20T12:00:00.000Z"
  }
}

Rejected response

{
  "verdict": {
    "schemaVersion": 1,
    "outcome": "rejected",
    "reasonCode": "chain_not_allowed",
    "humanReason": "The proposed chain is not allowed by the active policy.",
    "triggeringPolicyField": "venues.uniswap.chainAllowlist",
    "checks": [
      {
        "checkId": "chain",
        "status": "failed",
        "code": "chain_not_allowed",
        "humanReason": "Chain 11155111 is not in the allowlist.",
        "triggeringPolicyField": "venues.uniswap.chainAllowlist"
      }
    ],
    "evidence": {
      "decodedAction": {
        "protocol": "uniswap",
        "chainId": 11155111
      },
      "observations": {
        "chainId": 11155111
      },
      "sources": []
    },
    "policyVersion": 3,
    "latencyMs": 37,
    "dataFreshness": {
      "overall": "fresh",
      "sources": []
    },
    "trust": {
      "level": "high",
      "notes": null
    },
    "redaction": {
      "redacted": false,
      "fields": []
    },
    "usdNotional": null,
    "timestamp": "2026-07-20T12:00:00.000Z"
  }
}

Status-code handling

StatusOperationHandling
200StatusValidate the envelope and verdict; poll only a missing, null, or pending verdict.
201SubmitValidate and retain requestHash.
400SubmitCorrect the DTO or action; do not retry unchanged.
401BothAuthentication failed. Stop and replace or re-authenticate the key.
403BothScope, ownership, agent, or registered-wallet mismatch. Stop and correct configuration.
404StatusUnknown request. Stop and reconcile the captured hash/base URL.
429BothRate limited. A bounded GET retry is safe; do not blindly repeat a POST.
5xx or network failureBothKeep the action paused. Retry GET within a bounded deadline; reconcile an uncertain POST before resubmitting.

Polling, retries, and idempotency

Use bounded exponential backoff for a missing, null, or pending verdict and for transient status-read failures. Cap both the delay and total attempts, pass an abort signal to every request and delay, and fail closed when the bound is reached.

The Developer Preview submit DTO and controller expose no idempotency key. Do not automatically retry POST /transactions: a repeat can create another request. GET /transactions/:requestHash/approval-status is read-only and can be retried within the polling bound after 429, transient 5xx, or network interruption.

Malformed JSON, an unknown outcome, inconsistent required verdict fields, or a persistently unavailable service is not approval. Stop the action and surface a non-sensitive error alongside the requestHash when available.