Connect (multi-channel)

One hosted entry point that lets your users connect Airbnb, Booking.com, Vrbo and Plum Guide, plus 11 property management systems. We render a branded picker, walk the user through the per-channel handoff, and redirect them back to your app when they're done.

Connecting next to an existing PMS

On Airbnb, Booking.com and Vrbo a host can connect without disconnecting the PMS or channel manager they already use: accessType: "messaging" for Airbnb and Vrbo, and the Extranet login for Booking.com. See Use Repull alongside a PMS.

How it works

From your server, you create a Connect session. We give you a one-time URL on connect.repull.dev. Send your user there. We render a branded channel picker, the user clicks the channel they manage their listings on, and we take them through the rest of the flow. When everything's done, we redirect them back to your app with status query params on the URL.

  1. Your server calls POST /v1/connect with a redirectUrl.
  2. We return a url on connect.repull.dev.
  3. Redirect your user there.
  4. The picker shows a card for every channel they can connect (or just the ones in your allowed_providers list, if you set one).
  5. The user picks a channel; we walk them through that channel's connection pattern.
  6. The user lands on your redirectUrl when the connection is live.

Already know which channel you want?

Skip the picker — call POST /v1/connect/{provider} with the channel ID instead and the user lands directly on the per-provider screen.

The connection patterns

Every channel falls into one of these patterns. The picker handles the differences for you — but if you build your own picker against GET /v1/connect/providers, you'll see these in the response.

  • OAuth— the user is redirected to the channel's consent screen, approves access in one click, and we exchange the resulting code for tokens. Used by Airbnb today; coming for Hostaway, Guesty, BookingSync.
  • Credentials— we render a hosted form that collects API keys (or a client ID / secret pair). On submit we validate against the channel's API and persist on success. Used by Plum Guide and most PMSes. Vrbo uses it too: the host signs in with their Vrbo account and enters a verification code if Vrbo sends one.
  • Extranet— Booking.com's Extranet login. The host invites a Repull user into their Extranet (or signs in with their own user), next to whatever channel manager already runs the property.
  • Claim— connectivity-provider designation (Booking.com). We hold the platform-level secret; the user designates Repull as their connectivity provider in the channel's Extranet, then hands us a Hotel ID to claim.

Start a Connect session

Server-to-server. Authenticate with your live API key. The session expires after 30 minutes if the user doesn't finish.

curl -X POST 'https://api.repull.dev/v1/connect' \
  -H 'Authorization: Bearer sk_live_...' \
  -H 'Content-Type: application/json' \
  -d '{
    "redirectUrl": "https://yourapp.com/connect/done",
    "allowed_providers": ["airbnb", "hostaway", "guesty"]
  }'

Body parameters

redirectUrlstringRequired

Where we send the user when they finish (or cancel). We append status query params to this URL.

statestring

Opaque correlation token. Echoed back in the response so you can match the session to a user without storing the session ID server-side.

allowedProvidersstring[]

Optional whitelist of channel IDs the picker should show. Omit to show every channel.

reservationHistoryMonthsinteger

Airbnb only. How many months of past reservations the first import pulls, from 1 to 60. Omit it for the default window. Upcoming stays are always imported. A wider window takes longer to import, because every extra month is more stays to fetch.

localestring

Optional language for the hosted Connect pages. Any supported code — currently 'en' or 'fr'. See Localizing your Connect pages for the full resolution order.

Show the pages in your user's language

The hosted Connect pages render in English and French today. Pass a locale here, append ?locale=fr to the returned URL, or set a workspace default — see Localizing your Connect pages.

Response

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

List supported channels

The full registry is public. Use it to build your own picker or to validate which IDs you can pass to allowed_providers. No API key required.

curl https://api.repull.dev/v1/connect/providers

Each entry includes the channel ID, display name, category (ota or pms), connection pattern, status (live, beta, or coming-soon), logo URL, and a one-line description. The picker sorts OTAs first, then PMSes alphabetically.

Handle the redirect back

When the connection completes (or fails), we redirect the user to your redirectUrl with these query params appended:

?status=connected&provider=hostaway&accountId=42
# or
?status=cancelled
?status=expired

