Developer documentation

Build on Ascended Social with a cleaner, calmer API guide.

The Public API gives you read-only access to users, posts, videos, live sessions, books, SABS characters, and more — all paginated, all authenticated, all public data only.

Read-onlyPublic data
13+Endpoints
CachedSpec copy

What to expect

The page is tuned for scanning: clearer section rhythm, stronger callouts, and code examples that feel easier to inspect and copy.

Live API spec

Mobile-friendly layout

Brand-aligned docs chrome

🔑

Authentication

Bearer token in every request. Keys live in your account settings.

📡

13 Endpoints

Users, posts, videos, live, books, SABS, sigils — all read-only.

Rate Limited

100–10,000 req/min depending on tier. Headers tell you what's left.

🛡️

Privacy First

Only public data returned. PII, private posts, DMs never exposed.

Quick Start

1. Get an API Key

Create a free account at ascended.social, then go to Settings → Developer to generate a key. It will look like:

sk_live_REDACTED_EXAMPLE_KEY

2. Make your first request

The public health endpoint requires no key and tells you the API is up:

# No API key needed for health check
curl https://ascended.social/api/v1/healthz
# Response
{
  "status": "ok",
  "timestamp": "2026-06-03T12:00:00.000Z"
}

3. Fetch the post feed

curl -H "Authorization: Bearer sk_live_your_key" \
  "https://ascended.social/api/v1/posts?limit=5"
{
  "data": [
    {
      "id": "post_abc123",
      "authorId": "usr_xyz789",
      "content": "Just witnessed the most incredible sunrise 🌅",
      "createdAt": "2026-05-30T06:12:00.000Z"
    },
    // ... more posts
  ],
  "page": 0,
  "pageSize": 5,
  "hasMore": true
}

All endpoints except /healthz require the Authorization: Bearer sk_live_... header. Without it you get 401 Unauthorized.

Authentication

Pass your API key as a Bearer token in the Authorization header on every request:

Authorization: Bearer sk_live_<your_key_here>

Key types

Prefix Type Use
sk_live_ Production Live data — use in your backend only
sk_test_ Test / sandbox For development and CI pipelines

Never expose API keys in client-side code, browser JavaScript, or public repositories. Use environment variables (process.env.ASCENDED_API_KEY) or a secrets manager. Keys are hashed and cannot be recovered — if lost, revoke and regenerate.

Key management

  • Create and revoke keys at Settings → Developer
  • You can have multiple keys (useful for separating services or environments)
  • Revoked keys return 401 immediately and cannot be un-revoked
  • last_used_at is updated on every valid request for auditing

Base URL

All API endpoints are served under:

https://ascended.social/api/v1

Example — the posts feed is at:

GET https://ascended.social/api/v1/posts

The interactive API Explorer (Swagger UI) is pre-configured with this base URL. Use it to browse every endpoint and try requests live in your browser.

Versioning

The API version is embedded in the path (/api/v1). The current stable version is v1. We will not make breaking changes to v1 — any incompatible changes will be released under /api/v2 with ample advance notice.

Pagination

All list endpoints use page-based pagination. You control it with two query parameters:

Param Type Default Description
page integer 0 0-indexed page number
limit integer 20 Results per page (max 50)

Response envelope

Every paginated response wraps the array in a standard envelope:

{
  "data": [ /* array of results */ ],
  "page": 0,         // current page (0-indexed)
  "pageSize": 20,    // items per page you requested
  "hasMore": true    // false when you've reached the last page
}

Some endpoints add extra top-level keys (e.g. bookId in the chapters response, userId in character responses).

Walking all pages

async function fetchAll(endpoint) {
  const results = [];
  let page = 0;
  do {
    const res = await fetch(
      `https://ascended.social/api/v1/${endpoint}?page=${page}&limit=50`,
      { headers: { Authorization: `Bearer ${API_KEY}` } }
    );
    const json = await res.json();
    results.push(...json.data);
    if (!json.hasMore) break;
    page++;
  } while (true);
  return results;
}

