Your tests read the codes your service sends.
Point any client at a line’s proxy port. When your own service texts the line, your test suite or your agent reads the code through the REST API, a webhook or the MCP server. For services you own or are authorized to test, under one account and the same rules.
Every account gets the REST API, webhooks, the sandbox, the MCP server and the command line tool.
Request
GET /v1/lines/LAX-V-22/messages/wait?timeout=60
Authorization: Bearer $OSTRA_KEY
Response, when the text lands
200
{
"sender": "+12135550160",
"code": "482915",
"received_at": "2026-10-12T14:02:11Z"
}
Proxy ports, for any client
Every line has an HTTPS proxy port that takes its username and secret from anywhere. Pass it to your client’s proxy setting; four samples below.
curl
curl -x "https://$OSTRA_USER:$OSTRA_SECRET@lax.gw.ostranetwork.com:30022" \
https://example.com/
Python
import os, requests
line = f"https://{os.environ['OSTRA_USER']}:{os.environ['OSTRA_SECRET']}@lax.gw.ostranetwork.com:30022"
r = requests.get("https://example.com/", proxies={"https": line})
Node
import { ProxyAgent, fetch } from 'undici'
const auth = Buffer.from(`${process.env.OSTRA_USER}:${process.env.OSTRA_SECRET}`).toString('base64')
const line = new ProxyAgent({ uri: 'https://lax.gw.ostranetwork.com:30022', token: `Basic ${auth}` })
const res = await fetch('https://example.com/', { dispatcher: line })
Playwright
const browser = await chromium.launch({
proxy: {
server: 'https://lax.gw.ostranetwork.com:30022',
username: process.env.OSTRA_USER,
password: process.env.OSTRA_SECRET,
},
})
SOCKS5 and plain HTTP ports answer only the source addresses you list, with no credential. Ports by line ID
REST API
https://api.ostranetwork.com/v1, with a bearer key. The API uses your lines; it never creates them. Ostra assigns lines after verification.
| Call | Does |
|---|---|
| GET /lines | Your lines with their status, carrier and addresses |
| GET /lines/{id} | One line: its number, proxy endpoints, addresses and health |
| POST /lines/{id}/new-carrier-ip | Ask the carrier for a new address on this line; returns a job to follow |
| GET /lines/{id}/messages | Texts that arrived, with the codes Ostra read |
| GET /lines/{id}/messages/wait | Wait for the next text, up to 90 seconds |
| GET /lines/{id}/calls | Calls that came in, with any code the caller keyed |
| GET /usage | Bytes and connections per line per day |
| POST /orders | Order lines, on one carrier’s network or any. A line that is ready is assigned at once; otherwise the order waits for a line to be provisioned |
| POST /webhooks | Register an endpoint and the events it wants |
- Too soon
- A new carrier IP asked for too soon is refused at once with 429 and next_allowed_at, and nothing is held to run later. At most once every 5 minutes and 24 times in any 24 hours per line, and not for an hour after one that left the line much slower.
- Never on a schedule
- No schedule changes a line’s address. A new carrier IP happens when you ask, or when Ostra’s recovery asks after the line loses IPv4 or IPv6; both count toward the line’s limit, and each is reported as line.ip_changed.
Webhooks
Ostra posts to your endpoint as things happen. Each delivery is signed with a timestamp and an HMAC made with that endpoint’s secret, and a failed one is retried with backoff for 24 hours. The dashboard has a button that sends a test event.
- message.receivedA text arrived, with the code Ostra read from it
- call.receivedA call came in and ended, with whether it had a code
- line.ip_changedA line has a new carrier IP
- line.downA line stopped carrying traffic and its port closed
- line.upIt is carrying traffic again
- line.renewal_upcomingA line’s monthly subscription renews soon
MCP server, for agents
A remote MCP server at mcp.ostranetwork.com gives an AI agent your lines, their texts, calls and codes, and a new carrier IP, with an API key or an Ostra sign-in, under the same rules as the API. It does not order lines, manage webhooks or read usage. Its tools are for testing services you own or are authorized to test.
| Tool | Does |
|---|---|
| list_lines | Your lines and their status |
| get_line | A line’s proxy endpoints and address, so the agent can point its browser at it |
| wait_for_code | Waits for the next code on a line, up to 90 seconds (60 by default). With none by then, it says so and returns where to wait from next |
| new_carrier_ip | Ask for a new carrier IP; returns a handle at once, never a wait |
| get_new_carrier_ip | Follow that handle until the new address is read |
| list_messages | Recent texts on a line |
| list_calls | Recent calls on a line |
Not included, on purpose
Creating lines or buying numbers. Texting or calling from a line. Solving CAPTCHAs, changing a browser’s fingerprint, or creating accounts. The limits on what a line may be used for are enforced on Ostra’s side, not left to a tool’s description. Acceptable use
Keys and sign-in
- API keys
- Made in the dashboard by an admin of your account, optionally limited to some lines and to reading only. Shown once; Ostra keeps only a hash. Revoking one stops it at once. Until your account is verified, a key reaches only the sandbox.
- Apps and agents
- An MCP client uses an API key, or signs in with your Ostra account: it opens Ostra’s sign-in in your browser, shows what it asks for in plain words, and you choose the account it may reach. Only clients Ostra has registered can sign in this way, and a sign-in made for the MCP server works only there.
- The sandbox
- LAX-SANDBOX-00, a simulator, answers the API with sample data and no phone behind it, so you can build before a line is yours. The sandbox