Developer reference

Wedafeeds Market Data API

Look up the instruments over HTTPS — no credential needed — then hold one WebSocket, authenticated by your access key, for every feed you are granted. Every feed speaks the same message format.

APIhttps://socket-edith.data.wedafeeds.com
WSwss://socket-echo.data.wedafeeds.com/ws

Tenants

A tenant is one feed. Your access key names the tenants you may use; the welcome frame on connect tells you what each one carries right now, so treat that frame as authoritative over this table.

IDSlugNameMarket fieldStreamsModes
1US_EquityUS Equities— (omit)trade quote aggregatefull ltp
4CurrenciesCurrenciesforex (required)quote aggregatefull ltp
crypto (required)trade quote aggregatefull ltp
5FuturesFutures— (omit)trade quote aggregatefull ltp

Every feed delivers each event as its own frame tagged with its kind — a trade, a quote and a one-second OHLC bar for the same symbol are three separate frames, never merged. Forex has no trade stream at source, so it carries the two kinds it can.

Tenant 4 carries two markets under one ID. Because a pair like DOP-USD exists in both — a currency and a token — every subscribe on tenant 4 must say which market it means. Tenants 1 and 5 carry one market and reject a market field.

On tenant 5 a symbol is one contract, not a product: ESZ6 is the E-mini S&P for December 2026 (product code, month code, year digit). Prices are per unit of the underlying; apply the contract multiplier yourself. Recency is set by the plan.

Authentication

One credential. Your access key is issued to you during onboarding; it is what a client presents to the WebSocket and to historical bars, and it carries your tenant grants and per-client limits. The ticker list is public and takes no credential at all.

Access keys are issued during onboarding; there is no public sign-up.

Ticker list

The full instrument universe, across every tenant. No credential is needed; what you may actually subscribe to is decided by your access key on the WebSocket. symbol and market in each row are exactly what a subscribe frame takes.

ParameterMeaning
tenantslug or ID; omitted lists every tenant
marketforex or crypto — narrows tenant 4 to one market
searchprefix match on symbol, substring match on name
activetrue / false; omitted returns both
limit, offsetpaging; limit defaults to 100, max 1000

US Equities

sendGET /api/v1/tickers?tenant=US_Equity&search=apple
curl -s "https://socket-edith.data.wedafeeds.com/api/v1/tickers?tenant=US_Equity&search=apple&limit=5"
receive200 — no market on single-market rows
{"error":false,"statusCode":200,"status":"OK","message":"Tickers",
 "data":{"tenants":[{"id":"1","slug":"US_Equity"}],"total":3,"limit":5,"offset":0,
  "tickers":[
   {"id":"…","tenant":"1","symbol":"AAPL","name":"Apple Inc.","assetClass":"equity",
    "locale":"us","primaryExchange":"XNAS","type":"CS","currency":"USD","active":true,
    "identifiers":{"cik":"0000320193","compositeFigi":"BBG000B9XRY4"}},
   …]}}

Currencies — forex

sendGET /api/v1/tickers?tenant=Currencies&market=forex
curl -s "https://socket-edith.data.wedafeeds.com/api/v1/tickers?tenant=Currencies&market=forex&limit=3"
receive200 — 1,204 pairs
{"error":false,"statusCode":200,"status":"OK","message":"Tickers",
 "data":{"tenants":[{"id":"4","slug":"Currencies"}],"total":1204,"limit":3,"offset":0,
  "tickers":[
   {"tenant":"4","symbol":"AED-AUD","name":"United Arab Emirates dirham - Australian dollar","assetClass":"forex","market":"forex","locale":"global","currency":"AUD","active":true},
   {"tenant":"4","symbol":"AED-BHD","name":"United Arab Emirates dirham - Bahraini dinar","assetClass":"forex","market":"forex","locale":"global","currency":"BHD","active":true},
   {"tenant":"4","symbol":"AED-CAD","name":"United Arab Emirates dirham - Canadian dollar","assetClass":"forex","market":"forex","locale":"global","currency":"CAD","active":true}]}}

Currencies — crypto