const allPosts = await fetchAll('posts');

Be mindful of rate limits when paginating large datasets. Consider using limit=50 (the max) to minimize the number of requests.

Rate Limits

Every response includes these headers so you can track consumption in real time:

X-RateLimit-Limit: 100             # requests allowed per minute
X-RateLimit-Remaining: 87          # requests left this minute
X-RateLimit-Remaining-Month: 9134  # requests left this month (Free/Pro)

Tiers

Tier Req / minute Req / month How to get it
Free 100 10,000 All accounts, immediate access
Pro 1,000 1,000,000 Active Pro subscription
Enterprise 10,000 Unlimited Contact us

When you're rate limited

The API returns 429 Too Many Requests. The response includes a Retry-After header (seconds) and a JSON body:

{
  "error": "Too Many Requests",
  "message": "Rate limit exceeded: 100 requests per minute",
  "tier": "free",
  "retryAfter": 60
}

Handling 429s in code

async function fetchWithRetry(url, opts, retries = 3) {
  const res = await fetch(url, opts);
  if (res.status === 429 && retries > 0) {
    const wait = 1000 * (parseInt(res.headers.get('Retry-After') || '60'));
    await new Promise(r => setTimeout(r, wait));
    return fetchWithRetry(url, opts, retries - 1);
  }
  return res;
}

Error Handling

All error responses share a consistent shape:

{
  "error": "Not found",      // short identifier
  "message": "Post not found"  // human-readable explanation
}
Status When it happens Action
400 Invalid query parameter (e.g. non-numeric page) Fix the request parameters
401 Missing, malformed, or revoked API key Check the Authorization header format
404 Resource ID doesn't exist or profile is private The resource isn't available publicly
429 Per-minute or monthly quota exceeded Wait for Retry-After seconds
500 Unexpected server error Check status.ascended.social, retry with backoff

Robust error handling example

async function apiRequest(path, opts = {}) {
  const res = await fetch(`https://ascended.social/api/v1${path}`, {
    ...opts,
    headers: {
      Authorization: `Bearer ${process.env.ASCENDED_API_KEY}`,
      ...opts.headers,
    },
  });

  if (res.status === 404) return null;  // Not found — treat as absent
  if (res.status === 401) throw new Error('Invalid API key');
  if (res.status === 429) {
    const err = new Error('Rate limited');
    err.retryAfter = parseInt(res.headers.get('Retry-After') || '60');
    throw err;
  }
  if (!res.ok) throw new Error(`API error ${res.status}`);

  return res.json();
}

Privacy Model

The Ascended Social Public API is strictly read-only and returns only content users have made publicly visible:

  • Private profiles are excluded from all responses (404 is returned)
  • Direct messages and private posts are never accessible
  • PII (email addresses, phone numbers, IP data) is stripped at the query level
  • Row-Level Security (RLS) is enforced at the PostgreSQL layer — no code path can accidentally leak private data
  • All API key usage is logged per-key for audit and abuse prevention

By using this API you agree to the API Terms of Use. Do not use the API to build surveillance tools, scrape data in bulk for resale, or contact users without their consent.


API Reference

All endpoints are under https://ascended.social/api/v1. All except /healthz require Authorization: Bearer sk_live_.... For interactive docs, visit api-docs.ascended.social →

Health

GET /healthz PUBLIC No API key required

Returns server health. Used by uptime monitors and status pages. No authentication required.

Response

{
  "status": "ok",
  "timestamp": "2026-06-03T12:00:00.000Z"
}

Users

GET /users/{userId} Public profile

Returns a user's public profile. Returns 404 if the profile is private or the user doesn't exist.

Path Parameters

Param Type Description
userId string The user's ID

Response Fields

Field Type Description
id string Unique user ID
username string | null URL-safe username
displayName string | null Display name
bio string | null Short bio
profileImageUrl string | null Avatar image URL
createdAt ISO 8601 Account creation timestamp
curl -H "Authorization: Bearer sk_live_..." \
  https://ascended.social/api/v1/users/usr_abc123
