Guides
Rate limiting
The Puntjes API enforces two types of limits: rate limits (requests per minute) and plan limits (what the vendor's plan includes). Only the transaction allowance is monthly; the rest are standing ceilings that do not reset.
Rate limits
Each vendor's billing plan defines a maximum number of API requests per minute (rate_limit_per_minute). When this limit is exceeded, the API returns:
HTTP 429 Too Many Requests
Every response carries X-RateLimit-Limit and X-RateLimit-Remaining, so you can read your allowance without exhausting it first.
The count is kept per vendor. Your plan's number is the whole allowance, so a second set of credentials does not buy a second window: a till and a webshop on one account spend the same one, and a runaway integration throttles your others with it. It is not keyed on the calling address, so colleagues behind a single office connection never share an allowance with another vendor.
Refused requests count too
The limiter runs ahead of authentication and the account checks, so a request that is going to fail still spends one of your requests. A wrong client secret answers 401, a suspended account answers 403, and both decrement the counter that a successful call decrements.
This changes how you debug a new integration. A retry loop against a bad credential reaches 429, and that 429 tells you nothing about the credential. It only means you asked too often. Fix the secret; do not read the throttle as a second clue.
Requests with no valid vendor
When a credential resolves to no account that may use the API, the request is counted against a separate and much smaller allowance, keyed on the calling address instead of the vendor. There is no vendor to key on when the token cannot be read. Three cases land here: a missing or invalid bearer token, a client that is not linked to a vendor, and an account whose status refuses access.
Your plan's allowance is untouched by that counter. The two are separate, so someone probing your address with bad tokens cannot spend the requests you pay for.
Handling rate limits
When you receive a 429 response:
- Wait before retrying: implement exponential backoff
- Review your integration's request patterns
- Consider caching responses where appropriate (e.g., reward lists, campaign lists)
Plan usage limits
Each billing plan sets these ceilings. Zero means unlimited on every one of them.
| Limit | Resets | Description |
|---|---|---|
max_transactions | Monthly | Transactions per billing period |
max_customers | Never | Customers the vendor may hold in total |
max_rewards | Never | Active rewards |
max_campaigns | Never | Campaigns the vendor may hold |
max_locations | Never | Branches the vendor may hold |
rate_limit_per_minute | Per minute | API requests per minute |
Only the transaction allowance resets. A POST /customers refused because the plan's
customer ceiling is reached will still be refused next month. The vendor has to upgrade or
delete a customer. Retrying it later is not a fix.
That refusal is a 422 VALIDATION_ERROR, not a 429. The 429 PLAN_LIMIT_EXCEEDED code is
reserved for the transaction meter, because it is the only ceiling whose refusal clears with
time.
Overage threshold
Plans include an overage threshold (percentage buffer). For example, with a limit of 1000 transactions and a 10% overage threshold, the hard limit is 1100 transactions.
Once the hard limit is reached, the API returns:
{
"error": {
"code": "PLAN_LIMIT_EXCEEDED",
"message": "Transaction limit exceeded for your subscription plan.",
"status": 429
}
}
Feature flags
Some features are controlled by the billing plan:
| Capability | Description |
|---|---|
| Campaigns | Whether the vendor can create and use campaigns |
| Customer moment campaigns | Whether those campaigns may be birthday, anniversary or win-back gifts, or only point multipliers |
| Point expiration | Whether the vendor can enable point expiration |
If a feature is not included in the plan, attempting to use it returns an error.
Checking usage
Billing in the admin portal shows the current period: transactions recorded, the allowance the plan includes, whether that allowance is spent, and the last day of the period.
The API reports none of that. There is no usage endpoint and no remaining-allowance
header, so an integration still learns its allowance is gone from a
429 PLAN_LIMIT_EXCEEDED on the next POST /transactions: a response that does not clear
by waiting inside the period. Write that branch anyway; see
Error handling.
The meter measures against the number the tier advertises, not against the hard limit.
Filling it does not stop anything (the overage threshold above is how far writes keep
going), but it is the point the plan stops covering, so the meter marks it and says the
allowance is spent. It turns again at the hard limit, where the 429 starts.
Plan upgrades
If your integration consistently hits plan limits, contact your Puntjes administrator to upgrade to a plan with higher limits.