Connect Widget

TL;DR

Mint a session with POST /v1/connect, send your user to the url that comes back, and read the result from the redirect or a postMessage. Nothing to install.

The widget lets your users connect their channel or PMS without you building an OAuth flow, a credential form, or a room-mapping screen. It is hosted by Repull: the picker, the per-channel handoff and the credential handling all run on connect.repull.dev, so your app holds no tokens and ships no connection UI.

There is no package to install

Connect is a hosted page, not a component. Your side of it is one API call and a redirect, which works the same from any language, any framework, and a server with no frontend at all. The only client-side code on this page is the optional popup listener below.

Mint a session

Call this from your server — it needs your API key, which must never reach the browser. redirectUrl is where the user lands when the flow finishes:

import { Repull } from '@repull/sdk'

const repull = new Repull({ apiKey: process.env.REPULL_API_KEY! })

const session = await repull.connect.createSession({
  redirectUrl: 'https://your-app.com/connected',
  state: 'user-123',
})

You get back a one-time URL and the correlation values you will need on the way out:

{
  "sessionId": "cs_8gQrT2v9k3M4nLp7wJxYzAbCdEfGhIjKlMnOp",
  "url": "https://connect.repull.dev/cs_8gQrT2v9k3M4nLp7wJxYzAbCdEfGhIjKlMnOp",
  "expiresAt": "2026-04-29T18:25:14.000Z",
  "state": "user-123"
}

Send the user there

Navigate to url, or open it in a popup. The picker shows a card for every channel the user can connect, and walks them through whichever one they pick — Airbnb consent, the Booking.com property claim and room mapping, or a PMS credential form.

// Full-page redirect — the simplest path.
window.location.href = session.url

// Or a popup, so your app stays on screen.
window.open(session.url, 'repull-connect', 'width=900,height=700')

Read the result

A full-page redirect returns the user to your redirectUrl with status query params, and your server can confirm the connection from GET /v1/connect/{provider}. A popup instead posts a message back to window.opener and closes itself:

window.addEventListener('message', (event) => {
  // Pin the origin. Anything else on the page can post to you.
  if (event.origin !== 'https://connect.repull.dev') return
  // Correlate, so a stale popup from an earlier attempt is ignored.
  if (event.data?.sessionId !== session.sessionId) return

  switch (event.data.type) {
    case 'repull:connect:completed':
      // event.data.provider, event.data.connectionId
      break
    case 'repull:connect:error':
      console.error(event.data.error)
      break
    case 'repull:connect:close':
      // Cancelled or expired.
      break
  }
})

Narrow the picker

Pass allowedProviders to show only the channels that make sense for your product. The IDs come from GET /v1/connect/providers, which is public and needs no key:

const session = await repull.connect.createSession({
  redirectUrl: 'https://your-app.com/connected',
  allowedProviders: ['guesty', 'hostaway', 'lodgify'],
})

If you already know which channel the user manages their listings on, skip the picker entirely: POST /v1/connect/{provider}mints a session that opens on that channel's screen.

Appearance and language

The hosted pages render with the logo, colors and trust signals set in your dashboard under Settings → Connect, so they read as part of your product rather than ours. On the Scale plan you can serve them from your own subdomain instead of connect.repull.dev.

Pass locale when minting the session to pin the language for the whole flow. English and French are supported today; an unknown code falls back to your workspace default.

The long version

Connect covers the three connection patterns, the full session parameters and disconnection. OAuth Connect walks the Airbnb round trip end to end, and Localizing your Connect pages covers the language rules.
AI