GET /users/{userId}/posts Posts by user

Returns paginated posts authored by a user, newest first.

Query Parameters

Param Default Max
page 0
limit 20 50

Response

{
  "data": [{ "id", "content", "createdAt", "updatedAt" }],
  "page": 0, "pageSize": 20, "hasMore": false
}

Posts

GET /posts Public feed

Global public post feed, newest first. Returns each post with its author's ID.

Query Parameters

Param Default Max
page 0
limit 20 50

Response Fields (per item)

Field Type Description
id string Post ID
authorId string ID of the post author
content string Post text content
createdAt ISO 8601 Publication time
GET /posts/{postId} Single post

Returns a single post by ID. Returns 404 if it doesn't exist or is private.

Response Fields

Field Type Description
id string Post ID
authorId string Author's user ID
content string Post text
createdAt ISO 8601 Published at
updatedAt ISO 8601 | null Last edited at

Books

GET /books Library

Paginated list of public books in the library, newest first.

Response Fields (per item)

Field Type
id string
title string
description string | null
createdAt ISO 8601
GET /books/{bookId} Single book

Returns a single book by ID. Same fields as the list endpoint.

GET /books/{bookId}/chapters Chapters in a book

Paginated chapters for a book. Response also includes the top-level bookId field.

Response

{
  "bookId": "book_abc123",
  "data": [{ "id", "bookId", "title", "createdAt" }],
  "page": 0, "pageSize": 20, "hasMore": false
}

Videos

GET /videos Elements video feed

Paginated list of public videos from the Elements feed, newest first.

Response Fields (per item)

Field Type
id string
title string | null
description string | null
createdAt ISO 8601

Live Sessions

GET /live/sessions Live & recent sessions

Returns live and recently ended video sessions, newest first.

Response Fields (per item)

Field Type Description
id string Session ID
title string | null Session title
description string | null Description
status string | null "live", "ended", etc.
createdAt ISO 8601 Session start time

SABS — Soul-Bound Ascension System

SABS is Ascended Social's spiritual progression game. Users create characters, join campaigns, and level up through real-world spiritual practices.

GET /sabs/campaigns Public campaigns

Returns paginated public SABS campaigns, newest first.

Response Fields (per item)

Field Type Description
id string Campaign ID
title string | null Campaign name
description string | null Description
status string | null "active", "completed", etc.
createdAt ISO 8601 Creation time
GET /sabs/characters/by-user/{userId} Characters by user

Returns paginated SABS characters owned by a user. The top-level response also includes the userId.

Response

{
  "userId": "usr_abc123",
  "data": [{ "id", "userId", "name", "createdAt" }],
  "page": 0, "pageSize": 20, "hasMore": false
}

Sigils

Sigils are unique spiritual symbols minted by users. They can be offered for trade with other members of the community.

GET /sigils/trades/{tradeId} Trade listing

Returns public details for a sigil trade by its ID.

Response Fields

Field Type Description
id string Trade ID
state string | null "pending", "completed", "expired"
expiresAt ISO 8601 | null When the offer expires
completedAt ISO 8601 | null When the trade was accepted
createdAt ISO 8601 When the offer was created

Events

Public ceremonies and rituals hosted on Ascended Social. Seances are always private and are never returned by these endpoints. Draft and cancelled events are also excluded.

GET /events List public events

Returns paginated public events ordered by start time (newest first). Optional ?status= filter: scheduled, live, or ended.

Response Fields

Field Type Description
id string Event ID
kind string "ceremony" or "ritual" (seances excluded)
title string Event title
description string | null Optional long description
intention string | null Spiritual intention
mood string | null Energetic mood
chakra string | null Associated chakra
element string | null Elemental association
startsAt ISO 8601 | null Scheduled start time
endsAt ISO 8601 | null Scheduled end time
timezone string | null IANA timezone (e.g. "America/New_York")
status string "scheduled", "live", or "ended"
rrule string | null RFC 5545 recurrence rule — non-null for recurring rituals
rsvpGoingCount number Count of "going" RSVPs
rsvpInterestedCount number Count of "interested" RSVPs
subscriberCount number Total subscribers to this event
creatorId string User ID of the host — use GET /users/{creatorId}
createdAt ISO 8601 When the event was created
GET /events/{eventId} Single event

