Skip to content

Qualification Questions

The QualificationQuestions component is a self-contained, multi-page form that collects everything needed to generate an offer. It handles all 5 pages internally - home details, features, condition, additional questions, and contact info - and fires onSubmit when the user completes the flow.

QualificationQuestions - More questions page QualificationQuestions - Contact info page

Basic usage

import {
OpendoorProvider,
QualificationQuestions,
} from '@opendoor/partner-sdk-client-react';
import { OpendoorClient } from '@opendoor/partner-sdk-client-js-core';
const client = new OpendoorClient({ baseURL: '/api/opendoor/v1' });
function App({ offerId, address }) {
return (
<OpendoorProvider client={client}>
<QualificationQuestions
offerId={offerId}
address={address}
appearance={{ theme: 'minimal' }}
onSubmit={async (answers) => {
await client.updateOffer(offerId, answers);
// Poll for offer with pricing
const offer = await client.getOfferWithSellDirectPricing(offerId);
}}
/>
</OpendoorProvider>
);
}

Props

PropTypeDefaultDescription
offerIdstringRequiredOpendoor offer request ID from createOffer()
addressAddressRequiredAddress to display in the review sidebar
salesAssociateNamestring-Optional sales associate name
salesAssociateEmailstring-Optional sales associate email
initialAnswersRecord<string, AnswerValue>-Prefill data (e.g., from getHomeDetail())
appearanceOpendoorAppearance{ theme: 'minimal' }Visual theme configuration
showAttributionbooleantrueShow “Powered by Opendoor” in sidebar
mapImageUrlstring-Override the map image with a custom URL
mapboxAccessTokenstringBuilt-inOverride the Mapbox token for map rendering
mapPinMarkerstringBlue home pinCustom map pin (Mapbox spec or image URL)

Lifecycle callbacks

CallbackTypeWhen it fires
onReady() => voidComponent mounted and ready
onSubmit(answers) => voidUser completed all 5 pages
onPageChange(pageIndex, pageId) => voidUser navigates between pages
onAnswerChange(key, value, allAnswers) => voidAny answer changes
onError(error: Error) => voidValidation or internal error
onEditAddress() => voidUser clicks “Edit” on the address in the review card

Pages

The component renders 5 pages in sequence:

#PageWhat it collects
1Home DetailsBedrooms, bathrooms, sq ft, year built, dwelling type
2Features~57 optional toggles across kitchen, rooms, exterior, systems
3Condition10 damage categories + 4 seller-score card-selects with photos
4More QuestionsHOA, utilities, mortgage balance
5Contact InfoName, email, phone, marketing consent

Prefilling answers

Use getHomeDetail() to load property data Opendoor already knows (from MLS, public records). Pass the results as initialAnswers:

function QualificationFlow({ offerId, address }) {
const client = useOpendoorClient();
const [initialAnswers, setInitialAnswers] = useState({});
const [isLoading, setIsLoading] = useState(true);
useEffect(() => {
client
.getHomeDetail({ opendoorOfferRequestId: offerId })
.then((result) => {
// Extract values - keys are already dot-notation
const answers = {};
for (const [key, entry] of Object.entries(result.answerPrefills)) {
answers[key] = entry?.value ?? entry;
}
setInitialAnswers(answers);
})
.finally(() => setIsLoading(false));
}, [offerId]);
if (isLoading) return <p>Loading...</p>;
return (
<QualificationQuestions
offerId={offerId}
address={address}
initialAnswers={initialAnswers}
onSubmit={async (answers) => {
await client.updateOffer(offerId, answers);
}}
/>
);
}

Answer keys

Answers use dot-notation keys that match the qualification schema:

home.bedrooms, home.bathrooms.full, home.above_grade_sq_ft,
home.features.kitchen.island, home.condition.interior.flooring,
home.kitchen_seller_score, seller.full_name, seller.email, ...

When you call client.updateOffer(id, answers), the server SDK maps these keys to the GraphQL schema automatically.

Styling

The component uses the appearance prop for theming. It defaults to the minimal theme (thin borders, subtle styling). See the Styling & Themes guide for all available tokens.

<QualificationQuestions
offerId={offerId}
address={address}
appearance={{
theme: 'minimal',
variables: {
colorPrimary: '#003366',
fontFamily: '"Inter", sans-serif',
},
}}
/>

Map image

The review sidebar renders a map centered on the property address. The component geocodes the address and generates a Mapbox Static Images URL with a pin marker.

To customize the pin marker, pass a Mapbox marker spec or a URL to a custom PNG:

// Mapbox built-in pin with custom color and icon
<QualificationQuestions mapPinMarker="pin-l-star+ff0000" ... />
// Custom marker image from a URL
<QualificationQuestions mapPinMarker="https://your-cdn.com/custom-pin.png" ... />

To bypass the dynamic map entirely and use a static image, pass mapImageUrl:

<QualificationQuestions
offerId={offerId}
address={address}
mapImageUrl="https://your-cdn.com/maps/123-main-st.png"
/>

Resetting the form

The component manages its own state internally. To reset it (e.g., start over with a different address), change the React key prop:

<QualificationQuestions key={offerId} offerId={offerId} address={address} />

Changing the key forces React to unmount and remount the component with fresh state.