sendGET /api/v1/tickers?tenant=Currencies&market=crypto&search=btc
curl -s "https://socket-edith.data.wedafeeds.com/api/v1/tickers?tenant=Currencies&market=crypto&search=btc"
receive200 — 624 pairs in the crypto market
{"error":false,"statusCode":200,"status":"OK","message":"Tickers",
 "data":{"tenants":[{"id":"4","slug":"Currencies"}],"total":7,"limit":100,"offset":0,
  "tickers":[
   {"tenant":"4","symbol":"BTC-AUD","name":"Bitcoin - Australian Dollar","assetClass":"crypto","market":"crypto","locale":"global","currency":"AUD","active":true},
   {"tenant":"4","symbol":"BTC-EUR","name":"Bitcoin - Euro","assetClass":"crypto","market":"crypto","locale":"global","currency":"EUR","active":true},
   {"tenant":"4","symbol":"BTC-USD","name":"Bitcoin - United States dollar","assetClass":"crypto","market":"crypto","locale":"global","currency":"USD","active":true},
   …]}}

An unknown tenant or a misspelled market is 400.

Historical bars

OHLC bars for one symbol over a date window, paged by number. Three routes, one contract. Send your access key exactly as you do to the socket — X-API-Key header, Authorization: Bearer, or ?apiKey=. Each route needs the grant for the tenant that streams the same instruments.

RoutesymbolKey must be granted
GET /api/v1/equity/historicalticker — AAPL, BRK.Btenant 1 (US Equities)
GET /api/v1/crypto/historicalpair — BTC-USD or BTC/USDtenant 4 (Currencies)
GET /api/v1/forex/historicalpair — EUR-USD or EUR/USDtenant 4 (Currencies)
GET /api/v1/futures/historicalcontract — ESZ6, CLZ6tenant 5 (Futures)

The asset class is in the path, not a parameter, because the symbol alone cannot say which history you mean: DOP-USD is both a currency and a token, and both have bars. Pairs are spelled exactly as the ticker list and a subscribe frame spell them.

ParameterMeaning
symbolrequired; case-insensitive; a ticker on the equity route, a BASE-QUOTE pair on the others
from, torequired; inclusive window, YYYY-MM-DD or a millisecond timestamp
timespansecond minute hour day week month quarter year; default day
multipliera bar is multiplier × timespan wide — 5 + minute is a five-minute bar; default 1
limitsource records per page (see note); default 5000, max 50000
page1-based; default 1, max 100

US Equities — daily bars, five per page

sendGET /api/v1/equity/historical?symbol=AAPL&from=2024-01-01&to=2024-01-31&timespan=day&limit=5&page=1
curl -s -H "X-API-Key: YOUR_ACCESS_KEY" \
  "https://socket-edith.data.wedafeeds.com/api/v1/equity/historical?symbol=AAPL&from=2024-01-01&to=2024-01-31×pan=day&limit=5&page=1"
receive200 — nextPage says there is more
{"error":false,"statusCode":200,"status":"OK","message":"Historical bars",
 "data":{"assetClass":"equity","symbol":"AAPL","timespan":"day","multiplier":1,"from":"2024-01-01","to":"2024-01-31",
  "adjusted":true,"page":1,"limit":5,"count":5,"nextPage":true,
  "bars":[
   {"timestamp":1704171600000,"open":187.15,"high":188.44,"low":183.885,"close":185.64,"volume":82488674,"vwap":185.9374,"trades":1008875},
   {"timestamp":1704258000000,"open":184.22,"high":185.88,"low":183.43,"close":184.25,"volume":58414460,"vwap":184.3226,"trades":656853},
   …]}}
receive200 — the last page, then an empty one
// page=5 — January 2024 had 21 trading days
{"error":false,"statusCode":200,"status":"OK","message":"Historical bars",
 "data":{"assetClass":"equity","symbol":"AAPL","timespan":"day","multiplier":1,"from":"2024-01-01","to":"2024-01-31",
  "adjusted":true,"page":5,"limit":5,"count":1,"nextPage":false,
  "bars":[{"timestamp":1706677200000,"open":187.04,"high":187.095,"low":184.35,"close":184.4,"volume":55467803,"vwap":185.3525,"trades":679844}]}}

// page=9 — past the end is empty, not an error
{"error":false,"statusCode":200,"status":"OK","message":"Historical bars",
 "data":{"assetClass":"equity","symbol":"AAPL","timespan":"day","multiplier":1,"from":"2024-01-01","to":"2024-01-31",
  "adjusted":true,"page":9,"limit":5,"count":0,"nextPage":false,"bars":[]}}

