[GH-ISSUE #1173] Return rate limits when limited #827

Open
opened 2026-05-07 00:27:49 +02:00 by BreizhHardware · 4 comments

Originally created by @ThisIsMissEm on GitHub (Aug 27, 2024).
Original GitHub issue: https://github.com/binwiederhier/ntfy/issues/1173

💡 Idea

Currently when ntfy rate limits a client, it seems to just send the 429 status code back, but doesn't advise as to when the rate limit would be lifted. This means that clients can't dynamically pause sending notifications until the rate limit resets, which leads to IP bans.

There is a standards track IETF proposal for RateLimit headers, which could make sense to use: https://www.ietf.org/archive/id/draft-ietf-httpapi-ratelimit-headers-07.html

This currently affects Mastodon: https://github.com/mastodon/mastodon/issues/26078

By advertising when the rate limits reset, we could delay all other notification until after the rate limit resets. I tried to look at both the documentation and code to see if you currently have any code that advertises to the client information about the rate limit, and couldn't find any.

💻 Target components

  • ntfy server
Originally created by @ThisIsMissEm on GitHub (Aug 27, 2024). Original GitHub issue: https://github.com/binwiederhier/ntfy/issues/1173 :bulb: **Idea** Currently when ntfy rate limits a client, it seems to just send the 429 status code back, but doesn't advise as to when the rate limit would be lifted. This means that clients can't dynamically pause sending notifications until the rate limit resets, which leads to IP bans. There is a standards track IETF proposal for RateLimit headers, which could make sense to use: https://www.ietf.org/archive/id/draft-ietf-httpapi-ratelimit-headers-07.html This currently affects Mastodon: https://github.com/mastodon/mastodon/issues/26078 By advertising when the rate limits reset, we could delay all other notification until after the rate limit resets. I tried to look at both the documentation and code to see if you currently have any code that advertises to the client information about the rate limit, and couldn't find any. :computer: **Target components** <!-- Where should this feature/enhancement be added? --> <!-- e.g. ntfy server, Android app, iOS app, web app --> - ntfy server
Author
Owner

@ThisIsMissEm commented on GitHub (Oct 17, 2024):

You could also use the Retry-After header: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Retry-After

<!-- gh-comment-id:2420068723 --> @ThisIsMissEm commented on GitHub (Oct 17, 2024): You could also use the `Retry-After` header: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Retry-After
Author
Owner

@Kariton commented on GitHub (Jan 19, 2026):

i would like to have a general endpoint or way to query the current rate-limits.
similar to docker or github.

docker:

# TOKEN=$(curl "https://auth.docker.io/token?service=registry.docker.io&scope=repository:ratelimitpreview/test:pull" | jq -r .token)
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100  5429    0  5429    0     0  10325      0 --:--:-- --:--:-- --:--:-- 10321
# curl --head -H "Authorization: Bearer $TOKEN" https://registry-1.docker.io/v2/ratelimitpreview/test/manifests/latest
HTTP/2 200 
date: Mon, 19 Jan 2026 06:09:41 GMT
content-type: application/vnd.docker.distribution.manifest.v2+json
content-length: 527
docker-content-digest: sha256:c2d41d2ba6d8b7b4a3ffec621578eb4d9a0909df29dfa2f6fd8a2e5fd0836aed
docker-distribution-api-version: registry/2.0
etag: "sha256:c2d41d2ba6d8b7b4a3ffec621578eb4d9a0909df29dfa2f6fd8a2e5fd0836aed"
strict-transport-security: max-age=31536000
ratelimit-limit: 100;w=21600
ratelimit-remaining: 69;w=21600
docker-ratelimit-source: REDACTED

github:

# curl https://api.github.com/rate_limit
{
  "resources": {
    "code_search": {
      "limit": 60,
      "remaining": 25,
      "reset": 1768803517,
      "used": 35,
      "resource": "code_search"
    },
    "core": {
      "limit": 60,
      "remaining": 25,
      "reset": 1768803517,
      "used": 35,
      "resource": "core"
    },
    "graphql": {
      "limit": 0,
      "remaining": 0,
      "reset": 1768806666,
      "used": 0,
      "resource": "graphql"
    },
    "integration_manifest": {
      "limit": 5000,
      "remaining": 5000,
      "reset": 1768806666,
      "used": 0,
      "resource": "integration_manifest"
    },
    "search": {
      "limit": 10,
      "remaining": 10,
      "reset": 1768803126,
      "used": 0,
      "resource": "search"
    }
  },
  "rate": {
    "limit": 60,
    "remaining": 25,
    "reset": 1768803517,
    "used": 35,
    "resource": "core"
  }
}
<!-- gh-comment-id:3766573768 --> @Kariton commented on GitHub (Jan 19, 2026): i would like to have a general endpoint or way to query the current rate-limits. similar to docker or github. docker: ```sh # TOKEN=$(curl "https://auth.docker.io/token?service=registry.docker.io&scope=repository:ratelimitpreview/test:pull" | jq -r .token) % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 100 5429 0 5429 0 0 10325 0 --:--:-- --:--:-- --:--:-- 10321 # curl --head -H "Authorization: Bearer $TOKEN" https://registry-1.docker.io/v2/ratelimitpreview/test/manifests/latest HTTP/2 200 date: Mon, 19 Jan 2026 06:09:41 GMT content-type: application/vnd.docker.distribution.manifest.v2+json content-length: 527 docker-content-digest: sha256:c2d41d2ba6d8b7b4a3ffec621578eb4d9a0909df29dfa2f6fd8a2e5fd0836aed docker-distribution-api-version: registry/2.0 etag: "sha256:c2d41d2ba6d8b7b4a3ffec621578eb4d9a0909df29dfa2f6fd8a2e5fd0836aed" strict-transport-security: max-age=31536000 ratelimit-limit: 100;w=21600 ratelimit-remaining: 69;w=21600 docker-ratelimit-source: REDACTED ``` github: ``` # curl https://api.github.com/rate_limit { "resources": { "code_search": { "limit": 60, "remaining": 25, "reset": 1768803517, "used": 35, "resource": "code_search" }, "core": { "limit": 60, "remaining": 25, "reset": 1768803517, "used": 35, "resource": "core" }, "graphql": { "limit": 0, "remaining": 0, "reset": 1768806666, "used": 0, "resource": "graphql" }, "integration_manifest": { "limit": 5000, "remaining": 5000, "reset": 1768806666, "used": 0, "resource": "integration_manifest" }, "search": { "limit": 10, "remaining": 10, "reset": 1768803126, "used": 0, "resource": "search" } }, "rate": { "limit": 60, "remaining": 25, "reset": 1768803517, "used": 35, "resource": "core" } } ```
Author
Owner

@binwiederhier commented on GitHub (Feb 5, 2026):

We do have this, but it does not return all rate limits, so I think the request is still valid.

curl -s https://ntfy.sh/v1/account | jq .
{
  "username": "*",
  "role": "anonymous",
  "limits": {
    "basis": "ip",
    "messages": 250,
    "messages_expiry_duration": 43200,
    "emails": 5,
    "calls": 0,
    "reservations": 0,
    "attachment_total_size": 20971520,
    "attachment_file_size": 2097152,
    "attachment_expiry_duration": 10800,
    "attachment_bandwidth": 209715200
  },
  "stats": {
    "messages": 0,
    "messages_remaining": 250,
    "emails": 0,
    "emails_remaining": 5,
    "calls": 0,
    "calls_remaining": 0,
    "reservations": 0,
    "reservations_remaining": 0,
    "attachment_total_size": 0,
    "attachment_total_size_remaining": 20971520
  }
}
<!-- gh-comment-id:3850754379 --> @binwiederhier commented on GitHub (Feb 5, 2026): We do have this, but it does not return _all_ rate limits, so I think the request is still valid. ``` curl -s https://ntfy.sh/v1/account | jq . { "username": "*", "role": "anonymous", "limits": { "basis": "ip", "messages": 250, "messages_expiry_duration": 43200, "emails": 5, "calls": 0, "reservations": 0, "attachment_total_size": 20971520, "attachment_file_size": 2097152, "attachment_expiry_duration": 10800, "attachment_bandwidth": 209715200 }, "stats": { "messages": 0, "messages_remaining": 250, "emails": 0, "emails_remaining": 5, "calls": 0, "calls_remaining": 0, "reservations": 0, "reservations_remaining": 0, "attachment_total_size": 0, "attachment_total_size_remaining": 20971520 } } ```
Author
Owner

@disconn3ct commented on GitHub (Mar 13, 2026):

Is the returned username accurate? And does this include NTFY_VISITOR_REQUEST_LIMIT_EXEMPT_HOSTS?

<!-- gh-comment-id:4054821397 --> @disconn3ct commented on GitHub (Mar 13, 2026): Is the returned username accurate? And does this include `NTFY_VISITOR_REQUEST_LIMIT_EXEMPT_HOSTS`?
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
starred/ntfy#827
No description provided.