OAuth

A list of all publicly available methods for interacting with the API.

POST

Register a client (RFC 7591)

New/oauth/register

Register a client

Dynamic client registration (RFC 7591) for public clients such as MCP apps and CLIs. No secret is issued — every client uses PKCE.

Notes

  • redirect_uris must be https, or http on 127.0.0.1 / localhost (any port) for apps on the user's machine.
  • Self-registered clients show as "unverified" on the consent page; StableProxy staff can verify a client.

Query method

POSThttps://api.stableproxy.com/v3/oauth/register

Query parameters

IdentifierRegulationsExample
client_namerequiredstring75
redirect_urisrequiredarray[]
logo_uriNot necessarilynullableurlnull
token_endpoint_auth_methodNot necessarilynullablein:none"none"

Code examples

1const baseUrl = "https://api.stableproxy.com/v3";
2const response = await fetch(baseUrl + "/oauth/register", {
3 method: "POST",
4 headers: {
5 "Content-Type": "application/json"
6 },
7 body: JSON.stringify({
8 "client_name": 75,
9 "redirect_uris": "[]",
10 "logo_uri": "null",
11 "token_endpoint_auth_method": "\"none\""
12 })
13});
14const data = await response.json();

Examples of answers

Client created201application/json
{
  "client_id": "3f6c2a0e-8b1d-4c6f-9a77-1d2e3f4a5b6c",
  "client_name": "My scraper",
  "redirect_uris": [
    "http://127.0.0.1:53682/callback"
  ],
  "token_endpoint_auth_method": "none",
  "grant_types": [
    "authorization_code",
    "refresh_token"
  ],
  "response_types": [
    "code"
  ]
}
GET

Describe the current token

New/oauth/token-info

Describe the current token

Who and what the bearer token is: the user, where its orders are attributed (source), its abilities, OAuth scopes and audience, and whether automatic purchases are on.

Notes

  • 401 when the token is missing, expired or revoked — use it to check a token before calling other methods.
This method requires authorization!
You can use your own API key, which can be obtained at control panel.

Query method

GEThttps://api.stableproxy.com/v3/oauth/token-info

Code examples

1const baseUrl = "https://api.stableproxy.com/v3";
2const response = await fetch(baseUrl + "/oauth/token-info", {
3 method: "GET",
4 headers: {
5 "Authorization": "Bearer [YOUR TOKEN]",
6 "Content-Type": "application/json"
7 }
8});
9const data = await response.json();

Examples of answers

OAuth token200application/json
{
  "data": {
    "user_id": 2527,
    "source": "oauth:3f6c2a0e-8b1d-4c6f-9a77-1d2e3f4a5b6c",
    "abilities": [
      "cart.purchase",
      "packages.update"
    ],
    "scopes": [
      "orders:create",
      "offline_access"
    ],
    "audience": "https://mcp.stableproxy.com",
    "expires_at": "2026-10-06T17:00:00Z",
    "auto_confirm": false
  },
  "meta": []
}
No token401application/json
{
  "error": {
    "code": "unauthenticated",
    "message": "Sign in or send a valid token.",
    "details": []
  }
}
GET

Start an authorization (code + PKCE S256)

New/oauth/authorize

Start an authorization

Redirects the user's browser to the StableProxy consent page. Authorization code flow with PKCE S256 only.

Notes

  • Required: response_type=code, client_id, redirect_uri (exactly as registered), code_challenge, code_challenge_method=S256, scope, state.
  • Scopes: account:read, packages:read, proxies:manage, packages:manage, orders:create, payments:create, promos:manage, referrals:manage, offline_access.
  • After consent the user returns to redirect_uri?code=…&state=…&iss=…; an unknown client or redirect is shown an error and never redirected.

Query method

GEThttps://api.stableproxy.com/v3/oauth/authorize

Query parameters

IdentifierRegulationsExample
response_typerequiredin:code"code"
client_idrequireduuid20
redirect_urirequiredstring""
scoperequiredstring""
stateNot necessarilynullablestring""
code_challengerequiredstring""
code_challenge_methodrequiredin:_s256"_s256"
resourceNot necessarilynullableurlnull

Code examples

1const baseUrl = "https://api.stableproxy.com/v3";
2const response = await fetch(baseUrl + "/oauth/authorize", {
3 method: "GET",
4 headers: {
5 "Content-Type": "application/json"
6 }
7});
8const data = await response.json();
GET

Read a pending authorization for the consent page

New/oauth/request/{id}
This method requires authorization!
You can use your own API key, which can be obtained at control panel.

Query method

GEThttps://api.stableproxy.com/v3/oauth/request/{id}

Query parameters

IdentifierRegulationsExample
id1required36

Code examples

1const baseUrl = "https://api.stableproxy.com/v3";
2const response = await fetch(baseUrl + "/oauth/request/{id}", {
3 method: "GET",
4 headers: {
5 "Authorization": "Bearer [YOUR TOKEN]",
6 "Content-Type": "application/json"
7 }
8});
9const data = await response.json();
POST

Approve or deny an authorization

New/oauth/decision
This method requires authorization!
You can use your own API key, which can be obtained at control panel.

Query method

POSThttps://api.stableproxy.com/v3/oauth/decision

Query parameters

IdentifierRegulationsExample
requestrequiredstring""
approverequiredbooleanfalse
spend_limit_usd_dayNot necessarilynullablenumeric0
auto_confirmNot necessarilysometimesbooleanfalse

Code examples

1const baseUrl = "https://api.stableproxy.com/v3";
2const response = await fetch(baseUrl + "/oauth/decision", {
3 method: "POST",
4 headers: {
5 "Authorization": "Bearer [YOUR TOKEN]",
6 "Content-Type": "application/json"
7 },
8 body: JSON.stringify({
9 "request": "\"\"",
10 "approve": "false",
11 "spend_limit_usd_day": "0",
12 "auto_confirm": "false"
13 })
14});
15const data = await response.json();
POST

