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.
Project-based purchasing. Every project is purchased separately.
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 |
|
|
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
Customer requests a quote. The EMS receives a request from their customer.
Import the BOM into a project (RfQ) in Luminovo — done manually by the user.
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.
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 |
| Handle to the selected offer. Resolve with |
| Number of offer units to order (the amount to purchase). |
| What one offer unit is (e.g. 1 piece, or 5 m of cable). |
| Convenience total in base units = |
| From the selected price break — order must be ≥ this. |
| Order must be a multiple of this. |
| 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 |
| Manufacturer part number + manufacturer for the PO line. |
| The supplier and its ERP vendor number — often used to whitelist which suppliers are valid for PO creation. |
| Supplier branch / region (e.g. Europe, Asia). |
| The supplier's own part number for ordering. |
| Supplier quote/offer reference, for reconciliation. |
| ListPrice / ContractPrice / QuotePrice / customer-negotiated. |
| Full price-break ladder in original currency. |
| Lead time + stock for delivery-date planning. |
| Reel / Tape / Tray / Tube / Bulk … |
| Offer validity window — check the price is still current before ordering. |
| NCNR / cancellation window. |
| Tooling / NRE / setup fees (mostly custom parts). |
| Unit basis; custom parts carry per-tier |
Scenario 2 — Consolidated (bulk) project purchasing
Workflow
Demand is aggregated on the ERP side, so the ERP holds the definitive list of IPNs to be purchased (across many projects).
The ERP triggers a refresh of offers for those IPNs in Luminovo, so supplier prices/availability are re-pulled and current.
After a delay (the refresh needs time to update all offers), the ERP fetches all offers for the given IPNs from Luminovo.
The ERP decides which offers to prefer based on user-defined criteria — e.g. best purchase price or lowest lead time.
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 |
| The IPN + revision. |
|
|
| 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. |
| 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 richOfferResponseshape asGET /offers/{id}above):price_breaks[](MOQ / MPQ /unit_pricein original currency),availability(factory_lead_time,stock),linked_location(supplier + ERP vendornumber),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 |
|
|
Manufacturer + MPN |
|
|
IPN (internal part number) |
| ERP's own material number is matched via IPN. |
Supplier part number (SPN) |
|
|
Order quantity |
|
|
Unit of measure |
|
|
Unit price + currency |
| Original currency, no conversion. |
MOQ / MPQ |
| Order must be ≥ MOQ and a multiple of MPQ. |
Lead time |
| For delivery-date planning. |
Offer validity |
| 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 |
| GET | 1 | Selected offers + quantities to buy for a project |
2 |
| GET / POST | 1 (+2) | Full offer detail behind an |
3 |
| GET | 2 | IPN → off-the-shelf part id (mpn_id) + MPN |
4 |
| POST | 2 | Re-pull supplier offers (in development; add delay after) |
5 |
| POST | 2 | All offers for a set of part IDs → |
— |
| 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).



