Lifecycle

Public URLs

Expose ports from a box with public URLs. Each public URL maps to a specific port and can optionally require authentication.


Quickstart

Create a public URL

Start a web server inside your box and create a public URL to access it.

box.ts
import { Agent, Box } from "@upstash/box"const box = await Box.create({ runtime: "node" })// Start a web server on port 3000await box.exec.command("cd /work && npm install express")await box.files.write({  path: "/work/server.js",  content: `    const express = require('express')    const app = express()    app.get('/', (req, res) => res.send('Hello from Box!'))    app.listen(3000)  `,})await box.exec.command("node /work/server.js &")// Create a public URLconst publicUrl = await box.getPublicURL(3000)console.log(publicUrl.url)// → https://{BOX_ID}-3000.preview.box.upstash.com
box.py
from upstash_box import Boxbox = Box.create(runtime="node")# Start a web server on port 3000box.exec.command("cd /work && npm install express")box.files.write(    path="/work/server.js",    content="""    const express = require('express')    const app = express()    app.get('/', (req, res) => res.send('Hello from Box!'))    app.listen(3000)  """,)box.exec.command("node /work/server.js &")# Create a public URLpublic_url = box.get_public_url(3000)print(public_url.url)# -> https://{BOX_ID}-3000.preview.box.upstash.com

Add authentication

Protect your public URL with bearer token or basic authentication.

box.ts
// With bearer tokenconst publicUrl = await box.getPublicURL(3000, { bearerToken: true })console.log(publicUrl.token) // Use this in Authorization header// → "63d8b153..."// With basic authconst publicUrl = await box.getPublicURL(8080, { basicAuth: true })console.log(publicUrl.username) // → "user"console.log(publicUrl.password) // → "f0f145f0..."
box.py
# With bearer tokenpublic_url = box.get_public_url(3000, bearer_token=True)print(public_url.token)  # Use this in Authorization header# -> "63d8b153..."# With basic authpublic_url = box.get_public_url(8080, basic_auth=True)print(public_url.username)  # -> "user"print(public_url.password)  # -> "f0f145f0..."

API

Create Public URL

Creates a public URL that exposes a port on your box. Returns the URL and authentication credentials if requested.

box.ts
const publicUrl = await box.getPublicURL(3000)console.log(publicUrl.url)// → https://{BOX_ID}-3000.preview.box.upstash.com
box.py
public_url = box.get_public_url(3000)print(public_url.url)# -> https://{BOX_ID}-3000.preview.box.upstash.com

With Bearer Token

Add bearerToken: true to require an authorization header when accessing the public URL.

box.ts
const publicUrl = await box.getPublicURL(3000, { bearerToken: true })console.log(publicUrl.token)// → "63d8b153..."// Access the public URL:// curl -H "Authorization: Bearer 63d8b153..." https://{BOX_ID}-3000.preview.box.upstash.com
box.py
public_url = box.get_public_url(3000, bearer_token=True)print(public_url.token)# -> "63d8b153..."# Access the public URL:# curl -H "Authorization: Bearer 63d8b153..." https://{BOX_ID}-3000.preview.box.upstash.com

With Basic Authentication

Add basicAuth: true to require username and password when accessing the public URL.

box.ts
const publicUrl = await box.getPublicURL(8080, { basicAuth: true })console.log(publicUrl.username) // → "user"console.log(publicUrl.password) // → "f0f145f0..."// Access the public URL:// curl -u user:f0f145f0... https://{BOX_ID}-8080.preview.box.upstash.com
box.py
public_url = box.get_public_url(8080, basic_auth=True)print(public_url.username)  # -> "user"print(public_url.password)  # -> "f0f145f0..."# Access the public URL:# curl -u user:f0f145f0... https://{BOX_ID}-8080.preview.box.upstash.com

With Both Auth Methods

Enable both authentication methods. Either one will work when accessing the public URL.

