Zinevu
Guides

Importing prices

Keep the catalogue in your own system and push it here — whole grids, or a single cell that moved.

Two endpoints, both taking a list, both applied in one transaction. They need a key with prices:write — a scope that is never granted implicitly, so a key you minted for reading stays read-only.

Addressed by your code, never by our id#

Your catalogue decides what a grid is called, and you should not have to store an identifier of ours to update your own prices. A code you have not sent before creates a grid; one you have updates it. Re-running last night's import therefore changes nothing and adds nothing.

An update replaces the grid, it does not merge into it

That is what makes your list the master — and it also means a first experiment should use a code of its own, not one your catalogue already quotes from. The examples here deliberately use example_ codes. To change a few numbers in a grid you want to keep, patch the cells instead.

Pushing a catalogue#

POST /price-matrices?dry_run=1Idempotency-Key: 8f14e45f-ea8d-4b1f-9c2a-77bb0f2e6d31{  "matrices": [    {      "code": "example_roof",      "name": "Example — polycarbonate roof",      "matrix_type": "grid_2d",      "row_axis": "diepte_cm",      "col_axis": "breedte_cm",      "row_values": [250, 300],      "col_values": [300, 400],      "prices": [[1176, 1344], [1334, 1596]]    },    { "code": "example_montage", "name": "Example — installation", "matrix_type": "fixed", "fixed_price": 1250 }  ]}// -> { "data": { "dry_run": true, "created": 1, "updated": 1, "prices": 5,//                "matrices": [ { "code": "example_roof", "action": "update", "prices": 4 }, … ] } }

Nothing is applied unless everything validates. One bad row rejects the request with 422 and a list of every problem in it. Add ?dry_run=1 to any write to see exactly what would change without changing it; the dry run is the same validation with the last step skipped, not a second implementation of it.

Moving one price#

For a price that moved rather than a catalogue that did, patch the cells. A row or column value that is not already on the grid is an error, not an insertion — growing a grid changes what every pricing rule reading it can quote, so state the whole shape through the upsert instead.

PATCH /price-matrices/cells{  "updates": [    { "code": "example_roof", "cells": [ { "row": 300, "col": 400, "price": 1650 } ] }  ]}// list_1d grids take the same shape with "col" omitted.

Writing a price never reprices an offer#

Quotes already sent keep the numbers they were sent with. Repricing is a deliberate act inside the portal, because rebuilding a quote rewrites history and, on a hand-built one, stacks a second set of lines on the first.

Retries#

Send an Idempotency-Key if your importer retries. The second request with the same key and the same body replays the first response verbatim and writes nothing.

Ceilings#

  • 10 writes a minute and 500 a day, on top of the general budget.
  • 200 matrices per request.
  • 5,000 prices in a single grid, 50,000 across one request.
  • Over any of those is a 413 and nothing is written.

A full catalogue is normally one call, so if you are anywhere near these numbers, tell us what you are building rather than working around them.

A note on shapes#

Three shapes live behind one field. matrix_type tells you which — grid_2d, list_1d or fixed — but you do not have to branch on it when reading: cells is the same flat list in all three cases, and a missing axis is null rather than absent. The full read shape is on the reference page.