Exchange a code or refresh token for an access token

New/oauth/token

Exchange a code or a refresh token

application/x-www-form-urlencoded, RFC 6749 errors (invalid_grant, invalid_client, …).

Notes

  • grant_type=authorization_code with code, client_id, redirect_uri, code_verifier.
  • grant_type=refresh_token with refresh_token, client_id; refresh tokens rotate — keep the newest one. Reusing an old one revokes the whole connection.
  • Access tokens live 1 hour. A refresh token is issued only with the offline_access scope.

Query method

POSThttps://api.stableproxy.com/v3/oauth/token

Query parameters

IdentifierRegulationsExample
grant_typerequiredin:authorization_coderefresh_token"authorization_code"
client_idrequireduuid56
codeNot necessarilynullablestring""
redirect_uriNot necessarilynullablestring""
code_verifierNot necessarilynullablestring""
refresh_tokenNot necessarilynullablestring""
scopeNot necessarilynullablestring""
resourceNot necessarilynullableurlnull

Code examples

1const baseUrl = "https://api.stableproxy.com/v3";
2const response = await fetch(baseUrl + "/oauth/token", {
3 method: "POST",
4 headers: {
5 "Content-Type": "application/json"
6 },
7 body: JSON.stringify({
8 "grant_type": "\"authorization_code\"",
9 "client_id": 56,
10 "code": "\"\"",
11 "redirect_uri": "\"\"",
12 "code_verifier": "\"\"",
13 "refresh_token": "\"\"",
14 "scope": "\"\"",
15 "resource": "null"
16 })
17});
18const data = await response.json();

Examples of answers

Tokens200application/json
{
  "access_token": "412|9f2c…",
  "token_type": "Bearer",
  "expires_in": 3600,
  "refresh_token": "r1_7b0e…",
  "scope": "orders:create offline_access"
}
Bad code or verifier400application/json
{
  "error": "invalid_grant",
  "error_description": "The code or refresh token is invalid, expired, revoked or was issued to another client."
}
POST

Revoke an access or refresh token (RFC 7009)

New/oauth/revoke

Revoke a token

RFC 7009: revokes an access or refresh token. Always answers 200, even for an unknown token.

Query method

POSThttps://api.stableproxy.com/v3/oauth/revoke

Query parameters

IdentifierRegulationsExample
tokenrequiredstring""
token_type_hintNot necessarilynullablein:access_tokenrefresh_token"access_token"
client_idrequireduuid8

Code examples

1const baseUrl = "https://api.stableproxy.com/v3";
2const response = await fetch(baseUrl + "/oauth/revoke", {
3 method: "POST",
4 headers: {
5 "Content-Type": "application/json"
6 },
7 body: JSON.stringify({
8 "token": "\"\"",
9 "token_type_hint": "\"access_token\"",
10 "client_id": 8
11 })
12});
13const data = await response.json();
GET

List connected apps

New/oauth/apps

Connected apps

The apps the signed-in user allowed, with their scopes, purchase settings (auto_confirm, spend_limit_usd_day) and last use. Dashboard sign-in only.

This method requires authorization!
You can use your own API key, which can be obtained at control panel.

Query method

GEThttps://api.stableproxy.com/v3/oauth/apps

Code examples

1const baseUrl = "https://api.stableproxy.com/v3";
2const response = await fetch(baseUrl + "/oauth/apps", {
3 method: "GET",
4 headers: {
5 "Authorization": "Bearer [YOUR TOKEN]",
6 "Content-Type": "application/json"
7 }
8});
9const data = await response.json();
PUT

Change purchase settings of a connected app

New/oauth/apps/{grant}

Purchase settings of a connected app

Turns automatic purchases on or off and sets the daily spend limit. Dashboard login only.

Notes

  • Send only what changes: auto_confirm, spend_limit_usd_day (USD, null = no limit).
  • Automatic purchases need a limit: auto_confirm: true with no limit is a 422 auto_confirm_requires_limit.
  • With automatic purchases off, every purchase waits for the owner's confirmation in the browser.
This method requires authorization!
You can use your own API key, which can be obtained at control panel.

Query method

PUThttps://api.stableproxy.com/v3/oauth/apps/{grant}

Query parameters

IdentifierRegulationsExample
spend_limit_usd_dayNot necessarilysometimesnullablenumericdecimal:0, 28872
auto_confirmNot necessarilysometimesbooleanfalse
grant1requirednull

Code examples

1const baseUrl = "https://api.stableproxy.com/v3";
2const response = await fetch(baseUrl + "/oauth/apps/{grant}", {
3 method: "PUT",
4 headers: {
5 "Authorization": "Bearer [YOUR TOKEN]",
6 "Content-Type": "application/json"
7 },
8 body: JSON.stringify({
9 "spend_limit_usd_day": 8872,
10 "auto_confirm": "false"
11 })
12});
13const data = await response.json();
DELETE

Disconnect an app

New/oauth/apps/{grant}
This method requires authorization!
You can use your own API key, which can be obtained at control panel.

Query method

DELETEhttps://api.stableproxy.com/v3/oauth/apps/{grant}

Query parameters

IdentifierRegulationsExample
grant1requirednull

Code examples

1const baseUrl = "https://api.stableproxy.com/v3";
2const response = await fetch(baseUrl + "/oauth/apps/{grant}", {
3 method: "DELETE",
4 headers: {
5 "Authorization": "Bearer [YOUR TOKEN]",
6 "Content-Type": "application/json"
7 }
8});
9const data = await response.json();