box.ts
const publicUrl = await box.getPublicURL(8080, { bearerToken: true, basicAuth: true })console.log(publicUrl.token) // → "63d8b153..."console.log(publicUrl.username) // → "user"console.log(publicUrl.password) // → "f0f145f0..."
box.py
public_url = box.get_public_url(8080, bearer_token=True, basic_auth=True)print(public_url.token)     # -> "63d8b153..."print(public_url.username)  # -> "user"print(public_url.password)  # -> "f0f145f0..."

List Public URLs

Get all active public URLs for this box.

box.ts
const { publicURLs } = await box.listPublicURLs()console.log(publicURLs)// [//   { url: "https://{BOX_ID}-3000.preview.box.upstash.com", port: 3000 },//   { url: "https://{BOX_ID}-8080.preview.box.upstash.com", port: 8080 },// ]
box.py
result = box.list_public_urls()print(result["public_urls"])# [#   PublicURL(url="https://{BOX_ID}-3000.preview.box.upstash.com", port=3000),#   PublicURL(url="https://{BOX_ID}-8080.preview.box.upstash.com", port=8080),# ]

Delete Public URL

Remove a public URL by port number.

box.ts
await box.deletePublicURL(3000)
box.py
box.delete_public_url(3000)

Behavior

One Public URL Per Port

Creating a public URL for a port that already has one will overwrite the previous one, including any auth credentials.

box.ts
// First public URLconst publicUrl1 = await box.getPublicURL(3000)// Second public URL overwrites the first oneconst publicUrl2 = await box.getPublicURL(3000, { bearerToken: true })// publicUrl1.url is no longer accessible
box.py
# First public URLpublic_url1 = box.get_public_url(3000)# Second public URL overwrites the first onepublic_url2 = box.get_public_url(3000, bearer_token=True)# public_url1.url is no longer accessible

Public URL Lifecycle

Public URLs expire automatically when:

  • The box is paused
  • The box is deleted

Auto-Resume

Creating a public URL on a paused box automatically resumes it.

box.ts
await box.pause()// This will resume the boxconst publicUrl = await box.getPublicURL(3000)
box.py
box.pause()# This will resume the boxpublic_url = box.get_public_url(3000)

Examples

Expose an agent-built app

Let an agent build a web app, then create a public URL to test it.

box.ts
import { Agent, Box } from "@upstash/box"const box = await Box.create({  runtime: "node",  agent: {    harness: Agent.ClaudeCode,    model: "anthropic/claude-opus-4-6",    apiKey: process.env.ANTHROPIC_API_KEY,  },})await box.agent.run({  prompt: `Create a simple Express web server that:- Listens on port 3000- Has a / route that returns "Hello World"- Has a /health route that returns {"status": "ok"}- Start the server in the background  `,})const publicUrl = await box.getPublicURL(3000)console.log(`Public URL available at: ${publicUrl.url}`)// Test the endpointsconst response = await fetch(`${publicUrl.url}/health`)console.log(await response.json()) // { status: "ok" }
box.py
import osfrom upstash_box import Box, Agentbox = Box.create(    runtime="node",    agent={        "harness": Agent.CLAUDE_CODE,        "model": "anthropic/claude-opus-4-6",        "api_key": os.environ["ANTHROPIC_API_KEY"],    },)box.agent.run(    prompt="""Create a simple Express web server that:- Listens on port 3000- Has a / route that returns "Hello World"- Has a /health route that returns {"status": "ok"}- Start the server in the background  """,)public_url = box.get_public_url(3000)print(f"Public URL available at: {public_url.url}")# Test the endpointsimport httpxresponse = httpx.get(f"{public_url.url}/health")print(response.json())  # {"status": "ok"}

Share a secure public URL

Create a public URL with authentication for sharing with team members.

