# Proxy providers: Mosaic API reference

> Proxy providers in Mosaic’s local REST API: 10 routes, each with its method, path, fields, what it returns and the errors it names.

Source: https://mosaicbrowser.com/docs/api/providers

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

- [GETList providers](#list-providers)
- [POSTAdd a provider](#create-provider)
- [POSTRead a line without saving it](#parse-provider-line)
- [GETEvery seller this app recognises](#list-vendors)
- [GETWhere an exit can be asked to be](#list-places)
- [GETRead one provider](#get-provider)
- [PATCHRename, re-note, or replace the line](#update-provider)
- [DELETEDelete a provider](#delete-provider)
- [POSTCheck a provider](#check-provider)
- [POSTMint a proxy without attaching it](#mint-proxy)

## [List providers](#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](#create-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](#parse-provider-line)

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](#list-vendors)

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](#list-places)

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-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](#update-provider)

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-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](#check-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](#mint-proxy)

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.
