Skip to main content

Use Luminovo API to speed up your purchasing processes

Faster purchasing through price fetching automation

Written by Luminovo Support

Purchasing is complex and time consuming

And Luminovo is there to help purchasers at EMS or OEMs to purchase faster and at better conditions. Since the ERP system is the system of record for purchasing, the purchase orders have to get created in the ERP system before being sent out.

There're two different purchasing scenarios our customers can cover with Luminovo.

  1. Project-based purchasing. Every project is purchased separately.

  2. Consolidated purchasing. Multiple projects get bundled and purchased for in one go.

This document is about automating both scenarios. Everything below can already be done manually in the Luminovo UI — a purchaser can open a project, read off the selected offers, quantities and prices, and re-key them into the ERP by hand. The point here is the automated path: exchanging that data directly between the ERP and Luminovo over the API, so buyers skip the manual re-keying, avoid transcription errors, and always work from current prices and availability.

The API endpoints described are the building blocks for that automated data exchange.

Both scenarios rely only on the public API (https://api.luminovo.com, docs at docs.luminovo.com).


The two scenarios at a glance

Scenario 1 — Project-based purchasing

Scenario 2 — Consolidated (bulk) purchasing

Trigger

A single project's quote is accepted

ERP has aggregated demand across many projects

Unit of work

One project / sourcing scenario

A flat list of IPNs

Who selects the offer

Luminovo (the sourcing selection in the project)

The ERP, from all offers Luminovo returns

Direction

Pull the selected purchase options out of the project

Refresh, then pull all offers per IPN; ERP decides

Core endpoints

GET /sourcing-scenarios/{id}/purchase-optionsGET /offers/{id}

GET /components/ipn/{ipn}POST /offers/refresh (in dev) → POST /offers/find

Result in ERP

PO created per selected offer

Best prices pre-filled into the purchasing mask; buyer decides

Both scenarios end the same way: the purchase order is created and executed in the ERP. Luminovo only supplies the priced sourcing data.

The Luminovo-side automations are read-only. Nothing is ordered or emailed from Luminovo. The final purchasing decision is always made in the ERP system.

How the data exchange works

It’s important to emphasise — the exchange between the ERP system and Luminovo is running through Luminovo’s API. There always has to be an instance initiating this exchange (= making calls to Luminovo’s API). This system is either your ERP or some middleware you might be running. Luminovo never actively pushes data to your ERP system itself, it only provides the data, ready to be loaded any time.


Scenario 1 — Project-based purchasing

Workflow

  1. Customer requests a quote. The EMS receives a request from their customer.

  2. Import the BOM into a project (RfQ) in Luminovo — done manually by the user.

  3. Work the BOM and create the quote to the customer. Sourcing runs against the supplier APIs; Luminovo selects an offer per line item inside the project's sourcing scenario.

  4. Quote is accepted → the user triggers the pull. The ERP fetches the project's purchase options — the amounts to buy and the offer that was selected — and creates the purchase order(s) in the ERP.

Optionally, before step 4 the integration can refresh the supplier offers (POST /offers/refresh, in development) and then re-run the sourcing selection (POST /sourcing-scenarios/run-selection) so prices/availability are fresh at order time — this addresses the "how old is this offer?" concern (offers can be configured, for example, to be treated as outdated after 7 days and expired after 28).

Endpoints

1. GET /sourcing-scenarios/{id}/purchase-options"designed for ERP systems to create purchase orders."

Path param id = the sourcing-scenario UUID (obtain it from the project via GET /rfqs/{id} or GET /sourcing-scenarios).

Returns purchase_options[], one entry per selected offer:

Field

Meaning — why the ERP needs it

offer_id

Handle to the selected offer. Resolve with GET /offers/{id}.

quantity

Number of offer units to order (the amount to purchase).

unit_of_measurement

What one offer unit is (e.g. 1 piece, or 5 m of cable).

purchase_quantity

Convenience total in base units = quantity × unit_of_measurement.value.

minimum_order_quantity (MOQ)

From the selected price break — order must be ≥ this.

minimum_packaging_quantity (MPQ)

Order must be a multiple of this.

unit_price.amount + unit_price.currency

Price per offer unit in the offer's original currency — no conversion applied.

Solves a common currency pain point.

ERPs typically need the original order currency (e.g. USD for a US distributor), not a value pre-converted to the tenant currency (e.g. EUR). purchase-options returns unit_price in the original currency with an ISO-4217 code.

2. GET /offers/{id} (or POST /offers/bulk for many at once) — resolves each offer_id into the full record the ERP needs on the PO line:

Field

PO use

linked_partmpn, manufacturer{id,name}

Manufacturer part number + manufacturer for the PO line.

linked_location (Supplier) → name, number

The supplier and its ERP vendor number — often used to whitelist which suppliers are valid for PO creation.

linked_location.stock_location

Supplier branch / region (e.g. Europe, Asia).

supplier_part_number (SPN)

The supplier's own part number for ordering.

offer_number

Supplier quote/offer reference, for reconciliation.

price_type

ListPrice / ContractPrice / QuotePrice / customer-negotiated.

price_breaks[]minimum_order_quantity, minimum_packaging_quantity, unit_price

Full price-break ladder in original currency.

availabilityfactory_lead_time, factory_quantity, stock

Lead time + stock for delivery-date planning.

packaging

Reel / Tape / Tray / Tube / Bulk …

valid_from, valid_until

Offer validity window — check the price is still current before ordering.

cancellation_policyis_non_cancellable_non_returnable

NCNR / cancellation window.

one_time_costs[]

Tooling / NRE / setup fees (mostly custom parts).

unit_of_measurement, kind (StandardPart/CustomPart)

Unit basis; custom parts carry per-tier lead_time inside price_breaks instead of availability.


Scenario 2 — Consolidated (bulk) project purchasing

Workflow

  1. Demand is aggregated on the ERP side, so the ERP holds the definitive list of IPNs to be purchased (across many projects).

  2. The ERP triggers a refresh of offers for those IPNs in Luminovo, so supplier prices/availability are re-pulled and current.

  3. After a delay (the refresh needs time to update all offers), the ERP fetches all offers for the given IPNs from Luminovo.

  4. The ERP decides which offers to prefer based on user-defined criteria — e.g. best purchase price or lowest lead time.

  5. Prices are inserted into the purchasing mask, so the purchaser already sees the best prices and can decide where to buy from.

Endpoints

1. GET /components/ipn/{ipn} — the IPN → part mapping.

Path param ipn. Returns components[] (one per revision), each with:

Field

Use

internal_part_number.value / .revision

The IPN + revision.

type

OffTheShelf or Custom

linked_parts[] (OffTheShelf) → id, mpn, manufacturer{id,name}

The off-the-shelf part id (the "mpn_id" that identifies the part to price) plus its MPN/manufacturer. This is the ID you feed into the offer endpoints.

risk_datarohs_compliant, reach_compliant, lifecycle_status, lifecycle_yteol

Compliance/lifecycle, if you want to gate ordering on it. This data is always an aggregate from all connected MPNs. More on the aggregation rules in the API documentation.

2. POST /offers/refresh — re-pulls supplier-API offers for the given part(s) / mpn_id so pricing and availability are fresh.

Introduce a delay after this call before fetching — the refresh has to hit the supplier APIs and update all offers; reading too early returns stale data. Luminovo does not have a function to check the status of the offer update yet.

3. POST /offers/find (docs title "Get Offers By Part" — note: it is POST, not GET) — the bulk read.


Request body = a set of part IDs (off-the-shelf, custom, or IPN) — POST so you can pass many at once. Returns:

  • items[] — the offers (same rich OfferResponse shape as GET /offers/{id} above): price_breaks[] (MOQ / MPQ / unit_price in original currency), availability (factory_lead_time, stock), linked_location (supplier + ERP vendor number), supplier_part_number, price_type, valid_from/valid_until, packaging, etc. This is the list of offers carrying the prices, MOQs and lead times the ERP ranks on.

  • not_found_ids[] — part IDs that could not be resolved (handle/log these).

The ranking in step 4 (e.g. best price vs. lowest lead time) is done by the ERP over items[] — Luminovo returns every offer; the customer's own criteria pick the winner. The principle: Luminovo delivers the data; the decision and the order stay in the ERP.


What an ERP needs to create a PO — and where it comes from

Consolidated field map (for an account-assigned PO / "kontierte Bestellung"):

PO field (ERP)

Source in the Luminovo API

Notes

Supplier / vendor number

offer.linked_location.number

Manufacturer + MPN

offer.linked_part.mpn, .manufacturer

IPN (internal part number)

GET /components/ipn/{ipn} / project line item

ERP's own material number is matched via IPN.

Supplier part number (SPN)

offer.supplier_part_number

Order quantity

purchase_options.quantity / purchase_quantity (Sc. 1); chosen from price_breaks (Sc. 2)

Unit of measure

unit_of_measurement

Unit price + currency

purchase_options.unit_price / offer.price_breaks[].unit_price

Original currency, no conversion.

MOQ / MPQ

minimum_order_quantity / minimum_packaging_quantity

Order must be ≥ MOQ and a multiple of MPQ.

Lead time

offer.availability.factory_lead_time (standard) / price_breaks[].lead_time (custom)

For delivery-date planning.

Offer validity

offer.valid_from / valid_until

Check price freshness before ordering.

Account assignment / cost center / project

ERP side

Not in Luminovo — provided by the ERP for the account-assigned PO.

Delivery / demand date

ERP side (from aggregated demand)

Constraints to be explicit about

  • The PO is placed from the ERP, never from Luminovo. Goods receipt and invoice receipt also stay in the ERP.

  • No supplier emails from Luminovo. These read endpoints don't send anything — the final purchasing decision and the order stay in the ERP.

  • Freshness matters. Re-run selection (Sc. 1) or refresh offers (Sc. 2) before ordering; respect offer validity dates.


Endpoint quick-reference

#

Endpoint

Method

Scenario

Role

1

/sourcing-scenarios/{id}/purchase-options

GET

1

Selected offers + quantities to buy for a project

2

/offers/{id} (or /offers/bulk)

GET / POST

1 (+2)

Full offer detail behind an offer_id

3

/components/ipn/{ipn}

GET

2

IPN → off-the-shelf part id (mpn_id) + MPN

4

/offers/refresh

POST

2

Re-pull supplier offers (in development; add delay after)

5

/offers/find

POST

2

All offers for a set of part IDs → items[] + not_found_ids[]

/sourcing-scenarios/run-selection

POST

1 (opt.)

Refresh the project's sourcing selection before ordering

All calls: base URL https://api.luminovo.com, Bearer (JWT) auth, and a data-model-specific Accept header per endpoint. Always handle an "Unknown" case for any enum (forward-compatibility rule stated in the API preamble).

Did this answer your question?