API Reference

Agent & Client API

The wire shape your Agent SDK and Client SDK speak with the Noxy relay. Useful when you build a custom integration, debug a flow, or audit a payload.

Endpoint & transport

Agent APIClient API
Hostrelay.noxy.network
TransportgRPC over HTTP/2 (TLS)gRPC bi-di stream or WebSocket (JSON) over TLS
Authauthorization: Bearer APP_TOKENFirst message: Authenticate or RegisterDevice; then a relay-issued session_id on every message
Wire formatProtobufProtobuf (gRPC) or JSON / camelCase (WSS)

In normal use you call these through an SDK. The shapes below are the same ones the SDKs produce and consume; use them as a contract when extending.

Agent API

RouteDecision

Route an encrypted decision to a target device. Returns one delivery outcome per call.

Request

FieldTypeNotes
request_idstringStable per logical attempt; echoed in the response and in logs.
ciphertextbytesAES-256-GCM ciphertext of the decision JSON.
kyber_ctbytesKyber768 encapsulation of the symmetric key against the target device.
noncebytes12-byte random nonce used with AES-GCM.
target_device_idstringThe device the envelope is encrypted for.
ttl_secondsuint32Time-to-live in seconds. Omit or pass 0 for the default (600 s).

ResponseDeliveryOutcome

FieldTypeNotes
request_idstringEcho of your request id.
decision_idstringUse this with GetDecisionOutcome. Empty if the relay could not track human resolution (e.g. NO_DEVICES).
statusenumDELIVERED, QUEUED, NO_DEVICES, REJECTED, or ERROR.

Tip. Agent SDKs handle per-device fan-out for you. If an identity has three devices you get back three delivery outcomes, one per ciphertext. Pick any non-empty decision_id to poll — outcomes are identity-wide.

GetDecisionOutcome

Identity-wide outcome of a previously routed decision.

Request

FieldTypeNotes
request_idstringStable per poll attempt.
decision_idstringFrom the original RouteDecision response.
identity_idstringThe same logical id used to route the decision (e.g. email, wallet, user id).

Response

FieldTypeNotes
pendingbooltrue while no device has answered.
outcomeenumPENDING while in flight; one of APPROVED, REJECTED, EXPIRED when terminal.

Poll until pending is false. SDKs do this with exponential backoff.

GetQuota

Quota and status for your application.

Response

FieldType
app_namestring
quota_totaluint64
quota_remaininguint64
statusQUOTA_ACTIVE | QUOTA_SUSPENDED | QUOTA_DELETED

GetIdentityDevices

List the devices currently registered for a logical identity.

Request

FieldType
request_idstring
identity_idstring

Response — repeated devices

FieldType
device_idstring
public_keybytes — classical public key
pq_public_keybytes — Kyber768 public key

Client API

The Client API is a single bidirectional stream. The first message authenticates or registers the device; subsequent messages share a session_id issued by the relay.

Message envelope (all requests)

FieldTypeNotes
request_idstringStable per attempt.
app_idstringFrom the dashboard.
device_idstringIssued on first RegisterDevice or Authenticate response.
session_idstringIssued by the relay; required after first message.
timestampint64Client-side milliseconds.
noncebytes (12)Per-message anti-replay nonce.

Operations

OperationWhat it does
RegisterDeviceOne-time identity binding. Carries identity_type, identity_id, the registration HMAC signature, and the device's classical + post-quantum public keys.
AuthenticateReconnect with existing device keys. Returns the session id.
SubscribeDecisionsStart receiving DecisionEvent frames (ciphertext, Kyber capsule, nonce). The SDK drains any backlog first.
DecisionOutcomePublish the user's answer: APPROVE or REJECT, with decision_id and received_at.
RotateDeviceKeysReplace the device's key pairs without re-registration.
RevokeDeviceRemove the device permanently. Queued decisions are dropped.

JSON over WebSocket

Browsers connect with WSS to the same host. All messages are JSON with camelCase fields and binary values (nonce, publicKey, signature, ciphertext) base64-encoded. The semantics are identical to gRPC; the wire is different only in encoding.

{
  "requestId": "req-1",
  "appId": "your-app-id",
  "timestamp": 1731700000000,
  "nonce": "<base64 12 bytes>",
  "registerDevice": {
    "identityType": "email",
    "identityId": "user@example.com",
    "signature": "<base64 HMAC>",
    "devicePubkeys": {
      "publicKey": "<base64>",
      "pqPublicKey": "<base64>"
    }
  }
}

Status codes & errors

WhereWhat you'll see
HTTP / gRPCStandard gRPC status codes — UNAUTHENTICATED for bad tokens, RESOURCE_EXHAUSTED for rate limits, UNAVAILABLE for transient errors.
Per-decisionThe status field on DeliveryOutcome distinguishes QUEUED, DELIVERED, NO_DEVICES, REJECTED, and ERROR.
Per-pollpending and outcome on GetDecisionOutcome; SDKs raise WaitForDecisionOutcomeTimeoutError after maxWaitMs.

See Rate Limits for per-app and per-connection thresholds, Best Practices for retry and idempotency guidance, and Encryption & Security for the construction of the encrypted envelope.