box.ts
import { Agent, Box } from "@upstash/box"const box = await Box.create({ runtime: "python" })// Set up a Flask appawait box.files.write({  path: "/work/app.py",  content: `from flask import Flaskapp = Flask(__name__)@app.route('/')def home():    return 'Internal Dashboard'if __name__ == '__main__':    app.run(host='0.0.0.0', port=8080)  `,})await box.exec.command("pip install flask && python /work/app.py &")// Create authenticated public URLconst publicUrl = await box.getPublicURL(8080, { basicAuth: true })console.log(`Public URL: ${publicUrl.url}`)console.log(`Username: ${publicUrl.username}`)console.log(`Password: ${publicUrl.password}`)// Share these credentials with your team
box.py
import httpxfrom upstash_box import Boxbox = Box.create(runtime="python")# Set up a Flask appbox.files.write(    path="/work/app.py",    content="""from flask import Flaskapp = Flask(__name__)@app.route('/')def home():    return 'Internal Dashboard'if __name__ == '__main__':    app.run(host='0.0.0.0', port=8080)  """,)box.exec.command("pip install flask && python /work/app.py &")# Create authenticated public URLpublic_url = box.get_public_url(8080, basic_auth=True)print(f"Public URL: {public_url.url}")print(f"Username: {public_url.username}")print(f"Password: {public_url.password}")# Share these credentials with your team

Multi-port application

Create multiple public URLs for different services in the same box.

box.ts
import { Agent, Box } from "@upstash/box"const box = await Box.create({ runtime: "node" })// Start frontend on port 3000await box.files.write({  path: "/work/frontend.js",  content: `const express = require('express')const app = express()app.get('/', (req, res) => res.send('Frontend'))app.listen(3000)  `,})// Start API on port 8080await box.files.write({  path: "/work/api.js",  content: `const express = require('express')const app = express()app.get('/api/status', (req, res) => res.json({ status: 'ok' }))app.listen(8080)  `,})await box.exec.command("npm install express")await box.exec.command("node /work/frontend.js & node /work/api.js &")// Create a public URL for each serviceconst frontendPublicUrl = await box.getPublicURL(3000)const apiPublicUrl = await box.getPublicURL(8080)console.log(`Frontend: ${frontendPublicUrl.url}`)console.log(`API: ${apiPublicUrl.url}`)
box.py
from upstash_box import Boxbox = Box.create(runtime="node")# Start frontend on port 3000box.files.write(    path="/work/frontend.js",    content="""const express = require('express')const app = express()app.get('/', (req, res) => res.send('Frontend'))app.listen(3000)  """,)# Start API on port 8080box.files.write(    path="/work/api.js",    content="""const express = require('express')const app = express()app.get('/api/status', (req, res) => res.json({ status: 'ok' }))app.listen(8080)  """,)box.exec.command("npm install express")box.exec.command("node /work/frontend.js & node /work/api.js &")# Create a public URL for each servicefrontend_public_url = box.get_public_url(3000)api_public_url = box.get_public_url(8080)print(f"Frontend: {frontend_public_url.url}")print(f"API: {api_public_url.url}")

Temporary testing public URL

Create a public URL, run tests against it, then clean up.

box.ts
import { Agent, Box } from "@upstash/box"const box = await Box.create({ runtime: "node" })// Start test serverawait box.exec.command("npx http-server /work -p 3000 &")// Create a public URL for testingconst publicUrl = await box.getPublicURL(3000)// Run your tests against the public URLconst response = await fetch(publicUrl.url)console.log(response.status) // 200// Clean upawait box.deletePublicURL(3000)await box.delete()
box.py
import httpxfrom upstash_box import Boxbox = Box.create(runtime="node")# Start test serverbox.exec.command("npx http-server /work -p 3000 &")# Create a public URL for testingpublic_url = box.get_public_url(3000)# Run your tests against the public URLresponse = httpx.get(public_url.url)print(response.status_code)  # 200# Clean upbox.delete_public_url(3000)box.delete()
The SDK still supports getPreviewUrl, listPreviews, and deletePreview, but they are deprecated aliases for getPublicURL, listPublicURLs, and deletePublicURL.
Loading search…