Returns a single public event by its ID. Returns 404 for private events, seances, or unknown IDs — callers cannot distinguish between "does not exist" and "is private."


Network Bots

The Ascended Social bot platform lets you build automated agents that participate in networks — sending messages, responding to slash commands, and reacting to events via webhooks.

🤖

User API key

Use your sk_live_... key to create bots, manage tokens, and install bots into networks. All bot management endpoints follow the standard authentication model.

🔑

Bot token

Runtime actions (sending messages, listing channels/members) use a separate bt_live_... bot token issued via POST /bots/{botId}/tokens. Scopes control exactly what each token can do.

🌐

Webhooks

Register an HTTPS webhook URL on your bot to receive real-time events — messages, slash command invocations, installs, and more. Payloads are HMAC-signed for verification.

Lifecycle at a glance

  1. Create a bot — POST /bots
  2. Issue a bot token with the scopes you need — POST /bots/{botId}/tokens
  3. Install the bot in a network (you must be owner/admin) — POST /networks/{networkId}/bots/{botId}
  4. Send messages as the bot — POST /bot/networks/{networkId}/channels/{channelId}/messages
  5. Register slash commands and handle interactions via your webhook
  6. Uninstall or delete when done — DELETE /networks/{networkId}/bots/{botId}

Bot Tokens

Bot tokens (bt_live_...) are separate from user API keys and must be used for all runtime bot actions. Issue them via POST /bots/{botId}/tokens.

Available scopes

Scope Allows
messages:write Send messages to network channels
channels:read List channels the bot has access to
members:read List members of the bot's networks
slash-commands:write Register and manage slash commands

Issue a token

curl -X POST https://ascended.social/api/v1/bots/<botId>/tokens \
  -H "Authorization: Bearer sk_live_..." \
  -H "Content-Type: application/json" \
  -d '{
    "scopes": ["messages:write", "channels:read"],
    "label": "production"
  }'cURL
{
  "token": "bt_live_xxxxxxxxxxxxxxxxxxxx",
  "metadata": {
    "id": "tok_abc123",
    "scopes": ["messages:write", "channels:read"],
    "label": "production",
    "networkId": null,
    "expiresAt": null,
    "createdAt": "2026-06-10T00:00:00.000Z"
  }
}Response

⚠ The raw token value is returned only once. Store it securely (e.g. as an environment variable or in a secrets manager) — it cannot be retrieved again.

Use the token

// All bot runtime endpoints use bt_live_... instead of sk_live_...
const res = await fetch(
  "https://ascended.social/api/v1/bot/networks/<networkId>/channels/<channelId>/messages",
  {
    method: "POST",
    headers: {
      Authorization: "Bearer bt_live_xxxxxxxxxxxxxxxxxxxx",
      "Content-Type": "application/json",
    },
    body: JSON.stringify({ content: "🌙 Daily lunar update" }),
  }
);JavaScript

Webhooks

Set a webhookUrl on your bot (or per-install) to receive real-time events over HTTPS. The URL must be publicly reachable and cannot point to private/RFC1918 addresses.

Signature verification

Every delivery includes an X-Ascended-Signature header. Verify it before processing:

// Node.js verification example
import { createHmac } from "node:crypto";

function verifyWebhook(rawBody: Buffer, sig: string, secret: string, timestamp: string) {
  const expected = createHmac("sha256", secret)
    .update(`${timestamp}.${rawBody}`)
    .digest("hex");
  return sig === `sha256=${expected}`;
}

