Skip to main content

Prerequisites

Before managing notifications, ensure you have:

Best Practices

Performance

Use pagination (25-50 per page), cache data, and implement virtual scrolling for large lists.

User Experience

Show unread counts, “mark all read” buttons, and relative timestamps with graceful empty states.

Real-time Updates

Poll summary endpoint periodically and update local state optimistically when marking as read.

Notification History

Get Full Notification History

Retrieve paginated notification history for the authenticated user:
const response = await fetch('https://alerts-api.dial.to/v2/history?limit=25', {
  headers: {
    'Authorization': `Bearer ${jwtToken}`,
    'X-Dialect-Client-Key': 'YOUR_CLIENT_KEY'
  }
});

const data = await response.json();
Query Parameters:
  • appId (optional): Filter notifications for a specific app
  • limit (optional): Number of notifications to return (default: 25, max: 50)
  • cursor (optional): Base64-encoded cursor for pagination
Response:
{
  "notifications": [
    {
      "id": "notification-uuid",
      "title": "Trade Executed! 📈",
      "body": "Your buy order for 10 SOL has been executed at $142.50",
      "image": "https://example.com/notification-image.png",
      "timestamp": "2024-01-15T10:30:00Z",
      "readAt": null,
      "app": {
        "id": "app-uuid",
        "name": "SolTrader",
        "image": "https://example.com/app-logo.png"
      },
      "actions": [
        {
          "type": "link",
          "label": "View Trade",
          "url": "https://soltrader.com/trades/123"
        }
      ],
      "data": {
        "tradeId": "123",
        "amount": "10",
        "price": "142.50"
      }
    }
  ],
  "hasMore": true,
  "nextCursor": "eyJpZCI6ImFsZXJ0XzEyMyIsInRpbWVzdGFtcCI6MTcwNTMwNzQwMH0="
}

Pagination Example

async function getAllNotifications() {
  const notifications = [];
  let cursor = null;
  let hasMore = true;

  while (hasMore) {
    const url = cursor
      ? `https://alerts-api.dial.to/v2/history?cursor=${cursor}&limit=50`
      : 'https://alerts-api.dial.to/v2/history?limit=50';

    const response = await fetch(url, {
      headers: {
        'Authorization': `Bearer ${jwtToken}`,
        'X-Dialect-Client-Key': 'YOUR_CLIENT_KEY'
      }
    });

    const data = await response.json();
    notifications.push(...data.notifications);

    hasMore = data.hasMore;
    cursor = data.nextCursor;
  }

  return notifications;
}

Get Notification Summary

Get unread count and summary information without full notification data:
const response = await fetch('https://alerts-api.dial.to/v2/history/summary', {
  headers: {
    'Authorization': `Bearer ${jwtToken}`,
    'X-Dialect-Client-Key': 'YOUR_CLIENT_KEY'
  }
});

const summary = await response.json();
Query Parameters:
  • appId (optional): Filter summary for a specific app
Response:
{
  "unreadCount": 5,
  "lastUnreadNotification": {
    "id": "notification-uuid",
    "title": "Price Alert! 🚨",
    "body": "SOL reached your target price of $150",
    "timestamp": "2024-01-15T14:20:00Z",
    "app": {
      "id": "app-uuid",
      "name": "PriceTracker"
    }
  }
}

Mark Notifications as Read

Mark all notifications as read for the authenticated user:
const response = await fetch('https://alerts-api.dial.to/v2/history/read', {
  method: 'POST',
  headers: {
    'Authorization': `Bearer ${jwtToken}`,
    'X-Dialect-Client-Key': 'YOUR_CLIENT_KEY',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    appId: 'YOUR_APP_ID' // Optional: mark as read for specific app only
  })
});
Request Body:
  • appId (optional): If provided, only marks notifications from this app as read
Response:
{}

Clear Notification History

Clear all notifications for the authenticated user. This is a global action that applies across all clients:
const response = await fetch('https://alerts-api.dial.to/v2/history/clear', {
  method: 'POST',
  headers: {
    'Authorization': `Bearer ${jwtToken}`,
    'X-Dialect-Client-Key': 'YOUR_CLIENT_KEY',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    appId: 'YOUR_APP_ID' // Optional: clear notifications for specific app only
  })
});
Request Body:
  • appId (optional): Single app ID, array of app IDs, or omitted to clear notifications from all apps
Response:
{}
Alerts can now include blinks, enabling users to complete onchain transactions directly from your notification feed. This works as a two-step process:
1

Context Enrichment

When Dialect’s mapping service detects supported protocol URLs in notification actions, it automatically enriches them with a context object containing:
  • type: The kind of data available (e.g., "position" for lending/borrowing positions)
  • apiUrl: A pre-filled API endpoint to fetch detailed data
  • action: The suggested action for the user
2

Data Fetching

