Documentation

API: Errors & Rate Limits

Pingovo uses standard HTTP status codes, and every error body carries a machine-readable error code plus a human-readable message. Branch on the status and the code; show the message to people.

HTTP status codes

StatusMeaningRetry?
200Success.—
400The request is malformed or a field is invalid. Fix it and resend.No
401API key missing, invalid, deactivated or expired.No
402Not enough credits for this call.After topping up
403API access is not enabled on your plan, the request came from an IP that is not on the key’s allowlist, your email is unverified, campaign access is not approved (for /send), or the key was revoked by Pingovo.No
404The send or template does not exist on your account.No
422The recipient was refused: invalid, suppressed or skipped by your rules.No
429Too many requests, your daily send limit is used up, or too many sends are queued. Wait for Retry-After.Yes, after Retry-After
500Something went wrong on our side.Yes, with backoff
502Verification or delivery could not be completed.Yes, with backoff

Rate limits

Your plan sets how many requests you can make per minute and per day. The allowance is shared by all of your API keys, so a second key does not buy more. A key can additionally be given its own per-minute cap to stop one integration starving another.

Every authenticated response tells you where you stand:

HeaderMeaning
X-RateLimit-LimitRequests per minute allowed for your account.
X-RateLimit-RemainingRequests left in the current minute.
X-RateLimit-ResetSeconds until the per-minute window resets.
Retry-AfterOn a 429 only: seconds to wait before trying again.

A rate-limited call never reaches the endpoint, so it is never charged:

HTTP/1.1 429 Too Many Requests
Retry-After: 23

{
  "success": false,
  "error": "RATE_LIMITED",
  "message": "Rate limit exceeded (60 requests per minute). Retry after 23s.",
  "retry_after_seconds": 23,
  "limit": 60,
  "window": "minute"
}
errorCause
RATE_LIMITEDYour plan’s requests-per-minute or per-day allowance (or the key’s own cap) was exceeded. window says which.
AUTH_THROTTLEDThe IP address you are calling from presented too many unknown or missing API keys and is blocked for a while. Every call from it is refused, even with a valid key, until the block lifts.
DAILY_LIMIT_REACHEDYour own daily_send_limit on /send is used up. See resets_at.
SEND_QUEUE_BUSYToo many /send calls are waiting behind delay_between_emails.

Handling 429 properly

Wait the number of seconds in Retry-After, then retry. If the header is missing, back off exponentially. Do not retry in a tight loop — against AUTH_THROTTLED that only extends the block.

# -i prints the response headers: X-RateLimit-Limit, X-RateLimit-Remaining,
# X-RateLimit-Reset on every call, and Retry-After on a 429.
curl -i https://pingovo.com/api/v1/credits \
  -H "X-API-Key: YOUR_API_KEY"

Authentication errors

StatusmessageFix
401API key is required. Please provide X-API-Key header.Add the header.
401Invalid API keyCheck for a typo or a truncated copy.
401API key has been deactivatedRe-enable it in Dashboard → API, or create a new key.
401API key has expiredCreate a new key.
403IP address not whitelisted for this API keyCall from an allowed IP, or edit the key’s allowlist.
403Email verification requiredVerify your account email address.
403API_KEY_REVOKEDPingovo revoked this key (the response names a neutral reason category). It cannot be re-enabled from the dashboard — contact support.

Insufficient credits

A 402 from /send tells you exactly how short you are:

{
  "success": false,
  "error": "INSUFFICIENT_CREDITS",
  "message": "Not enough credits to send this email",
  "credits_required": 11,
  "credits_available": 4,
  "tracking_credits": 10
}

tracking_credits appears only when you asked for tracking and is the part of credits_required that tracking accounts for.

Verify endpoint errors

StatuserrorMeaning
400EMAIL_REQUIRED/verify was called without an email.
400INVALID_EMAILThe value is not a well-formed email address.
400EMAILS_REQUIRED/verify/batch was called without an emails array.
400EMPTY_ARRAYThe emails array is empty.
400BATCH_LIMIT_EXCEEDEDMore than 50 emails in one batch.
402INSUFFICIENT_CREDITSNot enough credits for the batch.

Reliability tips

  • Store the ids. Keep send_id and request_id next to your own record. They are how you and support find a specific email.
  • Retry only what is safe. A 429 or 5xx means the email was not sent, but a timeout leaves it unknown: check GET /sends?q=recipient before resending, or you may send a customer the same email twice.
  • Do not retry 4xx. The same request will fail the same way.
  • Set client timeouts above 50 seconds if you use delay_between_emails.

Still have questions?

Our support team is happy to help. Open a ticket from your dashboard or use the contact form.

We use essential cookies to run this site, and optional functional/analytics cookies to improve it. See our Privacy Policy for details.