Swap Sessions
User-approved auto-swap sessions and trusted backend execution.
Swap sessions are user-approved auto-swap permissions. The iframe asks the user to enable a session; your trusted backend executes against it. They are available only when the project owner has enabled auto-swaps for the HTML project (autoSwapsEnabled in project context).
Gate session UI on availability
If autoSwapsEnabled is false, do not render session controls — execution will be
rejected with SWAP_SESSION_DISABLED.
How sessions work
Enable (create)
The iframe requests a session with display-decimal budgets. Forest converts them
into contract base units, prepares the required token approvals for the session
executor contract, and prepares the session transaction. The user confirms the
wallet prompts; Forest then confirms the createSession transaction and stores
the active session.
Execute (backend)
Session execution is a backend-to-Forest API flow. Forest uses the user's managed executor wallet to send the on-chain execution transaction. HTML templates do not configure executor wallet addresses — Forest owns the executor-wallet setup and confirmation flow.
Revoke
Users can revoke active sessions from the Forest UI or via
forest.swap.session.revoke.
Never cache the session id
Before every backend execution, request forest.swap.session.current and use that returned
session.id. Do not execute against a session id restored from localStorage or another
stale client cache.
Approval hashes are progress, not completion
The create flow may emit hash responses with stage: "approval_submitted" before the final
stage: "create_submitted" hash. Treat approval hashes as progress updates; the session is
active only after the final success response.
Executor wallet needs gas
The managed executor wallet must hold native gas on the configured chain for executions to land.
Session Methods
forest.swap.session.create
callForest("forest.swap.session.create", {
forestBudget: "50",
projectBudget: "1000.5",
expiresAt: Math.floor(Date.now() / 1000) + 86400,
});Unlimited budget:
callForest("forest.swap.session.create", {
forestBudget: null,
projectBudget: null,
expiresAt: Math.floor(Date.now() / 1000) + 86400,
});Prop
Type
Budgets are display decimal strings. Use null for a side that should be unlimited until expiresAt is reached or the user revokes the session. Successful responses return the confirmed session plus the transaction hash:
{
session: {
id: "9db7f2d8-5e03-4c73-96f9-31b99747d0c6",
onChainSessionId: "42",
chainId: 97,
status: "active",
snapshot: {
routerAddress: "0x...",
forestBudget: "50000000000000000000",
projectBudget: "1000500000000000000000",
expiresAt: "2026-05-15T12:00:00.000Z",
createTxHash: "0x...",
createdAt: "2026-05-14T12:00:00.000Z"
},
createdAt: "2026-05-14T12:00:00.000Z",
updatedAt: "2026-05-14T12:00:00.000Z"
},
limits: {
forestBudget: "50000000000000000000",
projectBudget: "1000500000000000000000",
expiresAt: "2026-05-15T12:00:00.000Z"
},
txHash: "0x..."
}forest.swap.session.current
callForest("forest.swap.session.current");Returns the latest active session for the current project and authenticated wallet user, using the same response shape as forest.swap.session.get. Use this method immediately before passing a session id to your backend for execution.
forest.swap.session.get
callForest("forest.swap.session.get", {
sessionId: "9db7f2d8-5e03-4c73-96f9-31b99747d0c6",
});Returns the stored session so your app can inspect status, limits, and expiry. Forest resolves router and pair addresses internally; HTML apps never provide or persist those addresses.
Sessions do not re-route
Sessions do not fall back to a new route after router or pair changes. If the on-chain session route is no longer usable, the user must recreate the session.
{
limits: {
forestBudget: "50000000000000000000",
projectBudget: null,
expiresAt: "2026-05-15T12:00:00.000Z"
},
session: {
id: "9db7f2d8-5e03-4c73-96f9-31b99747d0c6",
onChainSessionId: "42",
chainId: 97,
status: "active",
snapshot: {
routerAddress: "0x...",
forestBudget: "50000000000000000000",
projectBudget: null,
expiresAt: "2026-05-15T12:00:00.000Z",
createTxHash: "0x...",
createdAt: "2026-05-14T12:00:00.000Z"
},
createdAt: "2026-05-14T12:00:00.000Z",
updatedAt: "2026-05-14T12:00:00.000Z"
}
}HTML SDK session responses use base-unit integer strings for budgets. limits mirrors session.snapshot budget fields and exists only as a convenient place to read the configured session caps and expiry.
forest.swap.session.revoke
callForest("forest.swap.session.revoke", {
sessionId: "9db7f2d8-5e03-4c73-96f9-31b99747d0c6",
});Revokes an active session through the connected wallet, then confirms the revoke transaction with Forest. This opens a wallet prompt and returns the same response shape as forest.swap.session.get, plus txHash when the revoke transaction is confirmed.
Trusted Swap Session Execution
Uploaded HTML can request that a user enables a session, but execution must come from your trusted backend. Use the same server-only Settlement Signing Secret and HMAC header as settlement:
POST /campaigns/{projectId}/html/swap-sessions/{sessionId}/executions
Content-Type: application/json
X-Forest-Settlement-Signature: v1=<hex-hmac>{
sessionId: "9db7f2d8-5e03-4c73-96f9-31b99747d0c6",
requestId: "6ae1ea37-19a2-46db-a59f-742e58fb8c4d",
direction: "buy",
projectAmount: "1000000000000000000",
forestAmountLimit: "1000000000000000000",
timestamp: Math.floor(Date.now() / 1000)
}Prop
Type
Sign the exact JSON string you send. Store the signed body by sessionId + requestId and replay that same body if the response is lost. Reusing a request id with a different direction, amount, or deadline is rejected.
A successful response contains the confirmed execution transaction:
{
id: "execution-id",
sessionId: "9db7f2d8-5e03-4c73-96f9-31b99747d0c6",
requestId: "same-request-id",
direction: "buy",
txHash: "0x...",
projectAmount: "1000000000000000000",
forestAmount: "100000000000000000",
forestBudgetRemaining: "49000000000000000000",
projectBudgetRemaining: "100000000000000000000",
replayed: false
}Forest records confirmed executions only after the contract emits the matching SwapSessionExecuted event. If your backend loses the response, retry the same requestId and exact signed body. Signature and timestamp failures use the shared settlement error taxonomy; session state, route mismatches, and chain-validation failures can return normal HTTP errors without an app-specific code.
Embedded HTML apps can revoke sessions with forest.swap.session.revoke; users can also revoke active sessions from Forest UI.