Skip to content

Project URLs

On this page

A Project URL is a stable public HTTPS address that all of the project's devboxes can share. You, or your agent on the devbox, choose which devbox receives its traffic. For example, register an OAuth callback once, then send callback requests to whichever devbox you're testing without changing the address in your OAuth provider's settings. Webhook endpoints and API base URLs work the same way. If you just want a person to try the app on one devbox, share a public link instead.

Create a URL and route it to your app

Use Routed delivery to send requests to one devbox and return your app's responses. This is the right choice for OAuth callbacks and APIs. The URL is public, so your app needs its own authentication for private data and actions.

Creating the URL and pointing it at a devbox are separate steps: the address exists as soon as you create it, but requests won't reach an app until a devbox claims it after the app starts.

  1. In the desktop sidebar, find Project URLs and choose New Project URL.
  2. Enter a Name, such as callbacks, and the Port your HTTP app will use, such as 3000. The name identifies the URL in boxes.dev and commands; it isn't part of the public address.
  3. Select Routed under Default delivery, then choose Create Project URL.
  4. Start your app on the configured port in the devbox that should receive requests. The port must be allowed by the project's forwarding rules and detected as HTTP in Ports, where its row offers a web URL.
  5. Back under Project URLs in the sidebar, open the URL's page and choose Route traffic here on that devbox. The page lists only devboxes eligible to receive traffic. If yours is missing, check that it is awake and meets the app and port requirements in step 4. Assigning the URL to a devbox is called claiming it.
  6. Copy the public address from the URL's page into the external service's callback or endpoint setting, including the path your app expects. Test the callback or send a request and check that the chosen devbox returns the expected response.

You can also claim a URL from Ports on the selected devbox. Choose Claim for this devbox on the URL's row. If another devbox holds the URL, choose Move traffic here… and confirm before live traffic is redirected.

Keep the devbox and app running while you need the endpoint. Project URL requests don't wake a sleeping devbox, and unlike public-link traffic they don't keep one awake either. If the app stops, the URL will stay assigned to that devbox, but requests will be unavailable until you restart the app on the configured port and boxes.dev checks it. If you later change the URL's port or other settings, the assignment itself can be cleared — see Configure URLs from your computer.

Choose webhook multicast when no response is needed

Choose Webhook multicast when several devboxes should receive the same webhook, such as an event you want to test on multiple branches. Each devbox needs to subscribe after its app starts.

With multicast, the sender will immediately receive an empty 200 response, even if no devbox is listening. boxes.dev makes one immediate delivery attempt per current subscriber, with no queue, retry, storage, or replay. A failed delivery can therefore lose a webhook that the sender considers acknowledged. Use Routed for verification challenges or anything that needs your app's status, headers, or response body.

You can mix both delivery types on one URL. On the Project URL's page, choose a default, then open Advanced to add up to 16 rules that override it for an HTTP method and path. For example, route a verification request to one devbox while multicasting POST requests to /webhooks/example. Exact paths take priority over prefixes; among matching path-segment prefixes, the longest wins. Each request uses one delivery type, even if a devbox both holds the routed claim and subscribes.

Claim traffic from a script or agent

To claim a URL automatically, add the claim command to your app's own start script, after the HTTP server is listening. You can also ask the agent on the devbox to claim it. These commands use dvb-onbox, which is installed on the machine itself and always acts on the devbox where it runs; replace <name> with the configured URL's name:

dvb-onbox url list --json
dvb-onbox url show <name> --json
dvb-onbox url claim <name> --if-free --json

--if-free will claim an unassigned URL or keep this devbox's existing claim. If another devbox holds the claim, the command will report a conflict, even if that devbox's app has stopped. To deliberately move traffic from another devbox, use dvb-onbox url claim <name> --take --json.

Don't release the claim during ordinary app shutdown: retaining it lets you restart the app without claiming again. Run dvb-onbox url release <name> when you want to make the URL available for another devbox to claim with --if-free.

