Beta

The Partner Trading API v1 is in beta — endpoints and response shapes may still change.

Developers
Cru World Wine
API v1 · REST & MCP
Your offers

Create an offer

List a line of your portfolio stored with Cru, wine you hold outside Cru, or your own stock as a supplier, for sale at a price per unit you choose.

POST/offersLIVE
Required scopeoffers:writeAuthentication required
Wine stored with Cru or held outside it, or a supplier’s own stock

stock_type cru puts units of a line of your portfolio stored with Cru on sale. stock_type external lists wine in your own storage, for accounts Cru has set up to sell it. stock_type supplier adds an offer of your own stock, for a supplier whose offer feed Cru imports. To sell into a bid now, POST /market/bids/{code}/sell.

How this write runs

offer.list
Partner credentialCLIENT-KEY · CLIENT-SECRET Executes at once and answers 201. The body must carry a reference: send the identical request again after a timeout and Cru replays the first outcome instead of acting twice.
Connected appAuthorization: Bearer Answers 202 with a confirmation code and does nothing else. It runs only when the app calls POST /confirmations/{code} within 15 minutes, after the customer agrees.

Writes & confirmations, in full →

Request body

APPLICATION/JSON
FIELDDESCRIPTION
referencestring · 1–50 chars · partners: requiredYour idempotency key: letters and digits, then . _ : or - allowed. Required on a partner credential’s write and kept for good, so a retry with it can never act twice. Ignored for connected apps.
stock_typestring · requiredWhat you are listing: cru, a line of your portfolio stored with Cru; external, wine you hold outside Cru; or supplier, your own stock as a supplier whose offer feed Cru imports. The fields below that say which of them they are for are refused for the others, with VALIDATION_UNKNOWN_PARAMETER. Anything else, bpo included, is refused with VALIDATION_INVALID_VALUE: BPO stock cannot be listed through the API.
portfolio_idstring · cru only · requiredThe line to list, from GET /portfolio: one with stock_type cru that is not listed yet (is_listed false). Its units go on sale as a listed line with a portfolio_id of its own, which the answer gives.
lwin18string · 18 digits · external or supplier only · requiredThe wine. Cru must trade it.
quantityinteger · 1–1000 · requiredUnits to list. For cru, at most the line’s quantity.
pricenumber · > 0 · requiredPrice per unit in the market’s currency, to at most 2 decimal places. For cru and external, the asking price, what the buyer pays: the line’s pricing.listing_price. For supplier, what you receive: buyers pay Cru’s price, and the line gives yours as both pricing.listing_price and pricing.net_proceeds.
warehouse_codestring · external only · requiredThe Cru warehouse it is sold through: one GET /warehouses marks sells_your_inbond_wine for you. The line gives it back as warehouse.deliverable_warehouse_code.
condition_statusstring · external or supplier only · optionalverified (Verified), client_reserves (Client Reserve) or apd (As per description). For external, it defaults to, and cannot exceed, the level Cru set for your account. For supplier, it defaults to verified, or to apd when duty_paid is true, which takes nothing else.
condition_textstring · ≤ 200 chars · supplier only · optionalWhat buyers are told about the condition. Required for apd, and refused for verified; client_reserves may have it. Duty-paid stock says “Duty Paid in the UK” unless you give it.
duty_paidboolean · supplier only · optionaltrue when the duty has been paid, which makes the offer apd. Defaults to false, in bond.
costnumber · > 0 · external only · optionalWhat you paid per unit, for your records.
inbond_address_idinteger · ≥ 1 · external only · optionalThe inbond warehouse the wine is in now, from GET /warehouses/inbond. Leave it out if you are not sure where the wine is: Cru records it as not sure, as the website’s “Not Sure” option does.

Any other field is refused with VALIDATION_UNKNOWN_PARAMETER / 400.

Changed: stock_type is required

Every POST /offers now needs stock_type. Send external to list wine you hold outside Cru, as before: a request without stock_type is refused with VALIDATION_REQUIRED_FIELD / 422. A connected app’s preview gives stock_type back, straight after summary.

Changed: wine stored with Cru, and a supplier’s own stock, can be listed here

Only wine held outside Cru could be listed here; wine stored with Cru was listed only on the Cru website. Now send stock_type cru, the portfolio_id of a line that is not listed yet, quantity and price, and nothing else: lwin18 and the other fields are for external and supplier only. stock_type supplier adds an offer of a supplier’s own stock.

Changed: offer is the wine, as GET /offers gives it

