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) and the sell-direct price breakdown:

const pricing = await client.getOfferWithSellDirectPricing(
offer.opendoorOfferRequestId
);
if (pricing.offerStatus === 'OFFERED' && pricing.offerData) {
console.log('Net proceeds:', pricing.offerData.netProceeds); // cents
console.log('Headline price:', pricing.offerData.headlinePriceCents);
console.log('Opendoor fee:', pricing.offerData.opendoorFeeCents);
console.log('Repair cost:', pricing.offerData.repairCostCents);
console.log('Closing costs:', pricing.offerData.closingCostsCents);
console.log('Mortgage balance:', pricing.offerData.mortgageBalance);
console.log('Seller:', pricing.offerData.sellerName);
console.log('Expires:', pricing.offerData.expirationAtDisplayDate);
}

If you only need Sell Direct, getOfferWithSellDirectPricing() is enough. For Sell Direct plus CNML (Sell With Upside) in one backend call, use the server SDK’s getOfferWithProductsPricing and proxy the result to the browser.

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 Node or Ruby server SDK. See Quick Start step 1 for Express and Rails examples, and the demo-rails sample for a full Rails BFF.