Your client uses the context.apiUrl to fetch detailed data. The response structure depends on the context.type. For type: "position", you’ll receive position and market data from our Markets API, including blink URLs for onchain actions.
Always check the context.type field to determine how to handle the data. Additional context types will be supported in the future beyond the current "position" type.
In the following examples, we’ll use Jupiter Borrow (a type: "position" context) to demonstrate this flow. Check if a notification has blink context by looking for the context object in actions. When present, check the type field to determine how to handle the data:
// Notification with blink context
const notification = {
  "id": "notification-uuid",
  "title": "Liquidation Warning",
  "body": "Your SOL/USDC position is at 78% LTV, approaching liquidation threshold of 80%.",
  "timestamp": "2024-01-15T10:30:00Z",
  "actions": [{
    "type": "link",
    "label": "Add Collateral",
    "url": "https://jup.ag/lend/borrow/1/nfts/2433",
    "context": {
      "type": "position",
      "apiUrl": "https://markets.dial.to/api/v0/positions/owners?walletAddresses=6JpNV6DK88auwzKVizdeT4Bw3D44sam5GqjcPCJ7y176&bundleIds=jupiter.borrow.1.2433",
      "action": "deposit"
    }
  }]
};

// Check if action has blink context and get the type
const action = notification.actions?.[0];
if (action?.context) {
  const contextType = action.context.type; // e.g., "position"

  // Handle based on context type
  if (contextType === 'position') {
    // Fetch position data from Markets API
    fetchPositionData(action.context.apiUrl);
  }
  // Future context types can be added here
}
The context object is only present when Dialect’s mapping service detects a supported protocol URL. Always check context.type to handle different data structures appropriately.

Fetching Position Data

For type: "position" contexts, use the apiUrl to fetch position and market data from the Markets and Positions API:
  • TypeScript
  • cURL
async function fetchPositionData(apiUrl: string) {
  const response = await fetch(apiUrl, {
    headers: {
      'x-dialect-api-key': 'pk_demo'
    }
  });

  const data = await response.json();
  return data.positions; // Array of positions (deposit/borrow sides)
}

// Usage
const action = notification.actions[0];
const positions = await fetchPositionData(action.context.apiUrl);

// Find the deposit position
const depositPosition = positions.find(p => p.side === 'deposit');

// Access position data (more examples below)
console.log('LTV:', depositPosition.ltv);
console.log('Amount:', depositPosition.amount, depositPosition.market.token.symbol);
console.log('Liquidation Price:', depositPosition.liquidationPrice);

// Get blink URL for deposit action
const blinkUrl = depositPosition.actions.deposit.blinkUrl;
// blink:https://jupiter.dial.to/api/v0/lend/borrow/1/deposit?positionId=2433

Response Structure