// In your Express handler:
app.post("/hooks/ascended", express.raw({ type: "*/*" }), (req, res) => {
  const sig = req.headers["x-ascended-signature"] as string;
  const ts  = req.headers["x-ascended-timestamp"]  as string;
  if (!verifyWebhook(req.body, sig, process.env.BOT_WEBHOOK_SECRET!, ts)) {
    res.status(401).end();
    return;
  }
  const event = JSON.parse(req.body.toString());
  // Handle event.type === "slash_command.invoked", "message.created", etc.
  res.json({ ok: true });
});Node.js

Retry policy

Failed deliveries are retried with exponential back-off at approximately 5 s → 30 s → 2 min → 10 min → 1 h → 1 h (6 attempts total). A delivery is considered failed if the webhook returns a non-2xx status or does not respond within the timeout.

Event types

Event type Triggered when
message.created A message is posted in a channel the bot can read
slash_command.invoked A member invokes one of the bot's registered slash commands
bot.installed Bot is installed in a network
bot.uninstalled Bot is removed from a network

Slash Commands

Register slash commands so network members can invoke your bot by typing /command-name in a channel. When a command is invoked, the platform sends a slash_command.invoked webhook event and your bot must respond within 3 seconds via POST /bot/interactions/{interactionId}/response.

Register a command (bot token)

// Register /transit in a network
await fetch(
  "https://ascended.social/api/v1/bot/networks/<networkId>/slash-commands",
  {
    method: "POST",
    headers: {
      Authorization: "Bearer bt_live_...",
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      name: "transit",
      description: "Get today's planetary transit report",
      usage: "/transit [date]",
    }),
  }
);JavaScript

Handle the invocation

// Your webhook receives:
{
  "type": "slash_command.invoked",
  "interactionId": "int_abc123",
  "commandName": "transit",
  "args": "2026-06-10",
  "networkId": "net_xyz",
  "channelId": "ch_123",
  "userId": "usr_invoker"
}

// Respond within 3 seconds:
await fetch("https://ascended.social/api/v1/bot/interactions/int_abc123/response", {
  method: "POST",
  headers: { Authorization: "Bearer bt_live_...", "Content-Type": "application/json" },
  body: JSON.stringify({ content: "🌙 Moon enters Scorpio at 14:32 UTC" }),
});JavaScript

Bots — Management

All endpoints below use your user API key (Authorization: Bearer sk_live_...).

GET /bots/directory PUBLIC Browse the bot directory

Returns publicly listed bots ordered by verified status then newest first. Use ?q= to search by name, username, or description. No API key required.

Query params

  • q — search string (optional)
  • limit — 1–100, default 50
GET /bots List your bots

Returns all bots owned by the authenticated user.

POST /bots Create a bot

Creates a new bot. name and username are required. Username must be unique (3–32 chars, letters/digits/underscores/hyphens).

Body

{
  "name": "AstrologyBot",
  "username": "astrology_bot",
  "description": "Daily planetary transits",
  "webhookUrl": "https://yourserver.example.com/hooks/ascended",
  "isPublic": true
}
POST /bots/{botId}/tokens Issue a bot token

Issues a bt_live_... token. The raw value is returned once only — store it immediately.

Body

{
  "scopes": ["messages:write", "channels:read"],
  "label": "production",
  "networkId": "net_xyz",       // optional — lock to one network
  "expiresAt": "2027-01-01T00:00:00Z"  // optional
}
DEL /bots/{botId}/tokens/{tokenId} Revoke a token

Revokes a token immediately. Any subsequent request using it returns 401.

POST /networks/{networkId}/bots/{botId} Install a bot

Installs a bot in a network. You must be the network owner or admin.

Body

{
  "permissions": ["read_messages", "write_messages", "read_members"],
  "webhookUrl": "https://yourserver.example.com/hooks/ascended"  // optional override
}
GET /networks/{networkId}/bots List bots in a network

Returns all bots installed in a network you are a member of.

DEL /networks/{networkId}/bots/{botId} Uninstall a bot

Removes a bot from a network. All webhooks and slash commands are deactivated immediately.

GET /bots/{botId}/deliveries Webhook delivery log

Returns recent webhook delivery attempts with HTTP status, attempt number, and error details. Useful for debugging failed deliveries.

