Vertical Taxonomy Translation
This API surface is for integration partners building on top of the Rokt network. Rokt ecommerce partners integrating placements on their own checkout should use the Rokt Ecommerce developer docs instead.
Your platform has its own vertical taxonomy (MCC codes, category IDs, your internal scheme), and Rokt has its own internal taxonomy of ~24 verticals and ~152 sub-verticals. The Partnerships API speaks your taxonomy on the wire. The server translates to Rokt's IDs through a vertical mapping table keyed by your platform_parent_account_id.
Where translation happens: register and MCL PUTsDirect link to Where translation happens: register and MCL PUTs
The vertical mapping is consulted on two partner-facing call shapes — not just marketplace controls:
POST /v1/accounts/register/partnership— thevertical_idandsub_vertical_idfields on the request body are your partner-taxonomy values, resolved server-side againstpartnership_vertical_mapfor yourplatform_parent_account_id. If either ID has no mapping row, register fails with400before the merchant is created.PUT /v1/partnership/accounts/{account_id}/marketplacecontrolslists— each{partnerVerticalId, partnerSubVerticalId}pair inblockedVerticalsis resolved the same way. See the next section for the atomic-400 behavior.
Both share the same partnership_vertical_map table, scoped to your platform_parent_account_id. Onboard a new partner-side vertical once and it works on both surfaces immediately.
Mapping rows are seeded by Rokt out-of-band through an admin-only POST /v1/partnership/vertical-mappings endpoint — it's not exposed on the partner API surface. Before launch, email smb-partnerships@rokt.com the complete list of category and sub-category IDs and names in use across your entire merchant network — every {sub_vertical_id, name} pair, not a sample (a CSV export of your taxonomy is ideal). You don't propose Rokt-side mappings: Rokt's team maps each of your categories to its own taxonomy out-of-band against your platform_parent_account_id and confirms when the mappings are live.
Forward translation (on PUT)Direct link to Forward translation (on PUT)
When you send a PUT /…/marketplacecontrolslists:
{
"blockedVerticals": [
{ "partnerVerticalId": 1500, "partnerSubVerticalId": 1610, "policy": "Block" }
]
}
For each {partnerVerticalId, partnerSubVerticalId} pair, the server looks up the row in the vertical mapping scoped to your platform_parent_account_id and resolves it to a Rokt vertical_id. The mapping is many-to-one: multiple partner pairs can legitimately resolve to the same Rokt vertical, and that's fine — your taxonomy is finer-grained or coarser-grained than Rokt's, and we preserve fidelity by storing both sides.
your taxonomy vertical mapping rokt taxonomy
{ 1500, 1610 } ─────translate────▶ parent_account_id=<your-platform-parent-account-id> ───▶ → Rokt internal mapping (not returned to partners)
{ 1500, 1611 } ─────translate────▶ parent_account_id=<your-platform-parent-account-id> ───▶ → Rokt internal mapping (not returned to partners)
{ 1502, 1620 } ─────translate────▶ parent_account_id=<your-platform-parent-account-id> ───▶ → Rokt internal mapping (not returned to partners)
Missing mapping = atomic 400Direct link to Missing mapping = atomic 400
If any pair in your blockedVerticals array has no corresponding row in the vertical mapping, the whole request rejects with 400. There are no partial writes — the request is atomic.
{
"status": 400,
"error": "BadRequest",
"message": "No partnership vertical mapping exists for MCL translation",
"request_id": "req_01HX9F2J7M3K8N5VYBQZP4R6T2",
"data": null
}
Send your full taxonomy before launch, not after. Email smb-partnerships@rokt.com the exhaustive list of category/sub-category IDs and names used anywhere in your merchant network — every {sub_vertical_id, name} pair, not just the ones you expect to launch with. Why exhaustive: any merchant registered under an ID that wasn't mapped fails registration with a vertical-mapping 400, and merchants on unmapped categories would fall outside the brand-safety controls configured for your network. Rokt handles the Rokt-side mapping internally and confirms when the rows are live. Mapping rows are added out-of-band before launch — there's no self-serve mapping route in the API.
You can surface a 400 safely without committing by using dry_run=true — useful in your onboarding UI to validate a merchant's category selection before the real save.
Reverse translation (on GET)Direct link to Reverse translation (on GET)
When you GET marketplace controls, the response is expressed in your taxonomy's IDs, not Rokt's. translated_verticals carries each mapped sub-vertical's effective policy, keyed by your sub-vertical ID (vertical_id):
{
"account_id": "<your-account-id>",
"marketplace_controls_list": {
"marketplace_controls_list_id": "8c8e1c12-...",
"domains": [],
"content_hash": "h_abc123"
},
"translated_verticals": [
{
"vertical_id": 1610,
"policy": "Block",
"position_1_policy": "Block"
},
{
"vertical_id": 1611,
"policy": "Allow",
"position_1_policy": "Allow"
}
]
}
Use translated_verticals in your UI — your end users think in their taxonomy. vertical_id is your sub-vertical ID (the partnerSubVerticalId you send on PUT); Rokt's internal IDs never appear in the response.
translated_verticals returns one entry per mapping row in your taxonomy with its effective policy — including sub-verticals you didn't send on the PUT (they show as their current effective state). If many of your sub-verticals map to the same Rokt vertical, you still see one entry per sub-vertical — no information loss across the round-trip.
Walkthrough: full round-tripDirect link to Walkthrough: full round-trip
- PUT with a partner-taxonomy pair
curl -X PUT https://accounts.rokt.com/v1/partnership/accounts/<your-account-id>/marketplacecontrolslists \
-H "Authorization: Bearer $ROKT_TOKEN" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{
"name": "Acme Network Controls",
"blockedVerticals": [
{"partnerVerticalId": 1500, "partnerSubVerticalId": 1610, "policy": "Block", "position1Policy": "Block"}
],
"domains": []
}'Server resolves
{1500, 1610}→rokt_vertical_id: 42, persists both, returns200. - GET the controls back
curl https://accounts.rokt.com/v1/partnership/accounts/<your-account-id>/marketplacecontrolslists \
-H "Authorization: Bearer $ROKT_TOKEN" - Observe the translation round-trip
The response carries:
translated_verticals[].vertical_id = 1610(your sub-vertical ID — thepartnerSubVerticalIdyou sent)translated_verticals[].policy = "Block"andposition_1_policy = "Block"(the effective state the server persisted)
Rokt's internal vertical IDs stay server-side. Render
translated_verticalsin your dashboard — the merchant sees the categories they understand.
Pre-flight checklist before launchDirect link to Pre-flight checklist before launch
- You've sent smb-partnerships@rokt.com your complete category/sub-category list — every
{sub_vertical_id, name}pair in use anywhere in your merchant network — and Rokt has confirmed the mappings are live. - Your onboarding UI surfaces only mapped partner verticals (or uses
dry_run=trueto validate before letting the merchant save). - Your dashboard renders from
translated_verticals. - You have an internal owner who owns the partner-side taxonomy and emails smb-partnerships the updated full list when it changes.