v1 · stable
REST · JSON

Sounds API Reference

Integrate the Sounds platform into your mobile app. Authenticate users with their existing account, list and stream sounds via short-lived signed URLs, and manage favorites — all over plain HTTPS + JSON.

Secure by default

Every request is authenticated; audio is delivered through expiring signed URLs.

Low latency

Edge-deployed endpoints with predictable response shapes and cursor pagination.

Row-level security

Tokens scope every query to the calling user — no manual ACL needed.

Base URL
https://aparmita.aurahimalaya.org/api/v1

Authentication

Every endpoint requires a bearer token. Mobile clients call our native auth endpoints (no third-party SDK or keys to bundle) and forward the returned access token.

1. Sign the user in

POST email + password to /auth/signin. You receive an access token (~1 hour) and a refresh token.

bash
curl -X POST https://aparmita.aurahimalaya.org/api/v1/auth/signin \
  -H "Content-Type: application/json" \
  -d '{"email":"user@example.com","password":"••••••••"}'

# => { "data": { "access_token": "...", "refresh_token": "...", "expires_in": 3600, ... } }

2. Call the API

Send the access token in the Authorization header.

bash
curl https://aparmita.aurahimalaya.org/api/v1/me \
  -H "Authorization: Bearer $ACCESS_TOKEN"

3. Refresh when it expires

On a 401, POST the refresh token to /auth/refresh and retry the original request with the new access token.

Service-to-service? Admins can issue long-lived API keys (prefixed sk_live_) from the admin panel. Use those only for trusted backends — never ship one inside a mobile binary.

Quickstart

List the first 20 sounds in the platform.

bash
curl "https://aparmita.aurahimalaya.org/api/v1/sounds?limit=20" \
  -H "Authorization: Bearer $ACCESS_TOKEN"

Endpoints

All endpoints return JSON. Errors follow the shape { "error": { "code", "message" } }.

POST/api/v1/auth/signup

Sign up

Create a new user with email + password. Returns session tokens immediately, or `needs_email_confirmation: true` if email confirmation is required.

Request
bash
curl -X POST https://aparmita.aurahimalaya.org/api/v1/auth/signup \
  -H "Content-Type: application/json" \
  -d '{"email":"user@example.com","password":"••••••••","full_name":"Asha P."}'
Response
json
{
  "data": {
    "access_token": "eyJhbGciOi…",
    "refresh_token": "v1.MR…",
    "token_type": "bearer",
    "expires_at": 1782215000,
    "expires_in": 3600,
    "user": { "id": "1c4b…", "email": "user@example.com" }
  }
}
POST/api/v1/auth/signin

Sign in

Exchange email + password for an access token and refresh token.

Request
bash
curl -X POST https://aparmita.aurahimalaya.org/api/v1/auth/signin \
  -H "Content-Type: application/json" \
  -d '{"email":"user@example.com","password":"••••••••"}'
Response
json
{
  "data": {
    "access_token": "eyJhbGciOi…",
    "refresh_token": "v1.MR…",
    "token_type": "bearer",
    "expires_at": 1782215000,
    "expires_in": 3600,
    "user": { "id": "1c4b…", "email": "user@example.com" }
  }
}
POST/api/v1/auth/refresh

Refresh access token

When a request returns 401, exchange the refresh token for a fresh access token and refresh token. Store the new refresh token — old ones are rotated.

Request
bash
curl -X POST https://aparmita.aurahimalaya.org/api/v1/auth/refresh \
  -H "Content-Type: application/json" \
  -d '{"refresh_token":"v1.MR…"}'
Response
json
{
  "data": {
    "access_token": "eyJhbGciOi…",
    "refresh_token": "v1.NR…",
    "token_type": "bearer",
    "expires_at": 1782218600,
    "expires_in": 3600
  }
}
POST/api/v1/auth/signout

Sign out

Revokes the refresh token associated with the current access token. Delete locally stored tokens after a successful response.

Request
bash
curl -X POST https://aparmita.aurahimalaya.org/api/v1/auth/signout \
  -H "Authorization: Bearer $ACCESS_TOKEN"
Response
json
{ "data": { "ok": true } }
POST/api/v1/auth/oauth/google

Sign in with Google (native)

Exchange a Google `id_token` (from the native iOS/Android Google Sign-In SDK) for an app session — no web redirect needed.

Request
bash
curl -X POST https://aparmita.aurahimalaya.org/api/v1/auth/oauth/google \
  -H "Content-Type: application/json" \
  -d '{"id_token":"<google_id_token>","nonce":"<optional_nonce>"}'
