Skip to content

Quick Start

1. Set up your backend

// server.ts (Express example)
import express from 'express';
import { OpendoorClient } from '@opendoor/partner-sdk-server-js-core';
const app = express();
app.use(express.json());
const opendoor = new OpendoorClient({
apiKey: process.env.OPENDOOR_API_KEY!,
});
// Proxy routes - the browser SDK calls these endpoints
app.post('/api/opendoor/v1/addresses/suggestions', async (req, res) => {
const result = await opendoor.getAddressSuggestions(req.body.query);
res.json(result);
});
app.post('/api/opendoor/v1/address/unit-check', async (req, res) => {
const result = await opendoor.checkAddressUnit(req.body);
res.json(result);
});
app.post('/api/opendoor/v1/offer/create', async (req, res) => {
const result = await opendoor.createOffer(req.body);
res.json(result);
});
app.post('/api/opendoor/v1/offer/update', async (req, res) => {
const { offerId, ...data } = req.body;
const result = await opendoor.updateOffer(offerId, data);
res.json(result);
});
app.post('/api/opendoor/v1/offer', async (req, res) => {
const result = await opendoor.getOffer(req.body.offerId);
res.json(result);
});
app.post('/api/opendoor/v1/offer/pricing', async (req, res) => {
const result = await opendoor.getOfferWithSellDirectPricing(req.body.offerId);
res.json(result);
});
app.post('/api/opendoor/v1/homeDetail', async (req, res) => {
const result = await opendoor.getHomeDetail(req.body);
res.json(result);
});
app.post('/api/opendoor/v1/homebuilders', async (req, res) => {
const result = await opendoor.getHomebuilders();
res.json(result);
});
app.listen(3002);

2. Add the frontend components

The browser client points at your backend, not at Opendoor. All requests go through the proxy you set up in step 1.

App.tsx
import { useState } from 'react';
import {
OpendoorProvider,
AddressEntry,
AddressUnitConfirmation,
QualificationQuestions,
} from '@opendoor/partner-sdk-client-react';
import { OpendoorClient } from '@opendoor/partner-sdk-client-js-core';
import type { Address } from '@opendoor/partner-sdk-client-js-core';
const client = new OpendoorClient({ baseURL: '/api/opendoor/v1' });
function App() {
const [offerId, setOfferId] = useState<string | null>(null);
const [address, setAddress] = useState<Address | null>(null);
const [needsUnit, setNeedsUnit] = useState(false);
const handleAddressSelect = async (addr: Address) => {
setAddress(addr);
// Check if the address needs a unit number
const { requiresUnitNumber } = await client.checkAddressUnit(addr);
if (requiresUnitNumber) {
setNeedsUnit(true);
} else {
await createOffer(addr);
}
};
const createOffer = async (addr: Address) => {
const offer = await client.createOffer({
address: addr,
salesAssociateName: 'Jane Smith', // optional
salesAssociateEmail: 'jane@partner.com', // optional
});
setOfferId(offer.opendoorOfferRequestId);
};
return (
<OpendoorProvider client={client}>
{offerId && address ? (
<QualificationQuestions
offerId={offerId}
address={address}
salesAssociateName="Jane Smith"
salesAssociateEmail="jane@partner.com"
appearance={{ theme: 'minimal' }}
onSubmit={async (answers) => {
await client.updateOffer(offerId, answers);
}}
/>
) : (
<>
<AddressEntry onAddressSelect={handleAddressSelect} />
{needsUnit && address && (
<AddressUnitConfirmation
address={address}
onConfirm={async (confirmed) => {
setNeedsUnit(false);
setAddress(confirmed);
await createOffer(confirmed);
}}
onEdit={() => {
setNeedsUnit(false);
setAddress(null);
}}
/>
)}
</>
)}
</OpendoorProvider>
);
}

3. That’s it

The SDK provides two questionnaire flows:

DTC Onboarding Flow (React & Vue) — 17-page one-question-per-page questionnaire matching the DTC flow on opendoor.com. Available in both frameworks via DtcOnboardingFlow.

Qualification Questions (React only) — 5-page multi-field form for the instant offer flow. Available via QualificationQuestions.

Both flows share the same address entry components:

  1. AddressEntry — address suggestions, validation, and selection
  2. AddressUnitConfirmation — collects unit/apt/floor when needed (see guide)

When the user completes a questionnaire, your onSubmit callback receives all answers as a flat object with dot-notation keys. Call client.updateOffer() to submit them — the server SDK automatically maps dot-notation keys to the GraphQL schema.

The API key never leaves your server. The browser SDK only talks to your backend at /api/opendoor/v1/*.