> ## Documentation Index
> Fetch the complete documentation index at: https://upstash.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# 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.

<CodeGroup>
  ```typescript box.ts theme={"system"}
  import { Agent, Box } from "@upstash/box"

  const box = await Box.create({ runtime: "node" })

  // Start a web server on port 3000
  await 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 URL
  const publicUrl = await box.getPublicUrl(3000)

  console.log(publicUrl.url)
  // → https://{BOX_ID}-3000.preview.box.upstash.com
  ```

  ```python box.py theme={"system"}
  from upstash_box import Box

  box = Box.create(runtime="node")

  # Start a web server on port 3000
  box.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 URL
  public_url = box.get_public_url(3000)

  print(public_url.url)
  # -> https://{BOX_ID}-3000.preview.box.upstash.com
  ```
</CodeGroup>

### Add authentication

Protect your public URL with bearer token or basic authentication.

<CodeGroup>
  ```typescript box.ts theme={"system"}
  // With bearer token
  const publicUrl = await box.getPublicUrl(3000, { bearerToken: true })

  console.log(publicUrl.token) // Use this in Authorization header
  // → "63d8b153..."

  // With basic auth
  const publicUrl = await box.getPublicUrl(8080, { basicAuth: true })

  console.log(publicUrl.username) // → "user"
  console.log(publicUrl.password) // → "f0f145f0..."
  ```

  ```python box.py theme={"system"}
  # With bearer token
  public_url = box.get_public_url(3000, bearer_token=True)

  print(public_url.token)  # Use this in Authorization header
  # -> "63d8b153..."

  # With basic auth
  public_url = box.get_public_url(8080, basic_auth=True)

  print(public_url.username)  # -> "user"
  print(public_url.password)  # -> "f0f145f0..."
  ```
</CodeGroup>

***

## API

### Create Public URL

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

<CodeGroup>
  ```typescript box.ts theme={"system"}
  const publicUrl = await box.getPublicUrl(3000)

  console.log(publicUrl.url)
  // → https://{BOX_ID}-3000.preview.box.upstash.com
  ```

  ```python box.py theme={"system"}
  public_url = box.get_public_url(3000)

  print(public_url.url)
  # -> https://{BOX_ID}-3000.preview.box.upstash.com
  ```
</CodeGroup>

#### With Bearer Token

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

<CodeGroup>
  ```typescript box.ts theme={"system"}
  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
  ```

  ```python box.py theme={"system"}
  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
  ```
</CodeGroup>

#### With Basic Authentication

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

<CodeGroup>
  ```typescript box.ts theme={"system"}
  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
  ```

  ```python box.py theme={"system"}
  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
  ```
</CodeGroup>

#### With Both Auth Methods

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

<CodeGroup>
  ```typescript box.ts theme={"system"}
  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..."
  ```

  ```python box.py theme={"system"}
  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..."
  ```
</CodeGroup>

***

### List Public URLs

Get all active public URLs for this box.

<CodeGroup>
  ```typescript box.ts theme={"system"}
  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 },
  // ]
  ```

  ```python box.py theme={"system"}
  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),
  # ]
  ```
</CodeGroup>

***

### Delete Public URL

Remove a public URL by port number.

<CodeGroup>
  ```typescript box.ts theme={"system"}
  await box.deletePublicUrl(3000)
  ```

  ```python box.py theme={"system"}
  box.delete_public_url(3000)
  ```
</CodeGroup>

***

## 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.

<CodeGroup>
  ```typescript box.ts theme={"system"}
  // First public URL
  const publicUrl1 = await box.getPublicUrl(3000)

  // Second public URL overwrites the first one
  const publicUrl2 = await box.getPublicUrl(3000, { bearerToken: true })

  // publicUrl1.url is no longer accessible
  ```

  ```python box.py theme={"system"}
  # First public URL
  public_url1 = box.get_public_url(3000)

  # Second public URL overwrites the first one
  public_url2 = box.get_public_url(3000, bearer_token=True)

  # public_url1.url is no longer accessible
  ```
