Arcjet helps developers protect their apps in just a few lines of code. Bot detection. Rate limiting. Email validation. Attack protection. Data redaction. A developer-first approach to security.
This is an example Vercel Eve agent protected by Arcjet AI guardrails. It demonstrates a simple agent that looks up orders, consults an API, receives inbound webhook messages, and records every guard decision with Arcjet.
- AI guardrails with the
@arcjet/guardpackage protect an Eve agent's tools, connections, and inbound channels from abuse. - An authored tool (
lookup_order) guarded withguardTooluses a token bucket rate limit keyed by order number. - An OpenAPI connection (the
ordersAPI) guarded withguardApprovalrate-limits API access per session. - An HTTP channel screens inbound webhook messages with
guardInboundand prompt injection detection before dispatching to the agent. - Hooks (
arcjetHooks) capture every guard decision for audit trails. - Two correlated Sequences per conversation — the inbound screen and the
in-session decisions — joined by an
eve.session-startedrecord.
-
Install dependencies:
npm ci
This example requires Node.js 24 or later — Eve's floor is Node 24 and earlier versions lack required language features and APIs.
-
Rename
.env.local.exampleto.env.localand add your keys:cp .env.local.example .env.local
See Setup below for details on the required keys.
-
Start the agent in development mode:
npm run dev
-
Send a POST request to the webhook channel (for example, to
http://localhost:3000/webhookif running locally) with a JSON body containing yourmessageand aconversationId. The agent processes it and responds.
This example needs two keys, both set in .env.local:
ARCJET_KEY— your Arcjet site key. Get it from https://console.arcjet.com by creating a free dev site.AI_GATEWAY_API_KEY— used by Eve to call the model that powers the agent. Get it from the Vercel AI Gateway.
An optional ORDERS_API_BASE_URL points the orders connection at a real API. It
defaults to a non-routable placeholder, so the connection is safe to leave
unconfigured while you explore the guardrails.
Watch the Arcjet Console for the captured decisions:
- Inbound decision: the
guardInboundgate screening the webhook message, correlated by the conversation id, on its own Sequence. - Tool and connection gates: the
guardToolrate limit onlookup_orderand theguardApprovalgate on the orders API connection. - Hook capture:
arcjetHooksrecording all guard decisions for audit.
The inbound decision and the tool/connection gate decisions are joined by two
distinct correlation IDs, reconciled by the arcjetHooks record at
session.started:
-
Inbound correlation ID — the
guardInboundgate assigns a correlation ID passed from the webhook handler. This ID is immutable and comes from the caller (e.g. theconversationIdin the request body), ensuring the same request always joins to the same decision even if the session is recreated. -
Session correlation ID — once the inbound decision passes, the handler creates a session and runs the agent. The tools and connection gate their decisions using the session id, not the inbound id. Those land on one Sequence; the inbound decision is on a second one.
arcjetHooksemits aneve.session-startedcapture carrying both, which is what lets you pivot from either Sequence to the other. Eve namespaces continuation tokens per channel, so that record'seve.continuation-tokenreads<channel-name>:<conversation-id>rather than the bare conversation id.
So the Console shows two Sequences per conversation — one for the inbound
screen, one for everything inside the session — joined by the
eve.session-started record. Two ids is the expected shape here, not a bug: the
channel boundary runs before Eve creates the session, so there is no session id
to correlate by yet.
- The example uses an HTTP channel for simplicity and to avoid external
dependencies. Swap it for a Slack channel by changing
agent/channels/webhook.tsand adding Slack credentials to.env.local. - The orders API connection is configured with a placeholder endpoint by
default. To test against a real API, update
agent/connections/orders.tsand setORDERS_API_BASE_URLin.env.local.
Check out the docs, contact support, or join our Discord server.
All development for Arcjet examples is done in the
arcjet/examples repository.
You are welcome to open an issue here or in
arcjet/examples directly.
However, please direct all pull requests to
arcjet/examples. Take a look at
our
contributing guide
for more information.