Skip to content

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

ApproachUse when
getOfferWithSellDirectPricing / get_offer_with_sell_direct_pricingYou only need net proceeds and the Sell Direct fee breakdown.
getOfferWithProductsPricing / get_offer_with_products_pricingYou 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]
end

BFF 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.