Response
json
{
  "data": {
    "access_token": "eyJhbGciOi…",
    "refresh_token": "v1.MR…",
    "token_type": "bearer",
    "expires_at": 1782215000,
    "expires_in": 3600,
    "user": { "id": "1c4b…", "email": "user@example.com" }
  }
}
GET/api/v1/sounds

List sounds

Returns active sounds, ordered by sort order then most recent. Supports cursor pagination.

Query parameters
NameTypeDescription
categorystringFilter by intention slug (parent or sub-intention).
include_childrenbooleanWhen `category` is a parent intention, also include sounds tagged with its sub-intentions.
featuredbooleanOnly return featured (true) or non-featured (false) sounds.
searchstringCase-insensitive match against the sound title.
limitinteger (1–100)Page size. Defaults to 50.
cursorISO8601 stringPass `next_cursor` from the previous response to fetch the next page.
Request
bash
curl "https://aparmita.aurahimalaya.org/api/v1/sounds?category=meditation&limit=20" \
  -H "Authorization: Bearer $ACCESS_TOKEN"
Response
json
{
  "data": [
    {
      "id": "9e7a…",
      "title": "Heart Bowl — F#",
      "category": "meditation",
      "frequency_hz": 369,
      "duration_sec": 412,
      "cover_image_url": "covers/abc.jpg",
      "is_featured": true,
      "play_count": 1284,
      "created_at": "2026-06-01T12:34:56Z"
    }
  ],
  "next_cursor": "2026-05-30T08:11:02Z"
}
GET/api/v1/sounds/{id}

Get sound + signed audio URL

Returns the full sound record along with a short-lived signed URL for streaming. The audio URL expires after 5 minutes — request it again right before playback.

Path parameters
NameTypeDescription
id*uuidSound ID.
Request
bash
curl "https://aparmita.aurahimalaya.org/api/v1/sounds/9e7a…" \
  -H "Authorization: Bearer $ACCESS_TOKEN"
Response
json
{
  "data": {
    "id": "9e7a…",
    "title": "Heart Bowl — F#",
    "audio_url": "https://…r2.cloudflarestorage.com/audio/abc.mp3?X-Amz-Signature=…",
    "audio_url_expires_in": 300,
    "cover_image_url": "https://…/covers/abc.jpg?X-Amz-Signature=…",
    "duration_sec": 412,
    "frequency_hz": 369
  }
}
POST/api/v1/sounds/{id}/play

Track a play

Atomically increments the sound's global play counter. Call this once when playback starts.

Path parameters
NameTypeDescription
id*uuidSound ID.
Request
bash
curl -X POST "https://aparmita.aurahimalaya.org/api/v1/sounds/9e7a…/play" \
  -H "Authorization: Bearer $ACCESS_TOKEN"
Response
json
{ "data": { "id": "9e7a…", "play_count": 1285 } }
GET/api/v1/favorites

List favorites

Returns the calling user's favorite sounds, newest first, with a compact sound preview.

Request
bash
curl "https://aparmita.aurahimalaya.org/api/v1/favorites" \
  -H "Authorization: Bearer $ACCESS_TOKEN"
Response
json
{
  "data": [
    {
      "sound_id": "9e7a…",
      "created_at": "2026-06-20T09:12:00Z",
      "sounds": {
        "id": "9e7a…",
        "title": "Heart Bowl — F#",
        "category": "meditation",
        "cover_image_url": "covers/abc.jpg",
        "duration_sec": 412
      }
    }
  ]
}
POST/api/v1/favorites

Add a favorite

Idempotent. Adds a sound to the user's favorites; calling it again is a no-op.

Body
NameTypeDescription
sound_id*uuidSound to favorite.
Request
bash
curl -X POST "https://aparmita.aurahimalaya.org/api/v1/favorites" \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"sound_id":"9e7a…"}'
Response
json
{ "data": { "ok": true } }
DELETE/api/v1/favorites/{soundId}

Remove a favorite

Removes a sound from the user's favorites.

Path parameters
NameTypeDescription
soundId*uuidSound to unfavorite.
Request
bash
curl -X DELETE "https://aparmita.aurahimalaya.org/api/v1/favorites/9e7a…" \
  -H "Authorization: Bearer $ACCESS_TOKEN"
Response
json
{ "data": { "ok": true } }
GET/api/v1/me

Current user

Returns the calling user's profile. Useful for validating a token after sign-in.

Request
bash
curl "https://aparmita.aurahimalaya.org/api/v1/me" -H "Authorization: Bearer $ACCESS_TOKEN"
Response
json
{
  "data": {
    "id": "1c4b…",
    "email": "user@example.com",
    "full_name": "Asha P.",
    "avatar_url": null
  },
  "auth_via": "jwt"
}
GET/api/v1/me/customer