The offer a write answers with is no longer a listing: it is now the wine as GET /offers/{code} gives it, with only the lines the units written are on now. Each line has its portfolio_id, stock_type, pricing and warehouse in place of the listing’s code, held, price, proceeds and holding_ids. A write’s answer no longer carries a listing’s code — only a connected app’s PATCH preview names the listing it changes — so give a line’s portfolio_id to PATCH or DELETE /offers/{code} to change or remove its units.

A line stored with Cru

Its units go on sale at your price, and you receive it less Cru’s commission: the listed line’s pricing gives commission_percent, commission and net_proceeds. Listing moves them to a listed line with a portfolio_id of its own, not the one you sent, so take the answer’s for PATCH and DELETE /offers/{code}. A line already listed is refused: change its price or quantity with PATCH /offers/{code} instead. Removing the offer later only takes it off sale.

Your next offer feed import replaces a supplier offer

An offer listed with stock_type supplier joins your offers on Cru only until your next offer feed import to Cru, which replaces it, as it replaces all your offers: your feed stays the source of truth. To keep selling the wine, put it in your feed too.

A supplier offer

It is sold from your own warehouse, so it takes no warehouse_code, and it must be priced in your offer feed’s currency: on a Cru site that quotes in another, it is refused with TRADE_REFUSED, and the message names the currency. Its line comes back with stock_type supplier, and your price as both pricing.listing_price and pricing.net_proceeds. You can change it afterwards with PATCH /offers/{code}, like any of your supplier offers.

Removing wine held outside Cru takes it out of your portfolio

Listing wine held outside Cru creates its units in your Cru portfolio, in bond. Removing the offer later deletes them again.

Response fields

201 Created · 202 Accepted

A partner credential gets 201 and the wine, with the line just listed. A connected app gets 202 and a confirmation.

Executed 201

actionstring

The action that ran, such as bid.place.

statusstring

completed.

offerobject | null

The wine as GET /offers/{code} gives it, with only the lines of what was just listed. Their portfolio_id is what PATCH and DELETE /offers/{code} take: for cru, a new one, not the one you sent.

Staged 202

confirmation.codestring

cnf_ and 43 more characters. A secret: the only handle on the instruction, valid for 15 minutes, once.

confirmation.actionstring

The action staged, such as bid.place.

confirmation.statusstring

pending.

confirmation.expires_atdatetime

RFC 3339 UTC.

confirmation.previewobject

summary, stock_type, then for cru portfolio_id, then lwin18, wine_name, quantity, price, total and currency; then for external warehouse_code, condition_status, cost and inbond_address_id — null when not given — or for supplier duty_paid, condition_status and condition_text, as they will be listed.

Errors

A request without stock_type, quantity or price, cru without portfolio_id, external or supplier without lwin18, or external without warehouse_code, returns VALIDATION_REQUIRED_FIELD / 422, and an lwin18 that is not 18 digits VALIDATION_INVALID_VALUE / 422. A wine Cru does not trade is TRADE_REFUSED / 422, “Cru does not trade wine … so it cannot be listed.” For cru, a portfolio_id that is not a line of your portfolio, or a line of another stock_type, returns VALIDATION_INVALID_VALUE / 422; a line already listed, one that needs a condition check first, more units than it can list, or units sold or moved before you confirm, TRADE_REFUSED / 422. For external, a warehouse not set up for your account, a condition_status above your level or an inbond_address_id GET /warehouses/inbond does not list returns VALIDATION_INVALID_VALUE / 422, and an account not set up to sell wine held outside Cru TRADE_REFUSED / 422. For supplier, apd without condition_text returns VALIDATION_REQUIRED_FIELD / 422; condition_text with verified, or duty_paid true with a condition_status other than apd, VALIDATION_INVALID_VALUE / 422; and an account with no supplier offers on Cru, or a price in a currency other than your feed’s, TRADE_REFUSED / 422. Missing or invalid credentials return AUTH_INVALID_CREDENTIALS / 401. A credential without offers:write gets AUTH_INSUFFICIENT_SCOPE / 403. View all error codes →

UP NEXT Change an offer

API credentials

Enter the client key and secret issued by Cru. They are kept for this browser tab’s session — a reload keeps them, closing the tab or clearing them ends them.

Credentials are never included in copied examples, and are redacted from anything the console prints back.

Request API access

Tell us who you are and what you want to build. Cru issues a client key and secret for your organisation, scoped to what you need.

Markets you trade in (choose one or more)

We use what you send here to reply about API access, and for nothing else. Cloudflare Turnstile checks the form for bots (privacy policy).