@marinade.finance/notifications-ts-subscription-client
v1.0.3
Published
TypeScript client for the Marinade notification subscription API. Allows users to subscribe/unsubscribe to notifications and list active subscriptions.
Readme
ts-subscription-client
TypeScript client for the Marinade notification subscription API. Allows users to subscribe/unsubscribe to notifications and list active subscriptions.
Usage
import {
createSubscriptionClient,
subscribeMessage,
unsubscribeMessage,
listSubscriptionsMessage,
} from '@marinade.finance/notifications-ts-subscription-client'
const client = createSubscriptionClient({
base_url: 'https://notifications.marinade.finance',
})The message format is built by helper functions (subscribeMessage,
unsubscribeMessage, listSubscriptionsMessage). Each request
includes a signature and message for server-side authentication.
For local development and testing subscriptions end-to-end, see notification-service/DEV_GUIDE.md.
Channels
A "channel" is a delivery medium for notifications. Each subscription binds a user to a channel + address pair.
telegram
Telegram subscriptions use a deep-link activation flow:
Subscribe — the client sends a
POST /v1/subscriptionsrequest withchannel=telegram. The server creates a subscription withtelegram_status='pending'and returns adeep_linkin the response (e.g.,https://t.me/MarinadeBot?start=feature_sam_auction-<uuid>).Activate — the user opens the deep link in Telegram and presses "Start". The telegram-bot processes the link and maps the user's chat to the subscription. From this point on, notifications are delivered as Telegram messages.
The telegram_status field tracks delivery state:
pending → active → inactive / unsubscribed / blocked
api
The API channel stores notifications in a server-side outbox. Clients pull them via the read API (notifications endpoint). No activation step is needed — subscribing is sufficient.
Notification types
sam_auction
SAM auction notifications for validators. Subscribing requires proof of authority over a bond — the signer must be the bond authority, validator identity, or vote account owner. The server verifies this against on-chain bond accounts.
The additional_data field for subscribe/unsubscribe should include:
{
config_address: string // bonds program config
vote_account: string // validator vote account
bond_pubkey: string // derived bond PDA
}For listing subscriptions (GET /v1/subscriptions), no additional_data
is needed — the server performs a reverse lookup from the pubkey.
Known limitations
Telegram subscription lifecycle
The notification service tracks telegram_status for each telegram subscription:
pending → active → inactive / unsubscribed / blocked.
The consumer filters by telegram_status before attempting delivery.
It does not attempt to send notifications to subscriptions marked as inactive,
unsubscribed, or blocked. The status is updated based on the telegram-bot's
/send response:
- 200 →
active(message delivered) - 404 →
inactive(subscription never existed in telegram-bot — bad external_id) - 410 "Subscription inactive" →
unsubscribed(user unsubscribed via bot UI) - 410 "User blocked bot" →
blocked(user blocked the bot in Telegram) - 429 / 5xx → retry with backoff, status unchanged
Re-subscribe after unsubscribe or block
When a user unsubscribes via the Telegram bot UI or blocks the bot, the
notification service marks the subscription as unsubscribed or blocked and
stops delivery. Clicking the original Telegram deep link again reactivates the
subscription on the telegram-bot side, but the notification service is not
notified — it still sees the old status and skips delivery.
To re-subscribe, the user must use the CLI subscribe command. This calls
POST /v1/subscriptions which resets telegram_status to pending, allowing
delivery to resume on the next event.
