Channel management
28 routes. Paths are relative to https://api.intersink.com/v1.
- GET/channelFetch my channels
- POST/channelCreate My Channel
- GET/channel/{channelId}/config/entriesSettings › App config: names, visibility, public values (managers)
- PUT/channel/{channelId}/config/entries/{name}Add or replace an entry: { value, visibility: public|secret }
- DELETE/channel/{channelId}/config/entries/{name}Remove an entry
- GET/channel/{channelId}/statsA channel's numbers for a period: orders, revenue by currency, new customers, leads
- GET/channel/{id}Fetch my single channel
- PATCH/channel/{id}Update my channel
- GET/channel/{id}/allowed-originsWeb origins this channel's browser apps may call the API from
- POST/channel/{id}/allowed-originsAdd an origin (https://host[:port], or http://localhost:* for development)
- DELETE/channel/{id}/allowed-originsRemove an origin (?origin=, or body { origin })
- PUT/channel/{id}/allowed-origins/credentialsTurn credentialed CORS (cookies) on or off for this channel's origins
- POST/channel/{id}/archiveArchive a channel (owner only). Channels are never deleted.
- GET/channel/{id}/booking-typesThe channel's calendar booking types, for every member (no settings access needed)
- GET/channel/{id}/domainsCustom domains of a channel with their TXT challenge
- POST/channel/{id}/domainsAdd a custom domain; returns the TXT record to create
- DELETE/channel/{id}/domains/{domainId}Remove a domain (archived, never deleted)
- POST/channel/{id}/domains/{domainId}/verifyCheck the TXT record in DNS and mark the domain verified
- GET/channel/{id}/settingsChannel settings (all sections, or ?section=)
- PATCH/channel/{id}/settingsChange keys of one settings section (schema-validated)
- GET/channel/app-configPublic: everything an app needs at start from its app key
- GET/channel/configServer: every config entry of the key's channel, secrets included (NAME → value)
- GET/channel/domain-challengeServer: the value the channel's site serves at /.well-known/kodkila-challenge for a host
- GET/channel/key-infoPublic: the channel an app key belongs to
- GET/channel/meServer: the channel a secret API key belongs to, with the key's mode and scopes
- GET/channel/publicPublic: Fetch a published channel by exact domain or id (Query Param)
- GET/channel/public/domain/{domain}Public: Fetch a published channel by exact domain or id (Route Param)
- GET/channel/resolvePublic: resolve the channel serving a hostname
Fetch my channels
GET/channel
Needs a signed-in user (Bearer token or access_token cookie).
The channels of the active business. has_app=true keeps the channels with a mobile app (a live or test publishable app key that is not revoked or expired, an app-updates setup, or APNs/FCM push credentials); has_app=false keeps the others. With the filter, each channel also carries has_app, and archived channels are left out unless include_archived=true. Both take exactly true or false, once; anything else is a 400.
Parameters
| Name | Type | Description |
|---|---|---|
| include_archived | string, query | One of: "true", "false". |
| has_app | string, query | One of: "true", "false". |
Response
200. The payload in data is not described in the spec yet. Channels list returned
Create My Channel
POST/channel
Needs a signed-in user (Bearer token or access_token cookie).
Request body application/json
| Field | Type | Description |
|---|---|---|
| titlerequired | string | Example: "My Online Store" |
| description | string | Example: "Official channel for our business" |
| trademark_id | number | Id of a trademark registered to a business you manage Minimum 1. Example: 3 |
| category_id | string | Example: "uuid-of-category" |
| business_id | string | Example: "uuid-of-business" |
| link | string | Example: "https://mywebsite.com" |
| keywords | string | Example: "keyword1, keyword2" |
Response
201. The payload in data is not described in the spec yet. Channel created successfully
Settings › App config: names, visibility, public values (managers)
GET/channel/{channelId}/config/entries
Needs a signed-in user (Bearer token or access_token cookie).
Parameters
| Name | Type | Description |
|---|---|---|
| channelIdrequired | string, path |
Response
200. The payload in data is not described in the spec yet.
Add or replace an entry: { value, visibility: public|secret }
PUT/channel/{channelId}/config/entries/{name}
Needs a signed-in user (Bearer token or access_token cookie).
Parameters
| Name | Type | Description |
|---|---|---|
| channelIdrequired | string, path | |
| namerequired | string, path |
Response
200. The payload in data is not described in the spec yet.
Remove an entry
DELETE/channel/{channelId}/config/entries/{name}
Needs a signed-in user (Bearer token or access_token cookie).
Parameters
| Name | Type | Description |
|---|---|---|
| channelIdrequired | string, path | |
| namerequired | string, path |
Response
200. The payload in data is not described in the spec yet.
A channel's numbers for a period: orders, revenue by currency, new customers, leads
GET/channel/{channelId}/stats
Needs a signed-in user (Bearer token or access_token cookie).
Channel managers (owner, admins, managers, business admins), or the channel's own server key with orders:read. Every figure is a database aggregate, so it is cheap at any size: use it for dashboards instead of paging /orders/seller. Revenue sums order totals per currency and leaves cancelled orders out. previous is the window of the same length just before.
Parameters
| Name | Type | Description |
|---|---|---|
| channelIdrequired | string, path | |
| period | string, query | today: start of today in tz until now. 7d / 30d: today and the 6 / 29 days before. custom: from to to (dates, both days included, at most 366 days). One of: "today", "7d", "30d", "custom". |
| from | string, query | period=custom: first day (YYYY-MM-DD in tz) or an ISO date-time At most 40 characters. Example: "2026-10-01" |
| to | string, query | period=custom: last day, included (YYYY-MM-DD in tz) or an ISO date-time (excluded) At most 40 characters. Example: "2026-10-31" |
| tz | string, query | IANA time zone the days are counted in At most 64 characters. Example: "Europe/London" |
Response
200. data is object (ChannelStatsDto).
| Field | Type | Description |
|---|---|---|
| channel_idrequired | string (uuid) | |
| periodrequired | object | |
| period.keyrequired | string | One of: "today", "7d", "30d", "custom". Example: "7d" |
| period.fromrequired | string (date-time) | Included Example: "2026-10-25T23:00:00.000Z" |
| period.torequired | string (date-time) | Excluded Example: "2026-11-01T10:30:00.000Z" |
| period.tzrequired | string | Example: "Europe/London" |
| currencyrequired | string | The channel's currency (Settings › General; GBP when unset) Example: "GBP" |
| ordersrequired | object | |
| orders.countrequired | number | Orders placed in the period, cancelled ones included Example: 42 |
| orders.cancelledrequired | number | Of those, cancelled now Example: 3 |
| revenuerequired | object[] | Revenue grouped by currency, the channel's own first. Empty when nothing was sold. |
| revenue[].currencyrequired | string | Example: "GBP" |
| revenue[].amountrequired | number | Sum of order totals in major units: paid (card payment succeeded) or delivered orders only. Cancelled and refunded orders are left out, never subtracted Example: 1234.5 |
| revenue[].amount_minorrequired | number | The same in minor units (pence, cents) Example: 123450 |
| revenue[].ordersrequired | number | Paid or delivered orders counted in this currency Example: 39 |
| buyersrequired | number | Distinct signed-in buyers who ordered in the period Example: 30 |
| new_customersrequired | number | Accounts that signed up on this channel in the period Example: 12 |
| leadsrequired | object | |
| leads.openrequired | number | CRM deals open now (not bound to the period) Example: 16 |
| leads.newrequired | number | CRM contacts (leads) created in the period Example: 5 |
| previousrequired | object | The window of the same length just before, for comparisons |
| previous.fromrequired | string (date-time) | |
| previous.torequired | string (date-time) | |
| previous.ordersrequired | object | |
| previous.orders.countrequired | number | Orders placed in the period, cancelled ones included Example: 42 |
| previous.orders.cancelledrequired | number | Of those, cancelled now Example: 3 |
| previous.revenuerequired | object[] | |
| previous.revenue[].currencyrequired | string | Example: "GBP" |
| previous.revenue[].amountrequired | number | Sum of order totals in major units: paid (card payment succeeded) or delivered orders only. Cancelled and refunded orders are left out, never subtracted Example: 1234.5 |
| previous.revenue[].amount_minorrequired | number | The same in minor units (pence, cents) Example: 123450 |
| previous.revenue[].ordersrequired | number | Paid or delivered orders counted in this currency Example: 39 |
| previous.new_customersrequired | number | Example: 8 |
| generated_atrequired | string (date-time) |
Fetch my single channel
GET/channel/{id}
Needs a signed-in user (Bearer token or access_token cookie).
Parameters
| Name | Type | Description |
|---|---|---|
| idrequired | string, path |
Response
200. The payload in data is not described in the spec yet. Channel details returned
Update my channel
PATCH/channel/{id}
Needs a signed-in user (Bearer token or access_token cookie).
Parameters
| Name | Type | Description |
|---|---|---|
| idrequired | string, path |
Request body application/json
| Field | Type | Description |
|---|---|---|
| title | string | Example: "My Online Store" |
| description | string | Example: "Official channel for our business" |
| trademark_id | number | Id of a trademark registered to a business you manage Minimum 1. Example: 3 |
| category_id | string | Example: "uuid-of-category" |
| link | string | Example: "https://mywebsite.com" |
| keywords | string | Example: "keyword1, keyword2" |
Response
200. The payload in data is not described in the spec yet. Channel updated successfully
Web origins this channel's browser apps may call the API from
GET/channel/{id}/allowed-origins
Needs a signed-in user (Bearer token or access_token cookie).
Parameters
| Name | Type | Description |
|---|---|---|
| idrequired | string, path |
Response
200. The payload in data is not described in the spec yet.
Add an origin (https://host[:port], or http://localhost:* for development)
POST/channel/{id}/allowed-origins
Needs a signed-in user (Bearer token or access_token cookie).
Parameters
| Name | Type | Description |
|---|---|---|
| idrequired | string, path |
Request body application/json
| Field | Type | Description |
|---|---|---|
| originrequired | string | Example: "https://web.example.com" |
Response
200. The payload in data is not described in the spec yet.
Remove an origin (?origin=, or body { origin })
DELETE/channel/{id}/allowed-origins
Needs a signed-in user (Bearer token or access_token cookie).
Parameters
| Name | Type | Description |
|---|---|---|
| idrequired | string, path | |
| originrequired | string, query |
Response
200. The payload in data is not described in the spec yet.
Turn credentialed CORS (cookies) on or off for this channel's origins
PUT/channel/{id}/allowed-origins/credentials
Needs a signed-in user (Bearer token or access_token cookie).
Parameters
| Name | Type | Description |
|---|---|---|
| idrequired | string, path |
Request body application/json
| Field | Type | Description |
|---|---|---|
| allow_credentialsrequired | boolean | Answer Access-Control-Allow-Credentials for these origins (cookies). Off by default: apps that send a Bearer token don't need it. |
Response
200. The payload in data is not described in the spec yet.
Archive a channel (owner only). Channels are never deleted.
POST/channel/{id}/archive
Needs a signed-in user (Bearer token or access_token cookie).
Parameters
| Name | Type | Description |
|---|---|---|
| idrequired | string, path |
Request body application/json
| Field | Type | Description |
|---|---|---|
| reason | string | At most 500 characters. Example: "Brand retired" |
Response
200. The payload in data is not described in the spec yet.
The channel's calendar booking types, for every member (no settings access needed)
GET/channel/{id}/booking-types
Needs a signed-in user (Bearer token or access_token cookie).
Parameters
| Name | Type | Description |
|---|---|---|
| idrequired | string, path |
Response
200. The payload in data is not described in the spec yet.
Custom domains of a channel with their TXT challenge
GET/channel/{id}/domains
Needs a signed-in user (Bearer token or access_token cookie).
Parameters
| Name | Type | Description |
|---|---|---|
| idrequired | string, path |
Response
200. The payload in data is not described in the spec yet.
Add a custom domain; returns the TXT record to create
POST/channel/{id}/domains
Needs a signed-in user (Bearer token or access_token cookie).
Parameters
| Name | Type | Description |
|---|---|---|
| idrequired | string, path |
Request body application/json
| Field | Type | Description |
|---|---|---|
| domainrequired | string | At most 253 characters. Example: "shop.example.com" |
Response
201. The payload in data is not described in the spec yet.
Remove a domain (archived, never deleted)
DELETE/channel/{id}/domains/{domainId}
Needs a signed-in user (Bearer token or access_token cookie).
Parameters
| Name | Type | Description |
|---|---|---|
| idrequired | string, path | |
| domainIdrequired | string, path |
Response
200. The payload in data is not described in the spec yet.
Check the TXT record in DNS and mark the domain verified
POST/channel/{id}/domains/{domainId}/verify
Needs a signed-in user (Bearer token or access_token cookie).
Parameters
| Name | Type | Description |
|---|---|---|
| idrequired | string, path | |
| domainIdrequired | string, path |
Response
200. The payload in data is not described in the spec yet.
Channel settings (all sections, or ?section=)
GET/channel/{id}/settings
Needs a signed-in user (Bearer token or access_token cookie).
Parameters
| Name | Type | Description |
|---|---|---|
| idrequired | string, path | |
| section | string, query | One of: "general", "channel", "notifications", "languages", "privacy", "protection", "auth", "usernames", "calendar", "branding", "web", "system". |
Response
200. The payload in data is not described in the spec yet.
Change keys of one settings section (schema-validated)
PATCH/channel/{id}/settings
Needs a signed-in user (Bearer token or access_token cookie).
Parameters
| Name | Type | Description |
|---|---|---|
| idrequired | string, path |
Request body application/json
| Field | Type | Description |
|---|---|---|
| sectionrequired | string | One of: "general", "channel", "notifications", "languages", "privacy", "protection", "auth", "usernames", "calendar", "branding", "web", "system". Example: "general" |
| valuesrequired | object | Keys of the section to change; each is validated against the section schema |
Response
200. The payload in data is not described in the spec yet.
Public: everything an app needs at start from its app key
GET/channel/app-config
Public: no sign-in needed.
Send the channel's publishable app key as X-App-Key. The same answer as /channel/key-info: the channel's public fields (id, title, logo, domain, installed app ids), signup (open | restricted | closed), branding, currency (ISO 4217, GBP when unset), media, app_key.mode, and config: the entries marked public in Settings › App config (NAME → value; secrets never). Before 1 Nov 2026 this route answered only the config map.
Response
200. data is object (AppKeyChannelDto).
| Field | Type | Description |
|---|---|---|
| idrequired | string (uuid) | Example: "65a4a10a-a7d0-4037-abc2-04445fedf8bb" |
| titlerequired | string | Example: "Acme Store" |
| description | string | Example: "Official channel of Acme" |
| logo | string | Example: "https://cdn.example.com/logo.png" |
| icon | string | |
| cover | string | |
| domain | string | Example: "shop.example.com" |
| link | string | Example: "https://shop.example.com" |
| keywords | string | Example: "fashion, retail" |
| category | object | |
| category.namerequired | string | Example: "Retail" |
| business | object | |
| business.tradenamerequired | string | Example: "Acme Trading" |
| business.logo | string | |
| appsrequired | string[] | Ids of the apps installed on the channel |
| signuprequired | string | Who may create an account here: a sign-up page can say "by invitation" up front One of: "open", "restricted", "closed". Example: "open" |
| brandingrequired | object | Settings › Branding: theme colours, fonts and tracking ids, each with its default when unset |
| currencyrequired | string | ISO 4217 currency the channel prices and settles in (Settings › General; GBP when unset). Orders are stamped with it. Example: "GBP" |
| mediarequired | object | How to ask the CDN for a sized image (docs/storage.md › Sized images) |
| app_keyrequired | object | |
| app_key.moderequired | string | A test app key only reads One of: "live", "test". Example: "live" |
| configrequired | object | Entries marked public in Settings › App config (NAME → value). Secrets never. |
Server: every config entry of the key's channel, secrets included (NAME → value)
GET/channel/config
Needs a signed-in user (Bearer token or access_token cookie).
For the channel's own servers: a secret API key of the channel with scope channel:config:read. Cache it; never ship it to a browser or app.
Response
200. The payload in data is of type object.
Server: the value the channel's site serves at /.well-known/kodkila-challenge for a host
GET/channel/domain-challenge
Public: no sign-in needed.
HTTP proof of a custom domain: the channel's own site answers GET https://<host>/.well-known/kodkila-challenge (the pre-rename /.well-known/westmonk-challenge is still checked until go-live + 90 days) with this value, then Verify in the domain settings (or the site's Domains card) succeeds. Send a secret server key of the channel (Bearer, any scope) or its app key (X-App-Key). Only pending domains of that same channel; 404 otherwise.
Parameters
| Name | Type | Description |
|---|---|---|
| hostrequired | string, query | Example: "example.com" |
Response
200. The payload in data is not described in the spec yet.
Public: the channel an app key belongs to
GET/channel/key-info
Public: no sign-in needed.
Send the channel's publishable app key as X-App-Key. Answers the same public fields as /channel/resolve (title, logo, domain, installed app ids, sign-up mode, branding), so an app needs no separate channel id.
Response
200. data is object (AppKeyChannelDto).
| Field | Type | Description |
|---|---|---|
| idrequired | string (uuid) | Example: "65a4a10a-a7d0-4037-abc2-04445fedf8bb" |
| titlerequired | string | Example: "Acme Store" |
| description | string | Example: "Official channel of Acme" |
| logo | string | Example: "https://cdn.example.com/logo.png" |
| icon | string | |
| cover | string | |
| domain | string | Example: "shop.example.com" |
| link | string | Example: "https://shop.example.com" |
| keywords | string | Example: "fashion, retail" |
| category | object | |
| category.namerequired | string | Example: "Retail" |
| business | object | |
| business.tradenamerequired | string | Example: "Acme Trading" |
| business.logo | string | |
| appsrequired | string[] | Ids of the apps installed on the channel |
| signuprequired | string | Who may create an account here: a sign-up page can say "by invitation" up front One of: "open", "restricted", "closed". Example: "open" |
| brandingrequired | object | Settings › Branding: theme colours, fonts and tracking ids, each with its default when unset |
| currencyrequired | string | ISO 4217 currency the channel prices and settles in (Settings › General; GBP when unset). Orders are stamped with it. Example: "GBP" |
| mediarequired | object | How to ask the CDN for a sized image (docs/storage.md › Sized images) |
| app_keyrequired | object | |
| app_key.moderequired | string | A test app key only reads One of: "live", "test". Example: "live" |
| configrequired | object | Entries marked public in Settings › App config (NAME → value). Secrets never. |
Server: the channel a secret API key belongs to, with the key's mode and scopes
GET/channel/me
Needs a signed-in user (Bearer token or access_token cookie).
Any secret API key of the channel (no scope needed). Same public fields as /channel/key-info.
Response
200. The payload in data is not described in the spec yet.
Public: Fetch a published channel by exact domain or id (Query Param)
GET/channel/public
Public: no sign-in needed.
Parameters
| Name | Type | Description |
|---|---|---|
| domain | string, query | Example: "svayam.in" |
| id | string, query | Example: "65a4a10a-a7d0-4037-abc2-04445fedf8bb" |
| searchrequired | string, query |
Response
200. The payload in data is not described in the spec yet. Channel details returned
Public: Fetch a published channel by exact domain or id (Route Param)
GET/channel/public/domain/{domain}
Public: no sign-in needed.
Parameters
| Name | Type | Description |
|---|---|---|
| domainrequired | string, path |
Response
200. The payload in data is not described in the spec yet. Channel details returned
Public: resolve the channel serving a hostname
GET/channel/resolve
Public: no sign-in needed.
Entry point for storefronts/apps. Looks up the EXACT lowercase hostname in the domain collection (published/active/verified rows), then falls back to channel.domain. Only published/active channels are returned, and only public fields (no owner, contact, IP or banking data).
Parameters
| Name | Type | Description |
|---|---|---|
| hostrequired | string, query | Example: "shop.example.com" |
Response
200. The payload in data is not described in the spec yet. The public channel for this host