Multi-product offer pricing
When you need more than Sell Direct pricing on the backend, use the Partnerships GraphQL query offerRequestWithProductsPricing. The server SDKs expose it as getOfferWithProductsPricing (Node) and get_offer_with_products_pricing (Ruby).
When to use this vs Sell Direct only
| Approach | Use when |
|---|---|
getOfferWithSellDirectPricing / get_offer_with_sell_direct_pricing | You only need net proceeds and the Sell Direct fee breakdown. |
getOfferWithProductsPricing / get_offer_with_products_pricing | You need per-product state: Sell Direct and optional CNML (Cash Now, More Later / Sell With Upside), each with its own status, denial, and offer line items. |
The response includes a rolled-up top-level offerStatus, denialInfo (when every present product is denied), and authenticatedDashboardUrl (a pre-authenticated link to the seller’s Opendoor dashboard). Per-product details live under sellDirect and cnml. The cnml field is null when the partner does not offer Sell With Upside.
For full field shapes, see the API reference: GetOfferWithProductsPricingResponse, SellDirectPricingResult, CnmlPricingResult, CnmlOfferData.
Node.js (@opendoor/partner-sdk-server-js-core)
import { OpendoorClient } from '@opendoor/partner-sdk-server-js-core';
const client = new OpendoorClient({ apiKey: process.env.OPENDOOR_API_KEY! });
const multi = await client.getOfferWithProductsPricing(offerId);
if (multi.sellDirect?.offerStatus === 'OFFERED' && multi.sellDirect.offerData) { console.log('Net proceeds (cents):', multi.sellDirect.offerData.netProceeds);}
if (multi.cnml?.offerStatus === 'ELIGIBLE' && multi.cnml.offerData) { console.log('Upfront cash (cents):', multi.cnml.offerData.upfrontCashCents);}Ruby (opendoor-partner-sdk-server-ruby)
require "opendoor/partner_sdk"
client = Opendoor::PartnerSdk::Client.new(api_key: ENV.fetch("OPENDOOR_API_KEY"), environment: :staging)
multi = client.get_offer_with_products_pricing(offer_id: offer_id)
sd = multi[:sellDirect]if sd && sd[:offerStatus] == "OFFERED" && sd[:offerData] puts sd[:offerData][:netProceeds]endBFF example
Expose a route that accepts offerId (same JSON body as POST /api/opendoor/v1/offer/pricing in the Quick Start).
app.post('/api/opendoor/v1/offer/products-pricing', async (req, res) => { const result = await opendoor.getOfferWithProductsPricing(req.body.offerId); res.json(result);});The local dev server and hosted demos include POST …/offer/products-pricing (see dev/server.ts in the repo).
Browser client
The browser OpendoorClient from @opendoor/partner-sdk-client-js-core does not include this call today. If you add a BFF route, call it with fetch or extend your proxy layer; the response JSON matches the server types above.