Appearance
API - Getting Started
The EasyDonate API lets you read your account data and control your timer widget programmatically. OAuth applications, the Connect with EasyDonate flow, and personal API keys are open to every account - create yours from Dashboard -> Developer.
The full reference (auto-generated OpenAPI 3) is rendered with Redoc at /docs.
Authentication
Every request uses the same header:
Authorization: Bearer <token>There are two kinds of token:
| Token | Type | Acts as | Where you get it |
|---|---|---|---|
Bearer ezdn_v1_<cuid> | Personal API key | Your own account | Dashboard -> Developer -> API Keys |
Bearer <jwt> | OAuth access token | The consenting user | OAuth flow (below) |
API keys are opaque strings prefixed with ezdn_v1_. OAuth access tokens are short-lived signed JWTs, so they look like xxxxx.yyyyy.zzzzz rather than a prefixed string.
Tokens are scoped - a request is rejected with 403 if the token lacks the scope the endpoint requires.
Scopes
| Scope | Grants |
|---|---|
read:profile | Account identity (PII redacted) |
read:donations | Donation transactions, stats, charts, trends, export |
read:widgets | Widget configs + data + timer/connection status |
write:timer | Control the running timer (play/pause/reset/adjust) |
read:subscription | Your EasyDonate plan, limits, sponsorships |
read:creator | Public creator lookups + your own creator stats |
read:channels | Donation channel status/type (secrets stripped) |
write:donations | Create external donations (inbound events) |
See Inbound Donations for pushing donate events from another platform.
Quick start with an API key
Create a key in the dashboard, pick the scopes you need, then:
bash
curl https://api.easydonate.app/api/v1/me \
-H "Authorization: Bearer ezdn_v1_xxxxxxxxxxxxxxxx"List recent donations:
bash
curl "https://api.easydonate.app/api/v1/donations?page=1" \
-H "Authorization: Bearer ezdn_v1_xxxxxxxxxxxxxxxx"Control the timer (needs write:timer):
bash
curl -X POST https://api.easydonate.app/api/v1/widgets/timer/control \
-H "Authorization: Bearer ezdn_v1_xxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{"action":"adjust","ms":60000}'Every response uses the standard envelope:
json
{ "statusCode": 200, "data": {} }OAuth2 (act on behalf of other users)
For apps that act on behalf of EasyDonate users, register an application (Dashboard -> Developer -> Applications) to receive a client_id and client_secret. The flow is Authorization Code + PKCE (PKCE is mandatory).
- Send the user to the authorize screen:
https://easydonate.app/oauth/authorize?client_id=<client_id>
&redirect_uri=<your_callback>
&scope=read:profile read:donations
&state=<random>
&code_challenge=<S256_challenge>
&code_challenge_method=S256The user logs in and approves. EasyDonate redirects to
redirect_uri?code=<code>&state=<state>.Exchange the code for tokens from your backend:
bash
curl -X POST https://api.easydonate.app/oauth/token \
-H "Content-Type: application/json" \
-d '{
"grant_type": "authorization_code",
"code": "<code>",
"client_id": "<client_id>",
"client_secret": "<client_secret>",
"redirect_uri": "<your_callback>",
"code_verifier": "<verifier>"
}'Response:
json
{
"access_token": "<jwt>",
"token_type": "Bearer",
"expires_in": 3600,
"refresh_token": "ezdn_v1_rt_...",
"scope": "read:profile read:donations"
}The access_token is a signed JWT - pass it verbatim in the Authorization header. The refresh_token is an opaque string prefixed with ezdn_v1_rt_.
- Call the API with the access token:
bash
curl https://api.easydonate.app/api/v1/me \
-H "Authorization: Bearer <jwt>"- Refresh when it expires (the refresh token rotates - store the new one):
bash
curl -X POST https://api.easydonate.app/oauth/token \
-H "Content-Type: application/json" \
-d '{
"grant_type": "refresh_token",
"refresh_token": "ezdn_v1_rt_...",
"client_id": "<client_id>",
"client_secret": "<client_secret>"
}'- Revoke a token (or remove the connection):
bash
curl -X POST https://api.easydonate.app/oauth/revoke \
-H "Content-Type: application/json" \
-d '{"token":"ezdn_v1_rt_...","client_id":"<client_id>","client_secret":"<client_secret>"}'Access tokens live 1 hour; refresh tokens never expire by default (per-app custom TTL configurable from the dashboard). Access tokens are stateless JWTs and cannot be revoked individually - revoke the refresh token (or remove the connection) to cut off an app. Unverified apps may connect at most 20 users
- request verification in the dashboard to lift the cap.
Rate limits
Requests are limited to 60 per minute per credential. Responses carry X-RateLimit-Limit, X-RateLimit-Remaining, and X-RateLimit-Reset; exceeding the limit returns 429.