Build vacation-rental tech in TypeScript.
One SDK over api.repull.dev — Airbnb, Booking.com, VRBO, Plum Guide, and 9 PMS connectors behind a single hosted Connect picker. Mint a session, send the user, get a connection back.
Connect any of these in one flow
Live from GET /v1/connect/providers. The picker above renders the same list.
Add an API key above to load the live channel list.
Live market intelligence
Atlas — the market-intelligence fleet behind Repull — surfaces ADR vs comps and day-by-day pricing recommendations for every connected listing.
Live markets
GET /v1/marketsAdd an API key above.
Pricing recommendations
GET /v1/listings/{id}/pricingAdd an API key above.
import { Repull } from '@repull/sdk';
const repull = new Repull({ apiKey: process.env.REPULL_API_KEY });
// Markets your workspace operates in (ADR diff vs comps, occupancy, share).
const markets = await repull.markets.list();
// Pricing recommendations for a listing's next 7 days.
const recs = await repull.listings.pricing.recommendations(listingId, {
startDate: '2026-05-01',
endDate: '2026-05-08',
});
// Apply the recommendation for a single date.
await repull.listings.pricing.action(listingId, {
dates: ['2026-05-04'],
action: 'apply',
});Multi-channel Connect picker
One session, 13 channels. Hosted at connect.repull.dev.
Where the user lands after they finish a connection in the picker.
import { Repull } from '@repull/sdk';
const repull = new Repull({ apiKey: process.env.REPULL_API_KEY });
const session = await repull.connect.createSession({
redirectUrl: "https://yourapp.com/connected",
// Optional — scope the picker to a subset of channels.
// allowedProviders: ['airbnb', 'booking', 'hostaway'],
});
// session.url -> hosted picker on connect.repull.dev/{sessionId}
// session.sessionId -> stable handle for follow-ups
// session.expiresAt -> ISO timestamp
// Open the picker in a popup window — OAuth providers (Airbnb, BookingSync,
// etc) set X-Frame-Options: sameorigin so iframes won't work for OAuth.
const popup = window.open(
session.url,
'repull-connect',
'width=480,height=720,popup=yes',
);
window.addEventListener('message', (ev) => {
if (ev.origin !== 'https://connect.repull.dev') return;
if (ev.data?.type === 'repull:connect:completed') {
// Refresh your "Your connections" list here.
}
});
Returns { sessionId, url, expiresAt, state }. The hosted page renders the channel chooser, runs each provider's pattern (OAuth / credentials / claim / activation), then sends the user to your redirectUrl.
Your connections
Live from GET /v1/connect.
Add an API key above.
Direct integrations
Most apps use the multi-channel picker above. Direct OAuth is for apps that only need Airbnb and want to skip the chooser screen entirely.
Airbnb OAuth Connect
Flagship flow. Live against api.repull.dev.
Read all data, send messages, manage listings (pricing, calendar, content).
Where Repull will send the user after they grant consent. Defaults to this demo's /airbnb-redirect.
import { Repull } from '@repull/sdk';
const repull = new Repull({ apiKey: process.env.REPULL_API_KEY });
const session = await repull.connect.airbnb.create({
redirectUrl: "https://yourapp.com/airbnb/return",
accessType: "full_access",
});
// session.url -> send the user here
// session.sessionId -> poll status with repull.connect.airbnb.status()
// session.expiresAt -> ISO timestamp
Returns { url, sessionId, provider, expiresAt }. Send the user to url — they'll land on connect.repull.dev, grant consent on Airbnb, then bounce back to your redirect.
Airbnb listings
Read-only — including each listing's linked Airbnb account(s).
Add an API key above.
const listings = await repull.channels.airbnb.listings.list({ limit: 8 });
// Each entry exposes its 'connections' array — one per linked Airbnb listing.Reservations
Real data from your API key. Read-only in v0.2.
Add an API key above to load reservations.
const { data, pagination } = await repull.reservations.list({
limit: 10
});
// Walk forward: pagination.nextCursor / pagination.hasMoreProperties
Aggregated across every connected channel.
Add an API key above.
const { data, pagination } = await repull.properties.list({ limit: 12 });