Skip to content

Product catalog

Your product catalog is the list of manufacturer partners you represent and the products underneath each one. It is the most direct evidence Prok has that you can actually supply what a solicitation asks for: when a requirement lines up with a product in your catalog, that lifts the opportunity’s score, and the matched product is named in the reasoning you see on the opportunity.

A profile without a catalog leaves Prok guessing from categories and prose alone. The catalog is where you tell it exactly what you sell.

Two fields on a product decide how much weight it carries.

rep_status says how you supply it:

rep_status Meaning
carried You represent or stock the product directly. This is the default.
catalog The manufacturer makes it and you could source it, but supply would have to be arranged. It scores slightly below an otherwise identical carried product.

status says whether it counts at all:

status Meaning
active In your catalog and matched against every opportunity Prok scores.
discontinued Kept on file and visible in the portal, but excluded from matching entirely.

Only active products are ever considered, so discontinuing one is how you stop it influencing scores without losing the record of it.

Any catalog change that could move a score queues a background re-score: a new product, a status or rep_status change, or an edit to a product’s name, model, description, specs or partner. The re-score waits for the required product indexing and stages qualifying results for a later digest, rather than sending an email of its own. Saving a change does not mean indexing or re-scoring has already finished.

Every product belongs to a partner, so a partner has to exist before its first product does.

Terminal window
curl "https://app.prokure.ca/api/v1/products/partners" \
-H "Authorization: Bearer $PROKURE_API_KEY"

Requires profile:read. Returns every partner ordered by name, each with a count of its active and discontinued products:

{
"partners": [
{
"id": "6f0a1c2d-0000-0000-0000-000000000000",
"name": "Vertex Optics",
"authorized": true,
"relationship": "Authorized reseller, Western Canada",
"source_url": "https://example.com/partners/vertex",
"active_product_count": 12,
"discontinued_product_count": 3,
"created_at": "2026-09-01T16:20:00.000Z"
}
]
}

authorized is false for a partner that has been removed from your company profile. It stays in this list with its products so the removal can be undone, but no product can be added or moved under it while it is false. Add the partner again to clear that.

Terminal window
curl -X POST "https://app.prokure.ca/api/v1/products/partners" \
-H "Authorization: Bearer $PROKURE_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Vertex Optics",
"relationship": "Authorized reseller, Western Canada",
"source_url": "https://example.com/partners/vertex"
}'

Requires profile:write. name is 1 to 200 characters; relationship is 1 to 200 characters or null; source_url is a URL or null. A 201 returns the partner object.

Adding a partner does two things at once. It creates the partner in the catalog, and it adds the name to manufacturer_partners on your company profile through the ordinary change history, with source set to portal_edit. That entry is revertible on the usual terms, so an accidental addition is undone the same way any other profile change is.

Posting a name that is already yours re-authorizes it rather than creating a duplicate, and updates relationship and source_url if you send them. That is also how you clear a partner_not_authorized refusal on a catalog write. It does not bring back that partner’s discontinued products: reactivating a product is a separate, deliberate step (see Discontinuing and reactivating).

Removal happens on the company profile, not here. Removing a manufacturer partner deactivates that partner’s products in the same change, so they stop counting toward match scores immediately, and reverting the removal brings the partner and exactly those products back. See Removing a manufacturer partner.

Terminal window
curl -X POST "https://app.prokure.ca/api/v1/products" \
-H "Authorization: Bearer $PROKURE_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"oem_partner_id": "6f0a1c2d-0000-0000-0000-000000000000",
"name": "Thermal monocular",
"model": "VX-640",
"description": "640x480 uncooled thermal monocular, 12 um pitch, NVG-compatible.",
"commodity_codes": ["5855"],
"specs": { "resolution": "640x480", "weight_g": 380 },
"rep_status": "carried"
}'

Requires profile:write. A 201 returns the product:

{
"id": "9c31d4e5-0000-0000-0000-000000000000",
"oem_partner_id": "6f0a1c2d-0000-0000-0000-000000000000",
"oem_name": "Vertex Optics",
"name": "Thermal monocular",
"model": "VX-640",
"description": "640x480 uncooled thermal monocular, 12 um pitch, NVG-compatible.",
"commodity_codes": ["5855"],
"specs": { "resolution": "640x480", "weight_g": 380 },
"rep_status": "carried",
"status": "active",
"source": "portal",
"source_url": null,
"created_at": "2026-09-05T14:03:11.000Z",
"updated_at": "2026-09-05T14:03:11.000Z"
}

The product is saved immediately, with its indexing work retained for background processing. It becomes available to product matching after that indexing succeeds. Temporary indexing failures can be retried without changing the description again; repeated failures may need the Prokure team to investigate.

Field Required Value
oem_partner_id Yes The id of one of your partners, from the partner list.
name Yes 1 to 200 characters.
model No 1 to 100 characters, or null.
description No 1 to 4000 characters, or null. The richer this is, the better a requirement can be matched against it.
commodity_codes No Up to 50 codes, each 1 to 50 characters.
specs No A JSON object of your own keys, serialising to at most 8,192 characters of JSON.
rep_status No carried or catalog. Defaults to carried.
source_url No A URL or null.

