Developer Guide

Build on Ooki Music

Everything a backend or frontend developer needs to connect the API, replace mock data, deploy to production, and integrate auth, payments, and webhooks.

REST API Stripe Payments Google SSO JWT Auth Webhooks
01 — Overview

How the Frontend is Wired

The Ooki Music frontend is 100% static HTML/CSS/JS. All data currently comes from js/ooki-data.js — a mock data service layer. Your job is to replace each mock function with real fetch() calls to your REST API. No framework changes needed.

48 HTML Pages
All pages built, dark/light mode, global player, futuristic search overlay.
Design System
css/ooki-system.css — all tokens, components, animations in one file.
Mock Data Layer
js/ooki-data.js — replace each function with real API calls.
Shell / UI Controller
js/ooki-shell.js — Player, ThemeManager, Search, Toast, Modal, Dropdowns.
Global Search
Text, voice (Web Speech API) and image search — ⌘K from any page.
Dark / Light Mode
ThemeManager persists via localStorage. Works on every page.

The frontend uses no framework (no React/Vue/Angular). It's vanilla HTML + CSS + JS. Any backend stack works — Node.js, Python, Go, PHP, etc.

02 — Folder Structure

Copy This Exact Structure to Your Server

All HTML files use relative paths. Preserve this structure exactly on your web server or CDN. Do not move files between folders without updating all relative path references.

Project RootTREE
ooki/
├── index.html              ← landing page
├── artists.html            ← browse all artists
├── search.html             ← global search results
├── store.html              ← digital store
├── sonic-capsules.html     ← Sonic Capsules
├── artist-covers.html      ← covers gallery
├── portals.html            ← sign-in hub
├── investor.html           ← investor pitch
├── artist.html             ← public artist profile
├── listener.html           ← public listener profile
├── developer.html          ← developer overview
├── handoff.html            ← this handoff package
├── dev-handoff.html        ← API spec & integration guide
├── admin/
│   ├── index.html          ← admin hub
│   ├── overview.html
│   ├── users.html
│   ├── permissions.html
│   ├── platform-analytics.html
│   ├── songwriters.html
│   └── merchant.html       ← store/merchant management
├── app/
│   ├── artist-dashboard.html
│   ├── listener-dashboard.html
│   └── app-analytics.html
├── artist/
│   ├── kira.html           ← live example
│   └── template.html       ← dynamic template (?artist=slug)
├── auth/
│   ├── login.html
│   ├── signup.html
│   ├── reset.html
│   ├── admin-login.html    ← admin only
│   └── 2fa.html            ← TOTP verification
├── css/
│   └── ooki-system.css     ← entire design system
├── developers/
│   ├── index.html
│   ├── api-keys.html
│   ├── sandbox.html
│   └── webhooks.html
├── guides/
│   ├── index.html
│   ├── artist-guide.html
│   ├── listener-guide.html
│   ├── developer.html      ← this page
│   └── user-guide.html
├── images/
│   ├── ooki-logo-wordmark.png
│   └── ooki-vinyl-icon.png
└── js/
    ├── ooki-shell.js       ← global UI controller (DO NOT rename)
    └── ooki-data.js        ← mock data → REPLACE with API calls
03 — Replace Mock Data

Swapping ooki-data.js for Real API Calls

Every function in js/ooki-data.js is marked with a // TODO: replace with API call comment. Keep the same function names and return shapes — the HTML pages call these functions directly.

js/ooki-data.js — Current Mock (example)JS
// MOCK — delete this entire block and replace
const OokiService = {
  getTracks: async (filter = {}) => {
    // TODO: replace with API call
    await delay(200);
    return { data: MOCK_TRACKS, total: MOCK_TRACKS.length };
  },
  getArtists: async (filter = {}) => {
    // TODO: replace with API call
    await delay(200);
    return { data: MOCK_ARTISTS, total: MOCK_ARTISTS.length };
  }
};
js/ooki-data.js — Production ReplacementJS
const API_BASE = 'https://api.ooki.music/v1';

async function apiFetch(path, options = {}) {
  const token = localStorage.getItem('ooki-token');
  const res = await fetch(`${API_BASE}${path}`, {
    headers: {
      'Content-Type': 'application/json',
      ...(token ? { 'Authorization': `Bearer ${token}` } : {})
    },
    ...options
  });
  if (!res.ok) throw new Error(await res.text());
  return res.json();
}

