Skip to content

Custom UI

If the prebuilt React and Vue components don’t fit your design, you can build your own UI using client-js-core directly.

When to use this approach

  • You need a layout that doesn’t match the prebuilt components
  • You’re using a framework other than React or Vue (Angular, Svelte, vanilla JS)
  • You want full control over every DOM element and CSS class

Setting up the client

import { OpendoorClient } from '@opendoor/partner-sdk-client-js-core';
const client = new OpendoorClient({
baseURL: '/api/opendoor/v1',
timeout: 30000,
});

Address suggestions

const { addresses } = await client.getAddressSuggestions('123 Main St');
// addresses: Address[]
// Each address has: street1, street2?, city, state, postalCode
addresses.forEach((addr) => {
console.log(
`${addr.street1}, ${addr.city}, ${addr.state} ${addr.postalCode}`
);
});

Creating an offer

const offer = await client.createOffer({
address: {
street1: '123 Main St',
city: 'Phoenix',
state: 'AZ',
postalCode: '85001',
},
salesAssociateName: 'Jane Smith', // optional
salesAssociateEmail: 'jane@partner.com', // optional
});
console.log(offer.opendoorOfferRequestId); // UUID
console.log(offer.offerStatus); // 'PENDING' | 'DENIED'
if (offer.denialInfo) {
console.log(offer.denialInfo.code); // e.g., 'DWELLING_TYPE'
console.log(offer.denialInfo.explanation); // Human-readable reason
}

Updating an offer

Send questionnaire answers as a flat object. The server SDK maps the keys to GraphQL automatically.

You can also pass a correlationId to associate the offer with your own internal tracking identifier (e.g., a session ID or lead ID).

const updated = await client.updateOffer(offer.opendoorOfferRequestId, {
correlationId: 'your-internal-id', // optional - link to your own tracking system
sellerEmail: 'seller@example.com',
sellerFullName: 'Jane Smith',
sellerPhoneNumber: '555-0100',
homeBedrooms: 3,
homeBathroomsFull: 2,
homeYearBuilt: 2005,
homeKitchenCondition: 'standard',
homeHoaFees: 250,
homeHasUpgrades: true,
});

Polling for offer status

const status = await client.getOffer(offer.opendoorOfferRequestId);
if (status.offerStatus === 'OFFERED' && status.offerData) {
console.log('Price:', status.offerData.headlinePriceCents / 100);
console.log('Dashboard:', status.offerData.url);
}

Getting offer with pricing details

For consumer-facing views, use getOfferWithSellDirectPricing() to get net proceeds (what the seller takes home) instead of the raw fee breakdown:

const pricing = await client.getOfferWithSellDirectPricing(
offer.opendoorOfferRequestId
);
if (pricing.offerStatus === 'OFFERED' && pricing.offerData) {
console.log('Net proceeds:', pricing.offerData.netProceeds); // cents
console.log('Mortgage balance:', pricing.offerData.mortgageBalance);
console.log('Seller:', pricing.offerData.sellerName);
console.log('Expires:', pricing.offerData.expirationAtDisplayDate);
}

Prefilling questionnaire data

const detail = await client.getHomeDetail({
opendoorOfferRequestId: offer.opendoorOfferRequestId,
});
// detail.answerPrefills: { "home.bedrooms": { value: 3, source: "MLS" }, ... }

Error handling

import {
ValidationError,
APIError,
} from '@opendoor/partner-sdk-client-js-core';
try {
await client.createOffer({ address });
} catch (err) {
if (err instanceof ValidationError) {
// Client-side validation failed (missing fields, etc.)
console.log(err.field); // e.g., 'address.street1'
} else if (err instanceof APIError) {
// Server returned an error
console.log(err.code); // 'API_ERROR' | 'TIMEOUT' | 'NETWORK_ERROR'
console.log(err.statusCode); // HTTP status code
}
}

Client SDK methods summary

MethodDescription
getAddressSuggestions(query)Search for addresses
checkAddressUnit(address)Check if address needs a unit number
createOffer({ address, salesAssociateName?, salesAssociateEmail? })Create an offer request
updateOffer(offerId, data)Submit questionnaire answers
getOffer(offerId)Poll for offer status (full details)
getOfferWithSellDirectPricing(offerId)Get offer with net proceeds pricing
getHomeDetail({ opendoorOfferRequestId })Load prefill data for questionnaire
getHomebuilders()List homebuilder partners for dropdown
getAssessmentSlots({ offerId })Get inspection time slots

Backend setup

Your backend needs to proxy these requests using the server SDK. See the Quick Start for a complete Express example.