API Reference
Integrate Valerie feedback collection into your applications. Programmatically manage sites, retrieve responses, and build custom feedback workflows.
Authentication
Valerie uses two types of authentication depending on the endpoint:
Site ID (Widget Endpoints)
Public widget endpoints use your Site ID for identification. Find your Site ID in theDashboard Settings.
Bearer Token (Dashboard API)
Dashboard API endpoints require authentication via Supabase session. Use the dashboard to access your data or integrate via the widget.
Your Site ID (example)
SITE_01HXYZ1234567890ABCDEFFind your Site ID at: Dashboard → Settings → Site Information
Base URL
All API requests should be made to:
https://talktovalerie.com/apiAll endpoints support HTTPS only. HTTP requests will be redirected.
Widget Endpoints
These endpoints power the Valerie feedback widget. They are public and require only your Site ID.
/api/valerie/decideDetermines whether to show the feedback widget to a visitor based on targeting rules, sampling rate, and frequency settings.
Query Parameters
sitestringrequiredYour Site IDpathstringCurrent page path (default: /)visitorIdstringUnique visitor identifier for consistent A/B assignmentExample Request
cURL
curl "https://talktovalerie.com/api/valerie/decide?site=SITE_01HXYZ&path=/pricing"JavaScript / TypeScript
const response = await fetch(
'https://talktovalerie.com/api/valerie/decide?' +
new URLSearchParams({
site: 'SITE_01HXYZ',
path: window.location.pathname,
visitorId: localStorage.getItem('valerie_visitor_id')
})
);
const decision = await response.json();
if (decision.show) {
// Show feedback widget with decision.question
console.log('Question:', decision.question.highlight);
console.log('Session Token:', decision.sessionToken);
}Example Response
{
"show": true,
"reason": "eligible",
"siteId": "SITE_01HXYZ",
"path": "/pricing",
"question": {
"prefix": "How helpful was",
"highlight": "this page?",
"leftLabel": "Not helpful at all",
"rightLabel": "Extremely helpful",
"format": "scale",
"options": []
},
"questionId": "123",
"followup": {
"low": { "title": "What could we improve?", "placeholder": "Tell us more..." },
"mid": { "title": "Any suggestions?", "placeholder": "Tell us more..." },
"high": { "title": "What did you like?", "placeholder": "Tell us more..." }
},
"sessionToken": "eyJhbGciOiJIUzI1NiIs...",
"frequency": { "mode": "always" },
"popup": {
"format": "floating_card",
"timing": "delay_5s",
"typingAnimation": false
},
"theme": {
"themePreset": "default",
"colors": {
"primary": "#8B5CF6",
"background": "#FFFFFF",
"text": "#1E293B",
"buttonText": "#FFFFFF"
}
}
}/api/valerie/ingestSubmit feedback events including widget interactions, score selections, and responses. Requires a valid session token from the decide endpoint.
Request Body
sessionTokenstringrequiredSession token from decide endpointvisitorIdstringrequiredUnique visitor identifierpageViewIdstringrequiredUnique page view identifiereventsarrayrequiredArray of event objectsclientobjectClient metadata (referrer, language, timezone)Example Request
cURL
curl -X POST "https://talktovalerie.com/api/valerie/ingest" \
-H "Content-Type: application/json" \
-d '{
"sessionToken": "eyJhbGciOiJIUzI1NiIs...",
"visitorId": "visitor_abc123",
"pageViewId": "pv_xyz789",
"events": [
{
"eventId": "evt_001",
"type": "response_submit",
"ts": 1706745600000,
"score": 9,
"comment": "Great pricing page!"
}
],
"client": {
"referrer": "https://google.com",
"language": "en-US",
"timezone": "America/New_York"
}
}'JavaScript / TypeScript
const submitFeedback = async (sessionToken, score, comment) => {
const response = await fetch('https://talktovalerie.com/api/valerie/ingest', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
sessionToken,
visitorId: localStorage.getItem('valerie_visitor_id'),
pageViewId: crypto.randomUUID(),
events: [{
eventId: crypto.randomUUID(),
type: 'response_submit',
ts: Date.now(),
score,
comment
}],
client: {
referrer: document.referrer,
language: navigator.language,
timezone: Intl.DateTimeFormat().resolvedOptions().timeZone
}
})
});
return response.status === 204; // Success
};Example Response
// Success: HTTP 204 No Content
// Error: HTTP 400/401/429 with JSON body
// Rate limit exceeded:
{
"error": "Rate limit exceeded"
}
// Invalid token:
{
"error": "Unauthorized"
}Dashboard API
These endpoints are used by the Valerie dashboard. They require authentication and are designed for internal use. For programmatic access, we recommend using the widget endpoints or contacting us for enterprise API access.
/api/dashboard/sitesRequires AuthList all sites associated with your account.
Example Request
cURL
curl "https://talktovalerie.com/api/dashboard/sites" \
-H "Authorization: Bearer YOUR_SESSION_TOKEN"Example Response
{
"sites": [
{
"id": "SITE_01HXYZ",
"name": "example.com",
"allowedDomains": ["example.com", "www.example.com"],
"createdAt": "2024-01-15T10:30:00Z"
}
]
}/api/dashboard/sitesRequires AuthCreate a new site for feedback collection.
Request Body
namestringrequiredDisplay name for the sitedomainstringrequiredPrimary domain (e.g., example.com)Example Request
cURL
curl -X POST "https://talktovalerie.com/api/dashboard/sites" \
-H "Authorization: Bearer YOUR_SESSION_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "My New Site",
"domain": "newsite.com"
}'Example Response
{
"site": {
"id": "SITE_01HABCD",
"name": "My New Site",
"allowedDomains": ["newsite.com"],
"createdAt": "2024-02-01T15:00:00Z"
}
}/api/dashboard/responsesRequires AuthRetrieve feedback responses with filtering and pagination.
Query Parameters
siteIdstringrequiredYour Site IDpagenumberPage number (default: 1)limitnumberResults per page (default: 20, max: 100)periodstringTime period: 24h, 7d, 30dpathstringFilter by page pathscoreMinnumberMinimum score filterscoreMaxnumberMaximum score filterwithCommentsbooleanOnly show responses with commentsgroupBystringGroup results: question, dateExample Request
cURL
curl "https://talktovalerie.com/api/dashboard/responses?siteId=SITE_01HXYZ&period=7d&limit=50" \
-H "Authorization: Bearer YOUR_SESSION_TOKEN"JavaScript / TypeScript
const getResponses = async (siteId, options = {}) => {
const params = new URLSearchParams({
siteId,
page: options.page || 1,
limit: options.limit || 20,
...(options.period && { period: options.period }),
...(options.path && { path: options.path }),
...(options.withComments && { withComments: 'true' }),
});
const response = await fetch(
`https://talktovalerie.com/api/dashboard/responses?${params}`,
{
headers: {
'Authorization': `Bearer ${sessionToken}`
}
}
);
return response.json();
};Example Response
{
"responses": [
{
"id": 12345,
"pageViewId": "pv_abc123",
"visitorId": "v_xyz789",
"path": "/pricing",
"score": 9,
"comment": "Very clear pricing tiers!",
"occurredAt": "2024-02-01T14:30:00Z",
"country": "US",
"device": "desktop",
"question": {
"prefix": "How helpful was",
"highlight": "this page?",
"path": "/*",
"format": "scale"
}
}
],
"pagination": {
"page": 1,
"limit": 20,
"totalCount": 156,
"totalPages": 8
},
"distribution": {
"promoters": 89,
"passives": 42,
"detractors": 25
},
"paths": ["/", "/pricing", "/features", "/docs"]
}/api/dashboard/responsesRequires AuthDelete individual or bulk responses.
Request Body
siteIdstringrequiredYour Site IDresponseIdnumberSingle response ID to deletevisitorIdstringDelete all responses from a visitorperiodstringBulk delete by period: 24h, 7d, 30dExample Request
cURL
curl -X DELETE "https://talktovalerie.com/api/dashboard/responses" \
-H "Authorization: Bearer YOUR_SESSION_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"siteId": "SITE_01HXYZ",
"responseId": 12345
}'Example Response
{
"success": true,
"deleted": 1
}Rate Limits
To ensure fair usage and protect our infrastructure, API endpoints have rate limits:
| Endpoint | Limit | Window | Scope |
|---|---|---|---|
| /api/valerie/decide | 60 requests | 1 minute | Per Site + IP |
| /api/valerie/ingest | 100 requests | 1 minute | Per Site + Session |
| /api/dashboard/* | 100 requests | 1 minute | Per User |
Rate Limit Headers
When rate limited, the API returns a 429 Too Many Requests status.
HTTP/1.1 429 Too Many Requests
Retry-After: 30Error Codes
The API uses standard HTTP status codes and returns JSON error responses:
Request completed successfully.
Request successful, no content to return (used for ingest).
Invalid request parameters or malformed JSON.
{ "error": "siteId required" }Missing or invalid authentication credentials.
{ "error": "Unauthorized" }Rate limit exceeded. Wait before retrying.
{ "error": "Rate limit exceeded" }Unexpected server error. Contact support if persistent.
{ "error": "Internal server error" }Webhooks
Coming Soon
Webhook support for real-time feedback notifications is on our roadmap. Get notified instantly when new feedback arrives.
In the meantime, use our email notifications for daily digests and urgent feedback alerts.
SDKs & Integrations
The easiest way to integrate Valerie is with our JavaScript widget:
Add to your HTML
<script src="https://talktovalerie.com/valerie/v1.js" data-site-id="YOUR_SITE_ID" async></script>JavaScript API
Once loaded, the widget exposes a global window.Valerie object:
// Open the feedback widget programmatically
window.Valerie.open();
// Close the widget
window.Valerie.close();
// Track a custom event
window.Valerie.track('button_click', { buttonId: 'cta-main' });
// Identify a user (for logged-in experiences)
window.Valerie.identify({
userId: 'user_123',
email: 'user@example.com',
plan: 'pro'
});
// Update page context (for SPAs)
window.Valerie.page('/new-path');Need Help?
Have questions about the API or need enterprise-level access? Our team is here to help you integrate Valerie into your workflow.