Authentication
One mechanism covers the whole platform: an email-and-password or OTP login returns a signed token, and you send it as a bearer header. There is no refresh flow, so the token's life is your session's life.
Open Appsinity StudioDeveloper (Studio) accounts
- Register.
POST /api/auth/registerwithemailandpassword. A malformed address returns Enter a valid email; a short password returns Password must be at least 6 characters; a taken address returns An account with this email already exists. - Verify the address.
POST /api/auth/send-verificationthenPOST /api/auth/verify-email-otp. The code is six digits and expires in ten minutes; Code expired. Please request a new one. and Invalid verification code are the two refusals. - Sign in.
POST /api/auth/login. Wrong credentials answer Email or password is incorrect — deliberately the same message for both halves. - Keep the token. The response carries a JWT whose payload is
{ uid, email, source: "appsinity_studio" }. Studio stores it asappsinity_studio_token. - Send it on every call.
Authorization: Bearer <token>. Nothing else identifies you.
POST /api/auth/login
{ "email": "[email protected]", "password": "..." }
200 { "token": "eyJhbGciOi...", "user": { "uid": "...", "email": "..." } }
GET /api/auth/me
Authorization: Bearer eyJhbGciOi...
200 { uid, email, display_name, onboarding_complete, approval_status, ... }Player accounts
The store front has its own account family under /api/user-auth/*: register, login, me, profile, send-verification, verify-email-otp and username-available. Passwords are hashed with bcrypt at cost twelve, and the same minimum length applies.
| Rule | Developer account | Player account |
|---|---|---|
| Route family | /api/auth/* | /api/user-auth/* |
| Identifier | Email plus a username | |
| Username format | None | ^[a-z0-9_]+$, 3 to 20 characters |
| Avatar | Display name only | HTTPS Cloudinary URL, 600 characters max |
| Password minimum | 6 characters | 6 characters |
| Hash | bcrypt cost 12 | bcrypt cost 12 |
| OTP step | Six digits, ten minutes | Six digits, ten minutes |
| Session | Bearer token, 30 days | Bearer token, 30 days |
| Used for | Publishing, analytics, payouts | Reviews, follows, library, purchases |
listingOptionalUser accepts any bearer token it can verify and ignores one it cannot.Every auth failure you will see
| Status | Body | Meaning | Fix |
|---|---|---|---|
| 401 | Sign in again first | No Authorization header, or no Bearer prefix | Send the header |
| 401 | Invalid session | Token present but verification failed | Sign in again |
| 401 | Sign in to write a review | Player endpoint without a verifiable token | Sign in on the store |
| 401 | Missing login token. | Upload Worker got no bearer token | Sign in on Studio |
| 401 | Invalid or expired login token. | Upload Worker could not verify it | Sign in again, then retry the upload |
| 403 | Only the workspace owner can manage members | Right role, wrong member | Ask the owner |
| 403 | You do not own this document | Another account's row | Check the uid in your token |
| 403 | Please sign in to follow creators. | Player action while signed out | Sign in |
| 400 | Password must be at least 6 characters | Registration input | Lengthen it |
| 409 | duplicate or already-exists message | Conflict with an existing row | Use the existing record |
Optional verification on writes
Traffic and play events accept a token but do not need one. The handler attempts verification, takes the uid if the signature checks out, and records the event either way. For your own instrumentation that means an unauthenticated call is a valid call — and one that a player cannot be blamed for.
POST /api/listing-traffic
Authorization: <ignored if absent>
{ "collection": "games", "listingId": "my-game", "eventType": "visit",
"source": "search", "country": "IN" }
200 -> the event row is written with uid = "" when no token was suppliedKeeping a session safe
- There is no two-factor option on either account family, so the password and the mailbox are the whole defense.
- Logout clears the stored token; there is no server-side revocation list, so a token you have already handed to a browser extension stays valid for its remaining thirty days.
- Never put a token in a URL, a log line or a screenshot of a support conversation.
- Do not run the token in CI. Without keys or scoped credentials, automation inherits your full account rights, see API keys.
- One password per account; a Studio password reused elsewhere is a breach of your store account waiting to happen.
Frequently asked questions
How long is a token valid?
Thirty days, with no refresh and no renewal call. When it expires the API says Invalid session and you sign in again.
Is there an OAuth login?
No. Email plus OTP is the only flow on both account families; there is no Google, GitHub or provider sign-in today, see OAuth.
Can I have two sessions at once?
Yes. Nothing tracks issued tokens, so signing in on a second device does not invalidate the first, and signing out on one does not stop the other.
Why does my player call work without a token?
Catalogue and traffic endpoints are public or optionally authenticated by design. Writing a review, following a creator or reading your own dashboard is where a token becomes required.
Developer publishing support: [email protected]
General support: [email protected]
Partnerships: [email protected]
APPSINITY