Starwide API docs
The Starwide API is a JSON REST API built on WordPress, BuddyPress and bbPress. Use it from JavaScript in the browser, from your own server, or from a game.
Base URL https://www.starwide.net/wp-json/starwide/v1
Quick start
- Create an app under Apps. You get a Title Token and a Secret Key.
- In the app console, generate a bearer token and copy it straight away. It's shown once.
- Call /apps/verify to check everything is wired up:
const BEARER = 'your-40-character-bearer-token';
const TITLE_TOKEN = 'your-16-char-title';
const res = await fetch('https://www.starwide.net/wp-json/starwide/v1/apps/verify', {
headers: {
Authorization: `Bearer ${BEARER}`,
'X-Starwide-App': TITLE_TOKEN,
},
});
if (!res.ok) throw new Error((await res.json()).message);
console.log(await res.json()); // { ok: true, app: {...}, token: {...} }curl https://www.starwide.net/wp-json/starwide/v1/apps/verify \
-H "Authorization: Bearer $BEARER" \
-H "X-Starwide-App: $TITLE_TOKEN"Credentials
| Credential | Format | Where it goes | Can you see it again? |
|---|---|---|---|
| Title Token | 16 characters: letters, numbers, symbols | X-Starwide-App | Yes, any time. It isn't secret. |
| Secret Key | 20 characters: letters, numbers, symbols | X-Starwide-Secret (server only) | Yes, from your console. Never share it. |
| Bearer token | 40 hex characters | Authorization: Bearer … | No. Shown once; only a hash is stored. |
Authentication
Every call to /apps/* (except the public directory) needs your bearer token and Title Token. The bearer token must be attached to the app the Title Token names.
GET /wp-json/starwide/v1/apps/users/neff
Authorization: Bearer 3f9a…c21e
X-Starwide-App: Kd7_mP2!xQ9.vR4zSome hosts strip the Authorization header. If you get "auth missing" errors, send X-Starwide-Bearer: <token> instead.
Bearer tokens may be used in browser code and shared with collaborators who build on your app. Your Secret Key may not: keep it on your server.
Endpoints
/apps/verifyBearerChecks your credentials and returns your app and token hint.
/apps/users/{username}BearerA member's public profile: display name, avatar, bio, links, follower count, whether they're a developer. Private profiles return only name and avatar. {username} can also be a numeric ID.
{
"id": 1,
"username": "neff",
"display_name": "Nepheon",
"avatar_url": "https://…",
"profile_url": "https://starwide.net/members/neff/",
"private": false,
"bio": "…",
"links": [{ "label": "YouTube", "url": "https://…" }],
"follower_count": 1280,
"member_since": "2020-04-01T12:00:00",
"is_developer": true,
"apps_url": "https://starwide.net/members/neff/apps/"
}/apps/directory?developer={username}&per_page=20PublicPublished and Early Access apps. Public: no token needed.
Sign in with Starwide
Let members log in to your app with their Starwide account and share data with it. It's standard OAuth 2.0 (authorization code), so most OAuth libraries work.
- Set your app's Callback URL in the console (https, or http://localhost while testing).
- Send the member to the authorize page with the scopes you need:
https://www.starwide.net/for-developers/authorize/?client_id=TITLE_TOKEN
&redirect_uri=https://yourapp.example/callback
&response_type=code
&scope=followers feed.read wallet.read
&state=RANDOM_VALUE
&code_challenge=BASE64URL_SHA256_OF_VERIFIER (browser & mobile apps)
&code_challenge_method=S256When they click Allow, they come back to your Callback URL with ?code=…&state=…. Check state matches, then swap the code (valid 10 minutes, once) for tokens:
// Server apps: send your Secret Key. Browser/mobile apps: send code_verifier instead.
const res = await fetch('https://www.starwide.net/wp-json/starwide/v1/oauth/token', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
grant_type: 'authorization_code',
client_id: TITLE_TOKEN,
code,
redirect_uri: 'https://yourapp.example/callback',
client_secret: SECRET_KEY, // or: code_verifier: VERIFIER
}),
});
const { access_token, refresh_token, expires_in, scope, user } = await res.json();- Access tokens (swu_…) last 1 hour. Refresh tokens (swr_…) last 60 days and change every time you use one: POST grant_type=refresh_token with client_id, refresh_token and (server apps) client_secret.
- Revoke a token with POST /oauth/revoke and token=….
- Members who already approved the same permissions skip the screen. Add prompt=consent to always show it.
- AO / NSFW apps can only be connected by members who are 18 or older.
| Scope | Gives your app |
|---|---|
profile (always) | Your profile, username and e-mail address. Display name, avatar, bio, bio links and the Pages you belong to. |
followers | Who you follow and who follows you. Your followers and following lists. |
feed.read | Your feed history. Posts and updates you've shared. |
feed.write | Post to your feed. Posts are labelled with the app's name. |
media.read | Your public uploads. Videos, images and music you've made public. |
tokens.read | Your bearer token inventory. Which tokens you own. Never the token values. |
wallet.read | Your wallet balance. The amount only. Never your cards, bank or payment methods. |
purchases.read | Your purchase history. Items, prices, licence ownership and subscriptions. Adult purchases and payment details are always hidden. |
arcade.write | Post your scores and achievements. Shown on the game's leaderboard under your name. |
comments.write | Comment and pin moments on media for you. Timestamped comments on videos and music, labelled with the app's name. |
feed.syndicate | Receive posts you choose to share with it. Only public posts, and only when you pick "Connected apps" under "Also post to". |
payments | Ask you to pay for things. You confirm every payment on Starwide. It can never charge you on its own. |
Member endpoints
Send the member's access token and your Title Token:
GET /wp-json/starwide/v1/apps/me
Authorization: Bearer swu_…
X-Starwide-App: TITLE_TOKEN/apps/meBearerProfile, username, e-mail and Pages. Scope: profile.
/apps/me/followers · /apps/me/followingBearerLists of members (?page, ?per_page up to 100). Scope: followers.
/apps/me/feedBearerThe member's posts. NSFW posts only reach AO-rated apps, for adult members. Scope: feed.read.
/apps/me/feedBearerPosts an update ({"content": "…"}), shown as "via your app". Scope: feed.write.
/apps/me/mediaBearerPublic Encore uploads. Scope: media.read.
/apps/me/tokensBearerBearer tokens they own, never the values. Scope: tokens.read.
/apps/me/walletBearerBalance and a top-up link. Nothing else. Scope: wallet.read.
/apps/me/purchasesBearerOrders with items and prices. NSFW items removed and totals recalculated; no payment details. Scope: purchases.read.
Missing a permission? You'll get 403 insufficient_scope. Expired token? 401 invalid_token — refresh it.
Arcade leaderboards
Submit scores and achievements for signed-in members (scope arcade.write). Each member's best score counts. Boards are any name you like (a–z, 0–9, _ and -); names ending in _asc rank lowest first, for speedruns. Link your app to one of your Arcade games in the console and its default board shows on that game's page. Anywhere else, use [starwide_leaderboard app="ID" board="default" limit="10"].
/apps/me/scoresBearer{"score": 1200, "board": "default", "meta": "level 3"} → personal_best, best, rank. Scope: arcade.write.
/apps/me/achievementsBearer{"key": "first_win", "title": "First win"} → newly_unlocked. GET lists the member's achievements. Scope: arcade.write.
/apps/leaderboard?board=default&period=all|week|day&limit=10BearerTop scores. App credentials only, no member needed.
Store & licence keys
Starwide staff can link a WooCommerce product to your app and switch on licence keys. Buyers get one key per unit (SW-XXXXX-XXXXX-XXXXX-XXXXX) when their order completes; refunds and cancellations revoke them. Store sales are paid to Starwide.
/apps/licenses/verifyBearer{"license_key": "SW-…", "activate": true} → valid, status, product, member, activations. Needs X-Starwide-Secret, so call it from your server. Only keys for products linked to your app are found.
/apps/me/owns?product_id=123BearerWhether the member bought a store product, plus their keys if it's linked to your app. Scope: purchases.read.
/apps/me/subscriptionsBearerActive creator tiers (like Starwide Tour) and WooCommerce subscriptions. Scope: purchases.read.
In-app purchases
Sell your own items, paid from the member's Starwide wallet straight into yours (Starwide keeps 0%). Members always confirm on Starwide; your app never sees how they pay. Up to $500.00 per purchase.
- Ask for the payment (scope payments): POST /apps/me/charges with amount, description, optional item_id and return_url (same site as your Callback URL).
- Send the member to the approve_url in the response.
- They come back to return_url?charge_id=…&status=paid (or declined). Don't trust the query string: confirm with GET /apps/charges/{id} or the charge.paid webhook, then deliver the item.
const charge = await fetch('https://www.starwide.net/wp-json/starwide/v1/apps/me/charges', {
method: 'POST',
headers: { Authorization: `Bearer ${accessToken}`, 'X-Starwide-App': TITLE_TOKEN, 'Content-Type': 'application/json' },
body: JSON.stringify({ amount: 4.99, description: 'Golden skin', item_id: 'skin_gold', return_url: 'https://yourapp.example/shop/done' }),
}).then(r => r.json());
location.href = charge.approve_url; // pending requests expire after 30 minutesWebhooks
Set a Webhook URL in the console and Starwide will POST JSON events to it: charge.paid, charge.declined, order.completed, license.issued, license.revoked, connection.revoked and ping (from Send test). Failed deliveries retry after 1 and 10 minutes; the console shows the latest results.
Check every request: X-Starwide-Signature is t=<time>,v1=<HMAC-SHA256 of "<time>.<raw body>" using your Secret Key>. Reject old timestamps.
// Node.js / Express — use the raw body, not parsed JSON
import crypto from 'node:crypto';
function verify(rawBody, header, secret) {
const { t, v1 } = Object.fromEntries(header.split(',').map(p => p.split('=')));
if (Math.abs(Date.now() / 1000 - Number(t)) > 300) return false;
const expected = crypto.createHmac('sha256', secret).update(`${t}.${rawBody}`).digest('hex');
return crypto.timingSafeEqual(Buffer.from(v1), Buffer.from(expected));
}Errors & limits
Errors come back as JSON with a code, a message and an HTTP status.
{ "code": "swdev_auth_invalid", "message": "…", "data": { "status": 401 } }401 swdev_auth_missing | No bearer token or Title Token sent. |
401 swdev_auth_invalid | Token revoked, or it isn't attached to this app. |
403 swdev_app_suspended | The app was suspended by Starwide. |
429 swdev_rate_limited | More than 1,000 calls this hour on one bearer token. Stack another token to spread load. |
Bearer tokens
- Your first bearer token is free. Each one after that costs $5.00 from your TeraWallet.
- Tokens stack: an app can hold several, and any of them works. Revoke a leaked one instantly; the others keep working.
- You can gift a token to any member, or sell it on the marketplace for $20.00 or more. The money goes to your wallet; Starwide takes no cut.
- A token gets a brand-new value whenever it changes owner, so the old owner's copy stops working.
- Members with tokens listed get a "Token(s) for Sale" badge on their profile.
Publishing
Use the Submit button at the bottom-right of the app console. Publish as Complete, or as Early Access while you're still building. Before either works:
- The app has its Title Token, Secret Key and at least one bearer token.
- You've picked a content rating: E, E10+, T, M or AO / NSFW.
- Your account is at least 30 days old.
- You're 18 or older (from the date of birth on your account).
Published apps appear in the Apps tab on your profile.
Data & privacy
What apps can read, once a member approves them through Sign in with Starwide:
- Profile, bio, bio links and associated Pages
- Followers and following
- Feed history and uploaded public media
- Their bearer token inventory
- Wallet balance — the number only
- Purchase history, with every NSFW purchase removed
- Username and e-mail address (included with every connection)
Apps never get card numbers, bank details, e-wallet accounts or any saved payment method. Apps can link members to the Starwide wallet top-up page, but can't take payments themselves.
Player pins
Pin a timestamped comment on a video, song or post for a member (scope comments.write). It appears as an avatar pin on the Encore player's timeline, labelled "via your app", and follows the site's normal comment moderation: if response.pending is true, it shows once approved.
/apps/me/pinsBearer{"object": "post:12" or "activity:34", "t": 83.5, "text": "The drop!", "public": true} → id, pending. Scope: comments.write.
/apps/pins?object=post:12BearerPublic, approved pins on that item in time order. App credentials only.
Receiving members' posts
Build a fediverse bridge, cross-poster, bot or magazine: ask for scope feed.syndicate and set a Webhook URL. Members who connect your app get "Connected apps" in the "Also post to" menu when they write a post; when they pick it, you receive an activity.syndicated webhook with the text, link, image and author. Only public posts are sent, and NSFW posts only reach AO-rated apps for adult members.
{
"event": "activity.syndicated",
"data": {
"activity_id": 812,
"member": { "id": 3, "username": "buyer", "display_name": "Buyer Bee", "profile_url": "…" },
"text": "Just hit 1,200 in Neon Drift!",
"url": "https://starwide.net/activity/p/812/",
"image": "",
"nsfw": false,
"idempotency_key": "swea-812-starwide_apps"
}
}Verified developers
Publish an app (Complete or Early Access) and you're a verified developer automatically: your profile picture becomes an octagon with a green check in the top-left corner, and visitors get an octagonal Commission button next to Follow. It opens your Encore commission settings (turn commissions on in your Studio) and any bearer tokens you have for sale. Unpublish every app and it goes back to normal. Brand accounts show square frames; everyone else is round.