Repository navigation
API Reference
- Introduction
- Project Structure
- Core Components
- Architecture Overview
- Detailed Component Analysis
- Dependency Analysis
- Performance Considerations
- Troubleshooting Guide
- Conclusion
- Appendices
This document describes Sigvara’s oracle REST API endpoints relevant to attestation submission, reputation scoring, and evidence access. It covers:
-
/attest— submit an attestation for a Sigvara agent. -
/score/:didHash— preview the computed score for an agent without writing to chain. -
/evidence/:didHash— retrieve the payments behind an agent’s score with Merkle proofs.
It also documents authentication, rate limiting, error handling, security considerations, input validation, and practical request/response examples.
The oracle is implemented as a Node.js HTTP server that routes requests directly in its main handler. Authentication, body parsing, credential loading, and rate limiting are shared helpers.
graph TB
Client["API Consumer"] --> Server["Oracle HTTP Server<br/>index.js"]
Server --> Helpers["HTTP Helpers<br/>http-helpers.js"]
Server --> Chain["Chain Layer"]
Server --> Payments["Payments Verification"]
Server --> Scoring["Scoring Logic"]
Server --> Store["Persistent State"]
Server --> Merkle["Merkle Utilities"]
Server --> Cache["Response Cache"]
Diagram sources
Section sources
-
Request router: Centralized HTTP handler dispatches paths such as
/health,/attest,/score/:didHash,/evidence/:didHash,/outcomes,/flag,/flag/resolve,/link,/jobs/<address>,/badge/<address>.svg,/metrics,/epoch, and divergence endpoints. A request target must be a path in canonical form://evidence/metrics,/evidence/../metrics, absolute-form targets and anything the URL parser would rewrite get400 bad request target, and an error a route does not handle itself is logged and answered500 internal error. - Authentication: Bearer tokens loaded from environment variables; supports a legacy admin token and named per-service tokens, optionally restricted to a list of scopes.
-
Rate limiting: In-memory fixed-window limiter keyed by client address and by kind of route, with
X-Forwarded-Forbelieved only from loopback and from the proxies listed inTRUSTED_PROXIES. - Payment verification: Optional verified-payment path where a transaction hash proves payment to the agent’s own address, read from the identity registry.
- Scoring inputs: Attestations, flags, external ERC-8004 feedback, measured fee volume, activity, and propagation factors.
- Evidence and Merkle proofs: Payment events are exposed with a Merkle root and leaf structure suitable for on-chain verification.
Section sources
- index.js:1868-2169
- index.js:2476-2553
- index.js:2253-2280
- http-helpers.js:61-113
- http-helpers.js:145-192
The oracle exposes read-only and write endpoints. Read endpoints (/score, /evidence, /outcomes) are intentionally unauthenticated but rate-limited. Write endpoints require bearer-token authorization and additional validation, with one exception: POST /attest accepts a positive attestation backed by a verified payment without a token, and then records the payment and no outcome. It also takes an outcome the payer signed (payerOutcome) without a token, because the signature is the credential.
sequenceDiagram
participant C as "Client"
participant S as "Server index.js"
participant H as "Helpers http-helpers.js"
participant P as "Payments"
participant CH as "Chain"
C->>S : POST /attest { didHash, success, payment, packetId }
S->>H : identifyCaller(headers, credentials)
alt Payments required and success is true
S->>S : no token needed, the payment is the credential for the payment
else Negative, success omitted, or payments off
S->>S : require bearer token
end
alt Payments required
S->>CH : getAgentInfo(didHash)
CH-->>S : agent info
S->>P : verifyPayment(txHash, agentAddress)
P-->>S : credited payer, amount, settledAt
end
S->>S : check cooldown, credit the payment, record the outcome for a token holder
S-->>C : 200 { didHash, attester, totals, payment?, outcomeRecorded? }, or 202 with durable false when the state could not be saved
Diagram sources
Submits an attestation for a Sigvara agent. The endpoint supports two modes:
-
Verified-payment mode (
PAYMENT_VERIFICATION=required): Every attestation carriespayment.txHash, the settlement of a real payment to the agent’s own address. A positive attestation (success: true) can be submitted without a bearer token: the verified payment is the credential for the payment, and the payer is read from the transfer log. Without a token it is recorded with no outcome (the response says"outcomeRecorded": false), because a settlement hash is public and does not show that the caller paid or saw the work. With a token the outcome is recorded:true,false, or left out for none. Negative attestations, and any whosesuccessis missing or not a boolean, still require a bearer token, unless the request carries the payer's signed outcome inpayerOutcomeinstead ofsuccess(below). -
Token-only mode (
PAYMENT_VERIFICATION=off, the default): A bearer token is always required, and the caller must provide anattesteridentifier.
- Method:
POST - Path:
/attest - Headers:
-
Authorization:Bearer <token>(required unless positive + verified-payment mode) -
Content-Type:application/json
-
- Body fields:
-
didHash(string, required): 32-byte hex identity hash of the agent. Any casing is accepted and it is stored in lowercase. -
success(boolean): Whether the work was successful. Exactlytrueis what lets a caller without a token through. A token holder may sendtrue,false, or leave it out for no outcome, and any other value is a400. -
payerOutcome(object, optional): An outcome the payer signed, in place ofsuccess, taken only wherePAYER_OUTCOMESis on. It holdspayer,outcome(1delivered,2not delivered), an optionalevidence(32 bytes, zero when left out),signedAtanddeadline(seconds) andsignature, EIP-712 overPaymentOutcome(bytes32 didHash, bytes32 txHash, address payer, uint8 outcome, bytes32 evidence, uint64 signedAt, uint64 deadline)in the domainSigvara, version1, onEXPECTED_CHAIN_IDwithREPUTATION_ADDRESSas the verifying contract. It needs no token. Sending bothsuccessandpayerOutcomeis a400. -
packetId(string, optional): An optional UUID-like identifier used as corroboration when payment verification is enabled. It is kept only from a token holder, or from whoever carries a payer-signed outcome (where it names the CounterAudit packet that sealed that outcome); a stranger's is ignored, as theirsuccessis. When a token holder gives an outcome to a payment credited without one, theirpacketIdgoes on with it unless the payment already has one. It is stored beside the payment and served from/evidence, and it is never part of the Merkle leaf. A value that is not 36 hex-or-dash characters is ignored. -
payment.txHash(string, required when payment verification is enabled): Transaction hash used to prove payment to the agent’s own address. A missing or malformed value is a402with codebad_tx_hash. -
attester(string, optional): Unique ID for the attestation source; required when payment verification is disabled, and ignored when it is enabled, because the attester is then the payer taken from the transfer log.
-
- Success:
200 OK, the attestation was accepted and saved- Fields include
didHash,attester, updated attestation totals (successful,total), and, when a payment was credited,payment.txHash,payment.amount(the total of the qualifying senders, in the asset’s base units) andoutcomeRecorded. The response to a payer-signed outcome also carriesoutcomeHash, the EIP-712 hash of what was recorded.
- Fields include
- Accepted but not saved:
202 Accepted, with the same fields anddurable: false. The oracle could not write its state file, so a restart before its next good save would lose what it just recorded, and/healthanswers 503 until a save works. Do not resend: the attestation is recorded in memory and the next save that works keeps it, and a resend is refused (409for a settlement already credited,429inside the cooldown). The count issigvara_oracle_attest_total{result="accepted_not_durable"}. - Errors:
-
400 Bad Request: Missing or invalid fields,successthat is not a boolean for a token holder, an unreadable body, or an unknowndidHash. For a payer-signed outcome alsobad_payer_outcome(malformed, or sent withsuccess),payer_outcomes_off,negative_not_accepted(a "not delivered" where only "delivered" is taken),outcome_window(timing) andbad_signature; after five bad signatures for one leg in an hour the answer is429withbad_signature_throttled. -
401 Unauthorized: Missing or invalid bearer token when required. -
402 Payment Required: Invalid payment, self-payment, or other payment-related failure. Thecodefield says which (bad_tx_hash,not_found,reverted,unconfirmed,no_transfer,below_minimum,self_payment), and for a payer-signed outcomepayer_mismatchwhen the signer has no leg of its own in the transaction. -
403 Forbidden: The credential is restricted byORACLE_SCOPES_<NAME>to scopes that do not includeattest. -
409 Conflict: Settlement already credited (replayed), or the credited payment already has an outcome, which is final (outcome_recorded), except that a payer's signed outcome can replace a token holder's insidePAYER_OUTCOME_WINDOW_DAYS(14 by default). For a payer-signed outcome both carrysameOutcome, andoutcome_recordedalso carriesheldOutcomeHashwhen the outcome held is one the payer signed (a token holder's held outcome gives onlysameOutcome: false), so a carrier sending an outcome again can tell its own from a different one. -
413 Payload Too Large: The body is over 1 MB./flag,/flag/resolveand/linkanswer the same way. A client still sending has the rest read and dropped, up to 8 MB, so it can read the answer; past that the oracle cuts the connection. -
429 Too Many Requests: Rate limited or attestation cooldown active. -
502 Bad Gateway: Upstream RPC failure while reading agent info or verifying payment. The body is{ error: "could not read the chain", code: "rpc_error" }, and the provider’s own message is logged and never sent.
-
- If payment verification is enabled and
success === true(exactlytrue, so"yes"is not a positive), no bearer token is required because the verified payment is the credential for the payment. Without a token the payment is recorded and the outcome is not. - Negative attestations (
success === false), a missingsuccessand any non-boolean value always require a bearer token. - A token holder reporting an outcome on a verified payment gets that outcome recorded, and can also give a payment credited without one (by the scan, or by a request with no token) its outcome afterwards, once. An outcome that is already recorded is final, except that the payer's own signed outcome can replace a token holder's within
PAYER_OUTCOME_WINDOW_DAYSof the payment when the payer's is the transaction's only paying leg. A token holder's outcome never replaces a payer's. - An outcome the payer signed (
payerOutcome) needs no token, whoever carries it: the signature is the credential. It goes on the signer's own leg and is final for that leg. - When payment verification is disabled, a bearer token is always required and
attestermust be provided. - A credential restricted with
ORACLE_SCOPES_<NAME>that does not includeattestis refused with403even for a positive, payment-backed attestation, because it presented a token.
-
didHashmust be present and must be a 32-byte hex string. -
attesteris required when payment verification is disabled. - With payment verification enabled,
txHashis validated against the chain and linked to the agent’s own address, which is read from the identity registry. The payer is taken from the transfer log, and each sender is held toPAYMENT_MIN_AMOUNTon its own. - Self-payments (from the agent’s own operator or agent address) are rejected.
- Cooldown prevents repeated attestations from the same
attesterto the same agent within a configured window. It applies to every attestation except a token holder's report on a payment the oracle has just verified; with verification off, token holders are throttled too. With verification on the cooldown keys on the verified payer.
- Request:
POST /attest Authorization: Bearer <token> Content-Type: application/json { "didHash": "0x...64-hex...", "success": true, "packetId": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx", "payment": { "txHash": "0x..." } } - Response:
{ "didHash": "0x...64-hex...", "attester": "0x...", "successful": 1, "total": 1, "payment": { "txHash": "0x...", "amount": "1000000000000000000" }, "outcomeRecorded": true }
Section sources
Returns a preview of the computed score for an agent without writing to chain. This endpoint is unauthenticated but rate-limited.
- Method:
GET - Path:
/score/:didHash - Query parameters: None defined for this endpoint.
- Path parameter:
-
didHash(string, required): 32-byte hex identity hash of the agent.
-
- Success:
200 OK- Fields include:
didHash-
status: the identity registry’sAgentStatusas a number (0 Active, 1 Suspended, 2 Slashed, 3 PendingBond) scores-
attestations: the raw tally -
weighted(present only when payment verification is enabled), including weighted attestations, distinct payers, activity (an object with the first and last activity time and a recency weight), trust weight, half-life days, and max per payer. It is what the score was computed from. -
flags(the raw count) andflagWeight(the age-weighted one the score charges for) -
erc8004AgentId(when linked)
- Fields include:
- The preview uses the same inputs as the epoch, including counterparty standing and the chain’s clock, so two operators’ answers can be compared by hand.
- Errors:
-
404 Not Found: The path is not/score/followed by a 32-byte hexdidHash. -
429 Too Many Requests: Rate limited. -
502 Bad Gateway: Upstream RPC failure reading agent info, or a node that could not answer for a payer after retries. The body carriescode: "rpc_error". -
500 Internal Server Error: Unexpected computation failure.
-
- Request:
GET /score/0x...64-hex... - Response:
{ "didHash": "0x...64-hex...", "status": 0, "scores": { ... }, "attestations": { "successful": 10, "total": 12 }, "weighted": { "attestations": { "successful": 8, "total": 10 }, "distinctPayers": 5, "activity": { "firstActivitySec": 1789734970, "lastActivitySec": 1789944267, "recency": 0.78 }, "trustWeight": 1, "halfLifeDays": 90, "maxPerPayer": 4 }, "flags": 1, "flagWeight": 0.0012, "erc8004AgentId": "123" }
Section sources
Retrieves the payments behind an agent’s score, including Merkle proofs. This endpoint is deliberately unauthenticated so anyone can audit the evidence.
- Method:
GET - Path:
/evidence/:didHash - Path parameter:
-
didHash(string, required): 32-byte hex identity hash of the agent.
-
- Success:
200 OK- Returns JSON containing the agent’s payment events (
evidence, withcount) and the Merkle root over them (evidenceRoot). Each entry carries itsleafandproof.
- Returns JSON containing the agent’s payment events (
- Errors:
-
400 Bad Request: MalformeddidHash. -
429 Too Many Requests: Rate limited.
-
- The response includes a Merkle root and leaf structure committed to by the oracle.
- Consumers can independently recompute the root over the payment events and compare it with the value stored on-chain (
evidenceRoots(didHash)onSigvaraReputation), or check one leaf withverifyEvidence(didHash, leaf, proof). The servedleafis a convenience: a verifier should derive it from the payment rather than trust it. - The response names the committed fields and leaf order so verifiers do not need to infer them from implementation details.
-
successis served astrue,falseornulland enters the leaf as a uint8: 0 failed, 1 succeeded, 2 not reported. A payment found by the scan, or credited without a token, carries no outcome and so readsnull. -
counterauditPacketIdappears on an event when the attestation carried apacketIdthat was kept (a token holder's, or one beside a payer-signed outcome), and the response lists it underunverifiedFields. It is corroboration, not evidence: the oracle checks only that it is UUID-shaped and never fetches the packet, and it is deliberately not in the leaf. For a payer-signed outcome the packet's public proof names the EIP-712 hash of what the payer signed, so the link can be checked. -
outcomeSourcesays whose word each outcome is:payer_signed,credentialed, ornullfor none. It is this oracle's label and not part of the leaf. WherePAYER_OUTCOMES_PUBLISH=on, a payer-signed entry also carries the signedpayerOutcome, and the response gives the signing domain aspayerOutcomeDomain, so a verifier can check that the committed outcome is one the payer signed.
- Request:
GET /evidence/0x...64-hex... - Response:
{ "didHash": "0x...64-hex...", "evidenceRoot": "0x...", "count": 1, "committedFields": ["txHash","payer","amount","settledAt","success"], "evidence": [ { "txHash": "0x...", "payer": "0x...", "amount": "1000000000000000000", "settledAt": 1700000000, "success": true, "leaf": "0x...", "proof": ["0x..."] } ] }
Section sources
-
/health: Health check with operational signals for alerting. It answers200when healthy and503when not. -
/outcomes?since=<ms>: The payer-signed outcomes this oracle has taken, oldest first, 500 to a page, for other operators to import and anyone to check. Unauthenticated;404unlessPAYER_OUTCOMESandPAYER_OUTCOMES_PUBLISHare on, and400for asincethat is not a time in milliseconds. -
/flagand/flag/resolve— Token-gated flag management affecting scores (scopeflag). While a save is failing they answer 202 withdurable: false, as/attestand/linkdo; do not resend a flag or a resolve. -
/link— Link a Sigvara agent to an ERC-8004 identity (token-gated, scopelink). -
/jobs/<address>— Observation-only ERC-8183 jobs data. It answers501with codejobs_disabledwhen no registry is configured. -
/badge/<address>.svg— Embeddable SVG badge showing finalized score state. -
/metrics— Prometheus metrics. -
/epoch— Manual epoch trigger (token-gated, scopeepoch). -
/divergenceand/divergence/:didHash— Checker-mode disagreement records. A primary answers404with the errornot_a_checker.
These endpoints share the same authentication and rate-limiting patterns described below.
Section sources
The following diagram shows how the core endpoints depend on shared modules.
graph LR
A["/attest"] --> H["identifyCaller()"]
A --> R["rateLimited()"]
A --> V["verifyPayment()"]
A --> S["store attestations"]
B["/score/:didHash"] --> H
B --> R
B --> M["measuredFactorsFor()"]
B --> C["computeScore()"]
E["/evidence/:didHash"] --> R
E --> ME["getPaymentEvents()"]
E --> MR["buildEvidenceBody()"]
Diagram sources
- index.js:1868-2169
- index.js:2476-2553
- index.js:2253-2280
- http-helpers.js:61-113
- http-helpers.js:145-192
Section sources
- index.js:1868-2169
- index.js:2476-2553
- index.js:2253-2280
- http-helpers.js:61-113
- http-helpers.js:145-192
-
/scoreperforms multiple chain reads (agent info, payer standing, external score when linked). It is rate-limited even though it is public. -
/evidencemay rebuild a Merkle tree over payment events on cache misses; it is rate-limited to bound first-request cost. -
/attestvalidates payments and updates persistent state; it is rate-limited and uses a per-attester cooldown. - Metrics expose counters for rate limits, RPC errors, attestations accepted/rejected, and more.
-
401 Unauthorizedon/attestoccurs when:- A negative attestation is submitted without a bearer token.
-
successis missing or is not exactlytrue, with no bearer token. - Payment verification is disabled and no bearer token is provided.
- The bearer token does not match any configured credential, and the request needed one.
-
403 Forbiddenon a write route occurs when the credential is restricted byORACLE_SCOPES_<NAME>to scopes that do not include the one the route needs (attest,flag,linkorepoch). -
Credentials are loaded from:
-
ORACLE_ADMIN_TOKEN(legacy admin token). -
ORACLE_TOKEN_<NAME>variables (per-service tokens).
-
-
ORACLE_SCOPES_<NAME>takes a comma-separated list of scopes for the credentialORACLE_TOKEN_<NAME>. A credential with no such variable keeps every scope, andadminis never restricted. An unknown scope, or a restriction naming a credential that does not exist, stops the process at startup. -
Tokens are matched using constant-time comparison against
Authorization: Bearer <token>. A token shorter than 32 characters still works but is named in a startup warning.
Section sources
-
Fixed-window rate limiter:
- Window: 60 seconds.
- Max: 60 requests per key per window.
- Key: the caller and the kind of route. Writes,
/evidence,/divergenceand the other reads each have their own bucket, so a flood against one cannot use up another’s allowance (the watcher polls/divergence). The write routes are metered before they are authorised, so guessing at a token is throttled too. The badge route limits only a cache miss. - Caller: the socket address, or the address in
X-Forwarded-Forwhen the connection arrives from loopback or from a proxy listed inTRUSTED_PROXIES. Behind a reverse proxy the socket address is the proxy’s, so withoutTRUSTED_PROXIESevery visitor shares one bucket.
-
Responses:
-
429 Too Many Requestswith{ error: "Rate limited" }.
-
Section sources
-
400 Bad Request:- Missing
didHash, or adidHashthat is not a 32-byte hex string. - Missing
attesterwhen payment verification is disabled. - Unknown
didHash. -
successthat is nottrue,falseor omitted, from a token holder. - A body that is not valid JSON.
- A payer-signed outcome that is malformed or sent with
success(bad_payer_outcome), a "not delivered" where only "delivered" is taken (negative_not_accepted), timing outside its window (outcome_window), or a signature that is not the payer's (bad_signature).
- Missing
-
402 Payment Required:- Invalid payment (
codeisbad_tx_hash,not_found,reverted,unconfirmed,no_transferorbelow_minimum). - Self-payment detected (
codeisself_payment). - A payer-signed outcome whose signer has no leg of its own in the transaction (
codeispayer_mismatch).
- Invalid payment (
-
403 Forbidden:- The credential is restricted to scopes that do not include
attest.
- The credential is restricted to scopes that do not include
-
409 Conflict:- Settlement already credited (
replayed). - The credited payment already has an outcome (
outcome_recorded). For a payer-signed outcome the body carriesheldOutcomeHashandsameOutcome;sameOutcome: truemeans the outcome sent is the one already held.
- Settlement already credited (
-
413 Payload Too Large:- The body is over 1 MB. The same applies to
/flag,/flag/resolveand/link.
- The body is over 1 MB. The same applies to
-
429 Too Many Requests:- Rate limited.
- Attestation cooldown active (includes
remainingSecondsandcooldownMs). It does not apply to a token holder reporting on a verified payment.
-
502 Bad Gateway:- RPC failure reading agent info or verifying payment. It is counted separately from rejected attestations, because a node having a bad minute must not read as a caller trying it on. Retry.
Section sources
-
502 Bad Gateway:- Upstream RPC failure reading agent info, or a node that could not answer for a payer after its retries (
code: "rpc_error"). A payer the node could not answer for is never read as having no standing, because that would serve a lower score than the oracle would propose.
- Upstream RPC failure reading agent info, or a node that could not answer for a payer after its retries (
-
500 Internal Server Error:- Unexpected computation failure; generic message returned to avoid leaking upstream details.
Section sources
-
400 Bad Request:- Malformed
didHash.
- Malformed
-
429 Too Many Requests:- Rate limited.
Section sources
Sigvara’s oracle API provides secure attestation submission, transparent reputation scoring, and auditable evidence with Merkle proofs. Authentication is flexible, supporting both legacy admin tokens and per-service bearer tokens. Public read endpoints are intentionally open but rate-limited. Consumers should handle 429, 401, 402, 403, 409, 502, and 500 responses appropriately, validate inputs, and use /evidence for independent verification of the oracle’s claims.
-
Admin token:
ORACLE_ADMIN_TOKENmaps to theadmincredential name. -
Named tokens:
ORACLE_TOKEN_<NAME>variables define per-service credentials; names are lowercased. The name is logged when a flag is raised or cleared, and the startup line lists the credential names, so deleting one variable revokes exactly that caller. -
Scopes:
ORACLE_SCOPES_<NAME>restricts a credential to some ofattest,flag,linkandepoch. With no variable a credential keeps every scope, andadminis never restricted. -
Header format:
Authorization: Bearer <token>. - Policy enforcement: Non-loopback binds require at least one configured credential; otherwise startup fails.
Section sources
- Fixed window: 60 seconds.
- Maximum: 60 requests per key per window.
- Key derivation:
- Direct socket address for connections that do not come from loopback or a listed proxy.
- For loopback connections and for proxies listed in
TRUSTED_PROXIES(comma-separated addresses or CIDR ranges),X-Forwarded-Foris read from the right: hops that are trusted proxies are skipped and the first address that is not one is the client, so a client that sends a forged prefix gains nothing. An entry that is not an IP address is never used as a key. - The key also carries the kind of route (writes,
/evidence,/divergence, other reads), so each kind has its own 60 a minute.
Section sources
- Always set bearer tokens before exposing the oracle publicly.
- Prefer per-service tokens for better revocation granularity, and restrict each to the scopes it needs.
- Do not proxy the whole service. The deployment publishes
/health,/score/*,/evidence/*,/badge/*,/outcomesandPOST /attest, and answers 404 for everything else, so/flag,/flag/resolve,/link,/epochand/metricsare reachable only from the host. - Use
/evidenceto independently verify Merkle roots and payment events. - Treat
502as upstream failures and retry with backoff. - Respect
429responses and implement exponential backoff. - Validate all inputs on the client side to reduce unnecessary retries.
- Avoid sending sensitive data in logs or error messages.
- Agent Registration and Lifecycle
- Contract Overview and Architecture
- Economic Security Model and Incentives
- Evidence Verification and Merkle Proofs
- Key Management and Rotation
- Maturity Mechanism and Score Release
- Proposal Workflow and Challenge System
- Score Storage and Data Model
- SigvaraIdentity Contract
- SigvaraOracleBond Contract
- SigvaraReputation Contract
- SigvaraStaking Contract
- Slashing Lifecycle and Dispute Resolution
- Stake Management Functions
- Status Management and Control
- Token and Fee Contracts
- Unbonding Period and Withdrawal Security
- Anti-Manipulation and Security Measures
- Community Flag Processing
- Evidence Sources and Verification
- External Trust Integration
- Merkle Proof System
- Oracle Score Computation
- Payment-Backed Attestations
- Scoring Model and Formulas
- Agent Creation and Key Management
- Agent Operations
- Agent Registration Workflow
- Challenge-Response Authentication
- Gate Access Control
- Integration Patterns and Examples
- SDK Overview and Setup
- Verifier Functions