The Markets and Positions API returns an array of positions. For a lending position like Jupiter Borrow, you’ll receive both deposit and borrow sides as well as all relevant market data:
{
  "positions": [
    {
      "id": "jupiter.borrow.1.2433.deposit",
      "type": "lending",
      "marketId": "jupiter.borrow.1",
      "ownerAddress": "6JpNV6DK88auwzKVizdeT4Bw3D44sam5GqjcPCJ7y176",
      "bundleId": "jupiter.borrow.1.2433",
      "side": "deposit",
      "additionalData": {
        "vaultId": 1,
        "nftId": 2433
      },
      "actions": {
        "deposit": {
          "blinkUrl": "blink:https://jupiter.dial.to/api/v0/lend/borrow/1/deposit?positionId=2433"
        },
        "withdraw": {
          "blinkUrl": "blink:https://jupiter.dial.to/api/v0/lend/borrow/1/2433/withdraw"
        }
      },
      "amount": 0.015060007,
      "amountUsd": 3.34,
      "ltv": 0.3033,
      "liquidationPrice": 84.00917409932147,
      "market": {
        "id": "jupiter.borrow.1",
        "type": "lending",
        "provider": {
          "id": "jupiter",
          "name": "Jupiter",
          "icon": "https://imagedelivery.net/C7jfNnfrjpAYWW6YevrFDg/5c23c065-89ef-413b-8deb-6d8c6a849300/public"
        },
        "token": {
          "address": "So11111111111111111111111111111111111111112",
          "symbol": "WSOL",
          "decimals": 9,
          "icon": "https://coin-images.coingecko.com/coins/images/21629/large/solana.jpg?1696520989"
        },
        "borrowToken": {
          "address": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
          "symbol": "USDC",
          "decimals": 6,
          "icon": "https://coin-images.coingecko.com/coins/images/6319/large/usdc.png?1696506694"
        },
        "websiteUrl": "https://jup.ag/lend/borrow/1",
        "depositApy": 0.0784,
        "baseDepositApy": 0.0484,
        "borrowApy": 0.0597,
        "baseBorrowApy": 0.0597,
        "totalDeposit": 665220.958436127,
        "totalDepositUsd": 147340132.39,
        "totalBorrow": 80014008.8212,
        "totalBorrowUsd": 79990184.41,
        "maxBorrow": 120021000.673021,
        "maxLtv": 0.75,
        "liquidationLtv": 0.8,
        "liquidationPenalty": 0.01,
        "additionalData": {},
        "actions": {
          "deposit": {
            "blinkUrl": "blink:https://jupiter.dial.to/api/v0/lend/borrow/1/deposit"
          }
        }
      }
    },
    {
      "id": "jupiter.borrow.1.2433.borrow",
      "type": "lending",
      "marketId": "jupiter.borrow.1",
      "ownerAddress": "6JpNV6DK88auwzKVizdeT4Bw3D44sam5GqjcPCJ7y176",
      "bundleId": "jupiter.borrow.1.2433",
      "side": "borrow",
      "additionalData": {
        "vaultId": 1,
        "nftId": 2433
      },
      "actions": {
        "borrow": {
          "blinkUrl": "blink:https://jupiter.dial.to/api/v0/lend/borrow/1/2433/borrow"
        },
        "repay": {
          "blinkUrl": "blink:https://jupiter.dial.to/api/v0/lend/borrow/1/2433/repay"
        }
      },
      "amount": 1.012143,
      "amountUsd": 1.01,
      "ltv": 0.3033,
      "liquidationPrice": 84.00917409932147,
      "market": {
        "id": "jupiter.borrow.1",
        "type": "lending",
        "provider": {
          "id": "jupiter",
          "name": "Jupiter",
          "icon": "https://imagedelivery.net/C7jfNnfrjpAYWW6YevrFDg/5c23c065-89ef-413b-8deb-6d8c6a849300/public"
        },
        "token": {
          "address": "So11111111111111111111111111111111111111112",
          "symbol": "WSOL",
          "decimals": 9,
          "icon": "https://coin-images.coingecko.com/coins/images/21629/large/solana.jpg?1696520989"
        },
        "borrowToken": {
          "address": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
          "symbol": "USDC",
          "decimals": 6,
          "icon": "https://coin-images.coingecko.com/coins/images/6319/large/usdc.png?1696506694"
        },
        "websiteUrl": "https://jup.ag/lend/borrow/1",
        "depositApy": 0.0784,
        "baseDepositApy": 0.0484,
        "borrowApy": 0.0597,
        "baseBorrowApy": 0.0597,
        "totalDeposit": 665220.958436127,
        "totalDepositUsd": 147340132.39,
        "totalBorrow": 80014008.8212,
        "totalBorrowUsd": 79990184.41,
        "maxBorrow": 120021000.673021,
        "maxLtv": 0.75,
        "liquidationLtv": 0.8,
        "liquidationPenalty": 0.01,
        "additionalData": {},
        "actions": {
          "deposit": {
            "blinkUrl": "blink:https://jupiter.dial.to/api/v0/lend/borrow/1/deposit"
          }
        }
      }
    }
  ]
}

Using the Data

The response includes everything needed to build feature rich UIs ranging from simple notification buttons to detailed position management screens. Use the data to create cards, input interfaces, action buttons, and more.

UI Component Examples

Here are examples of different UI patterns you can build using the data from the example above. Each component uses specific fields from the API response to create rich, informative interfaces: Position Widget A compact position summary card showing key metrics at a glance. Position widget showing compact position metrics This widget uses:
  • market.provider.name and market.provider.icon for protocol branding (e.g., “Jupiter”)
  • market.token.symbol and market.token.icon for collateral token display (e.g., “SOL”)
  • market.borrowToken.symbol and market.borrowToken.icon for borrowed token display (e.g., “USDC”)
  • amount and amountUsd from both deposit and borrow positions to show collateral and debt sizes
  • ltv for position health indicator (e.g., “Very Risky 78%”)
  • market.websiteUrl for the external link to the protocol
Market Cards Display multiple sides of a market in an easy to understand and actionable card layout. Cards showing multiple options for a market These cards use:
  • market.token.symbol and market.token.icon for collateral display (e.g., “SOL”)
  • market.borrowToken.symbol and market.borrowToken.icon for debt display (e.g., “USDC”)
  • amount and amountUsd from deposit and borrow positions for user’s position sizes
  • market.depositApy for collateral yield (e.g., “7.2% APY”)
  • market.borrowApy for borrow rate (e.g., “4.4% APY”)
  • actions.deposit.blinkUrl, actions.withdraw.blinkUrl, actions.borrow.blinkUrl, actions.repay.blinkUrl for action buttons

Available Data Fields by Group

The API response contains extensive data organized into three main categories:

Position Information

  • Protocol: market.provider.name, market.provider.icon, market.provider.id
  • Tokens: market.token.symbol, market.token.address, market.token.icon, market.borrowToken.symbol, market.borrowToken.address, market.borrowToken.icon
  • Health: ltv, liquidationPrice
  • Amounts: amount, amountUsd
  • Identifiers: id, bundleId, marketId, ownerAddress
  • APY rates: market.depositApy, market.baseDepositApy, market.borrowApy, market.baseBorrowApy
  • Liquidation: market.liquidationLtv, market.liquidationPenalty
  • Limits: market.maxLtv, market.maxBorrow
  • Totals: market.totalDeposit, market.totalDepositUsd, market.totalBorrow, market.totalBorrowUsd
  • Decimals: market.token.decimals, market.borrowToken.decimals
I