This document is the dense reference companion to the public guide Middleware performance and latency. It maps the HTTP hops Kit middleware triggers per guarded tool call, documents Gateway rate limits and timeouts, and states what observability exists today.
Paybond does not publish Kit p50/p99 benchmarks. Treat all duration guidance as qualitative unless you measure in your own environment.
Design principles
- Serial hops per guarded call. The interceptor authorizes, executes the handler, completes the spend decision, then submits evidence — in order. There is no batch verify API for multiple tools in one HTTP request.
- Gateway composes policy; Harbor authorizes capability.
POST /verifyalways reaches Harbor for capability validation when Harbor is configured. Gateway may add Postgres idempotency and spend-policy evaluation around that forward. - Evidence path differs by bind mode. Sandbox binds use Gateway guardrails evidence composition. Production attach binds sign payee evidence locally and call
/harbor/intents/{id}/evidencethrough recognition + fraud gates. - Kit runs off-platform. Production latency observation defaults to Gateway/Harbor SLIs and partner APM — not Paybond-hosted Kit telemetry.
Hop model (production attach)
sequenceDiagram
autonumber
actor Kit as Kit interceptor
participant GW as Gateway
participant PG as Postgres
participant HB as Harbor
Kit->>GW: POST /verify (Bearer API key)
GW->>PG: Idempotency + spend policy
GW->>HB: POST /verify (mTLS, 30s timeout)
HB-->>GW: allow / deny + audit
GW-->>Kit: decision_id, audit_id
Note over Kit: Local tool handler (durationMs in trace only)
Kit->>GW: POST /v1/spend/decisions/{id}/complete
opt stripe_mpp session metering
GW->>HB: POST /internal/v1/mpp/voucher/finalize
end
GW-->>Kit: consumed / released
Kit->>Kit: Sign payee evidence + recognition proof
Kit->>GW: POST /harbor/intents/{id}/evidence
GW->>GW: Recognition verify + fraud hardening
GW->>HB: POST /intents/{id}/evidence (mTLS)
HB-->>GW: predicate_passed, evaluation
GW-->>Kit: 200 JSONHop summary table
| Step | Kit API / trigger | Gateway route | Harbor route | Notes |
|---|---|---|---|---|
| 1 Authorize | guard.assertSpendAuthorized | POST /verify | POST /verify | Spend policy + idempotency in Gateway |
| 2 Execute | User handler | — | — | Not a Paybond HTTP hop |
| 3 Complete | guard.completeSpendAuthorization | POST /v1/spend/decisions/{decision_id}/complete | Optional POST /internal/v1/mpp/voucher/finalize | MPP session mode only |
| 4 Evidence (sandbox) | guardrails.submitSandboxEvidence | Composed guardrails evidence | Harbor evidence via internal forward | Simulator lifecycle |
| 4 Evidence (production) | harbor.submitEvidence | POST /harbor/intents/{id}/evidence | POST /intents/{id}/evidence | Recognition + fraud gate before proxy |
Settlement confirm (POST /harbor/intents/{id}/settlement/confirm) is outside the default auto-evidence interceptor path unless your app calls it explicitly after evidence.
Sandbox and offline paths
| Mode | Network hops | Representative use |
|---|---|---|
paybond dev loop --offline | 0 Paybond HTTP calls | Policy rehearsal, trace UX |
Sandbox bind (instrument({ sandbox: true })) | Verify + complete + guardrails evidence against sandbox tenant | Integration tests, paybond dev loop |
| Production attach | Full hop table above | Live funded intents |
Offline mode does not predict production latency.
Authorization cache
Split authorize / execute frameworks can avoid a second /verify when:
| Constant | Value | Source |
|---|---|---|
| TTL | 120 seconds | AUTHORIZATION_CACHE_TTL_SEC |
| Cache key | {toolCallId}:{operation} | authorization-cache.ts |
| Match fields | operation, requestedSpendCents, toolName | Must match at wrapExecute time |
Implementation: kit/ts/src/agent/authorization-cache.ts (Python parity in paybond_kit.agent).
Gateway timeouts and retries
Harbor client timeout
Gateway Harbor HTTP clients use a 30 second request timeout, including:
CallHarborVerify(go/gateway/internal/spendauth/harbor.go)- Harbor mutation proxies (
go/gateway/internal/httpserver/harbor.go) - Sandbox guardrail Harbor forwards (
sandbox_guardrails.go)
Kit SDK retry loop
Default maxRetries: 3 on Paybond / HarborClient gateway HTTP (kit/ts/src/index.ts).
| Behavior | Detail |
|---|---|
| Retriable status | 429, 500, 502, 503, 504 |
| Backoff | 200 * 2^attempt ms + jitter, cap 5000 ms (backoffMs) |
Retry-After header | Honored, cap 30 seconds |
| Cloudflare edge body | cloudflare_error: true — max 8000 ms delay, max 1 extra retry |
| Non-retriable | Cloudflare edge errors after one retry; other 4xx |
Tail latency on upstream blips can reach several seconds across retries — not represented in dev trace events.
Rate limits (default Gateway windows)
Per-tenant unless noted. Source: go/gateway/internal/httpserver/router.go.
| Limiter key | Default quota | Window | Applies to |
|---|---|---|---|
verify_capability | 240 | 1 minute | POST /verify |
mpp_voucher_verify | 120 (env override) | 1 minute | /verify with x-paybond-payment-authorization |
harbor_proxy_read | 120 | 1 minute | Harbor operator GET proxies |
Exceeding limits returns 429 with Retry-After — interacts with SDK retry backoff.
Spend-policy evaluation may contend on Postgres rows during high /verify concurrency; scope policies narrowly for hot operations.
Trace event limits
PaybondTraceEvent (kit/ts/src/agent/types.ts) exposes phase timestamps and handler timing only.
| Event | Latency field | Includes Paybond HTTP RTT? |
|---|---|---|
tool_executed | durationMs | No — local handler only |
spend_authorized | — | No |
evidence_submitted | — | No |
spend_finalized | — | No |
Dev trace (paybond dev trace, .paybond/dev-trace.jsonl) and hosted /demo/agent-trace replay use the same vocabulary. They are phase debuggers, not network profilers.
There are no authorize_duration_ms or evidence_duration_ms fields in the shipped trace schema today.
Production observability map
| Layer | What to monitor | Document |
|---|---|---|
| Gateway → Harbor | Error rate, harbor_unreachable, p99 upstream duration | Production operations v1 §3.2 |
| Gateway OTEL | otelhttp spans when OTLP configured | Same doc §1 |
| Harbor | /health, recovery errors, stuck intents | Runbook |
| Partner APM | Span around wrapExecute / authorizeToolCall with intent_id, operation | This doc — bring your own |
| Signal indexer | Ledger lag, receipt 404 spikes | Production operations v1 §3.5 |
| Console | Intent dossier, agent-run timeline | Middleware trace |
Kit does not phone home per-tool latency unless you wire traceSink or Gateway agent-run reporting.
Qualitative sizing guidance
| Workload | Expectation |
|---|---|
| Fast tool (<50ms handler) | Paybond serial hops often dominate wall time |
| Slow tool (seconds+) | Handler dominates; middleware overhead is a smaller fraction |
| High fan-out (many tools per turn) | Multiply hops per side-effecting tool; watch verify_capability quota |
| MPP session mode | Extra verify header processing + optional voucher finalize on complete |
| Predicate failure | HTTP 200 with predicate_passed: false — not a transport retry (Disputes reference) |
Order-of-magnitude on healthy same-region hosted infra: ~20–150ms per Paybond HTTP hop, plus handler time and retry tails on errors.
Related documentation
- Public guide: Middleware performance and latency
- Integration: Agent middleware
- Trace phases: Middleware trace
- Evidence signing cost path: Evidence & artifacts
- Support matrix (what Kit does not ship): Support matrix