AppsinityAPPSINITY
APIs

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 Studio

Developer (Studio) accounts

  1. Register. POST /api/auth/register with email and password. 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.
  2. Verify the address. POST /api/auth/send-verification then POST /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.
  3. Sign in. POST /api/auth/login. Wrong credentials answer Email or password is incorrect — deliberately the same message for both halves.
  4. Keep the token. The response carries a JWT whose payload is { uid, email, source: "appsinity_studio" }. Studio stores it as appsinity_studio_token.
  5. 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, ... }
Watch out: The token expires in thirty days and there is no refresh endpoint. Nothing in Studio warns you before it lapses, so a long publishing session can die mid-upload with Sign in again before uploading.

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.

RuleDeveloper accountPlayer account
Route family/api/auth/*/api/user-auth/*
IdentifierEmailEmail plus a username
Username formatNone^[a-z0-9_]+$, 3 to 20 characters
AvatarDisplay name onlyHTTPS Cloudinary URL, 600 characters max
Password minimum6 characters6 characters
Hashbcrypt cost 12bcrypt cost 12
OTP stepSix digits, ten minutesSix digits, ten minutes
SessionBearer token, 30 daysBearer token, 30 days
Used forPublishing, analytics, payoutsReviews, follows, library, purchases
Note: The same token type unlocks player endpoints, which is why a review can be written from the store front: listingOptionalUser accepts any bearer token it can verify and ignores one it cannot.

Every auth failure you will see

StatusBodyMeaningFix
401Sign in again firstNo Authorization header, or no Bearer prefixSend the header
401Invalid sessionToken present but verification failedSign in again
401Sign in to write a reviewPlayer endpoint without a verifiable tokenSign in on the store
401Missing login token.Upload Worker got no bearer tokenSign in on Studio
401Invalid or expired login token.Upload Worker could not verify itSign in again, then retry the upload
403Only the workspace owner can manage membersRight role, wrong memberAsk the owner
403You do not own this documentAnother account's rowCheck the uid in your token
403Please sign in to follow creators.Player action while signed outSign in
400Password must be at least 6 charactersRegistration inputLengthen it
409duplicate or already-exists messageConflict with an existing rowUse the existing record
Watch out: The Upload Worker decides its status by pattern-matching its own error text: a message containing token, login or expired becomes 401 and everything else becomes 400. Do not read a 400 from that service as proof that your session is fine.

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 supplied
Not available: There is no signing secret, no HMAC and no shared key for these endpoints. Anything the browser can compute, a player can compute, so treat every reported number as unaudited.

Keeping 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.
Note: Because the API answers CORS from any origin, a page that can read your local storage can also call these endpoints as you. That is the real reason not to stay signed in on a shared machine.

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.

Need help?

Developer publishing support: [email protected]
General support: [email protected]
Partnerships: [email protected]