Bots — Runtime Actions

All endpoints below require a bot token (Authorization: Bearer bt_live_...). Network scope and scopes are enforced per token.

POST /bot/networks/{networkId}/channels/{channelId}/messages Send a message

Posts a message to a channel as the bot. Requires scope messages:write and install permission write_messages.

Body

{ "content": "🌙 Moon enters Scorpio at 14:32 UTC" }
GET /bot/networks/{networkId}/channels List channels

Returns channels accessible to this bot. Requires scope channels:read and install permission read_messages.

GET /bot/networks/{networkId}/members List members

Returns members in the network. Requires scope members:read and install permission read_members.

POST /bot/networks/{networkId}/slash-commands Register a slash command

Registers or updates a slash command for this bot in a network. Requires scope slash-commands:write.

Body

{
  "name": "transit",
  "description": "Get today's planetary transit report",
  "usage": "/transit [date]"
}
POST /bot/interactions/{interactionId}/response Respond to a slash command

Must be called within 3 seconds of receiving the slash_command.invoked webhook event. Posts the response to the channel where the command was invoked.


JavaScript / TypeScript

Minimal API client

A lightweight wrapper you can copy into any project:

// ascended-api.ts
const BASE = "https://ascended.social/api/v1";

async function ascendedFetch(path: string, params: Record<string, any> = {}) {
  const url = new URL(BASE + path);
  Object.entries(params).forEach(([k, v]) => url.searchParams.set(k, String(v)));

  const res = await fetch(url.toString(), {
    headers: { Authorization: `Bearer ${process.env.ASCENDED_API_KEY}` },
  });

  if (res.status === 429) {
    const retry = parseInt(res.headers.get("Retry-After") || "60");
    throw Object.assign(new Error("Rate limited"), { retryAfter: retry });
  }
  if (!res.ok) throw new Error(`Ascended API error: ${res.status}`);
  return res.json();
}

// Usage
const posts = await ascendedFetch("/posts", { limit: 50, page: 0 });
const user  = await ascendedFetch(`/users/${userId}`);
const books = await ascendedFetch("/books", { page: 0 });

Fetch all pages (TypeScript)

async function fetchAllPages<T>(path: string): Promise<T[]> {
  const results: T[] = [];
  let page = 0;
  while (true) {
    const res: { data: T[]; hasMore: boolean } =
      await ascendedFetch(path, { page, limit: 50 });
    results.push(...res.data);
    if (!res.hasMore) break;
    page++;
  }
  return results;
}

const allBooks = await fetchAllPages<Book>("/books");

Next.js API Route example

// app/api/feed/route.ts
import { NextResponse } from "next/server";

export async function GET(req: Request) {
  const { searchParams } = new URL(req.url);
  const page = searchParams.get("page") || "0";

  const res = await fetch(
    `https://ascended.social/api/v1/posts?page=${page}&limit=20`,
    { headers: { Authorization: `Bearer ${process.env.ASCENDED_API_KEY}` },
      next: { revalidate: 60 } }  // Cache for 60s
  );

  if (!res.ok) return NextResponse.json({ error: "upstream error" }, { status: 502 });
  return NextResponse.json(await res.json());
}

Python

Using httpx

# pip install httpx
import httpx, os

BASE = "https://ascended.social/api/v1"
HEADERS = {"Authorization": f"Bearer {os.environ['ASCENDED_API_KEY']}"}

def fetch_posts(page=0, limit=20):
    r = httpx.get(f"{BASE}/posts", params={"page": page, "limit": limit}, headers=HEADERS)
    r.raise_for_status()
    return r.json()

def fetch_user(user_id: str):
    r = httpx.get(f"{BASE}/users/{user_id}", headers=HEADERS)
    if r.status_code == 404:
        return None
    r.raise_for_status()
    return r.json()

def fetch_all_books():
    books, page = [], 0
    while True:
        resp = fetch_posts.__globals__['httpx'].get(
            f"{BASE}/books", params={"page": page, "limit": 50}, headers=HEADERS
        ).json()
        books.extend(resp["data"])
        if not resp["hasMore"]: break
        page += 1
    return books

