Proxies REST API
Proxy providers
A provider is an account with a seller, kept as a template. You paste one gateway line — the one the dashboard gives you — and it mints a different proxy for every profile: a different session id, and therefore a different exit address.
That is the difference from /proxies, which is a library of addresses. A provider is the thing addresses come out of. POST /profiles with {"proxy": {"providerId": "…", "country": "US"}} is the whole flow: one call, one profile, one exit nothing else shares.
The pasted line is the specification. The vendor, the separator, which credential carries the tokens, the account prefix and the shape of a session id are all read back off it, so a seller that spells its keys differently still round-trips, and a token this app has never heard of survives untouched. What the vendor table adds is the part one line cannot tell you: the word to use when adding an option the line did not carry.
A provider is refused an option its gateway cannot spell, by name. Writing city-miami into a credential whose seller has no city key produces a proxy that authenticates and then quietly comes out somewhere else — success from outside, and a profile whose timezone now contradicts its address. supports on every provider says which of country, state, city, session and duration are real for that seller.
Providers are global. There is no projectId on any route here and no query parameter to add one: an account is not an exit you keep to one customer, and a scope would invite the same credential to be pasted once per project.
List providers
GET/api/v1/providers
Every provider, newest first. Each row is the stored record plus four things computed from it: vendor (the seller’s name, or the host for one nobody recognises), supports (which options this gateway can be asked for), current (what the pasted line already asks for) and preview (one real example of the credential it will produce, minted the same way a launch mints one). usedBy counts the profiles minted from it.
Returns
{ total, providers: Provider[] }
Add a provider
POST/api/v1/providers
Reads one pasted gateway line and keeps it as a template.
A line that is the same gateway as one already stored — same host, port, account prefix and credential — is a 400 naming the existing provider. Five lines off one dashboard are five examples of one gateway differing in a session id this app rewrites anyway, and storing all five produces a list nobody can read.
Body
| Field | Type | What it is |
|---|---|---|
line | string | Required. One gateway line, in any format the proxy importer reads: scheme://user:pass@host:port, user:pass@host:port, host:port:user:pass, host:port@user:pass or a bare host:port. |
name | string | What to call it. Defaults to the vendor’s own name, with the line’s country if it names one. |
notes | string | Free text. |
type | string | Default proxy type when the line carries no scheme: http, https, socks5 or socks4. Default http. |
defaults | object | { country, state, city, minutes } — what every profile minted from this provider asks for unless it says otherwise. A field this seller cannot spell is a 400 naming it. |
Returns
The created provider, in the same shape GET /providers returns.
curl -X POST -H "Authorization: Bearer $KEY" -H 'content-type: application/json' \
-d '{"line":"gate-eu.provider.com:8668:user-abc-region-us-sess-146592-sessTime-30:pw",
"name":"Residential — main"}' \
"$BASE/providers"
Read a line without saving it
POST/api/v1/providers/parse
Says what a pasted line means — vendor, mark, which options it can be asked for, what it already asks for, and one real example credential — and stores nothing. The preview comes from the same function a launch uses, so what this shows and what would be stored cannot disagree.
Useful for a seller with more than one pool: only the hostname tells them apart, and the grammars differ.
Body
| Field | Type | What it is |
|---|---|---|
line | string | Required. |
type | string | Default type when the line carries no scheme. |
Returns
{ vendorId, vendor, slug, label, host, port, type, supports, current, preview, docs }
Every seller this app recognises
GET/api/v1/providers/vendors
The vendor table: which hostnames belong to whom, and which of country, state, city, session and duration each one’s gateway can be asked for. A seller not in this list still works — its line is read and used exactly as pasted — but nothing is added to it, because a guessed key name produces a proxy that authenticates and comes out in the wrong country without saying so.
Returns
{ total, vendors: { id, label, slug, hosts, supports, docs }[] }
Where an exit can be asked to be
GET/api/v1/providers/places
With no country: every country code and name. With one: that country’s subdivisions and its larger cities.
The subdivisions matter beyond being a list. Sellers disagree about whether a state is written as a code (state-AZ) or spelled out (state-california), and a gateway handed the wrong form matches nothing and returns an exit somewhere else without mentioning it. This is the table the conversion uses, so a state you send from here is written in whichever form the provider wants. Cities are suggestions — every vendor takes a city as a free string.
Query parameters
| Field | Type | What it is |
|---|---|---|
country | string | ISO country code. |
Returns
Without country: { total, countries: { code, name }[] }. With one: { country, states: { code, name }[], cities: string[] }.
Read one provider
GET/api/v1/providers/:id
The same shape as a row of GET /providers.
Returns
A provider.
Rename, re-note, or replace the line
PATCH/api/v1/providers/:id
Absent fields are left alone, as on every PATCH here.
A new line is re-read from scratch rather than merged: a seller that moves an account to a different host is a different grammar, a different vendor and possibly a different carrier, and a merged parse would match neither. Its lastCheck is cleared with it, because that result describes the old gateway. An empty line is a 400 rather than a no-op — emptying the credential of a template that mints proxies would leave every future mint pointing at nothing, so it says to delete the provider instead.
Body
| Field | Type | What it is |
|---|---|---|
line | string | A replacement gateway line. |
name | string | New name. Empty is refused. |
notes | string | New notes. |
type | string | Default type for a replacement line. |
defaults | object | { country, state, city, minutes }. |
Returns
The updated provider.
Delete a provider
DELETE/api/v1/providers/:id
Profiles minted from it keep the proxy they were given and go on browsing from it: the credential lives on the profile, not behind a reference. What is lost is the ability to mint more, which is the truth about a deleted account. keptProfiles says how many profiles are in that position, said rather than left to be inferred — a caller who read { deleted: true } and assumed forty profiles had just lost their exits would be wrong in the alarming direction.
Returns
{ deleted: true, keptProfiles }
Check a provider
POST/api/v1/providers/:id/check
Mints one proxy and sends a real request through it. There is nothing else to check: a template is not an address, and nothing is listening until a credential names a session.
The result is recorded on the provider, which makes it evidence about the account — has the balance run out, has the session limit been hit — rather than about any exit a profile will later use. The minted proxy is thrown away; it is never added to /proxies.
Returns
A ProxyCheckResult.
Mint a proxy without attaching it
POST/api/v1/providers/:id/mint
Returns a credential and the line it writes as, and attaches it to nothing.
Every call mints a new session id, because that is what minting is: two profiles sharing a session id share an exit address, which is the one thing a proxy per profile exists to prevent. A pick this seller’s gateway cannot spell is a 400 naming the field, never a quiet drop.
Most automations do not need this — POST /profiles takes {"proxy": {"providerId": "…"}} and mints in the same call. Use it to see the credential before committing, or to drive something outside Mosaic.
Body
| Field | Type | What it is |
|---|---|---|
country | string | ISO country code, or "any" to take the option off the credential and let the gateway choose. |
state | string | A subdivision name or code. Written in whichever form this vendor wants — see GET /providers/places. |
city | string | A city name with ordinary spaces. Each vendor’s own spelling of a space (new_york, New-York, newyork, new+york) is applied when it is written. |
minutes | number | How long the exit holds, 0–1440. Written in the seller’s own unit — bare minutes, seconds, or 30m. |
Returns
{ proxy: ProxyConfig, line }
curl -X POST -H "Authorization: Bearer $KEY" -H 'content-type: application/json' \
-d '{"country":"US","state":"California","minutes":30}' \
"$BASE/providers/$PROVIDER/mint"
Run the API on your own profiles
The REST API and the MCP server are part of Pro: $49 a month, with the first 14 days free. Free has every browser feature and no API key.
Mosaic is a desktop app
Email yourself the link and open it on your computer.