Error 131056 WhatsApp API: Rate Limit Hit — How to Fix
Complete guide to fix error 131056 (rate limit hit) on WhatsApp Business API. Causes, subcodes, pair rate limit and solutions with code examples.
What is Error 131056?
Error 131056 is the rate limit hit error from the WhatsApp Business API. It occurs when your application exceeds sending limits — either the account's global limit, the per-phone-number limit, or the pair rate limit (the limit between your business number and a specific consumer number).
{
"error": {
"message": "(#131056) (business account, consumer account) pair rate limit hit",
"type": "OAuthException",
"code": 131056,
"error_subcode": 2494055,
"fbtrace_id": "..."
}
}
This is one of the most common errors in high-scale operations and can seriously impact your campaigns if not handled correctly.
Types of Rate Limits That Trigger 131056
Error 131056 is not a single limit — it can be triggered by three different types of rate limiting:
1. Pair Rate Limit (Business ↔ Consumer)
The most frequent. Occurs when you send too many messages to the same number in a short period.
Your Business Number → Customer Number = PAIR
Approximate limits:
- Maximum ~80 messages per second per pair
- Maximum ~256 template messages per active conversation
- If the user doesn't reply, Meta progressively reduces the limit
2. Phone Number Throughput Limit
Occurs when your Business number sends messages too fast, regardless of destination.
Cloud API:
- Default limit: 80 msg/s
- Maximum limit: 1,000 msg/s (for eligible accounts that request an increase)
Business App:
- Default limit: ~10 msg/min
- Maximum limit: N/A
3. 24h Conversation Tier Limit
Occurs when you exceed the number of new conversations you can initiate in 24 hours.
- Unverified: 250 conversations/24h
- Tier 1: 1,000 conversations/24h
- Tier 2: 10,000 conversations/24h
- Tier 3: 100,000 conversations/24h
- Tier 4: Unlimited
Error Subcodes
Error 131056 may come with different subcodes indicating which type of rate limit was reached:
- 2494055 — Pair rate limit: Too many messages to the same user
- 2494056 — Account rate limit: Global account limit reached
- 2494057 — Spam rate limit: Spam pattern detected
- 2494058 — Throughput limit: Too many API calls per second
Common Causes
1. Spamming the Same User
The most common scenario: sending multiple template messages to the same number without waiting for a reply.
// ❌ WRONG: bombarding the same number
for (const template of templates) {
await sendTemplate(userPhone, template); // Will trigger 131056
}
// ✅ CORRECT: space out and limit per user
const MAX_TEMPLATES_PER_USER = 3;
const DELAY_BETWEEN_MESSAGES = 5000; // 5 seconds
for (let i = 0; i < Math.min(templates.length, MAX_TEMPLATES_PER_USER); i++) {
await sendTemplate(userPhone, templates[i]);
await new Promise(r => setTimeout(r, DELAY_BETWEEN_MESSAGES));
}
2. Bulk Campaign Without Rate Limiting
Sending to your entire contact base at once without speed control.
3. Aggressive Retry
When the first attempt fails and the system retries immediately without backoff.
4. Multiple Systems Sending
Two or more systems (CRM, chatbot, campaigns) sending through the same number without coordination.
Solutions
1. Implement Rate Limiter with Bottleneck
import Bottleneck from 'bottleneck';
// Global limiter: respects Cloud API throughput
const globalLimiter = new Bottleneck({
minTime: 15, // ~66 msg/s (below the 80 limit)
maxConcurrent: 10,
reservoir: 5000,
reservoirRefreshAmount: 5000,
reservoirRefreshInterval: 60 * 1000
});
// Per-user limiter: prevents pair rate limit
const userLimiters = new Map();
function getUserLimiter(userId) {
if (!userLimiters.has(userId)) {
userLimiters.set(userId, new Bottleneck({
minTime: 3000, // 1 msg every 3 seconds per user
maxConcurrent: 1,
reservoir: 10, // Max 10 msgs per window
reservoirRefreshAmount: 10,
reservoirRefreshInterval: 60 * 60 * 1000 // Refreshes every hour
}));
}
return userLimiters.get(userId);
}
async function safeSendMessage(to, message) {
const userLimiter = getUserLimiter(to);
return globalLimiter.schedule(() =>
userLimiter.schedule(() =>
sendWhatsAppMessage(to, message)
)
);
}
2. Exponential Backoff with Jitter
When you receive 131056, don't retry immediately. Use backoff with jitter to avoid thundering herd:
async function sendWithBackoff(to, message, attempt = 1, maxAttempts = 5) {
try {
return await sendWhatsAppMessage(to, message);
} catch (error) {
if (error.code === 131056 && attempt < maxAttempts) {
// Exponential backoff with jitter
const baseDelay = Math.pow(2, attempt) * 1000;
const jitter = Math.random() * 1000;
const delay = baseDelay + jitter;
console.log(
`[131056] Rate limit for ${to}. ` +
`Attempt ${attempt}/${maxAttempts}. ` +
`Waiting ${(delay / 1000).toFixed(1)}s...`
);
await new Promise(r => setTimeout(r, delay));
return sendWithBackoff(to, message, attempt + 1, maxAttempts);
}
throw error;
}
}
3. Queue with BullMQ and Rate Limiting
For high-scale operations, use queues with speed control:
import { Queue, Worker } from 'bullmq';
const messageQueue = new Queue('whatsapp-messages', {
connection: { host: 'localhost', port: 6379 }
});
// Enqueue message
async function queueMessage(to, message, priority = 'normal') {
await messageQueue.add(
'send',
{ to, message },
{
priority: priority === 'urgent' ? 1 : 10,
attempts: 5,
backoff: {
type: 'exponential',
delay: 3000
},
// Group by recipient to avoid pair rate limit
group: { id: to }
}
);
}
// Worker with built-in rate limiting
const worker = new Worker(
'whatsapp-messages',
async job => {
return await sendWhatsAppMessage(job.data.to, job.data.message);
},
{
connection: { host: 'localhost', port: 6379 },
limiter: {
max: 50, // 50 messages
duration: 1000 // per second
},
concurrency: 5
}
);
worker.on('failed', (job, error) => {
if (error.code === 131056) {
console.log(`Rate limit for ${job.data.to}. Auto-retry scheduled.`);
}
});
4. Monitor and Auto-Pause
class RateLimitMonitor {
constructor() {
this.rateLimitCount = 0;
this.totalSent = 0;
this.windowStart = Date.now();
}
recordSent() {
this.totalSent++;
}
recordRateLimit() {
this.rateLimitCount++;
}
getRateLimitPercentage() {
if (this.totalSent === 0) return 0;
return (this.rateLimitCount / this.totalSent) * 100;
}
shouldPause() {
// Pause if more than 5% of messages hit rate limit
return this.getRateLimitPercentage() > 5;
}
shouldSlowDown() {
// Slow down if more than 2% hit rate limit
return this.getRateLimitPercentage() > 2;
}
reset() {
this.rateLimitCount = 0;
this.totalSent = 0;
this.windowStart = Date.now();
}
}
const monitor = new RateLimitMonitor();
async function sendWithMonitoring(to, message) {
if (monitor.shouldPause()) {
console.log('⚠️ High rate limit ratio. Pausing for 60s...');
await new Promise(r => setTimeout(r, 60000));
monitor.reset();
}
try {
const result = await sendWhatsAppMessage(to, message);
monitor.recordSent();
return result;
} catch (error) {
if (error.code === 131056) {
monitor.recordRateLimit();
}
throw error;
}
}
Difference Between 131056 and Other Errors
- 131056 — Rate limit hit: ✅ Yes, retry with backoff
- 131047 — 24h window expired: ❌ No (use template)
- 131026 — Message undeliverable: ❌ No (invalid number)
- 130429 — Cloud API throttle: ✅ Yes, retry with backoff
The key difference: 131056 is temporary. Waiting and retrying resolves it. Other errors indicate problems that retry won't fix.
Prevention: Best Practices
-
Gradual warm-up: Never send at maximum capacity on new accounts. Start at 10% and scale up over 14 days.
-
Respect opt-out: Users who block or report reduce your Quality Rating and increase rate limiting chances.
-
Coordinate systems: If multiple services send through the same number, use a centralized queue.
-
Monitor Quality Rating: Low Quality Rating = more aggressive limits.
async function checkQualityAndLimits() {
const response = await fetch(
`https://graph.facebook.com/v22.0/${phoneNumberId}` +
`?fields=quality_rating,messaging_limit_tier`,
{
headers: {
'Authorization': `Bearer ${accessToken}`
}
}
);
const data = await response.json();
console.log('Quality:', data.quality_rating);
console.log('Tier:', data.messaging_limit_tier);
return data;
}
- Use response headers: The Cloud API returns rate limit headers. Monitor them:
async function sendAndCheckHeaders(to, message) {
const response = await fetch(/* ... */);
// Rate limit headers
const remaining = response.headers.get('x-ratelimit-remaining');
const reset = response.headers.get('x-ratelimit-reset');
if (remaining && parseInt(remaining) < 10) {
console.log(`⚠️ Only ${remaining} calls remaining. Reset in ${reset}s`);
}
return response.json();
}
Conclusion
Error 131056 is recoverable — unlike other WhatsApp API errors, you just need to wait and retry. The key takeaways:
- Implement rate limiting before sending (prevent > cure)
- Exponential backoff with jitter on retries
- Centralized queue to coordinate multiple systems
- Active monitoring to pause when error rates climb
Need help scaling your WhatsApp operation without rate limits? Contact me for specialized consulting.