Documentation Index
Fetch the complete documentation index at: https://docs.velt.dev/docs/llms.txt
Use this file to discover all available pages before exploring further.
- Only notifications where
notificationSource === 'custom' are routed through the notification resolver.
- Ensure that the data providers are set prior to calling the
identify method.
- The data provider methods must return the correct status code (e.g.
200 for success, 500 for errors) and a success boolean in the response object. This ensures proper error handling and retries.
Overview
Velt supports self-hosting your custom notification PII data:
- Custom notification content (headline, body, source data) can be stored on your own infrastructure, with only necessary identifiers on Velt servers.
- Velt components automatically hydrate notification data in the frontend by fetching from your configured data provider.
- This gives you full control over notification PII while maintaining all Velt notification features.
How does it work?
When custom notifications are fetched or deleted:
- The SDK uses your configured
NotificationDataProvider to handle retrieval and deletion.
- Your data provider implements two optional methods:
get: Fetches notification PII from your database
delete: Removes notification PII from your database
Resolution pipeline order: notification → user → comment
The process works as follows:
When a notification fetch operation occurs:
- The SDK calls your
get handler with the notification IDs and organization ID.
- If successful:
- The notification objects are hydrated with your returned PII fields.
- The
Notification object is updated with isNotificationResolverUsed: true once enriched via the notification resolver.
- If the operation fails, the notification is rendered without enriched PII, and the operation is retried if you have configured retries.
Implementation Approaches
You can implement notification self-hosting using either of these approaches:
- Endpoint based: Provide endpoint URLs and let the SDK handle HTTP requests
- Function based: Implement
get and delete methods yourself
Both approaches are fully backward compatible and can be used together.
| Feature | Function based | Endpoint based |
|---|
| Best For | Complex setups requiring middleware logic, dynamic headers, or transformation before sending | Standard REST APIs where you just need to pass the request “as-is” to the backend |
| Implementation | You write the fetch() or axios code | You provide the url string and headers object |
| Flexibility | High | Medium |
| Speed | Medium | High |
Endpoint based DataProvider
Instead of implementing custom methods, you can configure endpoints directly and let the SDK handle HTTP requests.
getConfig
Config-based endpoint for fetching notification PII. The SDK automatically makes HTTP POST requests with the request body.
React / Next.js
Other Frameworks
const notificationDataProvider = {
config: {
getConfig: {
url: 'https://your-backend.com/api/velt/notifications/get',
headers: { 'Authorization': 'Bearer YOUR_TOKEN' }
}
}
};
<VeltProvider
apiKey='YOUR_API_KEY'
dataProviders={{ notification: notificationDataProvider }}
>
</VeltProvider>
const notificationDataProvider = {
config: {
getConfig: {
url: 'https://your-backend.com/api/velt/notifications/get',
headers: { 'Authorization': 'Bearer YOUR_TOKEN' }
}
}
};
Velt.setDataProviders({ notification: notificationDataProvider });
deleteConfig
Config-based endpoint for deleting notification PII. The SDK automatically makes HTTP POST requests with the request body.
React / Next.js
Other Frameworks
const notificationDataProvider = {
config: {
deleteConfig: {
url: 'https://your-backend.com/api/velt/notifications/delete',
headers: { 'Authorization': 'Bearer YOUR_TOKEN' }
}
}
};
<VeltProvider
apiKey='YOUR_API_KEY'
dataProviders={{ notification: notificationDataProvider }}
>
</VeltProvider>
const notificationDataProvider = {
config: {
deleteConfig: {
url: 'https://your-backend.com/api/velt/notifications/delete',
headers: { 'Authorization': 'Bearer YOUR_TOKEN' }
}
}
};
Velt.setDataProviders({ notification: notificationDataProvider });
Endpoint based Complete Example
React / Next.js
Other Frameworks
const notificationDataProvider = {
config: {
getConfig: {
url: 'https://your-backend.com/api/velt/notifications/get',
headers: { 'Authorization': 'Bearer YOUR_TOKEN' }
},
deleteConfig: {
url: 'https://your-backend.com/api/velt/notifications/delete',
headers: { 'Authorization': 'Bearer YOUR_TOKEN' }
},
resolveTimeout: 5000,
getRetryConfig: { retryCount: 3, retryDelay: 2000 },
deleteRetryConfig: { retryCount: 3, retryDelay: 2000 }
},
};
<VeltProvider
apiKey='YOUR_API_KEY'
dataProviders={{ notification: notificationDataProvider }}
>
</VeltProvider>
const notificationDataProvider = {
config: {
getConfig: {
url: 'https://your-backend.com/api/velt/notifications/get',
headers: { 'Authorization': 'Bearer YOUR_TOKEN' }
},
deleteConfig: {
url: 'https://your-backend.com/api/velt/notifications/delete',
headers: { 'Authorization': 'Bearer YOUR_TOKEN' }
},
resolveTimeout: 5000,
getRetryConfig: { retryCount: 3, retryDelay: 2000 },
deleteRetryConfig: { retryCount: 3, retryDelay: 2000 }
},
};
Velt.setDataProviders({ notification: notificationDataProvider });
Function based DataProvider
Implement custom methods to handle data operations yourself.
get
Fetch notification PII data from your database. Called when notifications need to be hydrated in the frontend.
React / Next.js
Other Frameworks
const getNotificationFromDB = async (request) => {
const response = await fetch('/api/velt/notifications/get', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(request)
});
return await response.json();
};
const notificationDataProvider = {
get: getNotificationFromDB,
};
<VeltProvider
apiKey='YOUR_API_KEY'
dataProviders={{ notification: notificationDataProvider }}
>
</VeltProvider>
const getNotificationFromDB = async (request) => {
const response = await fetch('/api/velt/notifications/get', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(request)
});
return await response.json();
};
const notificationDataProvider = {
get: getNotificationFromDB,
};
Velt.setDataProviders({ notification: notificationDataProvider });
delete
Remove notification PII from your database. Called when a custom notification is deleted.
React / Next.js
Other Frameworks
const deleteNotificationFromDB = async (request) => {
const response = await fetch('/api/velt/notifications/delete', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(request)
});
return await response.json();
};
const notificationDataProvider = {
delete: deleteNotificationFromDB,
};
<VeltProvider
apiKey='YOUR_API_KEY'
dataProviders={{ notification: notificationDataProvider }}
>
</VeltProvider>
const deleteNotificationFromDB = async (request) => {
const response = await fetch('/api/velt/notifications/delete', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(request)
});
return await response.json();
};
const notificationDataProvider = {
delete: deleteNotificationFromDB,
};
Velt.setDataProviders({ notification: notificationDataProvider });
config
Configuration for the notification data provider.
- Type:
NotificationResolverConfig. Relevant properties:
resolveTimeout: Timeout duration (in milliseconds) for resolver operations
getRetryConfig: RetryConfig. Configure retry behavior for get operations.
deleteRetryConfig: RetryConfig. Configure retry behavior for delete operations.
const notificationResolverConfig = {
resolveTimeout: 5000,
getRetryConfig: { retryCount: 3, retryDelay: 2000 },
deleteRetryConfig: { retryCount: 3, retryDelay: 2000 }
};
Function based Complete Example
React / Next.js
Other Frameworks
const getNotificationFromDB = async (request) => {
const response = await fetch('/api/velt/notifications/get', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(request)
});
return await response.json();
};
const deleteNotificationFromDB = async (request) => {
const response = await fetch('/api/velt/notifications/delete', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(request)
});
return await response.json();
};
const notificationResolverConfig = {
resolveTimeout: 5000,
getRetryConfig: { retryCount: 3, retryDelay: 2000 },
deleteRetryConfig: { retryCount: 3, retryDelay: 2000 }
};
const notificationDataProvider = {
get: getNotificationFromDB,
delete: deleteNotificationFromDB,
config: notificationResolverConfig,
};
<VeltProvider
apiKey='YOUR_API_KEY'
dataProviders={{ notification: notificationDataProvider }}
>
</VeltProvider>
const getNotificationFromDB = async (request) => {
const response = await fetch('/api/velt/notifications/get', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(request)
});
return await response.json();
};
const deleteNotificationFromDB = async (request) => {
const response = await fetch('/api/velt/notifications/delete', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(request)
});
return await response.json();
};
const notificationResolverConfig = {
resolveTimeout: 5000,
getRetryConfig: { retryCount: 3, retryDelay: 2000 },
deleteRetryConfig: { retryCount: 3, retryDelay: 2000 }
};
const notificationDataProvider = {
get: getNotificationFromDB,
delete: deleteNotificationFromDB,
config: notificationResolverConfig,
};
Velt.setDataProviders({ notification: notificationDataProvider });
Writing Resolver-Eligible Notifications
To create a notification whose content will be resolved from your own infrastructure at read time, set isNotificationResolverUsed: true and notificationSource: 'custom' in your REST write. Omit displayHeadlineMessageTemplate and displayBodyMessage — the resolver will supply that content when the notification is fetched by the client.
Only notifications where notificationSource === 'custom' are routed through the notification resolver. Notifications without this field will not call your data provider.
Minimal POST body for a resolver-eligible notification:
{
"data": {
"organizationId": "yourOrganizationId",
"documentId": "yourDocumentId",
"actionUser": {
"userId": "yourUserId",
"name": "User Name",
"email": "user@example.com"
},
"notificationId": "custom-notif-001",
"isNotificationResolverUsed": true,
"notificationSource": "custom",
"notifyUsers": [
{
"userId": "recipientUserId",
"email": "recipient@example.com"
}
],
"notifyAll": false
}
}
See the Add Notifications API (v2) for the full parameter reference.
Resolver Status Field
The Notification object includes a field to detect whether the notification resolver was used:
| Field | Type | Description |
|---|
isNotificationResolverUsed | boolean | true once the notification has been enriched via the notification resolver. Use this field to detect resolver usage downstream. |
Sample Data
Stored on your database
Stored on Velt servers
{
"notificationId": "custom-notif-001",
"displayHeadlineMessageTemplate": "{actionUser} left a note on {document}",
"displayHeadlineMessageTemplateData": {
"actionUser": { "userId": "user-123", "name": "Alice" },
"recipientUser": { "userId": "user-456", "name": "Bob" },
"actionMessage": "Check this out"
},
"displayBodyMessage": "Hey Bob, take a look at this section.",
"notificationSourceData": {
"documentId": "doc-789",
"sectionId": "sec-2"
}
}
{
"notificationId": "custom-notif-001",
"notificationSource": "custom",
"isNotificationResolverUsed": true,
"actionUser": { "userId": "user-123" },
"notifyUsers": [{ "userId": "user-456" }]
}
Note: Headline/body templates, template data, and notificationSourceData are NOT stored on Velt servers when using the notification resolver. Only routing identifiers (notificationId, actionUser, notifyUsers), notificationSource, and the isNotificationResolverUsed flag are stored.
Debugging
You can subscribe to dataProvider events to monitor and debug notification resolver operations.
React / Next.js
Other Frameworks
import { useVeltClient } from '@veltdev/react';
const { client } = useVeltClient();
useEffect(() => {
if (!client) return;
const subscription = client.on('dataProvider').subscribe((event) => {
console.log('Data Provider Event:', event);
});
return () => subscription?.unsubscribe();
}, [client]);
const subscription = Velt.on('dataProvider').subscribe((event) => {
console.log('Data Provider Event:', event);
});
// Unsubscribe when done
subscription?.unsubscribe();