Crypto — hourly bars

sendGET /api/v1/crypto/historical?symbol=BTC-USD&from=2024-01-01&to=2024-01-02&timespan=hour
curl -s -H "X-API-Key: YOUR_ACCESS_KEY" \
  "https://socket-edith.data.wedafeeds.com/api/v1/crypto/historical?symbol=BTC-USD&from=2024-01-01&to=2024-01-02×pan=hour"
receive200 — the pair as you spelled it; the slash form works too
{"error":false,"statusCode":200,"status":"OK","message":"Historical bars",
 "data":{"assetClass":"crypto","symbol":"BTC-USD","timespan":"hour","multiplier":1,"from":"2024-01-01","to":"2024-01-02",
  "adjusted":true,"page":1,"limit":5000,"count":48,"nextPage":false,
  "bars":[
   {"timestamp":1704067200000,"open":42241.1,"high":42591,"low":42241.1,"close":42452.66,"volume":499.65044691,"vwap":42416.5499,"trades":9099},
   …]}}

Forex — daily bars

sendGET /api/v1/forex/historical?symbol=EUR-USD&from=2024-01-01&to=2024-01-10&limit=3
curl -s -H "X-API-Key: YOUR_ACCESS_KEY" \
  "https://socket-edith.data.wedafeeds.com/api/v1/forex/historical?symbol=EUR-USD&from=2024-01-01&to=2024-01-10&limit=3"
receive200 — forex has no trade tape, so volume and trades count quotes
{"error":false,"statusCode":200,"status":"OK","message":"Historical bars",
 "data":{"assetClass":"forex","symbol":"EUR-USD","timespan":"day","multiplier":1,"from":"2024-01-01","to":"2024-01-10",
  "adjusted":true,"page":1,"limit":3,"count":3,"nextPage":true,
  "bars":[
   {"timestamp":1704067200000,"open":1.1038,"high":1.1077,"low":1.091,"close":1.1037,"volume":8793,"vwap":1.1042,"trades":8793},
   …]}}

Futures — session bars

sendGET /api/v1/futures/historical?symbol=ESZ6&from=2026-09-01&to=2026-09-17&limit=3
curl -s -H "X-API-Key: YOUR_ACCESS_KEY" \
  "https://socket-edith.data.wedafeeds.com/api/v1/futures/historical?symbol=ESZ6&from=2026-09-01&to=2026-09-17&limit=3"
receive200 — a session bar carries its settlement and the date it is named for
{"error":false,"statusCode":200,"status":"OK","message":"Historical bars",
 "data":{"assetClass":"futures","symbol":"ESZ6","timespan":"day","multiplier":1,"from":"2026-09-01","to":"2026-09-17",
  "adjusted":false,"page":1,"limit":3,"count":3,"nextPage":true,
  "bars":[
   {"timestamp":1788220800000,"open":7713.5,"high":7757,"low":7685.5,"close":7736,"volume":3305,"vwap":7730.4372,"trades":2447,
    "settlementPrice":7743.5,"sessionDate":"2026-09-02"},
   …]}}

On futures, day is one trading session, which opens the evening before it settles — so timestamp falls on the calendar day before sessionDate. Intraday bars carry sessionDate but no settlement. Here limit counts bars. Minute bars go up to 59; ask for hour beyond that, or the answer is 400.

receive403 — valid key, wrong grant
// a key granted only tenant 1 asking the crypto route
{"error":true,"statusCode":403,"status":"Forbidden","message":"Access key is not granted Currencies"}

timestamp is the bar's open in Unix milliseconds. Equity prices are split-adjusted. A bar built from over-the-counter prints carries "otc":true; every other bar omits the field. assetClass and symbol echo the route and the symbol as this API spells it.

Paging is a number and a flag. nextPage says whether a further page exists; ask for page+1. There is no cursor and no URL to follow. Page n costs more to serve than page 1, which is why page stops at 100 — raise limit to reach further.

limit counts source records, not bars. A daily bar is its own record, so limit=5 on day is five bars. Hourly bars are built from minutes, weekly and longer from days, N-second bars from seconds — limit=100 on hour is a page built from 100 minutes, roughly a bar and a half. count reports what a page actually holds; the 5000 default is enough for most windows.