const OokiService = {
  getTracks: (filter = {}) =>
    apiFetch(`/tracks?${new URLSearchParams(filter)}`),

  getArtists: (filter = {}) =>
    apiFetch(`/artists?${new URLSearchParams(filter)}`),

  getArtist: (slug) =>
    apiFetch(`/artists/${slug}`),

  getAlbums: (filter = {}) =>
    apiFetch(`/albums?${new URLSearchParams(filter)}`),

  uploadTrack: (data) =>
    apiFetch('/tracks', { method: 'POST', body: JSON.stringify(data) })
};

Keep the same return shape: All pages expect { data: [], total: number } from list endpoints and a single object from detail endpoints. Your API should return this format or add a thin adapter wrapper in ooki-data.js.

04 — Auth Integration

JWT + Google SSO + Admin 2FA

The auth pages are fully built — they just need their form actions and API endpoints wired up.

1
Wire login form — auth/login.html
The form POSTs to # currently. Set action="https://api.ooki.music/v1/auth/login" and method="POST", or intercept with fetch() in JS, store the returned JWT in localStorage.setItem('ooki-token', token), and redirect based on role.
2
Google SSO — all auth pages
Load the Google Identity SDK and init with your client ID. The button is already in the HTML with id googleSignInBtn. Call google.accounts.id.initialize({ client_id: GOOGLE_CLIENT_ID, callback: handleCredential }).
3
Admin login + 2FA — auth/admin-login.html → auth/2fa.html
Admin login POSTs credentials. If 2FA is required, your API returns { requires_2fa: true, temp_token: "..." }. Store temp_token, redirect to auth/2fa.html. The 2FA page submits the TOTP code + temp_token to POST /auth/2fa/verify.
4
Token refresh + logout
Store ooki-token (JWT) and ooki-refresh-token in localStorage. On 401 responses, call POST /auth/refresh with the refresh token and retry the request. All Sign Out buttons call localStorage.clear() + redirect to index.html.
Auth Helper (add to ooki-data.js)JS
const Auth = {
  login: async (email, password) => {
    const res = await apiFetch('/auth/login', {
      method: 'POST',
      body: JSON.stringify({ email, password })
    });
    if (res.token) localStorage.setItem('ooki-token', res.token);
    return res;
  },
  logout: () => {
    localStorage.clear();
    window.location.href = '../index.html';
  },
  isLoggedIn: () => !!localStorage.getItem('ooki-token'),
  getRole: () => {
    const token = localStorage.getItem('ooki-token');
    if (!token) return null;
    try {
      return JSON.parse(atob(token.split('.')[1])).role;
    } catch { return null; }
  }
};
05 — Stripe Payments

Wiring the Store & Artist Payouts

The store UI is complete. You need to load Stripe.js, create checkout sessions server-side, and connect artist payout accounts via Stripe Connect.

1
Load Stripe.js in store.html and admin/merchant.html
Add before </body>: <script src="https://js.stripe.com/v3/"></script> and init: const stripe = Stripe('pk_live_...')
2
Create checkout session server-side
When the user clicks "Buy Now", call POST /api/checkout with { product_id, price, user_id }. Your server creates a Stripe Checkout Session and returns { session_id }. Then call stripe.redirectToCheckout({ sessionId }).
3
Artist payouts — Stripe Connect
Artists need Stripe Connect accounts. The merchant dashboard shows payout balance and history. Connect via POST /api/connect/onboard which returns a Stripe onboarding URL. Artists keep 85% — your backend splits via Stripe's transfer API.

Never put Stripe secret keys in frontend JS. All payment session creation must happen on your backend. Only the publishable key (pk_live_...) belongs in the frontend.

06 — Webhooks

Event System Integration

The webhooks dashboard is built at developers/webhooks.html. Register your endpoint URL and Ooki will POST events to it. Your backend must verify the X-Ooki-Signature header using HMAC-SHA256.

EventTriggerPayload (key fields)
track.publishedArtist publishes a tracktrack_id, artist_id, title, genre
track.removedTrack taken downtrack_id, reason
user.signupNew user registereduser_id, role, email, plan
user.subscribedUser upgrades to Prouser_id, plan, amount
payment.successStore purchase completedorder_id, user_id, product_id, amount
artist.verifiedArtist account verified by adminartist_id, verified_by
capsule.unlockedUser unlocks a Sonic Capsulecapsule_id, user_id, artist_id
Webhook Signature Verification (Node.js)JS
const crypto = require('crypto');

