Skip to main content

Updating Marketplace Controls

Audience

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.

This recipe covers ongoing edits to marketplace controls on an already-onboarded merchant.

warning

Verticals merge; domains replace. Send only the verticals whose policy you are changing; the rest keep their stored policy. To unblock a vertical, send it with policy: "Allow" — omitting it does nothing. domains is different: send the full list every time, because anything you omit is removed. See Update Semantics.

  1. GET the current state

    Do this unless you know the merchant has no domain rules. Verticals merge, so you do not need the current vertical list, but domains replaces and omitting it clears whatever is stored.

    curl https://accounts.rokt.com/v1/partnership/accounts/<your-account-id>/marketplacecontrolslists \
    -H "Authorization: Bearer $TOKEN" \
    -H "X-Platform-Parent-Account-Id: $PARENT"
    {
    "status": 200,
    "error": null,
    "message": "ok",
    "request_id": "0e3a1b9c-...",
    "data": {
    "account_id": "<your-account-id>",
    "marketplace_controls_list": {
    "marketplace_controls_list_id": "8c6f2a1e-...",
    "domains": [ { "domain": "competitor.example.com", "policy": "Block" } ],
    "content_hash": "v7-1a9e3f4c"
    },
    "translated_verticals": [
    { "vertical_id": 1610, "policy": "Block", "position_1_policy": "Block" },
    { "vertical_id": 1611, "policy": "Allow", "position_1_policy": "Allow" }
    ]
    }
    }

    translated_verticals carries the effective policy for every sub-vertical mapped in your taxonomy; vertical_id is your sub-vertical ID, not a Rokt ID.

  2. Build the request body

    Include only the verticals you are changing. Include the full domain list if you are touching domains at all.

    const envelope = await getMcl(accountId); // the GET above
    const current = envelope.data; // unwrap the envelope

    const next = {
    name: "Acme Network Controls",
    // Only the vertical being changed. Everything else keeps its stored policy.
    blockedVerticals: [
    { partnerVerticalId: 1500, partnerSubVerticalId: 1612, policy: "Block", position1Policy: "Block" },
    ],
    // Domains replace, so send the full list from the GET.
    domains: current.marketplace_controls_list.domains,
    };

    To unblock instead, send the same entry with policy: "Allow".

  3. PUT the change
    curl -X PUT https://accounts.rokt.com/v1/partnership/accounts/<your-account-id>/marketplacecontrolslists \
    -H "Authorization: Bearer $TOKEN" \
    -H "X-Platform-Parent-Account-Id: $PARENT" \
    -H "Content-Type: application/json" \
    -H "Idempotency-Key: $(uuidgen)" \
    -d @next.json
  4. Optionally dry-run first

    Append ?dry_run=true to validate the payload (full validation and taxonomy translation) without committing. No state is persisted.

    curl -X PUT 'https://accounts.rokt.com/v1/partnership/accounts/<your-account-id>/marketplacecontrolslists?dry_run=true' \
    -H "Authorization: Bearer $TOKEN" \
    -H "X-Platform-Parent-Account-Id: $PARENT" \
    -H "Content-Type: application/json" \
    -H "Idempotency-Key: $(uuidgen)" \
    -d @next.json

    When you re-call without dry_run for the real write, use a fresh Idempotency-Key. The dry-run key is now cached. See Dry-Run Mode.

  5. Verify

    GET again and confirm the change landed, your previous blocks are still there, and domains is what you expect.

    curl https://accounts.rokt.com/v1/partnership/accounts/<your-account-id>/marketplacecontrolslists \
    -H "Authorization: Bearer $TOKEN" \
    -H "X-Platform-Parent-Account-Id: $PARENT"

Common gotchasDirect link to Common gotchas

I sent a vertical with policy Allow and nothing happened

Check the pair. A vertical is identified by {partnerVerticalId, partnerSubVerticalId} together, and the merge is keyed on the sub-vertical. If the sub-vertical ID doesn't match the one that is currently blocked, you have added an Allow for a different vertical rather than lifting the block you meant.

GET .../marketplacecontrolslists returns translated_verticals with the sub-vertical IDs currently in effect, as vertical_id. Use those as your partnerSubVerticalId. That call does not return the parent partnerVerticalId, so take it from your own taxonomy or from GET /v1/partnership/vertical-mappings.

I only changed verticals and my domain blocks disappeared

Domains replace. Omitting domains from the body is the same as sending [], which clears the list. Always carry the current domains array through from your GET, even on a vertical-only change.

I want to lift several blocks at once

There is no bulk clear. blockedVerticals: [] is a no-op, not a reset. Send one Allow entry per vertical.

It takes two GETs to assemble that list, because each PUT entry needs partnerVerticalId and partnerSubVerticalId while the controls GET only gives you the sub-vertical:

  1. GET .../marketplacecontrolslists and collect every translated_verticals entry whose policy is Block. Each vertical_id is a partnerSubVerticalId.
  2. GET /v1/partnership/vertical-mappings?parent_account_id=<your-parent> and join on partner_sub_vertical_id to recover each partner_vertical_id.
  3. PUT one entry per vertical with both IDs, policy: "Allow" and position1Policy: "Allow".

If you already hold your own parent-to-sub taxonomy, skip step 2 and use it directly.

PUT returns 503 ServiceUnavailable
{
"status": 503,
"error": "ServiceUnavailable",
"message": "Internal error. Contact support with your request_id.",
"request_id": "0e3a1b9c-..."
}

One cause is specific to controls: the server could not read the merchant's stored policy, so it rejected the write rather than overwrite it from an incomplete picture. Nothing was changed. The response body is deliberately generic on any 5xx, so it will not tell you which cause applied.

Retry with the same Idempotency-Key; a 503 is classified transient and will re-execute, up to three retries per key. Beyond that the cached failure is replayed for the rest of the 24-hour window, so a further attempt needs a fresh key. If it persists, contact smb-partnerships@rokt.com with the request_id.

Server returns 400: 'No vertical mapping found for the following partner vertical(s)'

One or more of your partnerVerticalId / partnerSubVerticalId pairs isn't in Rokt's vertical mapping table. The PUT is rejected atomically: no partial writes.

The message names every unmapped pair, so you can fix them in one pass:

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.

Resolution: call GET /v1/partnership/vertical-mappings?parent_account_id=<your-parent> to see the current set (see Check what's mapped), then email smb-partnerships@rokt.com with the unmapped IDs and we'll add the rows. Meanwhile, omit the unmapped verticals from your PUT.

Was this article helpful?
Last updated Sep 1, 2026