Username
Always included. Display name and account id.
Create an app, choose what it can see, and let people approve access with their Raidstrats account.
Give it a name and a return address, then pick what people share.
You can read the guide without an account. Creating an app, and removing access you have given, needs a Raidstrats login.
These are apps you allowed to use your Raidstrats account. Removing one stops it from reading your data.
Log in to see apps you have allowed.
code. That code is not the bearer token./oauth/token. The JSON field access_token is the bearer token.Authorization: Bearer ACCESS_TOKEN.You choose these when you create the app. A login can only ask for data the app was given. The person still has to approve it.
Always included. Display name and account id.
Linked in-game name, realm, region, and class.
Guild name and rank.
Plans that person created, plus guild plans they can open. Each guild plan includes an embed link. The drawing stays in the embed.
Names, links, and players for rosters that person created.
Open this URL in their browser. Replace the values with your app.
https://raidstrats.gg/oauth/authorize?response_type=code&client_id=CLIENT_ID&redirect_uri=https%3A%2F%2Fexample.com%2Fcallback&scope=profile%20plans&state=RANDOM_STATE
codehttp://localhost:8000/auth/callback and http://localhost:8000/oauth/callback are different. Localhost may use http. Every other site must use https.profile guild plans. Username is included even when this is left off. Asking for data the app was not given is rejected.consent to show the approval page again even if they already allowed the app.code_verifier you keep on your server. If you send this, the token request must send that same verifier.S256. Required whenever code_challenge is sent.If they approve, their browser is sent to your return address. The code is a one-time login code. It is not the bearer token.
https://example.com/callback?code=ONE_TIME_CODE&state=RANDOM_STATE
If they cancel, the URL contains error=access_denied instead of a code. The code expires after 5 minutes and works once. Save it and continue to the next step from your server.
The bearer token is created only when your server trades the login code. Opening /oauth/token in a browser does not create one.
code.https://raidstrats.gg/oauth/token.access_token from the JSON reply. That value, starting with rsoat_, is the bearer token.Authorization: Bearer ACCESS_TOKEN.client_id, client_secret, code, and redirect_uri are read from the form body only. A link such as /oauth/token?client_id=...&client_secret=... does not send them, so the reply says the client_id and secret were not received. Never put the secret in a URL.POST https://raidstrats.gg/oauth/token
Content-Type: application/x-www-form-urlencoded
grant_type=authorization_code
&code=ONE_TIME_CODE
&redirect_uri=https://example.com/callback
&client_id=CLIENT_ID
&client_secret=CLIENT_SECRET
&code_verifier=CODE_VERIFIER
authorization_code for the first token. refresh_token later.rs_....code_challenge. Leave it off only if the login URL had no challenge. A wrong or missing verifier does not create a bearer token.You can send the client_id and secret as Basic authentication instead of body fields. Encode client_id:client_secret in base64 and send Authorization: Basic .... The other fields still go in the POST body.
curl -X POST https://raidstrats.gg/oauth/token \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=authorization_code" \
-d "code=ONE_TIME_CODE" \
-d "redirect_uri=https://example.com/callback" \
-d "client_id=CLIENT_ID" \
-d "client_secret=CLIENT_SECRET"
A successful reply looks like this. Copy access_token. That is the bearer token. Raidstrats keeps only a hash of it, so it cannot be read back out of the database later.
{
"access_token": "rsoat_...",
"token_type": "Bearer",
"expires_in": 3600,
"refresh_token": "rsort_...",
"scope": "plans profile"
}
The bearer token lasts 1 hour. The refresh token lasts 30 days. Refresh from your server with another POST. Each refresh replaces the old refresh token.
POST https://raidstrats.gg/oauth/token
Content-Type: application/x-www-form-urlencoded
grant_type=refresh_token
&refresh_token=REFRESH_TOKEN
&client_id=CLIENT_ID
&client_secret=CLIENT_SECRET
Use the bearer token from access_token. Send it on each request. The site login cookie is not accepted here.
Authorization: Bearer ACCESS_TOKEN
guildPlans they can open. A private guild plan includes an embedUrl for your group page. The normal plan link does not open it for other people.curl https://raidstrats.gg/api/oauth/v1/me \
-H "Authorization: Bearer ACCESS_TOKEN"
{
"sub": "42",
"scope": "guild profile",
"username": "Nairyana",
"createdAt": 1710000000000,
"guild": { "name": "Example Guild", "rank": "Raider", "rankId": 4 }
}
Plan and roster lists accept limit (up to 100) and offset. Guild plans use the same guild access as on Raidstrats, up to 100. The list does not include the drawing. People who only have the normal plan link still cannot open a private guild plan. If that person removes the app, or can no longer open the plan, the group embed stops working.
Use embedUrl as the iframe address. Do not take the plan id out and build a new link. The private key is already inside embedUrl.
const res = await fetch('https://raidstrats.gg/api/oauth/v1/plans', {
headers: { Authorization: `Bearer ${accessToken}` }
});
const data = await res.json();
const plan = data.guildPlans[0];
iframe.src = plan.embedUrl;
If someone pastes a normal plan link, read the id from it and ask for an embed link. Then use that embedUrl the same way.
POST https://raidstrats.gg/api/oauth/v1/plans/PLAN_ID/embed
Authorization: Bearer ACCESS_TOKEN
{
"id": "41824f15-5860-4ab4-9655-ba4736fa99a5",
"name": "Mythic positions",
"embedUrl": "https://raidstrats.gg/planner?embed=true&id=41824f15-5860-4ab4-9655-ba4736fa99a5&embed_key=..."
}
The person can remove an app from this page. Your server can also revoke a token.
POST https://raidstrats.gg/oauth/revoke
Content-Type: application/x-www-form-urlencoded
token=ACCESS_OR_REFRESH_TOKEN
&token_type_hint=refresh_token
&client_id=CLIENT_ID
&client_secret=CLIENT_SECRET