# Testing locally

Your agent can run on your machine while the pages it creates are hosted by Page Systems. You use the same API key and the same hosted service in development and production; there is nothing to run locally except your own agent.

## Why a local callback URL does not work

When the person answers a page, Page Systems sends `POST <callbackUrl>` with `{ "type": "page.submitted", "pageId": "..." }` from its servers on the internet. Those servers cannot reach `localhost` on your machine. For that reason, creating a page with a `localhost` or private-network `callbackUrl` fails with `400 invalid_request` ("callbackUrl: cannot be a local address"), and any other `http:` URL fails with "callbackUrl: must use https". Pick one of the three ways below.

## Way 1: no callback, read the result

Leave `callbackUrl` out. The eve extension does this automatically when it is not running on Vercel. Create the page, open the link and answer it in a browser or on your phone, then tell the agent you answered. The agent calls `get_page_result` and continues.

This tests the tools and the page. It does not test the answer arriving as a new turn without you telling the agent.

## Way 2: a tunnel (the full test)

A tunnel gives your local server a public https URL. Start one on the port your app listens on:

```bash
cloudflared tunnel --url http://localhost:3000   # no account needed
# or
ngrok http 3000
```

Then set the callback URL to `https://<tunnel-host>` plus your callback route's path, and restart the app. Next.js guides use `/api/page-systems` and Python guides use `/page-systems/callback`. For eve, set `PAGE_SYSTEMS_CALLBACK_URL` to the tunnel URL followed by `/eve/v1/page-systems/callback`.

**Each answer goes only to the callback URL the page was created with.** Most free tunnels give you a new host every time they start. After the tunnel URL changes, pages created earlier are not delivered; read them with `get_page_result`.

## Way 3: send the callback yourself

Create a page without a callback (way 1) and answer it. The page still needs an `agentRef` (a small JSON object that names your conversation, such as `{ "conversationId": "..." }`), because your handler uses it to find the conversation to resume. The framework guides and the eve extension already send one, whether or not there is a `callbackUrl`. Then post the callback to your own route:

```bash
curl -X POST http://localhost:3000/api/page-systems \
  -H 'content-type: application/json' \
  -d '{"type":"page.submitted","pageId":"<id>"}'
```

Use your own route's path. For eve it is `/eve/v1/page-systems/callback`. Your handler reads the answer from the API with your API key, starts the new turn, and then claims the answer. This is safe because the callback carries only the page id and the route trusts only what it reads from the API. Once the answer is claimed, sending the callback again does nothing.

## What each way tests

| | Tools and page | Your callback route | New turn without you prompting |
|---|---|---|---|
| Way 1: no callback | Yes | No | No |
| Way 2: tunnel | Yes | Yes | Yes |
| Way 3: curl | Yes | Yes | Only if you send the request |

Before you go live, use the real https callback URL of your deployed app. See [Callbacks](/docs/api#callbacks) for the retry rules.