</CodeGroup>

### 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.

<CodeGroup>
  ```typescript box.ts theme={"system"}
  await box.pause()

  // This will resume the box
  const publicUrl = await box.getPublicUrl(3000)
  ```

  ```python box.py theme={"system"}
  box.pause()

  # This will resume the box
  public_url = box.get_public_url(3000)
  ```
</CodeGroup>

***

## Examples

### Expose an agent-built app

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

<CodeGroup>
  ```typescript box.ts theme={"system"}
  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 endpoints
  const response = await fetch(`${publicUrl.url}/health`)
  console.log(await response.json()) // { status: "ok" }
  ```

  ```python box.py theme={"system"}
  import os
  from upstash_box import Box, Agent

  box = 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 endpoints
  import httpx
  response = httpx.get(f"{public_url.url}/health")
  print(response.json())  # {"status": "ok"}
  ```
</CodeGroup>

### Share a secure public URL

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

<CodeGroup>
  ```typescript box.ts theme={"system"}
  import { Agent, Box } from "@upstash/box"

  const box = await Box.create({ runtime: "python" })

  // Set up a Flask app
  await box.files.write({
    path: "/work/app.py",
    content: `
  from flask import Flask
  app = 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 URL
  const 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
  ```

  ```python box.py theme={"system"}
  import httpx
  from upstash_box import Box

  box = Box.create(runtime="python")

  # Set up a Flask app
  box.files.write(
      path="/work/app.py",
      content="""
  from flask import Flask
  app = 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 URL
  public_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
  ```
</CodeGroup>

### Multi-port application

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

<CodeGroup>
  ```typescript box.ts theme={"system"}
  import { Agent, Box } from "@upstash/box"

  const box = await Box.create({ runtime: "node" })

  // Start frontend on port 3000
  await 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 8080
  await 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 service
  const frontendPublicUrl = await box.getPublicUrl(3000)
  const apiPublicUrl = await box.getPublicUrl(8080)

  console.log(`Frontend: ${frontendPublicUrl.url}`)
  console.log(`API: ${apiPublicUrl.url}`)
  ```

  ```python box.py theme={"system"}
  from upstash_box import Box

  box = Box.create(runtime="node")

  # Start frontend on port 3000
  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 8080
  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)
    """,
  )

  box.exec.command("npm install express")
  box.exec.command("node /work/frontend.js & node /work/api.js &")

  # Create a public URL for each service
  frontend_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}")
  ```
</CodeGroup>

### Temporary testing public URL

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

<CodeGroup>
  ```typescript box.ts theme={"system"}
  import { Agent, Box } from "@upstash/box"

  const box = await Box.create({ runtime: "node" })

  // Start test server
  await box.exec.command("npx http-server /work -p 3000 &")

  // Create a public URL for testing
  const publicUrl = await box.getPublicUrl(3000)

  // Run your tests against the public URL
  const response = await fetch(publicUrl.url)
  console.log(response.status) // 200

  // Clean up
  await box.deletePublicUrl(3000)
  await box.delete()
  ```

  ```python box.py theme={"system"}
  import httpx
  from upstash_box import Box

  box = Box.create(runtime="node")

  # Start test server
  box.exec.command("npx http-server /work -p 3000 &")

  # Create a public URL for testing
  public_url = box.get_public_url(3000)

  # Run your tests against the public URL
  response = httpx.get(public_url.url)
  print(response.status_code)  # 200

  # Clean up
  box.delete_public_url(3000)
  box.delete()
  ```
</CodeGroup>

<Note>The SDK still supports `getPreviewUrl`, `listPreviews`, and `deletePreview`, but they are deprecated aliases for `getPublicUrl`, `listPublicUrls`, and `deletePublicUrl`.</Note>