# Example
feed = fetch_posts(limit=50)
print(f"Got {len(feed['data'])} posts, hasMore={feed['hasMore']}")

Using requests

# pip install requests
import requests, os

session = requests.Session()
session.headers.update({
    "Authorization": f"Bearer {os.environ['ASCENDED_API_KEY']}"
})

BASE = "https://ascended.social/api/v1"

resp = session.get(f"{BASE}/posts", params={"page": 0, "limit": 20})
resp.raise_for_status()
data = resp.json()

for post in data["data"]:
    print(post["id"], post["content"][:60])

cURL

# Health check (no key needed)
curl https://ascended.social/api/v1/healthz

# Post feed
curl -H "Authorization: Bearer $ASCENDED_API_KEY" \
  "https://ascended.social/api/v1/posts?limit=20&page=0"

# User profile
curl -H "Authorization: Bearer $ASCENDED_API_KEY" \
  https://ascended.social/api/v1/users/usr_abc123

# Books library
curl -H "Authorization: Bearer $ASCENDED_API_KEY" \
  "https://ascended.social/api/v1/books?page=0&limit=50"

# Chapters in a book
curl -H "Authorization: Bearer $ASCENDED_API_KEY" \
  https://ascended.social/api/v1/books/book_abc123/chapters

# Video feed
curl -H "Authorization: Bearer $ASCENDED_API_KEY" \
  https://ascended.social/api/v1/videos

# Live sessions
curl -H "Authorization: Bearer $ASCENDED_API_KEY" \
  https://ascended.social/api/v1/live/sessions

# Public events (ceremonies + rituals)
curl -H "Authorization: Bearer $ASCENDED_API_KEY" \
  "https://ascended.social/api/v1/events?limit=20&page=0"

# Single public event
curl -H "Authorization: Bearer $ASCENDED_API_KEY" \
  https://ascended.social/api/v1/events/evt_abc123

# SABS campaigns
curl -H "Authorization: Bearer $ASCENDED_API_KEY" \
  https://ascended.social/api/v1/sabs/campaigns

# SABS characters for a user
curl -H "Authorization: Bearer $ASCENDED_API_KEY" \
  https://ascended.social/api/v1/sabs/characters/by-user/usr_abc123

# Sigil trade
curl -H "Authorization: Bearer $ASCENDED_API_KEY" \
  https://ascended.social/api/v1/sigils/trades/trade_abc123

# Save rate limit headers to a file for inspection
curl -D headers.txt -H "Authorization: Bearer $ASCENDED_API_KEY" \
  https://ascended.social/api/v1/posts -o /dev/null 2>&1
grep -i "X-RateLimit" headers.txt

Changelog

v1.0.0 — June 2026

  • Initial public release of the Ascended Social Public API
  • 15 read-only REST endpoints: users, posts, events (ceremonies & rituals), books, chapters, videos, live sessions, SABS campaigns, SABS characters, sigil trades, and health
  • SHA-256 API key hashing for O(1) indexed key lookup
  • Per-minute and per-month rate limiting with response headers
  • Full usage tracking to api_usage table (per-request endpoint, method, status, response time)
  • Row-Level Security enforced at the database layer for all API tables
  • Interactive Swagger UI at api-docs.ascended.social
  • OpenAPI 3.1 spec at api-docs.ascended.social/openapi.yaml
  • MCP server at developers.ascended.social/mcp — 15 tools, 2 resources, 2 prompts for AI agent integrations
  • Status monitoring at status.ascended.social

Support

💬

Developer Support

Questions about the API, rate limit increases, enterprise plans:

api@ascended.social →

🔍

Interactive Explorer

Browse every endpoint and try requests in your browser with no setup.

api-docs.ascended.social →

📊

Service Status

Real-time uptime, latency, and incident history for all API services.

status.ascended.social →

🛡️

Security Issues

Found a vulnerability? Please report it through our responsible disclosure policy.

Disclosure policy →