---
title: Request path
description: One protected action, traced from the agent's process to your downstream and back.
---

The same journey as [How it works](/how-it-works), from the process and network
point of view.

## 1. The agent signs

In the agent's process. The private key never leaves it.

```ts
const assertion = createAssertion({
  agentId, keyId, privateKey,
  audience: 'https://gateway.veefore.example.com',
  purpose: 'agent_authentication',
});
```

Ed25519 over `base64url(header) + "." + base64url(canonicalJson(payload))`, with
a fresh nonce and a two-minute expiry.

## 2. Token exchange

```http
POST /gateway/v1/token
```

The gateway verifies the signature against the stored public key, checks the
audience string, the timestamp window, the nonce, the key generation and the
revocation state. Then it issues a session token with a 15-minute lifetime.

No refresh token. The agent re-signs when the token expires, because the key is
a strictly better credential than a refresh token would be.

## 3. The protected action

```http
POST /gateway/v1/actions
authorization: Bearer aos_at_…
idempotency-key: refund-ord_8812
```

This is where the twelve stages run. Each stage is cheaper than the one after it
and narrows what the next has to consider.

```text
 1  REQUEST          schema, timestamp, nonce
 2  AUTHENTICATION   session token → agent identity
 3  IDENTITY         generation current, not revoked
 4  LIFECYCLE        agent ACTIVE, not isolated, environment not paused
 5  CAPABILITY       capability held, tool enabled and authorized, destination allowed
 6  DELEGATION       chain resolves; intersect every hop; compare the request
 7  POLICY           every in-scope policy, every rule; strictest decision wins
 8  RISK             thirteen signals, weighted; policy already read these
 9  APPROVAL         create, or validate a presented one
10  CREDENTIAL       ── first side effect outside Veefore ──
11  EXECUTION        real HTTP, six egress guards
12  RESULT           apply limits and masking, seal the record
```

:::security Stages 1–9 can all refuse, and none of them has an external effect
Which is what makes stage 10 the first irreversible step. A blocked action never
causes a credential to be issued, so "we blocked it" and "the secret did not go
out" are the same statement rather than two.
:::

### Database reads during the pipeline

Stages 3 through 9 read from PostgreSQL: the identity and its generation, the
agent and environment state, capability grants and tool authorizations, the
delegation chain, the active policy versions bound to the scope, velocity and
history counters, trust evidence, and any presented approval.

No decision is cached. Every action re-resolves live state. That is why
revocation is instant: there is no cached grant to expire.

## 4. The credential lease

Stage 10. The broker unseals the material with
`VEEFORE_DATA_ENCRYPTION_KEY`, issues a lease scoped to this action with a
600-second default lifetime, and records it **by reference**.

The lease goes to the **tool runtime**, inside the gateway process. The agent
never receives it and has no way to ask for it.

## 5. Egress

Stage 11. Six guards, in order:

| | Refusal |
| --- | --- |
| Tool kind is `HTTP` | Otherwise the simulated runtime runs |
| `endpoint_url` is set | `UNPROCESSABLE` |
| Host is in **this tool's own** `destination_allowlist` | `DESTINATION_BLOCKED` |
| HTTPS, unless the host is loopback | `DESTINATION_BLOCKED` |
| `redirect: 'error'` | Execution fails |
| Timeout at 15s | `EXECUTION_TIMEOUT` |

Plus a per-tool circuit breaker: five consecutive failures opens it for 20
seconds.

The destination allowlist is checked **twice** — once in stage 5, once here. The
second check protects you if the endpoint was edited after the first, and if a
code path ever reaches execution without stage 5 having run.

Headers sent:

```http
content-type: application/json
accept: application/json
user-agent: Veefore-Gateway/1.0
x-veefore-request-id: req_01JAV…
x-veefore-agent-id: agt_01JAV…
idempotency-key: refund-ord_8812
traceparent: 00-4bf92f35…-00f067aa…-01
```

Plus whatever the leased credential contributes. `x-veefore-request-id` is worth
logging on your side — it ties your downstream log line to the Veefore action
record.

## 6. Result

Stage 12. `LIMIT` caps are applied, `MASK` paths are redacted from the response
before the agent sees them and from the audit record, the stage results are
assembled, and the action record is sealed.

The audit event is hash-chained into the trail.

## 7. The response

```json
{
  "actionId": "act_01JAV…",
  "requestId": "req_01JAV…",
  "traceId": "4bf92f35…",
  "mode": "ENFORCE",
  "decision": "ALLOW",
  "outcome": "ALLOWED",
  "allowed": true,
  "result": { "refundId": "rfnd_0005", "status": "accepted" },
  "reason": "Within the refund policy baseline.",
  "explanation": { … },
  "latencyMs": 84,
  "stages": [ … ]
}
```

## Network boundaries

```text
agent host                gateway host              downstream host
──────────                ────────────              ───────────────
 private key     ──TLS──▶  pipeline      ──TLS──▶    real effect
 no credential             credential
                           broker
                              │
                              ▼
                        Postgres (private)
                              ▲
                              │
 browser, CLI    ──TLS──▶  control plane
```

:::danger Separate ingresses
The gateway exposes only `/gateway/v1/*` and
`/.well-known/veefore-platform-key`. The control plane exposes only `/v1/*`,
and is not reachable from wherever agents run.

That separation is the control that makes the plane split worth having.
[→ Deployment](/operate/deployment)
:::

## Latency

| | Typical |
| --- | --- |
| Signature verification | 1–3 ms |
| Policy evaluation | under 1 ms, in-process |
| The full pipeline, excluding execution | 20–50 ms |
| Execution | your downstream |

Policy evaluation being in-process is a deliberate requirement, not an
optimisation: the gateway cannot take a network hop to another service that
could be down in order to decide whether to allow something.
[→ Policy engine](/architecture/adr/0003-policy-engine)

`veefore_gateway_request_duration_ms` is labelled by `outcome`, and the trace
has one span per stage — so "why was that slow" is answered by looking at which
stage holds the time. Usually `EXECUTION`, which means your downstream.

## What changes by mode

| | `OBSERVE` | `SIMULATE` | `ENFORCE` |
| --- | --- | --- | --- |
| Stages 1–9 | run | run | run |
| A refusal stops the action | **no** | yes | yes |
| Stage 10 credential | leased | skipped | leased if allowed |
| Stage 11 execution | **runs** | skipped | runs if allowed |
| Stage 12 record | written | written | written |

`OBSERVE` runs the whole pipeline, records the refusal in `shadow`, and then
lets the action proceed. [→ Enforcement modes](/concepts/enforcement-modes)

## Related

:::cards

:::card How it works | /how-it-works
The same pipeline, stage by stage.
:::

:::card The boundary | /secure/boundary
Why the gateway is authoritative.
:::

:::card Data model | /architecture/data-model
What the pipeline reads and writes.
:::

:::card Gateway architecture | /architecture/adr/0002-gateway-architecture
Why a separate plane.
:::

:::
