API Quickstart
Use an API client — a confidential OAuth client using the Client Credentials grant — to call the RemiliaNET public API as itself, with no user involved.
To act on behalf of a signed-in user (reading their private profile, poking on their behalf), use a login client (Authorization Code + PKCE) — see Login Quickstart.
Prerequisites
- An issued API client with a client ID and client secret.
curlandjqfor the examples below.
Keep the client secret out of source control, shell history, and logs.
Base URL
https://www.remilia.net/api/v11. Load your credentials
export REMILIA_CLIENT_ID="your-client-id"
read -rs REMILIA_CLIENT_SECRET # paste the secret; it is not echoed
export REMILIA_CLIENT_SECRETAvoid set -x / curl -v while these are set — both echo the secret and the Authorization header.
2. Get an access token
Request a token with the client_credentials grant:
ACCESS_TOKEN=$(curl --fail-with-body -sS \
https://www.remilia.net/oidc/realms/remilia/protocol/openid-connect/token \
-d grant_type=client_credentials \
-d client_id="$REMILIA_CLIENT_ID" \
--data-urlencode "client_secret=$REMILIA_CLIENT_SECRET" \
| jq -er '.access_token')Do not pass a scope parameter — a client's granted scopes are attached automatically. See Scopes.
The response fields you need:
{
"access_token": "eyJhbGciOi...",
"expires_in": 300
}access_token— the bearer token to send on API requests.expires_in— its lifetime in seconds.
Reuse the token until it is close to expiring; do not fetch one per request. When it expires, repeat the call above — there is no refresh token for Client Credentials. Send the token only over HTTPS, never log it, and never place it in a URL.
3. Make your first request
GET /users/{username} returns a user's public profile and requires no scope:
curl --fail-with-body -sS \
https://www.remilia.net/api/v1/users/remilia \
-H "Authorization: Bearer $ACCESS_TOKEN"The call returns the profile object directly (no data envelope):
{
"user": {
"username": "remilia",
"displayName": "Remilia",
"bio": "...",
"location": "...",
"pfpUrl": "..."
},
"achievementContext": {},
"viewerContext": { "areFriends": false }
}The response also carries isAuthenticated and isOwnProfile flags describing the viewer relative to the profile. Private fields require a user-delegated token; an API-client token cannot read them. See Endpoints.
App-only vs. user-delegated access
| API client (this guide) | Login client | |
|---|---|---|
| OAuth grant | Client Credentials | Authorization Code + PKCE |
| Confidentiality | Confidential (has a secret) | Public (no secret; PKCE required) |
| Acts as | The application itself | A consenting RemiliaNET user |
| Acts for a user | No | Yes |
Use a login client for user-authorized operations:
GET /me/profile—remilia:profile.privatePOST /pokes—remilia:interact.poke
See Login Quickstart and Scopes.
Common errors
| Status | error.code | When |
|---|---|---|
| 401 | invalid_token | The bearer token is invalid or expired — request a new one |
| 401 | unauthorized | A scoped endpoint was called with no token |
| 403 | insufficient_scope | The token lacks a scope the endpoint requires |
| 403 | forbidden | The endpoint requires a user-delegated token; the token carries the scope but has no user attached |
| 404 | not_found | No such endpoint under /api/v1 |
| 405 | method_not_allowed | Wrong HTTP method for the path |