Skip to content

fix(auth): resolve V2 API 429 rate limit during authentication - #34

Draft
mattpetters wants to merge 1 commit into
dev-mirzabicer:mainfrom
mattpetters:fix/v2-auth-429-rate-limit
Draft

fix(auth): resolve V2 API 429 rate limit during authentication#34
mattpetters wants to merge 1 commit into
dev-mirzabicer:mainfrom
mattpetters:fix/v2-auth-429-rate-limit

Conversation

@mattpetters

Copy link
Copy Markdown

Summary

Fixes #33 - V2 API returns 429 rate limit during client.connect() after fresh OAuth flow.

Root Cause

TickTick added rate limiting at their AWS ELB level that blocks requests missing proper browser headers. The SDK's minimal header approach was being flagged as bot traffic.

Changes

  • Add Origin: https://ticktick.com header (required)
  • Add Referer: https://ticktick.com/ header (required)
  • Update X-Device header to match web app format with full device info
  • Update web app version from 6430 to 8010

Investigation

Headers were identified by:

  1. Capturing a working auth request from ticktick.com via Chrome DevTools
  2. Comparing against the SDK implementation
  3. Testing minimal header sets via curl to identify the required ones

Testing

Verified fix works with:

  • Direct Python SDK connection test
  • MCP server startup
2026-02-05 14:18:48,257 - httpx - INFO - HTTP Request: POST https://api.ticktick.com/api/v2/user/signon?wc=true&remember=true "HTTP/1.1 200 "
2026-02-05 14:18:48,257 - ticktick_sdk.api.v2.auth - INFO - Successfully authenticated user: ...

@mattpetters
mattpetters marked this pull request as draft February 5, 2026 22:20
The V2 API signon endpoint now requires additional headers to avoid
429 rate limiting at the AWS ELB level:

- Add Origin: https://ticktick.com header
- Add Referer: https://ticktick.com/ header
- Update X-Device header to use full web app format (os, device, channel, etc.)

The version number in X-Device is NOT strictly validated - the original
6430 works fine. The key fix is the Origin/Referer headers and the full
X-Device structure.

Fixes dev-mirzabicer#33
@mattpetters
mattpetters force-pushed the fix/v2-auth-429-rate-limit branch from 3c63359 to 23f4ab5 Compare February 5, 2026 22:25
TWDickson added a commit to TWDickson/ticktick-sdk that referenced this pull request Mar 9, 2026
- Add Origin: https://ticktick.com header
- Add Referer: https://ticktick.com/ header
- Update X-Device header to web app format with full device info
- Update User-Agent to Chrome 120.0

Fixes upstream issue dev-mirzabicer#33, based on PR dev-mirzabicer#34 by mattpetters
hardane pushed a commit to hardane/ticktick-sdk that referenced this pull request Mar 16, 2026
- auth.py & client.py: Mimic real browser headers (Chrome UA, Origin,
  Referer, full x-device) to avoid TickTick's AWS ELB rate limiting.
  Ref: dev-mirzabicer#34

- task.py: Add field_validator for repeat_from to handle string/empty
  values from TickTick API (e.g. "0", "1", "").
  Ref: dev-mirzabicer#29

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@LittleNightmare

Copy link
Copy Markdown

Thanks for this fix — verified working here (Windows 11, ticktick-sdk 0.4.3 installed via pipx, used as an MCP server): sign-on went 429 → 200 with these headers.

One heads-up from testing: after applying only this patch, /api/v2/user/signon succeeds but regular V2 data requests still get 429. Concretely, GET /api/v2/batch/check/0 fails during the post-auth verification, and every read tool call (list_projects, etc.) returns "Rate limit exceeded". I reproduced this twice back-to-back — sign-on 200 and batch/check 429 within the same second — which points to header-based blocking on that endpoint as well, not genuine rate limiting.

The root cause is that request headers are built in two independent places, and this PR only covers the auth one:

  • SessionHandler._get_headers() in api/v2/auth.py — ✅ patched by this PR
  • TickTickV2Client._get_auth_headers() / _get_x_device_header() in api/v2/client.py — ❌ still sends Mozilla/5.0 (rv:145.0) Firefox/145.0, the minimal 3-field X-Device, and no Origin/Referer

Locally I extended the same treatment to the data path (Chrome User-Agent + Origin + Referer + full web-app X-Device format, reusing the SessionHandler helpers, plus aligning the UA constants). After that, batch/check returns 200 and all tools work.

Would you consider extending this PR to cover api/v2/client.py too? Happy to test any follow-up.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

V2 API returns 429 rate limit during client.connect() after fresh OAuth flow

2 participants