On connected, query GET /v1/connect/{provider} to confirm the connection is live and pull host metadata.

The redirect above is one of two completion paths. If you open the Connect URL in a popup rather than navigating the whole page, the hosted page posts a message back to window.opener and closes itself — your app never leaves the screen. It emits one of three messages, each carrying the sessionId correlation value and the provider:

repull:connect:completed   { sessionId, provider, connectionId }   // live
repull:connect:error       { sessionId, provider, error }          // failed
repull:connect:close       { sessionId, provider }                 // cancelled / expired

Full listener example

Always pin event.origin to https://connect.repull.dev and correlate on sessionId. See the complete round-trip — popup open, origin check, the three message types, and the redirect fallback when there's no opener — on OAuth Connect → Popup completion.

Disconnect an account

DELETE /v1/connect/{provider} disconnects one connected account from your workspace. Airbnb and Booking.com are supported; other providers return 501 not_implemented, with a fixexplaining how to disconnect on the provider's side.

Provider support is checked first, before your workspace's connections are looked at. So an unsupported provider answers 501 whether or not you have a connection to it — the answer depends on the provider alone, and you can branch on it without first knowing your own connection state. On a supported provider, 404 means this workspace has no connection to it.

accountIdstring

Query parameter. The account to disconnect: for Airbnb, the host id (accounts[].externalAccountId from GET /v1/connect/airbnb); for Booking.com, the hotel id. Optional when the workspace has exactly one account for the provider, required when it has several.

# Airbnb: list connected accounts, then disconnect one
curl 'https://api.repull.dev/v1/connect/airbnb' \
  -H 'Authorization: Bearer sk_live_...'
# { "connected": true, ..., "accounts": [
#     { "externalAccountId": "143778955", "name": "Lidia", "status": "active", "connected": true },
#     { "externalAccountId": "380436627", "name": "Marco", "status": "active", "connected": true }
# ] }

curl -X DELETE 'https://api.repull.dev/v1/connect/airbnb?accountId=143778955' \
  -H 'Authorization: Bearer sk_live_...'

# {
#   "disconnected": true,
#   "provider": "airbnb",
#   "accountId": "143778955",
#   "listingsDeactivated": ["4118", "4119"]
# }
  • Only that account is disconnected. Its stored authorization is removed and it stops syncing. Other accounts for the same provider stay connected.
  • Its listings are deactivated, not deleted.They stop counting toward your plan's listing limit, their data is kept, and their ids are returned in listingsDeactivated. A listing that is still connected through another account or channel stays active. To bring them back, reconnect the account and activate them with POST /v1/listings/status. See Active & inactive listings.
  • All or nothing. If the call fails, the account and its listings are unchanged.

Errors

  • 422 invalid_params: several accounts are connected and you did not pass accountId. valid_values lists the account ids you can pass.
  • 404 not_found: on a supported provider — accountId is not an account connected to this workspace, or the workspace has no connection to that provider at all.
  • 501 not_implemented: the provider cannot be disconnected over the API. Returned for every unsupported provider, connected or not — it is decided before your connections are read.
# Unsupported provider — 501 even with no hostaway connection in the workspace
curl -X DELETE 'https://api.repull.dev/v1/connect/hostaway' \
  -H 'Authorization: Bearer sk_live_...'
# 501
# { "error": { "code": "not_implemented",
#     "message": "Disconnecting hostaway over the API is not supported yet — ...",
#     "fix": "Remove the hostaway credentials in the provider's own dashboard. Confirm with `GET /v1/connect/hostaway`." } }

# Supported provider, nothing connected — 404
curl -X DELETE 'https://api.repull.dev/v1/connect/airbnb' \
  -H 'Authorization: Bearer sk_live_...'
# 404
# { "error": { "code": "not_found", "message": "No airbnb connection found" } }

The accountId here is the same Airbnb host id the Airbnb collection routes take as ?account_id= — see Account scope → Several Airbnb accounts.

Revoking on Airbnb is not enough

A host can also revoke access from their Airbnb account (Account → Privacy & sharing → Connected apps). That alone does not update your workspace, so call this endpoint as well.
AI