Channels
A channel is a route to market: a webshop, a punch-out catalogue, a feed, a kiosk. It is the second scoping axis after markets, and what it decides is assortment visibility.
Base path: https://api.revenexx.com/v1/channels.
Channel types
A type is what lets a merchant name a kind of channel this app never thought of, without waiting for a release.
curl -X POST https://api.revenexx.com/v1/channels/types \
-H "X-Revenexx-Tenant: <TENANT_SLUG>" \
-H "X-Revenexx-Api-Key: rvxk_..." \
-H "Content-Type: application/json" \
-d '{"code":"kiosk","title":"Kiosk","position":40}'
code and title are the only two required. The code is trimmed, lowercased and fixed from then on — it becomes exactly what channels.type stores, and there is no foreign key behind that column to carry a rename, so every channel holding the old string would be left pointing at nothing. title is the part a merchant renames later.
Two things worth knowing about the 409:
- The uniqueness is wider than your tenant. The code is unique on the column alone, so a code held by another tenant collides too — and the read this route does before inserting cannot see it.
- A tenant keeps at most 200 types. The 201st is a
409withtype_limit_reached.
Creating a type changes nothing about existing channels: it is a name that becomes available, not one that gets applied. It does not become the default either — pass is_default: true for that, which demotes the current holder.
Channels
curl -X POST https://api.revenexx.com/v1/channels \
-H "X-Revenexx-Tenant: <TENANT_SLUG>" \
-H "X-Revenexx-Api-Key: rvxk_..." \
-H "Content-Type: application/json" \
-d '{"code":"punchout","name":"Punch-out catalogue","type":"punchout","unassigned_visibility":"assigned_only"}'
| Field | Meaning |
|---|---|
code | Stable identifier, and what a caller names to select the channel. |
name, labels | Display name and localized names. |
type | One of the tenant's channel type codes. |
status | active or inactive. |
is_default | The channel a caller naming none falls back to. |
unassigned_visibility | inherit (use the tenant answer), all, or assigned_only. |
position | Sort order, and the tie-break when more than one channel claims default. |
POST /v1/channels/defaults restores the shipped defaults.
The bootstrap
curl "https://api.revenexx.com/v1/channels/context?channel=punchout" \
-H "X-Revenexx-Tenant: <TENANT_SLUG>" \
-H "X-Revenexx-Api-Key: rvxk_..."
One call tells a shop front, a punch-out front-end or a feed builder which channel it is in and what an unassigned row means there, so it applies the policy itself instead of hard-coding one.
Two things come back, not one: the channel that resolved, and the visibility policy in force for it. The policy travels with the channel because a caller holding one and not the other still cannot render anything — knowing you are in the punch-out channel says nothing about whether an unassigned product belongs in its assortment.
Resolution order
Through the public gateway it is: ?channel=, then the principal's channel claim, then the channel flagged is_default. source in the response names which of them answered.
api.revenexx.com the header step is inert because the gateway does not forward it. Use the query parameter.It never errors on an unknown channel
That is deliberate, and it is why this operation declares no 4xx of its own. An unknown or inactive channel answers 200 with resolved: false and a reason, so a caller can tell no such channel from the service is down:
channel_required no_default_channel unknown_channel channel_inactive
A tenant with no channels at all answers 200 with reason: "no_default_channel". default_ambiguous says when more than one channel claims the flag — the lowest position wins.
The visibility gate
curl -X POST https://api.revenexx.com/v1/channels/visibility \
-H "X-Revenexx-Tenant: <TENANT_SLUG>" \
-H "X-Revenexx-Api-Key: rvxk_..." \
-H "Content-Type: application/json" \
-d '{
"channel": "punchout",
"items": [
{ "id": "…", "channels": ["webshop"] },
{ "id": "…", "channels": [] }
]
}'
Two cases, and only one of them needs a policy:
- A row with channel assignments is visible if and only if the active channel is among them. No configuration involved.
- A row without assignments is the case
unassigned_channel_visibilityowns:allshows it,assigned_onlyhides it.
A channel may override the tenant answer for itself, through its own unassigned_visibility. That is how the webshop stays open while a punch-out channel serves only its negotiated assortment.
assigned_only on that channel — do not rely on the assignment absence.The same asymmetry applies to markets: a row created without X-Revenexx-Market is unassigned, and unassigned is visible everywhere. See Settings.
Where channels show up elsewhere
| Place | Effect |
|---|---|
A product attribute marked scopable | One value per channel, in attribute_values.channel_specific — see Products. |
family_attributes.required_channels | Narrows a required attribute to named channels. |
| A channel-scoped price list | Specificity level 2 in the price resolution order. |
carts.channel_id, orders.channel_id | Which channel the buying happened in. |
Where to go next
- Markets — the other scoping axis.
- Price lists — channel-scoped pricing.
- Products — channel-scoped attribute values.