app.post('/api/webhooks', (req, res) => {
  const sig = req.headers['x-ooki-signature'];
  const expected = crypto
    .createHmac('sha256', process.env.WEBHOOK_SECRET)
    .update(req.rawBody)
    .digest('hex');

  if (sig !== `sha256=${expected}`) {
    return res.status(401).send('Invalid signature');
  }

  const { event, data } = req.body;
  switch (event) {
    case 'payment.success':
      handlePayment(data); break;
    case 'user.signup':
      sendWelcomeEmail(data); break;
  }
  res.sendStatus(200);
});
07 — API Reference

Core Endpoints Your Backend Must Implement

These are the endpoints the frontend calls. Build them in any language/framework. Full spec is in dev-handoff.html.

Auth
MethodEndpointDescription
POST/auth/loginReturns JWT + refresh token + user role
POST/auth/signupCreates user, returns JWT
POST/auth/refreshReturns new JWT from refresh token
POST/auth/reset-passwordSends reset email
POST/auth/2fa/verifyValidates TOTP code, returns full JWT
POST/auth/googleGoogle SSO token exchange
Tracks & Artists
MethodEndpointDescription
GET/tracksList tracks — ?genre=&artist=&search=&page=&limit=
GET/tracks/:idSingle track detail
POST/tracksUpload new track (multipart/form-data)
PATCH/tracks/:idUpdate track metadata
DELETE/tracks/:idRemove track
GET/artistsList artists — ?genre=&search=&verified=&page=
GET/artists/:slugArtist profile + discography
POST/artists/:id/followFollow/unfollow artist
Store & Payments
MethodEndpointDescription
GET/store/productsList albums/EPs/singles for sale
POST/checkoutCreate Stripe Checkout Session
GET/store/downloads/:idSigned download URL for purchased track
GET/payoutsArtist payout history
Admin
MethodEndpointDescription
GET/admin/usersAll users — ?role=&status=&search=&page=
PATCH/admin/users/:id/statusBan/restore user
GET/admin/analyticsPlatform KPIs — DAU, streams, revenue
GET/admin/songwritersISRC, splits, publishing rights
08 — Environment Variables

Required Configuration

Set these on your server/hosting platform. Never commit them to Git.

VariableExample ValueRequired?Used In
OOKI_API_BASE_URLhttps://api.ooki.music/v1Requiredooki-data.js API_BASE
JWT_SECRETsuper-secret-256bit-keyRequiredBackend JWT signing
GOOGLE_CLIENT_ID1234567890.apps.googleusercontent.comRequiredauth/*.html Google SSO
STRIPE_PKpk_live_abc123...Requiredstore.html, merchant.html
STRIPE_SKsk_live_abc123...RequiredBackend checkout sessions
ADMIN_2FA_SECRETBASE32ENCODED...Requiredauth/2fa.html TOTP
CDN_URLhttps://cdn.ooki.musicRequiredAudio/image CDN base URL
SENDGRID_API_KEYSG.abc123...RequiredTransactional emails
WEBHOOK_SECRETwhsec_abc123...Optionaldevelopers/webhooks.html
SENTRY_DSNhttps://[email protected]/123OptionalError monitoring
POSTHOG_KEYphc_abc123OptionalProduct analytics
09 — Deployment

Get it Live in 3 Ways

The frontend is purely static — it deploys anywhere. Pick the option that matches your infrastructure.

GitHub Pages (simplest)
Push the ooki/ folder to a GitHub repo. Enable Pages under Settings → Pages → Deploy from branch (main / root). Free, automatic SSL.
AWS S3 + CloudFront
Sync files: aws s3 sync . s3://your-bucket --delete. Point CloudFront distribution at the bucket. Enable OAC for private bucket. Invalidate on deploy: aws cloudfront create-invalidation --distribution-id YOUR_ID --paths "/*"
AWS Amplify (CI/CD included)
Push to GitHub, connect repo in Amplify Console. The included amplify.yml handles build + deploy automatically on every push to main. Zero config needed.
amplify.yml (already in project root)YAML
version: 1
frontend:
  phases:
    build:
      commands:
        - echo "Static site — no build step required"
  artifacts:
    baseDirectory: /
    files:
      - '**/*'
  cache:
    paths: []
10 — Launch Checklist

Before You Go Live

Run through this list before flipping the switch to production.

All 15 checks passed? You're ready to go live. Push to your deployment branch and ship it.

Ready to start building?

Download every file from the handoff package and hand it to your backend team.