A missing from, a timespan of fortnight, limit=ten or page=0 is 400 naming the parameter. No key, or an unknown or revoked one, is 401; a valid key without the route's grant is 403 naming the tenant. If the data source cannot be reached the answer is 502; retry later.

WebSocket

Connect

Present the access key as a header where you can; browsers cannot set headers on the handshake, so the query string is accepted too.

sendhandshake — any one of these
wss://socket-echo.data.wedafeeds.com/ws?apiKey=YOUR_ACCESS_KEY

# or, for non-browser clients:
X-API-Key: YOUR_ACCESS_KEY
Authorization: Bearer YOUR_ACCESS_KEY

The first frame describes what your key may use. available:false means granted but currently down — distinct from not granted. A tenant with a markets array requires market on every subscribe.

receivewelcome
{"type":"welcome","message":"connected","ts":1789390028000,
 "tenants":[
  {"id":"1","name":"US Equities","assetClass":"equity",
   "streams":["trade","quote","aggregate"],"modes":["full","ltp"],"available":true},
  {"id":"4","name":"Currencies","assetClass":"currency",
   "streams":["quote","aggregate","trade"],"modes":["full","ltp"],
   "markets":[
     {"market":"forex", "assetClass":"forex", "streams":["quote","aggregate"],        "modes":["full","ltp"]},
     {"market":"crypto","assetClass":"crypto","streams":["trade","quote","aggregate"],"modes":["full","ltp"]}],
   "available":true}]}

US Equities — tenant 1

One market, so there is no market field. Omitting mode means full.

sendsubscribe, full
{"action":"subscribe","tenant":"1","tickers":["AAPL","MSFT"]}
receiveack, then trade, quote and aggregate frames — three kinds, each its own frame
{"type":"ack","tenant":"1","tickers":["AAPL","MSFT"],"mode":"full","message":"subscribed","ts":1789390028000}

{"type":"data","tenant":"1","symbol":"AAPL","kind":"trade",
 "data":{"kind":"trade","symbol":"AAPL","price":"224.28","size":"100","eventTime":1788948548063,"tradeId":"52983525029262"}}

{"type":"data","tenant":"1","symbol":"AAPL","kind":"quote",
 "data":{"kind":"quote","symbol":"AAPL","bidPrice":"224.27","bidSize":"3","askPrice":"224.29","askSize":"5","eventTime":1788948548071}}

{"type":"data","tenant":"1","symbol":"AAPL","kind":"aggregate",
 "data":{"kind":"aggregate","symbol":"AAPL","open":"224.26","high":"224.31","low":"224.25","close":"224.28","volume":"1840","eventTime":1788948548000}}
sendsubscribe, last price only
{"action":"subscribe","tenant":"1","tickers":["AAPL"],"mode":"ltp"}
receiveone ltp frame per one-second bar
{"type":"ack","tenant":"1","tickers":["AAPL"],"mode":"ltp","message":"subscribed","ts":1789390028000}

{"type":"data","tenant":"1","symbol":"AAPL","kind":"ltp",
 "data":{"kind":"ltp","symbol":"AAPL","ltp":"224.28","eventTime":1788948548000}}

On US Equities the last price is the one-second bar's close, not the individual print — many prints (odd lots, extended-hours, average-price) are not eligible to set the consolidated last, and the bar already applies those rules. In full mode you still receive every trade.

Currencies — tenant 4

market is required. A slash in a pair is accepted and folded to a hyphen, so USD/JPY and USD-JPY are the same subscription — the ack shows the canonical form.

sendforex, full
{"action":"subscribe","tenant":"4","market":"forex","tickers":["EUR-USD","USD/JPY"]}
receiveack, then quote and aggregate frames — forex has no trades
{"type":"ack","tenant":"4","market":"forex","tickers":["EUR-USD","USD-JPY"],"mode":"full","message":"subscribed","ts":1789390028000}

{"type":"data","tenant":"4","market":"forex","symbol":"EUR-USD","kind":"quote",
 "data":{"kind":"quote","symbol":"EUR-USD","bidPrice":"1.15324","askPrice":"1.15329","eventTime":1789389703000}}

{"type":"data","tenant":"4","market":"forex","symbol":"EUR-USD","kind":"aggregate",
 "data":{"kind":"aggregate","symbol":"EUR-USD","open":"1.1529","high":"1.1529","low":"1.1529","close":"1.1529","volume":"1","eventTime":1789393857000}}
