SET Semantics
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.
PUT on Controls and Status routes replaces the full state. There is no merge, no diff, no PATCH. The single most common integration bug we see is partners treating PUT as an incremental update. Read this page before you touch putMarketplaceControls or putPartnershipStatus.
PUT replaces. If you send blockedVerticals: [{partnerVerticalId: 1500, ...}], only that one vertical is blocked. Any vertical you previously had blocked and didn't include is now allowed. Same for domains. Always GET → modify → PUT the full list.
Why PUT replacesDirect link to Why PUT replaces
A PUT says "this is the merchant's complete desired control state right now." The server reconciles its stored state to match yours. Anything not in your request body is, by definition, not in the desired state — so it's removed.
The correct workflow is always:
GET /…/marketplacecontrolslists ──▶ current full list + contentHash
│
▼
modify locally (add/remove/change)
│
▼
PUT /…/marketplacecontrolslists ──▶ send the full modified list
Wrong vs rightDirect link to Wrong vs right
A merchant currently has verticals 1500 and 1502 blocked. The partner wants to add a block on 1504.
- wrong.json
- right.json
{
"name": "Acme Network Controls",
"blockedVerticals": [
{ "partnerVerticalId": 1504, "partnerSubVerticalId": 1612, "policy": "Block" }
]
}
{
"name": "Acme Network Controls",
"blockedVerticals": [
{ "partnerVerticalId": 1500, "partnerSubVerticalId": 1610, "policy": "Block" },
{ "partnerVerticalId": 1502, "partnerSubVerticalId": 1620, "policy": "Block" },
{ "partnerVerticalId": 1504, "partnerSubVerticalId": 1612, "policy": "Block" }
],
"contentHash": "h_abc123"
}
wrong.json unblocks 1500 and 1502. The server faithfully replaces state with what you sent. There is no error, no warning — the merchant just wakes up tomorrow with two formerly-blocked categories now live.
right.json does what the partner intended: adds 1504 to the blocked set, preserves 1500 and 1502, includes the contentHash from the prior GET for optimistic-concurrency safety.
Endpoints that follow SET semanticsDirect link to Endpoints that follow SET semantics
| Endpoint | What's SET |
|---|---|
PUT /v1/partnership/accounts/{account_id}/marketplacecontrolslists | blockedVerticals, domains |
PUT /v1/partnership/accounts/{account_id}/status | the active/paused state across every non-archived variant |
For status: PUT status=paused pauses every non-archived page variant. There is no "pause only variant X" — that would be a partial state, which the SET model forbids. If you need per-variant control, that's not in the Partnerships API surface today.
Optimistic concurrency with contentHashDirect link to optimistic-concurrency-with-contenthash
Every GET response includes a contentHash. Pass it back as the contentHash field of your PUT to safely detect concurrent edits — if another caller (or a Rokt-side admin tool) updated the row between your GET and PUT, the server rejects the PUT with a conflict. Without contentHash, last-write-wins.
{
"name": "Acme Network Controls",
"blockedVerticals": [...],
"contentHash": "h_abc123"
}
Use this when:
- Multiple humans in your dashboard could edit the same merchant simultaneously.
- A long-running batch job and a real-time UI might race on the same account.
Skip it when:
- You're scripting a one-shot migration with a single writer.
Walkthrough: add a domain blockDirect link to Walkthrough: add a domain block
- GET the current MCL state
curl https://accounts.rokt.com/v1/partnership/accounts/<your-account-id>/marketplacecontrolslists \
-H "Authorization: Bearer $ROKT_TOKEN"Response (abbreviated):
{
"name": "Acme Network Controls",
"blockedVerticals": [
{ "partnerVerticalId": 1500, "partnerSubVerticalId": 1610, "policy": "Block" }
],
"domains": [
{ "domain": "competitor.example.com", "policy": "Block" }
],
"contentHash": "h_abc123"
} - Append the new domain block locally
Add
{ "domain": "competitor-two.example.com", "policy": "Block" }to thedomainsarray. Keep everything else. - PUT the FULL modified state back
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"}
],
"domains": [
{"domain": "competitor.example.com", "policy": "Block"},
{"domain": "competitor-two.example.com", "policy": "Block"}
],
"contentHash": "h_abc123"
}'Both domains are now blocked. The vertical block on 1500/1610 is preserved because you sent it.