Channels
Introduction
Since version 3.0, Saleor has supported multiple sales channels. This feature allows the shop owner to configure many aspects of the store depending on the channel used.
- Your store needs at least one channel to display products
- You can add as many channels as you need
- Each channel has precisely one currency
- Channels can be deactivated for customers
Popular use cases:
- If you sell internationally, you can use separate channels for different currencies or regions
- If you want to have different prices in the custom mobile app and website, you can set up
website-channel
andmobile-channel
There are many models you can customize per channel. The details of which fields you can define on a per-channel basis are described in the ChannelListing
models:
Many Saleor Apps allow to configure them per-channel. We recommend to allow it for the best flexibility.
Permissions
Listing channels is allowed only for users with the active isStaff
flag.
You need the MANAGE_CHANNELS
permission to create, edit, and remove channels.
Changing ChannelListing
does not require additional permissions. For example, changing Product availability requires only MANAGE_PRODUCTS
permission.
Objects with customized per-channel visibility are restricted by channel permissions. If a user with restricted channel access fetches per-channel objects, only objects from accessible channels will be returned. You can read more about channel permissions here.
Getting channel details
Use channel
query to get channel details.
Channel query requires channel ID, but from Saleor 3.6 it can be executed with channel slug too.
Available fields:
id
: Channel object IDname
: Channel nameisActive
: Flag signalling that the channel is available for shop customers.slug
: When using channel-dependant queries, the slug is used to select the right one (for example, when requesting Product details)currencyCode
: Currency code used by the channel.defaultCountry
: Default country for the channel. The default country will be used in checkout to determine the stock quantities or calculate taxes when the country was not explicitly provided, either as a query parameter or through a shipping address.hasOrders
: Returnstrue
when there are already created orders using that channel. If that's the only channel using this currency, you won't be able to remove it.warehouses
: Warehouses that are available in the given channel.stockSettings
: contains all stock-related settings, f.e. the allocation strategy for the channel.
Request:
query {
channel(slug: "mobile") {
id
isActive
name
slug
defaultCountry {
code
country
}
hasOrders
warehouses {
slug
}
stockSettings {
allocationStrategy
}
}
}
Response:
{
"data": {
"channel": {
"id": "Q2hhbm5lbDo0MzM=",
"isActive": false,
"name": "Mobile",
"slug": "mobile",
"currencyCode": "USD",
"defaultCountry": {
"code": "US",
"country": "United States of America"
},
"hasOrders": false,
"warehouses": [
{
"slug": "oceania"
},
{
"slug": "europe"
}
],
"stockSettings": {
"allocationStrategy": "PRIORITIZE_HIGH_STOCK"
}
}
}
Creating a new channel
You can create a new channel using channelCreate
mutation.
During checkout creation, you can define the allocation strategy. Right now the
two possible options are available: PRIORITIZE_HIGH_STOCK
and PRIORITIZE_SORTING_ORDER
,
the PRIORITIZE_SORTING_ORDER
strategy is used as default.
You can read more about the allocation strategies here
.
Request:
mutation {
channelCreate(
input: {
currencyCode: "USD"
defaultCountry: US
name: "Mobile"
slug: "mobile"
stockSettings: { allocationStrategy: PRIORITIZE_HIGH_STOCK }
}
) {
channel {
id
isActive
name
slug
currencyCode
defaultCountry {
code
country
}
stockSettings {
allocationStrategy
}
}
errors {
code
field
message
}
}
}
Response:
{
"data": {
"channelCreate": {
"channel": {
"id": "Q2hhbm5lbDo0MzM=",
"isActive": false,
"name": "Mobile",
"slug": "mobile",
"currencyCode": "USD",
"defaultCountry": {
"code": "US",
"country": "United States of America"
},
"stockSettings": {
"allocationStrategy": "PRIORITIZE_HIGH_STOCK"
}
},
"errors": []
}
}
}
Channel list
Because some of the channels may be considered non-public (for example - a channel for business partners), non-staff users cannot use the channels
query.
Request:
query {
channels {
name
}
}
Response:
{
"data": {
"channels": [
{
"name": "Mobile"
},
{
"name": "Website"
}
]
}
}
Activate / Deactivate channel
If you want to make the channel unavailable for customers, you can change it's status to deactivated
using channelDeactivate
mutation:
mutation {
channelDeactivate(slug: "default-channel") {
channel {
name
isActive
}
errors {
message
}
}
}
Response:
{
"data": {
"channelDeactivate": {
"channel": {
"name": "Facebook",
"isActive": false
},
"channelErrors": []
}
}
}
And to reverse the previous operation use the channelActivate
mutation:
mutation {
channelActivate(slug: "default-channel") {
channel {
name
isActive
}
errors {
message
}
}
}
Response:
{
"data": {
"channelDeactivate": {
"channel": {
"name": "Facebook",
"isActive": true
},
"channelErrors": []
}
}
}
Reorder warehouses within channels
The warehouses assigned to the channel can be sorted. The provided order defines the
warehouses' order used in PRIORITIZE_SORTING_ORDER
allocation strategy.
The sort_order
in moves
input represents the new relative position of the item.
So when 1 is provided, the item will be moved one position forward; when -1 - one
position backward.
Let's assume that we have a channel
with three channels in the following order.
{
"data": {
"channel": {
"id": "Q2hhbm5lbDox",
"warehouses": [
{
"id": "V2FyZWhvdXNlOjU1NTZiOWI0LTc1ZTItNGI3YS1hZWM1LTQxOTY4NDA2OGE4OA==",
"slug": "europe"
},
{
"id": "V2FyZWhvdXNlOjQwZWY1MTQwLWQ5OTYtNDVlNy04NzUzLTlkZThkMTdhMjg1Yw==",
"slug": "oceania"
},
{
"id": "V2FyZWhvdXNlOjY4M2FkMzZhLTRmNjktNDI2ZS1iYzUyLTMyZGJiZTQ2NjUyZA==",
"slug": "americas"
}
]
}
}
}
To move the americas
warehouse to the first place and the europe
warehouse to
third, we can run the following mutation.
mutation {
channelReorderWarehouses(
channelId: "Q2hhbm5lbDox"
moves: [
{
# move for `americas` warehouse
id: "V2FyZWhvdXNlOjY4M2FkMzZhLTRmNjktNDI2ZS1iYzUyLTMyZGJiZTQ2NjUyZA=="
sortOrder: -2
}
{
# move for `europe` warehouse
id: "V2FyZWhvdXNlOjU1NTZiOWI0LTc1ZTItNGI3YS1hZWM1LTQxOTY4NDA2OGE4OA=="
sortOrder: 1
}
]
) {
channel {
id
warehouses {
id
slug
}
}
errors {
field
code
message
warehouses
}
}
}
And as a response, we get:
{
"data": {
"channelReorderWarehouses": {
"channel": {
"id": "Q2hhbm5lbDox",
"warehouses": [
{
"id": "V2FyZWhvdXNlOjY4M2FkMzZhLTRmNjktNDI2ZS1iYzUyLTMyZGJiZTQ2NjUyZA==",
"slug": "americas"
},
{
"id": "V2FyZWhvdXNlOjQwZWY1MTQwLWQ5OTYtNDVlNy04NzUzLTlkZThkMTdhMjg1Yw==",
"slug": "oceania"
},
{
"id": "V2FyZWhvdXNlOjU1NTZiOWI0LTc1ZTItNGI3YS1hZWM1LTQxOTY4NDA2OGE4OA==",
"slug": "europe"
}
]
},
"errors": []
}
}
}
Removing a channel
Channels can be removed only when:
- There are no orders created in them.
- If there are orders created,
targetChannel
is required. Its currency has to be the same as the channel you are about to delete. All orders will be moved totargetChannel
.
channelDelete
mutation takes input:
id
: ID of the Channel that will be deletedchannelId
: all existing orders will be moved into this channel
channelDelete(
id: ID!
input: ChannelDeleteInput
): ChannelDelete
input ChannelDeleteInput {
channelId: ID! # ID of the channel to migrate orders from origin channel.
}
Errors
type ChannelError {
field: String
message: String
code: ChannelErrorCode!
}
enum ChannelErrorCode {
ALREADY_EXISTS
GRAPHQL_ERROR
INVALID
NOT_FOUND
REQUIRED
UNIQUE
CHANNEL_TARGET_ID_MUST_BE_DIFFERENT
CHANNELS_CURRENCY_MUST_BE_THE_SAME
}
ChannelErrorCode
values:
ALREADY_EXISTS
: Object already exists in the databaseGRAPHQL_ERROR
: Wrong queryINVALID
: Invalid data providedNOT_FOUND
: Could not found objectREQUIRED
: Missing required fieldsUNIQUE
: Provided value for field needs to be uniqueCHANNEL_TARGET_ID_MUST_BE_DIFFERENT
: Cannot move orders into the channel you want to deleteCHANNELS_CURRENCY_MUST_BE_THE_SAME
: Target channel has to have the same currency