Three failures are worth handling specifically:

Status error Meaning
404 not_found oem_partner_id is not a partner of yours.
409 already_exists You already have a product with this partner, name and model.
409 partner_not_authorized The partner has been removed from your company profile. Add it again with POST /api/v1/products/partners, which re-authorizes it, before adding products under it.
Terminal window
curl -X PATCH "https://app.prokure.ca/api/v1/products/$ID" \
-H "Authorization: Bearer $PROKURE_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "description": "640x480 uncooled thermal monocular, 12 um pitch, MIL-STD-810H." }'

Requires profile:write. Send any subset of the create fields plus status, which takes active or discontinued. At least one field has to be present, and a field the endpoint does not define is rejected with 400 validation_failed rather than ignored. A 200 returns the product in the same shape the create does.

An edit is refused on the same terms a create is, because a rename can move a product onto an identity another product already holds:

Status error Meaning
404 not_found No such product, or oem_partner_id is not a partner of yours.
409 already_exists The new partner, name and model would collide with another product of yours. Identity is checked against the product as it would stand afterwards, so a field you leave out keeps its current value for that comparison.
409 partner_not_authorized The partner you are moving the product to has been removed from your company profile. Add it again first.

Changing the name, model, description, specs or partner schedules product indexing for matching. Specs contribute to the product text used to find candidates and to the evidence supplied for selected candidates. Very large spec objects are bounded for processing, so do not assume every stored field reaches the model. Changing only source_url does not change the matching text.

Products are never deleted. A product that has been quoted, matched or drafted against is part of the record of why an opportunity scored the way it did, and deleting it would rewrite that history.

Retire one by discontinuing it instead:

Terminal window
curl -X PATCH "https://app.prokure.ca/api/v1/products/$ID" \
-H "Authorization: Bearer $PROKURE_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "status": "discontinued" }'

It disappears from matching immediately and stays in the catalog, counted under discontinued_product_count on its partner. Setting status back to active brings it back into scoring.

A whole catalog does not have to go in one product at a time. POST /api/v1/products/import takes a CSV of up to 500 products, validates it as a unit, and writes partners and products in one transaction. Start from the template:

Terminal window
curl "https://app.prokure.ca/api/v1/products/import/template" \
-H "Authorization: Bearer $PROKURE_API_KEY" \
-o product-import-template.csv

GET /api/v1/products/import/template returns the header row plus one example row, which is the fastest way to see the shape the import expects. Send the file with ?dry_run=true first to see what it would create and update before anything is written.

The import has no specs column and never changes a product’s status, so a discontinued product stays discontinued through a re-import. Everything the file does carry is authoritative, blank cells included. See Importing products from CSV for the columns, the validation rules and the re-import contract.

Terminal window
curl "https://app.prokure.ca/api/v1/products?status=active&limit=50" \
-H "Authorization: Bearer $PROKURE_API_KEY"

Requires profile:read. Products come back newest first:

{
"products": [
{
"id": "9c31d4e5-0000-0000-0000-000000000000",
"oem_partner_id": "6f0a1c2d-0000-0000-0000-000000000000",
"oem_name": "Vertex Optics",
"name": "Thermal monocular",
"model": "VX-640",
"description": "640x480 uncooled thermal monocular, 12 um pitch, NVG-compatible.",
"commodity_codes": ["5855"],
"specs": { "resolution": "640x480", "weight_g": 380 },
"rep_status": "carried",
"status": "active",
"source": "portal",
"source_url": null,
"created_at": "2026-09-05T14:03:11.000Z",
"updated_at": "2026-09-05T14:03:11.000Z"
}
],
"next_cursor": null
}
Parameter Value
status active or discontinued. Both are returned when it is omitted.
partner_id Restrict to one partner.
q Free text, up to 200 characters, matched case-insensitively against name, model and description.
limit 1 to 100. Defaults to 50.
cursor The previous page’s next_cursor.

next_cursor is opaque. Pass it back verbatim as cursor and stop when it comes back null. Do not decode it or construct one; a malformed cursor is rejected with 400 validation_failed. Keep the filters identical for every request in a paging pass. These are the same rules the opportunity list follows, described in Filtering and pagination.

Settings has a Product catalog page that does all of the above without the API: partners with their active and discontinued counts, adding a partner, adding and editing products, searching and filtering the list, and discontinuing or reactivating a product. An Import button on the same page loads a catalog from a CSV, with a dry-run preview before anything is written. The Company Profile page’s partner-removal dialog now tells you how many active products the removal will deactivate before you confirm it.

  • Product fields. Name up to 200 characters, model up to 100, description up to 4000, up to 50 commodity codes of up to 50 characters each, and specs serialising to at most 8,192 characters of JSON.
  • Partner fields. Name and relationship up to 200 characters each.
  • 60 requests per minute on each read route, 10 per minute on each write route, counted per client IP like every other route. See Rate limits and errors.