# ISV program

> Build an app that STX members connect to their account, with scoped, revocable access they approve on STX.

Source: https://docs.stxapp.io/isv/

export const demo = (id) => cfg.regions.find((r) => r.id === id).environments.find((e) => e.id === 'integration').url

**An ISV (independent software vendor) builds an app that acts on behalf of other STX members, using OAuth.** Your users keep their own STX accounts and connect them to your app. They sign in on STX, approve the access you ask for, and can disconnect at any time. You never see their password, their keys or their funds, and nothing your app holds can move money.

How the protocol works, from the authorization code flow to scopes, tokens and errors, is covered in the [OAuth](/oauth/) section. These pages cover what the program gives you and how to get access.

## What you get

- **Scoped access.** Named slices of a member's account, such as `profile.read`, `balance.read`, `orders.read` and `orders.write`. You ask for the fewest you need, and every token is confined to them. No scope moves money. See [Scopes](/oauth/scopes/).
- **Consent hosted by STX.** Sign-in, sign-up, two-factor and the consent screen all run on STX. Members see your app's name and logo, and can revoke it from **Connected apps** in their account. See [Hosted pages](/isv/hosted-pages/).
- **Member and app tokens.** A member token to act for one member, a refresh token to keep that access alive, and an app token to read the market and event catalogue as your app. See [Tokens and security](/oauth/tokens-and-security/).
- **The same API.** An access token is a bearer on the same [REST API](/api/rest/) and [WebSocket channels](/websockets/) a signed request uses, limited to the scopes the member approved.
- **Attribution.** Every order your app places for a member is recorded as placed by your app.
- **A TypeScript SDK.** `@stxapp/stx-typescript` runs the whole flow for you, from linking a member to refreshing and revoking their tokens. See [With the TypeScript SDK](/isv/typescript-sdk/).

## Access

Access is by invite. STX registers your app and gives you its client credentials, the host to test against, and a member account funded with play money to connect it to.

### Get demo access

To ask for an invite, contact [developer support](/support/) with your app's name and what it does. To set up your app, STX needs:

- an application **name** and **logo**, shown to members on the consent screen and in Connected apps;
- its **application type**, from the table below;
- one or more **callback URLs** (redirect URIs), where STX returns the member after consent. They are matched exactly, byte for byte, at both the authorize and token steps, except a local callback (`localhost`, `127.0.0.1`, `[::1]`), which matches on any port. The allowed forms depend on your application type. None for a Server-to-server app. No fragment;
- the **scopes** your app may ever request: member scopes, app scopes, or both. Every request is narrowed against this list;
- the **IP addresses** your app calls STX from, as CIDR blocks (`203.0.113.0/24`, `2001:db8::/32`; no wider than /8 for IPv4 or /32 for IPv6). Required if your app has any write scope (`orders.write`, `terms.write`), optional otherwise. When set, token requests, REST calls and WebSocket connections from any other address are refused with `403 ip_not_allowed`. Developing locally? Add your own public IP.

You receive a `client_id` and, for a Web app or Server-to-server app, a one-time `client_secret`. The secret is shown once and cannot be recovered; store it on your server. Rotating it invalidates the old one immediately.

### Application types

| Type | For | Client secret | Callbacks in production |
| --- | --- | --- | --- |
| Web app | an app with its own server | yes | `https` only |
| Browser app | a single-page app with no server | no, PKCE only | `https` only |
| Mobile or desktop app | an installed app | no, PKCE only | `https` link, reverse-domain custom scheme (`com.example.app:/callback`), or `http://localhost` / `127.0.0.1` / `[::1]` on any port |
| Server-to-server | your backend, no member sign-in (`client_credentials`) | yes | none |

The type is fixed at registration. Outside production, every type with callbacks may also register `localhost`, `127.0.0.1` and `[::1]` callbacks (http or https) that match on any port, so you can develop locally.

## What it takes to integrate

<OAuthFlowDiagram />

1. **Get a demo client** through your invite (see [Get demo access](#get-demo-access)).
2. **Run the authorization code flow** to turn a member's consent into tokens. See [Authorization code flow](/oauth/authorization-flow/).
3. **Call STX for the member** with the access token as a bearer on `/api/v1` and the WebSocket, limited to the [effective scope](/oauth/scopes/#effective-scope).
4. **Keep access alive** by refreshing, and drop it cleanly when the member disconnects. See [Tokens and security](/oauth/tokens-and-security/).

## Sample app

[Sideline](https://github.com/stxapp/stx-isv-demo) is a fictional app built on STX OAuth, published as a public example. It links a member's account from its backend, reads their balance, positions and orders, places and cancels orders for them, streams their account data, reads public market data on its own app token, and unlinks on request. It is built on the [TypeScript SDK](/isv/typescript-sdk/) and runs against the demo exchange with the client you are given.

Try it live at <a href={cfg.sampleApps.sideline.url}>{cfg.sampleApps.sideline.url.replace('https://', '')}</a>. It runs against the US demo exchange: to link an account, sign up on <a href={demo('us')}>{demo('us').replace('https://', '')}</a> first. No real money is involved.

## In this section

  - [Hosted pages](/isv/hosted-pages/): Consent, sign-in and sign-up, and Connected apps, all hosted by STX.
  - [With the TypeScript SDK](/isv/typescript-sdk/): Link a member, act for them, read market data as your app, and unlink, with @stxapp/stx-typescript.
  - [OAuth](/oauth/): The protocol: authorization code flow, scopes, tokens, discovery and errors.
