Hi @lubos and community,
I’m automating payroll posting to Managerio via API2, and I’m consistently hitting HTTP 429
“Too Many Requests” when pushing multiple payslips in sequence.
I’d appreciate guidance on the rate limit policy and the recommended approach for batch operations.
## Context
Use case: Monthly payroll — compute PPh 21 (Indonesian income tax) locally, then push payslips to Managerio via `PUT /api2/payslip-form/{uuid}`
Expected scale: 10–100 payslips per run, processed in one batch (typical Indonesian company payroll size)
Edition: Cloud (`.manager.io`)
Managerio version: 26.4.20.3419
API API2 (`/api2/…` endpoints)
Auth: `X-API-KEY` header with access token
## The Problem
When pushing multiple payslips in quick succession, the server returns 429 for all requests. Pattern observed during testing: -
Two payslips pushed via `httpx` async client → each payslip gets 3 retries → all 6 attempts return 429
Total of 6 requests fail within ~10 seconds
Same pattern reproduced across different days and times (morning 09:42 WIB and afternoon 15:18 WIB) -
After waiting ~1 hour, requests succeed again
Also observed during `curl` probing — 5 consecutive requests within <5 seconds all returned 429
Service temporarily unavailable. Please try again in a few seconds. HTTP 429
*(Note: No `Retry-After`, `X-RateLimit-Limit`, `X-RateLimit-Remaining`, or `X-RateLimit-Reset` headers present in the 429 response. I didn’t capture full response headers during testing — happy to rerun with full header logging if that helps diagnosis.)*
## Pattern Details
Observation
Detail
Trigger threshold
2 parallel PUTs → 429 within seconds
Retry behavior
Immediate retries all fail with 429
Time of day
Observed at both 09:42 WIB and 15:18 WIB
## What I’ve Already Implemented
Idempotent PUT with client-generated UUIDs (retry-safe, no duplicates)
Three retry attempts per payslip with ~2-second spacing
Fail-fast circuit after consecutive failures
Honoring `Retry-After` header via tenacity (but 429 responses don’t include it)
## Questions
Source of the 429: Is the rate limiting applied at the Manager.io application layer, or is it coming from the Cloudflare edge (since manager.io is behind Cloudflare)? The absence of any Manager-specific rate limit headers suggests it might be a Cloudflare edge rule, but confirmation would help me design proper mitigation.
Rate limit policy: Is there a documented rate limit for API2 endpoints, particularly for write operations (POST/PUT)? The API documentation at `/api2/` doesn’t seem to mention rate limits explicitly.
Recommended throttling: For batch operations like pushing 50–100 payslips sequentially, what request-per-second rate would you recommend to stay safely under the limit? I’ve seen MarkLL’s 2021 benchmark of ~7 req/sec sequential working for GET operations on self-hosted — is the cloud limit more restrictive, especially for writes?
Bulk endpoint: Is there a bulk/batch endpoint for creating multiple payslips in a single request, or one planned for the future? This would significantly reduce round-trip overhead for monthly payroll runs.
## What Would Help
Even a rough answer like *“keep it under N requests per second, sequential”* or *“the edge rule blocks >M requests per minute”* would be hugely useful for designing the retry and throttling strategy correctly.
Thanks for any guidance and thanks for maintaining such a capable API.
Happy to provide more diagnostic data (timestamps, full response headers from a reproduction run, etc.) if useful for investigation.
This is solved in APIv4 which has /api4/payslip-batch endpoint which allows to submit unlimited payslips in single request. Although I don’t support PUT yet. Only POST. I will add PUT because I need it too.
Thanks for the incredibly fast response, @lubos — and great to hear /api4/payslip-batch is the intended solution for this. That changes the architectural picture significantly.
One concern, though: idempotency is critical for my use case. Payroll runs must be retry-safe — if a network timeout hits mid-batch, I need to safely re-submit without creating duplicate payslips. With PUT /api2/payslip-form/{uuid} + client-generated UUIDs I get that guarantee today. With POST /api4/payslip-batch, a retry after partial success risks duplicates.
So while I wait for PUT support on the batch endpoint, I plan to stay on /api2/payslip-form with sequential requests + throttling for the short term.
A few quick questions if you have a moment:
Rough ETA for PUT on /api4/payslip-batch? Even an order-of-magnitude answer (weeks vs. months) would help me plan migration timing. No pressure — totally understand roadmap uncertainty.
For /api2/payslip-form PUT in the meantime — is there a recommended request rate to stay below the 429 threshold? I’m thinking ~1 request per 2 seconds sequential. Is that safe, or still too fast?
When /api4/payslip-batch PUT ships — will it accept client-generated UUIDs per payslip in the batch, so the same idempotency model applies (retry = replace-in-place per payslip)?
Thanks again — really appreciate you maintaining such an active response channel for API users.
Wow, thank you @lubos — that’s incredibly fast turnaround. Migrating to /api4/payslip-batch PUT is now the clear path forward for my integration.
The client-generated UUID confirmation is exactly what I needed — same
idempotency model as /api2/payslip-form PUT means minimal architectural
change on my end. I’ll test against version 26.4.22.3433 in the coming
days and can share feedback if I hit anything unexpected.
Really appreciate the API responsiveness and the active development on /api4/. Will follow up here if I find anything worth reporting during
integration.
Quick update @lubos — started testing /api4/payslip-batch and hit an authentication blocker I wanted to flag before going further.
When I call /api4/ endpoints with the same X-API-KEY header that works fine for /api2/, I consistently get:
HTTP/2 401
www-authenticate: Basic realm=“Manager”
{“error”:“authentication_required”,“message”:“Authentication is required to access this endpoint.”}
Looking at the OpenAPI spec, the AccessToken schema exposes separate name and password fields — but in the UI, the access token page only displays a single encoded string (which works as X-API-KEY for /api2/).
Question: For external clients (not running inside an IFRAME extension), how do I obtain the Basic Auth credentials for /api4/?
Are they the same name/password I use to log into the Manager.io web UI?
Or are they separate credentials generated per access token that I’m missing in the UI?
Or should existing access tokens continue to work on /api4/ once I figure out the right header/format?
For context on why this matters: if the credentials are the UI login credentials, that creates security/scoping concerns for integration patterns where the token holder isn’t the Manager.io account owner. The current /api2/ access token model (scoped, revocable, not tied to user login) is ideal for that use case.
Apologies for the back-and-forth — just want to make sure I understand the intended auth model before investing in the migration.
Currently, api4 supports username/password only. I don’t like “access tokens” concept anymore. I think I will implement OAuth for api4 so you can either supply username:password (not very secure but simple) or obtain OAuth token.
Crystal clear, thanks @lubos. For my use case — integration where the token holder isn’t the Managerio account owner (so sharing username/password isn’t really on the table) — I’ll stay on /api2/ with access tokens for now. That model is exactly the scoped, revocable fit I need.
The OAuth direction for /api4/ sounds ideal. Any rough sense of timing? Fully understand if there’s no ETA — even “this quarter” vs “next year” would help me decide whether to design my integration layer with a near-term OAuth migration in mind or treat /api2/ as the stable path for the foreseeable future.
Either way, really appreciate the transparency on the roadmap thinking. Super helpful for planning.