sendforex, last price only
{"action":"subscribe","tenant":"4","market":"forex","tickers":["EUR-USD"],"mode":"ltp"}
receiveone ltp frame per one-second bar (its close)
{"type":"ack","tenant":"4","market":"forex","tickers":["EUR-USD"],"mode":"ltp","message":"subscribed","ts":1789390028000}

{"type":"data","tenant":"4","market":"forex","symbol":"EUR-USD","kind":"ltp",
 "data":{"kind":"ltp","symbol":"EUR-USD","ltp":"1.1529","eventTime":1789393857000}}
sendcrypto, full
{"action":"subscribe","tenant":"4","market":"crypto","tickers":["BTC-USD","ETH-USD"]}
receiveack, then trade, quote and aggregate frames — separate, never merged
{"type":"ack","tenant":"4","market":"crypto","tickers":["BTC-USD","ETH-USD"],"mode":"full","message":"subscribed","ts":1789390028000}

{"type":"data","tenant":"4","market":"crypto","symbol":"BTC-USD","kind":"trade",
 "data":{"kind":"trade","symbol":"BTC-USD","price":"77791.5","size":"0.00101162","eventTime":1789390028834,"tradeId":"1092498786"}}

{"type":"data","tenant":"4","market":"crypto","symbol":"BTC-USD","kind":"quote",
 "data":{"kind":"quote","symbol":"BTC-USD","bidPrice":"77739","bidSize":"0.06431702","askPrice":"77754","askSize":"0.064306","eventTime":1789389693541}}

{"type":"data","tenant":"4","market":"crypto","symbol":"BTC-USD","kind":"aggregate",
 "data":{"kind":"aggregate","symbol":"BTC-USD","open":"78337.8","high":"78342.67","low":"78337.8","close":"78342.45","volume":"0.0050004","eventTime":1789393851000}}
sendcrypto, last price only
{"action":"subscribe","tenant":"4","market":"crypto","tickers":["SOL-USD"],"mode":"ltp"}
receiveone ltp frame per trade; quotes produce nothing
{"type":"ack","tenant":"4","market":"crypto","tickers":["SOL-USD"],"mode":"ltp","message":"subscribed","ts":1789390028000}

{"type":"data","tenant":"4","market":"crypto","symbol":"SOL-USD","kind":"ltp",
 "data":{"kind":"ltp","symbol":"SOL-USD","ltp":"142.31","eventTime":1789390029102}}

Mode is per subscribe, not per connection: one socket can hold BTC-USD in full and SOL-USD in ltp. Re-subscribing a symbol with a different mode switches it in place.

Futures — tenant 5

One market, so no market field. A symbol is one contract: ESZ6 is the E-mini S&P 500 for December 2026 — product code, month code (F G H J K M N Q U V X Z), year digit. Subscribe to the expiry you want; there is no continuous or product-level symbol.

sendsubscribe, full
{"action":"subscribe","tenant":"5","tickers":["ESZ6","CLZ6"]}
receiveack, then trade, quote and aggregate frames — the same shape as every other tenant
{"type":"ack","tenant":"5","tickers":["ESZ6","CLZ6"],"mode":"full","message":"subscribed","ts":1789731745145}

{"type":"data","tenant":"5","symbol":"ESZ6","kind":"trade",
 "data":{"kind":"trade","symbol":"ESZ6","price":"7715.25","size":"1","eventTime":1789731745600}}

{"type":"data","tenant":"5","symbol":"ESZ6","kind":"quote",
 "data":{"kind":"quote","symbol":"ESZ6","bidPrice":"7715.25","bidSize":"7","askPrice":"7715.5","askSize":"22","eventTime":1789731745600}}

{"type":"data","tenant":"5","symbol":"ESZ6","kind":"aggregate",
 "data":{"kind":"aggregate","symbol":"ESZ6","open":"7715.25","high":"7715.25","low":"7715.25","close":"7715.25","volume":"1","eventTime":1789731741000}}

Prices are per unit of the underlying; multiply by the product's contract multiplier for notional. size and volume count contracts. On this tenant ltp comes from the trade itself, as on crypto — a futures print is a real last price. Recency (10-minute delayed or real-time) is set by the plan.