Current customer

Returns the calling end-user's customer record (profile data for the mobile app, including signup source — `email`, `google`, or `apple` — and marketing preferences).

Request
bash
curl "https://aparmita.aurahimalaya.org/api/v1/me/customer" \
  -H "Authorization: Bearer $ACCESS_TOKEN"
Response
json
{
  "data": {
    "id": "1c4b…",
    "email": "user@example.com",
    "full_name": "Asha P.",
    "avatar_url": null,
    "phone": null,
    "provider": "google",
    "source": "google",
    "locale": "en-US",
    "country": "IN",
    "marketing_opt_in": false,
    "is_active": true,
    "last_seen_at": null,
    "created_at": "2026-06-20T09:12:00Z",
    "updated_at": "2026-06-20T09:12:00Z"
  },
  "auth_via": "jwt"
}
PATCH/api/v1/me/customer

Update current customer

Update editable fields on the caller's customer record. Email and provider are managed by auth and cannot be changed here.

Body
NameTypeDescription
full_namestring | nullDisplay name.
avatar_urlstring | nullPublic avatar URL.
phonestring | nullContact phone number.
localestring | nullBCP-47 locale, e.g. `en-US`.
countrystring | nullISO 3166-1 alpha-2 country code.
marketing_opt_inbooleanOpt in/out of marketing emails.
Request
bash
curl -X PATCH "https://aparmita.aurahimalaya.org/api/v1/me/customer" \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"full_name":"Asha P.","country":"IN","marketing_opt_in":true}'
Response
json
{
  "data": {
    "id": "1c4b…",
    "full_name": "Asha P.",
    "country": "IN",
    "marketing_opt_in": true,
    "updated_at": "2026-06-23T10:00:00Z"
  }
}
GET/api/v1/home

Homepage sections

Returns active homepage sections in display order, each with its resolved list of sounds (manual picks or rule-based).

Request
bash
curl "https://aparmita.aurahimalaya.org/api/v1/home" \
  -H "Authorization: Bearer $ACCESS_TOKEN"
Response
json
{
  "sections": [
    {
      "id": "7d1c…",
      "slug": "editors-picks",
      "title": "Editor's Picks",
      "mode": "manual",
      "rule_type": null,
      "rule_value": null,
      "rule_include_children": false,
      "sounds": [
        {
          "id": "9e7a…",
          "title": "Heart Bowl — F#",
          "category": "meditation",
          "cover_image_url": "covers/abc.jpg",
          "duration_sec": 412
        }
      ]
    }
  ]
}
GET/api/v1/categories

Intentions (categories)

Returns active intentions in display order, each with its nested sub-intentions. Auth is optional — guests may call it without a token.

Request
bash
curl "https://aparmita.aurahimalaya.org/api/v1/categories"
Response
json
{
  "data": [
    {
      "id": "3a1f…",
      "name": "Sleep",
      "slug": "sleep",
      "description": "Wind down and drift off.",
      "sort_order": 1,
      "children": [
        {
          "id": "b92c…",
          "name": "Falling asleep",
          "slug": "falling-asleep",
          "description": null,
          "sort_order": 0
        }
      ]
    }
  ]
}

Errors

All errors share a consistent envelope.

json
{ "error": { "code": "unauthorized", "message": "Invalid or expired access token." } }
StatusCodeMeaning
400invalid_requestBody or query parameters failed validation.
401unauthorizedMissing, invalid, or expired token.
404not_foundThe requested resource doesn't exist or is not visible to you.
429rate_limitedToo many requests — back off and retry after the reset window.
500server_errorSomething went wrong on our side. Safe to retry with backoff.

Rate limits

Default limit: 60 requests per minute per user. Every response includes:

  • X-RateLimit-Limit — the window's allowed requests
  • X-RateLimit-Remaining — requests left in this window
  • X-RateLimit-Reset — Unix timestamp when the window resets

Exceeded limits return 429 rate_limited. Implement exponential backoff (start at 1s, double up to 30s).

Security best practices

  • Use user JWTs in mobile apps. Never bundle an sk_live_ key in a binary you ship to end users.
  • Store tokens securely. iOS Keychain / Android Keystore — not plain SharedPreferences or UserDefaults.
  • Refresh signed audio URLs. They expire after 5 minutes. Re-request right before playback; don't cache.
  • Rotate compromised keys immediately from Admin → API Keys. Revocation takes effect within a few seconds.
  • HTTPS only. The API rejects plain HTTP. Pin certificates for high-assurance deployments.

Changelog

  • 2026-06-23 · v1.0 — Initial release. Sounds, favorites, play tracking, and current-user endpoints.