One limit that matters for most integrations: messages per day, by plan. Everything else you need is in three response headers.
Counted per user, resets on a rolling 24-hour window from your first message of the day. Service-account API-key traffic (a platform integration acting on behalf of many users) isn't counted against any one user's cap.
Daily message allowance
Need a higher Free/Plus cap for a specific use case? See plans or contact us.
Every response carries your current standing. Check these instead of tracking your own counter.
Response headers
X-RateLimit-LimitX-RateLimit-RemainingX-RateLimit-ResetHTTP/1.1 200 OK
Content-Type: application/json
X-RateLimit-Limit: 50
X-RateLimit-Remaining: 47
X-RateLimit-Reset: 1741521600Hit the daily cap and the next message returns 429. error.detail spells out the limit and the reset window in plain text. Parse it for a person, don't try to extract a machine value from it.
{
"error": {
"code": 429,
"message": "Daily message limit reached",
"detail": "Limit: 50/day. Resets in 6h. Upgrade for more."
}
}X-RateLimit-Reset to pass, or upgrade the account's plan.A small helper that surfaces remaining quota before the request fails outright.
async function dyvaSend(url, options = {}) {
const res = await fetch(url, options);
const remaining = Number(res.headers.get("X-RateLimit-Remaining"));
if (Number.isFinite(remaining) && remaining <= 5) {
console.warn(`Only ${remaining} messages left today.`);
}
if (res.status === 429) {
const { error } = await res.json();
const resetAt = new Date(Number(res.headers.get("X-RateLimit-Reset")) * 1000);
throw new Error(`${error.detail} (resets ${resetAt.toLocaleTimeString()})`);
}
return res.json();
}