The ticker list carries every listed contract under tenant=Futures: search by product with ?tenant=Futures&search=ES, and read the expiry, tick sizes and the product's settlement terms from each row's metadata.

Unsubscribe, list, ping

sendunsubscribe — some symbols, or everything on a tenant / market
{"action":"unsubscribe","tenant":"1","tickers":["MSFT"]}
{"action":"unsubscribe","tenant":"1"}
{"action":"unsubscribe","tenant":"4","market":"crypto","tickers":["ETH-USD"]}
{"action":"unsubscribe","tenant":"4","market":"crypto"}
receiveack lists exactly what was released
{"type":"ack","tenant":"4","market":"crypto","tickers":["BTC-USD","ETH-USD"],"message":"unsubscribed","ts":1789390038058}
sendlist
{"action":"list"}
receivestatus — tenant:symbol, or tenant:market:symbol on tenant 4
{"type":"status","message":"active subscriptions",
 "tickers":["1:AAPL","4:forex:EUR-USD","4:forex:USD-JPY","4:crypto:BTC-USD"],
 "tenants":[…same shape as welcome…],"ts":1789390038058}
sendping
{"action":"ping"}
receivepong
{"type":"pong","ts":1789390038058}

The server also sends protocol-level pings every ~54 s and expects a pong within 60 s; most WebSocket libraries answer these automatically.

Data frames

Every feed emits the same envelope. Prices and sizes are strings so decimal precision survives; eventTime is epoch milliseconds from the source. Fields absent from an event are omitted, not sent as null.

tradequoteaggregateltp
Envelope fieldMeaning
typealways data for market data
tenanttenant ID
marketpresent only on multi-market tenants (tenant 4)
symbolthe symbol as you subscribed it
kindtrade · quote · aggregate · ltp
datathe event; its own kind and symbol are repeated inside for convenience
kindFields in dataNotes
tradeprice size eventTime tradeId buyerIsMaker?one frame per execution
quotebidPrice bidSize? askPrice askSize? eventTimeforex quotes carry no sizes; much higher volume than trades
aggregateopen high low close volume eventTimeone-second bar; eventTime is the window start
ltpltp eventTimeonly in mode:"ltp"; from the trade on crypto, from the bar's close on equities and forex

Errors

Errors are frames, not disconnects. Each names the tenant it concerns and says what to send instead.

receivecommon error frames
// tenant not on your key
{"type":"error","tenant":"99","message":"access denied for tenant","ts":…}

// tenant granted but not running
{"type":"error","tenant":"4","message":"tenant is not available","ts":…}

// market omitted on tenant 4
{"type":"error","tenant":"4","message":"market is required for this tenant (forex, crypto)","ts":…}

// market sent to a single-market tenant
{"type":"error","tenant":"1","message":"tenant carries a single market; remove \"crypto\"","ts":…}

// typo in market or mode — never silently defaulted
{"type":"error","tenant":"4","message":"unknown market: fx (want \"forex\" or \"crypto\")","ts":…}
{"type":"error","tenant":"4","message":"unknown mode: LAST (want \"full\" or \"ltp\")","ts":…}

// over your per-connection symbol cap
{"type":"error","tenant":"4","message":"ticker limit exceeded: 98 of 100 in use","ts":…}

At the handshake, an invalid key is 401, a key with no grants 403, and a key already at its connection cap 429 — all as JSON, before the upgrade, so your client reads a real message rather than a socket that opens and closes.

Rules & limits

Symbols
Upper-cased and de-duplicated on receipt. Currency pairs are BASE-QUOTE; a slash is folded to a hyphen.
market
Required on tenant 4, refused on tenant 1. The value comes straight from the ticker list's market column.
mode
Per subscribe. Omitted means full. ltp is offered only where the welcome frame lists it.
Idempotence
Subscribing a symbol you already hold does not count against your cap; it re-acks (and may switch the mode).
Symbol cap
Concurrent symbols per connection, across all tenants — your key's maxTickers.
Connection cap
Concurrent sockets per key — your key's maxConnections. Refused at the handshake with 429; existing sockets are never dropped to make room.
Slow consumers
Each socket has a bounded outbound queue. A client that stops reading is disconnected rather than allowed to stall others.
Reconnects
Subscriptions do not survive a disconnect; re-send them after reconnecting. Read the fresh welcome first.
Inbound surface
Clients can only manage their own subscriptions. There is no publish action.