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:This vertical isn't mapped yet (vertical_id=1500, sub_vertical_id=1610). Contact smb-partnerships@rokt.com to have it mapped.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; creating rows is 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.
Reading the result back is partner-callable. GET /v1/partnership/vertical-mappings returns every row seeded for your parent account, so you can verify seeding landed instead of taking the confirmation email on faith. See Check what's mapped.
Check what's mappedDirect link to Check what's mapped
GET /v1/partnership/vertical-mappings returns every mapping row seeded for your parent account, in your taxonomy. Call it before your first register call, and again whenever you add categories on your side.
curl "https://accounts.rokt.com/v1/partnership/vertical-mappings?parent_account_id=$PARENT" \
-H "Authorization: Bearer $ROKT_TOKEN"
{
"status": 200,
"error": null,
"message": "ok",
"request_id": "0e3a1b9c-...",
"data": {
"vertical_mappings": [
{
"partner_vertical_id": 1500,
"partner_vertical_name": "Apparel",
"partner_sub_vertical_id": 1610,
"partner_sub_vertical_name": "Womenswear",
"vertical_name": "Retail",
"created_at": "2026-07-01T00:00:00Z"
},
{
"partner_vertical_id": 1500,
"partner_vertical_name": "Apparel",
"partner_sub_vertical_id": 1611,
"partner_sub_vertical_name": "Menswear",
"vertical_name": "Retail",
"created_at": "2026-07-01T00:00:00Z"
}
]
}
}
Any pair in this list is safe to send on register and on the marketplace-controls PUT. Anything absent returns a 400 on both.
- Rows are ordered by
partner_vertical_id, thenpartner_sub_vertical_id. - No pagination. The whole set comes back at once.
vertical_nameis the only Rokt-side field. Display only; no endpoint takes it as input.- Auth is the same
parent_account_idgrant asGET /v1/partnership/accounts. You cannot read another platform's mappings.
{ "data": { "vertical_mappings": [] } }
Nothing is mapped, so every register call fails with a 400. Check this first when a new integration can't register anything.
Email smb-partnerships@rokt.com your complete category list and wait for confirmation. Don't substitute a category the merchant isn't in to get past it.
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 vertical mapping found for the following partner vertical(s): (partner_vertical_id=1500, partner_sub_vertical_id=1610). Call GET /v1/partnership/vertical-mappings to see which verticals are currently mapped, and contact smb-partnerships@rokt.com to request additions. The MCL write was rejected atomically; no partial update was applied.",
"request_id": "req_01HX9F2J7M3K8N5VYBQZP4R6T2",
"data": null
}
The message names every unmapped pair, not just the first, so you can diff the whole set against what's mapped in one pass instead of bisecting your array.
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. Adding rows stays out-of-band; there's no self-serve creation route in the API, though you can read the current state any time. See Check what's mapped.
You can surface a 400 safely without committing by using dry_run=true. This is 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; there is 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. - You've called
GET /v1/partnership/vertical-mappingsagainst your parent account and the returned set covers every category you'll register merchants under. A non-empty response is the only real confirmation that seeding landed. See Check what's mapped. - 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.