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

# Instrument account linking

> Add lifecycle callbacks, safe diagnostics, and production checks to account linking.

Start with the [Quickstart](/content/quickstart) for the first working integration. This page adds customer handling, lifecycle callbacks, and safe diagnostics.

## Configure the browser flow

Create one Connect instance, call `setup()` once, and call `open()` from a user action.

```javascript theme={null}
import Connect from "@mono.co/connect.js"

const connect = new Connect({
  key: "PUBLIC_KEY",
  scope: "auth",
  data: {
    customer: {
      name: "Ada Lovelace",
      email: "ada@example.com"
    }
  },
  reference: crypto.randomUUID(),
  onSuccess: ({ code }) => sendCodeToBackend(code),
  onLoad: () => setLinkButtonEnabled(true),
  onClose: () => console.log("Connect closed"),
  onEvent: (eventName, data) => recordConnectEvent(eventName, data)
})

connect.setup()
```

The required account-linking configuration is:

| Parameter       | Purpose                                                            |
| --------------- | ------------------------------------------------------------------ |
| `key`           | Identifies the Mono application in browser-safe configuration.     |
| `scope: "auth"` | Selects the account-linking flow.                                  |
| `data.customer` | Identifies an existing customer or supplies details for a new one. |
| `onSuccess`     | Receives `{ code }` after successful linking.                      |

## Existing and new customers

Use the Mono customer ID when your backend already has one.

```javascript theme={null}
data: {
  customer: { id: "CUSTOMER_ID" }
}
```

Supply customer details when creating a new customer in the flow.

```javascript theme={null}
data: {
  customer: {
    name: "Ada Lovelace",
    email: "ada@example.com",
    identity: {
      type: "bvn",
      number: "CUSTOMER_BVN"
    }
  }
}
```

Confirm current identity requirements in Mono's official documentation before collecting or sending sensitive identity data.

## Open and close

`setup()` mounts the hidden widget. `open()` makes it visible, and `close()` hides it programmatically.

```javascript theme={null}
document
  .querySelector("#link-account")
  .addEventListener("click", () => connect.open())

document
  .querySelector("#cancel-linking")
  .addEventListener("click", () => connect.close())
```

## Complete the link on your backend

The browser should send the short-lived code to an authenticated backend endpoint. The backend exchanges it with `MONO_SECRET_KEY`, verifies the result, and stores the account ID for the current application user.

```javascript theme={null}
async function sendCodeToBackend(code) {
  const response = await fetch("/api/mono/exchange", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({ code })
  })

  if (!response.ok) {
    throw new Error("Mono account linking could not be completed")
  }

  return response.json()
}
```

See the [Quickstart](/content/quickstart) for the corresponding backend exchange request.

## Instrument the flow

Use `onEvent` for product analytics and debugging. Use `onSuccess` as the browser-side success signal instead of relying on an intermediate event.

```javascript theme={null}
function recordConnectEvent(eventName, data) {
  switch (eventName) {
    case "OPENED":
      analytics.track("mono_connect_opened")
      break
    case "INSTITUTION_SELECTED":
      analytics.track("mono_institution_selected", {
        institutionId: data?.institution?.id
      })
      break
    case "ERROR":
      errorTracker.captureMessage("Mono Connect error", {
        extra: data
      })
      break
  }
}
```

Event payloads vary by event. Read properties defensively and avoid logging credentials, identity values, or other sensitive user input.

## Completion checklist

* The widget uses the public key and `auth` scope, and `setup()` runs before `open()` from a user action.
* `onSuccess` sends the auth code to an authenticated backend endpoint.
* The secret key is present only on the backend.
* The returned account ID is associated with the correct application user.
* Event and error logs use an allowlist that excludes sensitive data.
