> ## Documentation Index
> Fetch the complete documentation index at: https://docs.rangler.co/llms.txt
> Use this file to discover all available pages before exploring further.

# Rangler Connect

> Embed read-only account and portfolio linking with Rangler Connect.

Rangler Connect is the hosted Link flow for read-only account and portfolio aggregation. v1 is available to design partners and does not support trade execution, order routing, payments, or money movement.

## Security model

Keep `rgl_test_` and `rgl_live_` API keys on your backend only. Never put them in browser code, mobile apps, or client-side environment variables.

Connect uses short-lived browser tokens:

* your backend creates a `link_token` with `X-API-Key`
* your browser opens the hosted modal with that `link_token`
* the hosted modal returns a one-use `public_token`
* your backend exchanges the `public_token` for the persistent `connection_id`

The JavaScript SDK supports `fetchLinkToken` so your button can open Connect without exposing your API key. `fetchLinkToken` should call your own backend endpoint, and that endpoint should call Rangler with `X-API-Key`.

## Flow

1. Your backend creates a short-lived link token with `X-API-Key`.
2. Your frontend opens the hosted Connect modal with `@rangler/connect-js`.
3. The hosted modal links the customer to an enabled institution and returns a one-use `public_token`.
4. Your backend exchanges the public token for a persistent `connection_id`.
5. Your backend reads accounts, positions, and transactions through the Connect API.

## Create a link-token endpoint

Create this endpoint in your own backend. It authenticates your current user, maps that user to a stable `client_user_id`, and calls Rangler with your server-side API key.

```ts theme={null}
app.post('/api/rangler/link-token', async (req, res) => {
  const response = await fetch('https://sandbox-api.rangler.co/v1/connect/link-tokens', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'X-API-Key': process.env.RANGLER_API_KEY,
    },
    body: JSON.stringify({
      client_user_id: req.user.id,
      client_name: req.user.name,
      products: ['accounts', 'positions', 'transactions'],
      allowed_origins: ['https://app.example.com'],
    }),
  });

  res.status(response.status).json(await response.json());
});
```

Direct HTTP equivalent:

```bash theme={null}
curl -s https://sandbox-api.rangler.co/v1/connect/link-tokens \
  -H "X-API-Key: rgl_test_your_key_here" \
  -H "Idempotency-Key: 7b830fc3-848d-4c21-92d6-4f5243c1f45f" \
  -H "Content-Type: application/json" \
  -d '{
    "client_user_id": "customer_123",
    "client_name": "Ada Okafor",
    "products": ["accounts", "positions", "transactions"],
    "allowed_origins": ["https://app.example.com"]
  }'
```

The response contains `link_token`, `link_token_id`, `request_id`, and `expiration`.

Generate a new `Idempotency-Key` for each logical link-token request. Reuse it only when retrying the same body after a timeout or transport failure. Rangler returns the same unused, unexpired token for a valid replay. Reusing the key with a different body, or after that token is used or expired, returns `409 Conflict`.

## Open the hosted modal

Use the npm package when your app has a build system.

```ts theme={null}
import { Connect } from '@rangler/connect-js';

const connect = new Connect({
  fetchLinkToken: async () => {
    const response = await fetch('/api/rangler/link-token', { method: 'POST' });
    const data = await response.json();
    return data.link_token;
  },
  environment: 'sandbox',
  onSuccess: async ({ public_token }) => {
    await fetch('/api/rangler/exchange-token', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ public_token }),
    });
  },
  onClose: ({ status }) => {
    console.log(status);
  },
});

connect.setup().open();
```

You can also pass a pre-created `linkToken` directly if your app already fetched one before rendering the button.

For plain HTML or apps that do not use npm, load the hosted script tag. This uses the same token model: the script calls your backend for a link token and sends the public token back to your backend for exchange.
Define `window.RanglerConnect.onLoad` before the async script loads; otherwise the SDK may load before your callback is registered.

```html theme={null}
<button id="connect">Connect portfolio</button>
<script>
  window.RanglerConnect = window.RanglerConnect || {};
  window.RanglerConnect.onLoad = function () {
    var connect = window.RanglerConnect.init({
      environment: 'sandbox',
      fetchLinkToken: async function () {
        var response = await fetch('/api/rangler/link-token', { method: 'POST' });
        var data = await response.json();
        return data.link_token;
      },
      onSuccess: async function ({ public_token }) {
        await fetch('/api/rangler/exchange-token', {
          method: 'POST',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify({ public_token }),
        });
      },
    });

    document.getElementById('connect').onclick = function () {
      connect.open();
    };
  };
</script>
<script src="https://connect.rangler.co/connect.js" async></script>
```

## Create an exchange endpoint

Create this endpoint in your own backend. It receives the one-use `public_token` from the browser and exchanges it with your server-side API key.

```ts theme={null}
app.post('/api/rangler/exchange-token', async (req, res) => {
  const response = await fetch('https://sandbox-api.rangler.co/v1/connect/token/exchange', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'X-API-Key': process.env.RANGLER_API_KEY,
    },
    body: JSON.stringify({ public_token: req.body.public_token }),
  });

  res.status(response.status).json(await response.json());
});
```

Direct HTTP equivalent:

```bash theme={null}
curl -s https://sandbox-api.rangler.co/v1/connect/token/exchange \
  -H "X-API-Key: rgl_test_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{ "public_token": "rgl_public_..." }'
```

The public token is one-use and short-lived. Store the returned `connection_id`, not the public token.

## Read linked data

```bash theme={null}
curl -s https://sandbox-api.rangler.co/v1/connect/connections/{connection_id}/positions \
  -H "X-API-Key: rgl_test_your_key_here"
```

Available resources:

* `/v1/connect/connections`
* `/v1/connect/connections/{connection_id}/accounts`
* `/v1/connect/connections/{connection_id}/positions`
* `/v1/connect/connections/{connection_id}/transactions`

## Webhooks

Subscribe to Connect events from the portal:

* `connect.connection.created`
* `connect.connection.updated`
* `connect.connection.revoked`
* `connect.sync.completed`
* `connect.sync.failed`
* `connect.item.login_required`

Connect webhook payloads use the same delivery and signature model as other Rangler events.

## Provider availability

Sandbox institutions are available for integration testing. Real providers move into beta only after approved access is in place for that provider. Restricted providers are not shown to external customers.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.