Subscribe to webhooks

On each devbox that should receive multicast webhooks, start the app on the URL's configured port, then run this command with the URL's name:

dvb-onbox url subscribe <name> --json

The devbox will receive every request assigned to multicast on that URL. Unlike a routed claim, the subscription is temporary: it expires when the app stops listening, the devbox sleeps, its machine is replaced during recovery, or it is destroyed. Subscribe again after the app restarts. To stop receiving multicast requests while the app keeps running, use dvb-onbox url unsubscribe <name> --json.

Keep a browser on one devbox

For ordinary OAuth testing, use the Project URL directly. To test different devboxes through the same Project URL at the same time, use separate browser profiles and a browser entry link for each devbox. Opening the link will pin that profile's requests to the chosen devbox. Create a link on each intended devbox, replacing <name> with the Project URL's name:

dvb-onbox url browser-link <name> --return-to /oauth/google/start --json

Replace /oauth/google/start with the path that begins sign-in in your app. Open the returned link in the browser profile you want to use for that devbox. Opening it sets a cookie and continues to the app path; from then on, that browser's requests to the Project URL — including the OAuth provider's callback redirect — will go to the pinned devbox. The URL's default claim and the callback registered with the OAuth provider will stay unchanged.

You can reopen the entry link for 120 seconds. Once the cookie is set, the browser will stay pinned when the entry link expires.

If the pinned devbox becomes unavailable, the browser will show recovery options instead of silently switching to the devbox with the default claim.

You can also give each devbox a separate Project URL and claim it there. Those independent addresses don't require browser pinning.

Configure URLs from your computer

Use the Project URL's page in the desktop app to change its settings, disable or enable it, replace its public address, or delete it. Changing the port, delivery settings, enabled state, or public address will clear its claims and subscriptions, so claim or subscribe again after making those changes. Renaming the URL will preserve its claims and subscriptions.

For scripts on your laptop, use the dvb CLI (install and sign in). The commands below cover individual management actions. Replace <project> with your project; you can omit --project if your account has exactly one project.

Create and inspect URLs:

dvb url list --project <project>
dvb url create callbacks --project <project> --port 3000 --default-delivery routed
dvb url show callbacks --project <project>

Change settings or availability — these are the changes that clear claims and subscriptions, as described above:

dvb url edit callbacks --project <project> --port 4000
dvb url disable callbacks --project <project>
dvb url enable callbacks --project <project>

Manage per-path delivery rules:

dvb url route add callbacks --project <project> --method POST \
  --path /webhooks/example --delivery webhook-multicast
dvb url route list callbacks --project <project>
dvb url route edit callbacks <rule-id> --project <project> --delivery routed
dvb url route remove callbacks <rule-id> --project <project>

Use --default-delivery webhook-multicast when every request should be sent to subscribers. Claim, release, subscribe, and unsubscribe stay on-machine actions: run them on the devbox with dvb-onbox, as described above.

Add browser pinning to an application

To make browser pinning part of your app's sign-in flow, open Connect your app on the Project URL's page. It includes a prompt for your coding agent and Node and Python examples.

A server running directly on the devbox can request an entry link through this local API:

POST http://127.0.0.1:29998/.boxes.dev/api/v1/project-urls/<name>/browser-link
Authorization: Bearer <token read from ~/.devbox/daemon/project-url-api-token>
Idempotency-Key: <unique key for this request>
Content-Type: application/json

{"returnTo":"/oauth/google/start"}

Read the token from ~/.devbox/daemon/project-url-api-token and keep it on the server. This API accepts calls only through the devbox's loopback address; browser calls and redirects are rejected. The token permits only this devbox's Project URL participation. If your app also runs outside boxes.dev, check for the token file and use the ordinary OAuth flow when it's absent.

An isolated container can't call this API directly. Publish its application port to the host's loopback address, then request the entry link from code running on the host.