Instance API Reference
Instances are running Chrome browser processes managed by PinchTab. Each instance is associated with a profile (browser user data directory) and has its own independent browser state.
Quick Start
List Running Instances
# CLIpinchtab instances# Curlcurl http://localhost:9867/instances | jq .# Response[ { "id": "inst_0a89a5bb", "profileId": "prof_278be873", "profileName": "Pinchtab org", "port": "9868", "headless": true, "status": "running", "startTime": "2026-03-01T05:21:38.27432Z" }]
Start an Instance
# CLI (all parameters optional)pinchtab instance start# CLI with profilepinchtab instance start --profileId 278be873adeb# CLI with mode and portpinchtab instance start --mode headed --port 9999# Curlcurl -X POST http://localhost:9867/instances/start \ -H "Content-Type: application/json" \ -d '{"profileId": "278be873adeb", "mode": "headed", "port": 9999}'# Response{ "id": "inst_ea2e747f", "profileId": "prof_278be873", "profileName": "Pinchtab org", "port": "9868", "headless": false, "status": "starting"}
Get Instance Logs
# CLIpinchtab instance logs inst_ea2e747fpinchtab instance logs --id inst_ea2e747f# Curlcurl http://localhost:9867/instances/inst_ea2e747f/logs
Stop an Instance
# CLIpinchtab instance stop inst_ea2e747fpinchtab instance stop --id inst_ea2e747f# Curlcurl -X POST http://localhost:9867/instances/inst_ea2e747f/stop# Response{ "id": "inst_ea2e747f", "status": "stopped"}
Complete API Reference
1. List Instances
Endpoint: GET /instances
CLI:
pinchtab instances
Curl:
curl http://localhost:9867/instances | jq .
Response: Array of Instance objects
[
{
"id": "inst_0a89a5bb",
"profileId": "prof_278be873",
"profileName": "Pinchtab org",
"port": "9868",
"headless": true,
"status": "running",
"startTime": "2026-03-01T05:21:38.27432Z"
}
]
Instance Status Values:
starting— Instance process spawning, Chrome initializingrunning— Instance healthy and ready to accept commandserror— Instance failed to startstopping— Instance is shutting down
2. Start Instance
Endpoint: POST /instances/start
CLI:
# All parameters optional - uses defaultspinchtab instance start# With specific profilepinchtab instance start --profileId 278be873adeb# With mode and portpinchtab instance start --profileId abc123 --mode headed --port 9999# Combine flagspinchtab instance start --mode headed --port 9998
Curl:
# Minimal (all defaults)curl -X POST http://localhost:9867/instances/start \ -H "Content-Type: application/json" \ -d '{}'# With profile IDcurl -X POST http://localhost:9867/instances/start \ -H "Content-Type: application/json" \ -d '{ "profileId": "278be873adeb", "mode": "headed", "port": "9999" }'
Request Body (all optional):
{
"profileId": "278be873adeb",
"mode": "headed",
"port": "9999"
}
Parameters:
profileId(string, optional) — Profile ID or name. If omitted, creates temporary instancemode(string, optional, default: “headless”) — “headed” or “headless”port(string, optional) — Port number. If omitted, auto-allocated from available ports
Response: Instance object
{
"id": "inst_ea2e747f",
"profileId": "prof_278be873",
"profileName": "Pinchtab org",
"port": "9868",
"headless": false,
"status": "starting",
"startTime": "2026-03-01T05:21:38.27432Z"
}
Defaults:
profileId— If omitted, auto-generates temporary profile namemode— Defaults to “headless” if not specifiedport— Auto-allocated if not specified (finds first available port)
3. Get Instance Logs
Endpoint: GET /instances/{id}/logs
CLI:
# Positional argumentpinchtab instance logs inst_ea2e747f# With --id flagpinchtab instance logs --id inst_ea2e747f
Curl:
curl http://localhost:9867/instances/inst_ea2e747f/logs
Response: Text (plain text log output)
2026-03-01 05:21:38 INFO starting instance process id=inst_ea2e747f profile=Pinchtab org port=9868
2026-03-01 05:21:40 INFO instance ready id=inst_ea2e747f
Notes:
- Returns raw text output (not JSON)
- Includes timestamps and log levels
- Useful for debugging instance startup issues
4. Stop Instance
Endpoint: POST /instances/{id}/stop
CLI:
# Positional argumentpinchtab instance stop inst_ea2e747f# With --id flagpinchtab instance stop --id inst_ea2e747f
Curl:
curl -X POST http://localhost:9867/instances/inst_ea2e747f/stop
Response:
{
"id": "inst_ea2e747f",
"status": "stopped"
}
Notes:
- Gracefully shuts down Chrome process
- Returns immediately (shutdown happens in background)
- Instance moved to stopped state
- Profile is preserved (not deleted)
Complete Workflow Examples
Example 1: Simple Start and Stop
#!/bin/bash# Start headless instance (auto-allocated port, temporary profile)INST=$(curl -s -X POST http://localhost:9867/instances/start \ -H "Content-Type: application/json" \ -d '{"mode":"headless"}' | jq -r .id)echo "Started instance: $INST"# Wait a moment for instance to be readysleep 2# Get logsecho "Instance logs:"curl -s http://localhost:9867/instances/$INST/logs | head -5# Stop instancecurl -s -X POST http://localhost:9867/instances/$INST/stop | jq .echo "Stopped instance: $INST"
Example 2: Start with Specific Profile
#!/bin/bash# Get first available profile IDPROF=$(curl -s http://localhost:9867/profiles | jq -r '.[0].id')echo "Using profile: $PROF"# Start instance with that profile in headed modeINST=$(curl -s -X POST http://localhost:9867/instances/start \ -H "Content-Type: application/json" \ -d "{ \"profileId\": \"$PROF\", \"mode\": \"headed\", \"port\": \"9999\" }" | jq -r .id)echo "Started instance: $INST on port 9999"# List running instancesecho -e "\nRunning instances:"curl -s http://localhost:9867/instances | jq '.[] | {id, port, mode: (if .headless then "headless" else "headed" end)}'# Stop when donecurl -s -X POST http://localhost:9867/instances/$INST/stop
Example 3: CLI-Based Workflow
#!/bin/bash# Start instanceecho "Starting instance..."INST=$(pinchtab instance start --mode headed --port 9998 | jq -r .id)echo "Instance: $INST"# Wait for readysleep 3# View logsecho -e "\nInstance logs:"pinchtab instance logs $INST | tail -5# List instancesecho -e "\nRunning instances:"pinchtab instances | jq '.[] | {id, port}'# Stopecho -e "\nStopping..."pinchtab instance stop $INST
Example 4: Multiple Instances
#!/bin/bashdeclare -a INSTANCES# Start 3 instances with different profilesPROFILES=$(curl -s http://localhost:9867/profiles | jq -r '.[0:3] | .[] | .id')i=0for prof in $PROFILES; do PORT=$((9868 + i)) INST=$(curl -s -X POST http://localhost:9867/instances/start \ -H "Content-Type: application/json" \ -d "{\"profileId\":\"$prof\",\"port\":\"$PORT\"}" | jq -r .id) INSTANCES+=($INST) echo "Started: $INST on port $PORT" i=$((i + 1))done# Wait and verifysleep 2echo -e "\nRunning instances:"curl -s http://localhost:9867/instances | jq length | xargs echo "Count:"# Stop allecho -e "\nStopping all instances..."for inst in "${INSTANCES[@]}"; do curl -s -X POST http://localhost:9867/instances/$inst/stop > /dev/null echo "Stopped: $inst"done
CLI Examples
Quick Start with CLI
# List instancespinchtab instances# Start headless instancepinchtab instance start# Start headed instance on specific portpinchtab instance start --mode headed --port 9999# Start with profilepinchtab instance start --profileId 278be873adeb# Get logs (both syntaxes work)pinchtab instance logs inst_0a89a5bbpinchtab instance logs --id inst_0a89a5bb# Stop instance (both syntaxes work)pinchtab instance stop inst_0a89a5bbpinchtab instance stop --id inst_0a89a5bb
Script Example
#!/bin/bash# Simple instance management scriptcase "$1" in "start") pinchtab instance start --mode $2 --port $3 ;; "logs") pinchtab instance logs $2 ;; "stop") pinchtab instance stop $2 ;; "list") pinchtab instances ;; *) echo "Usage: $0 {start|logs|stop|list} [args]" ;;esac
Integration Examples
With Bash
# Start instance and capture IDINST=$(curl -s -X POST http://localhost:9867/instances/start \ -d '{}' | jq -r .id)# Use instancePORT=$(curl -s http://localhost:9867/instances | jq -r ".[] | select(.id == \"$INST\") | .port")echo "Instance $INST running on port $PORT"# Cleanupcurl -s -X POST http://localhost:9867/instances/$INST/stop
With Python
import requests
import json
BASE = "http://localhost:9867"
# Start instance
resp = requests.post(f"{BASE}/instances/start", json={
"profileId": "278be873adeb",
"mode": "headed",
"port": "9999"
})
inst = resp.json()
print(f"Started: {inst['id']} on port {inst['port']}")
# List instances
instances = requests.get(f"{BASE}/instances").json()
print(f"Total running: {len(instances)}")
# Get logs
logs = requests.get(f"{BASE}/instances/{inst['id']}/logs").text
print("Recent logs:", logs[:200])
# Stop instance
resp = requests.post(f"{BASE}/instances/{inst['id']}/stop")
print(f"Stopped: {resp.json()}")
With JavaScript/Node.js
const BASE = "http://localhost:9867";
async function manageInstances() {
// Start instance
const startResp = await fetch(`${BASE}/instances/start`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
profileId: "278be873adeb",
mode: "headed",
port: "9999"
})
});
const inst = await startResp.json();
console.log(`Started: ${inst.id} on port ${inst.port}`);
// List instances
const listResp = await fetch(`${BASE}/instances`);
const instances = await listResp.json();
console.log(`Total running: ${instances.length}`);
// Get logs
const logsResp = await fetch(`${BASE}/instances/${inst.id}/logs`);
const logs = await logsResp.text();
console.log("Recent logs:", logs.substring(0, 200));
// Stop instance
const stopResp = await fetch(`${BASE}/instances/${inst.id}/stop`, {
method: "POST"
});
const stopped = await stopResp.json();
console.log(`Stopped: ${stopped.id}`);
}
manageInstances().catch(console.error);
Error Handling
Profile Not Found (404)
curl -X POST http://localhost:9867/instances/start \ -d '{"profileId":"nonexistent"}'# Response (400 Bad Request){ "error": "profile \"nonexistent\" not found", "statusCode": 404}
Port Already in Use (409)
curl -X POST http://localhost:9867/instances/start \ -d '{"port":"9867"}'# Response (409 Conflict){ "error": "port 9867 already in use", "statusCode": 409}
Instance Not Found (404)
curl http://localhost:9867/instances/nonexistent/logs# Response (404 Not Found){ "error": "instance not found", "statusCode": 404}
Invalid JSON (400)
curl -X POST http://localhost:9867/instances/start \ -d 'invalid json'# Response (400 Bad Request){ "error": "invalid JSON", "statusCode": 400}
Best Practices
Port Management
# Let PinchTab auto-allocate ports (recommended)pinchtab instance start# Or manually specify if you need a specific portpinchtab instance start --port 9999
Profile Selection
# Start with specific profile to preserve statepinchtab instance start --profileId 278be873adeb# Or use temporary profile (good for isolated testing)pinchtab instance start
Cleanup
# Always stop instances when donepinchtab instance stop $INSTANCE_ID# Check for orphaned instancespinchtab instances | jq length
Monitoring
# Check instance statuspinchtab instances | jq '.[] | {id, port, status}'# View recent logspinchtab instance logs $INSTANCE_ID | tail -20
Instance Lifecycle
START (POST /instances/start) ↓[status: "starting"] — Chrome initializing, health checks running ↓[status: "running"] — Ready to accept commands ↓STOP (POST /instances/{id}/stop) ↓[status: "stopping"] — Graceful shutdown ↓Instance removed from list, profile preserved
Status Codes
| Code | Meaning | Example |
|---|---|---|
| 200 | Success (GET) | List retrieved, logs retrieved |
| 201 | Created | Instance started successfully |
| 400 | Bad request | Invalid JSON, missing required field |
| 404 | Not found | Instance/profile not found |
| 409 | Conflict | Port already in use, launch error |
| 500 | Server error | Internal error |
Summary Table
| Operation | Method | Endpoint | CLI |
|---|---|---|---|
| List | GET | /instances | pinchtab instances |
| Start | POST | /instances/start | pinchtab instance start [opts] |
| Logs | GET | /instances/{id}/logs | pinchtab instance logs <id> |
| Stop | POST | /instances/{id}/stop | pinchtab instance stop <id> |
FAQ
Q: What’s the difference between headless and headed mode? A: Headless runs without a GUI window (good for servers), headed shows the browser window (good for debugging).
Q: Can I run multiple instances simultaneously? A: Yes, each gets its own port and Chrome process.
Q: What happens to my profile when I stop an instance? A: Profile is preserved. Stop just closes the browser. You can start the same instance again.
Q: How do I choose between temporary and named profiles? A: Use named profiles when you need to preserve state (logins, settings). Use temporary when testing.
Q: Can I change the port after starting? A: No, port is assigned on start. Stop and restart with a new port if needed.
Q: How do I know when an instance is ready? A: Status transitions from “starting” to “running” when healthy.
Related Documentation
- Profile API (docs/references/profile-api.md) — Manage browser profiles
- Tab API (docs/references/tab-api.md — coming soon) — Control tabs within instances
- CLI Design (docs/references/cli-design.md) — CLI command patterns