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.
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
413and 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.