ASQ API Reference

Thread-native community Q&A — REST API with configurable role-based access control

Base URL for all API requests:

https://api.asq.ai/v1

Every request scopes to a community. Most endpoints follow the pattern:

/v1/communities/{communityId}/resource

All responses return JSON. Timestamps are ISO 8601. IDs are Firestore-compatible strings. Pagination uses cursor-based startAfter + limit params.

Authentication

ASQ supports two auth modes. All requests require an Authorization header.

1. Firebase Auth Token (widget / client-side)

Authorization: Bearer {firebase_id_token}

Used by the embedded widget. The token carries the user's UID and custom claims (including role).

2. API Key + Secret (server-to-server)

Authorization: ApiKey {api_key}:{api_secret}
X-ASQ-As: {user_id}  

Used for backend integrations, pre-seeding sessions, bulk imports, and admin operations. API keys are created in the community dashboard and scoped to a role.

API keys inherit the role assigned at creation. A key with moderator role cannot perform admin actions. Use X-ASQ-As to impersonate a user — requires admin role on the key.

Permission Model

ASQ uses a capability-based RBAC system. Each community defines roles, and each role is a set of capability flags. This means permissions are fully configurable — you decide exactly what each role can and cannot do.

How it works

API Request
Auth Check
Resolve Role
user → community role
Check Capability
role.capabilities[action]
Allow / Deny

Each user has a role per community. A user can be admin in one community and viewer in another. Roles are stored in the user's community membership document.

{
  "userId": "usr_abc123",
  "communityId": "expo-2026",
  "role": "speaker",
  "customCapabilities": {           // optional overrides
    "session.create": true,
    "thread.create": true,
    "tag.manage": false
  },
  "joinedAt": "2026-03-28T10:00:00Z"
}

Custom overrides: The customCapabilities field lets you grant or revoke individual capabilities per user, on top of their role defaults. This is how you give one specific exhibitor tag-management powers without changing the whole exhibitor role.

Roles & Capabilities

ASQ ships with 6 default roles. All are fully configurable — rename them, change their capabilities, or create entirely new roles.

Default Roles

Capability admin organizer speaker exhibitor member viewer
session.createCFG
session.manage
session.joinCFG
thread.createCFG
thread.reply
thread.read
room.createCFG
room.joinCFG
room.message
tag.createCFGCFG
tag.manage
tag.assignCFG
member.inviteCFGCFG
member.list
member.manage
knowledge.read
knowledge.curate
community.configureCFG
analytics.viewCFGCFG

= always on   CFG = configurable (off by default)   = always off unless custom override

Community Configuration

Each community stores its permission config, session defaults, and feature flags in a single config document.

{
  "communityId": "expo-2026",
  "name": "PM Career Expo 2026",
  "features": {
    "sessions": true,
    "rooms": true,
    "knowledge": true,
    "tags": true,
    "meetingLinks": true,
    "dm": false
  },
  "defaults": {
    "sessionModes": ["ask-session","private-room","public-convo","ama","workshop"],
    "sessionCategories": ["exhibitor","speaker","community","sponsor"],
    "maxParticipantsDefault": 25,
    "sessionDurationDefault": 45,
    "threadVisibility": "community",
    "autoSummarize": true
  },
  "roles": {
    "admin":     { "capabilities": { "session.create":true, "session.manage":true, "thread.create":true, "thread.reply":true, "thread.read":true, "room.create":true, "room.join":true, "room.message":true, "tag.create":true, "tag.manage":true, "tag.assign":true, "member.invite":true, "member.list":true, "member.manage":true, "knowledge.read":true, "knowledge.curate":true, "community.configure":true, "analytics.view":true }},
    "organizer": { "capabilities": { "session.create":true, "session.manage":true, "thread.create":true, "thread.reply":true, "thread.read":true, "room.create":true, "room.join":true, "room.message":true, "tag.create":true, "tag.manage":true, "tag.assign":true, "member.invite":true, "member.list":true, "member.manage":true, "knowledge.read":true, "knowledge.curate":true, "community.configure":false, "analytics.view":true }},
    "speaker":   { "capabilities": { "session.create":true, "thread.create":true, "thread.reply":true, "thread.read":true, "room.create":true, "room.join":true, "room.message":true, "tag.create":true, "tag.assign":true, "member.list":true, "knowledge.read":true, "knowledge.curate":true }},
    "exhibitor": { "capabilities": { "session.create":true, "thread.create":true, "thread.reply":true, "thread.read":true, "room.create":true, "room.join":true, "room.message":true, "tag.assign":true, "member.list":true, "knowledge.read":true }},
    "member":    { "capabilities": { "thread.reply":true, "thread.read":true, "room.join":true, "room.message":true, "member.list":true, "knowledge.read":true, "session.join":true }},
    "viewer":    { "capabilities": { "thread.read":true, "member.list":true, "knowledge.read":true }}
  },
  "registrationDefaults": {
    "defaultRole": "member",
    "approvalRequired": false,
    "allowSelfRegister": true
  }
}

Role Templates

Create custom roles for your community. Roles are just named capability bundles.

POST /communities/{id}/roles Create a custom role

Request Body

{
  "name": "panelist",
  "label": "Panel Speaker",
  "description": "Can create AMA sessions and threads, but not manage tags",
  "capabilities": {
    "session.create": true,
    "session.join": true,
    "thread.create": true,
    "thread.reply": true,
    "thread.read": true,
    "room.create": true,
    "room.join": true,
    "room.message": true,
    "tag.assign": true,
    "member.list": true,
    "knowledge.read": true,
    "knowledge.curate": true
  },
  "sessionModes": ["ama", "public-convo"],
  "maxSessions": 3
}

Response

{
  "id": "role_panelist",
  "name": "panelist",
  "label": "Panel Speaker",
  "capabilities": { ... },
  "createdAt": "2026-03-28T10:00:00Z"
}

Requires community.configure

GET /communities/{id}/roles List all roles

Returns all roles (built-in + custom) with their capability maps.

Requires community.configure or analytics.view

PUT /communities/{id}/roles/{roleName} Update role capabilities

Request Body

{
  "capabilities": {
    "tag.create": true,
    "member.invite": true
  }
}

Merges with existing capabilities. Send false to revoke.

Requires community.configure

Capability Flags Reference

FlagScopeDescription
session.createsessionCreate new sessions (Ask, AMA, Workshop, etc.)
session.managesessionEdit/delete any session, change status, pin sessions
session.joinsessionJoin/reserve a spot in sessions
thread.createthreadPost new question threads
thread.replythreadAdd answers/replies to threads
thread.readthreadView threads and answers
room.createroomSpin up live rooms from threads
room.joinroomEnter an active room
room.messageroomSend messages in live rooms
tag.createtagCreate new tags in the community taxonomy
tag.managetagEdit, merge, delete, and re-parent tags
tag.assigntagApply tags to threads/sessions
member.invitememberSend invitations to join the community
member.listmemberView the people directory
member.managememberChange roles, ban, remove members
knowledge.readknowledgeView summaries and knowledge base
knowledge.curateknowledgeEdit/approve/reject auto-generated summaries
community.configureadminChange community settings, roles, features
analytics.viewadminView engagement analytics and reports

Sessions

Sessions are scheduled or live rooms — AMAs, workshops, exhibitor booths, public conversations. They can be pre-created by the API for conferences or created on-the-fly by users with the right role.

POST /communities/{id}/sessions Create a session

Request Body

{
  "title": "Building Products That Scale",
  "description": "Interactive AMA with product leaders",
  "mode": "ama",
  "category": "speaker",
  "status": "scheduled",
  "scheduledAt": "2026-04-15T14:00:00Z",
  "duration": 60,
  "maxParticipants": 50,
  "meetLink": "https://meet.google.com/abc-defg-hij",
  "visibility": "public",
  "tags": ["product","leadership","scaling"],
  "hosts": ["usr_sarah","usr_mike"],
  "preCreatedThreads": [
    {
      "title": "What's the biggest mistake PMs make at Series B?",
      "body": "Seed question for the AMA",
      "tags": ["series-b","mistakes"],
      "pinned": true
    },
    {
      "title": "How do you prioritize when everything is P0?",
      "body": "Common question — let's dig in",
      "tags": ["prioritization"]
    }
  ],
  "settings": {
    "allowAudienceThreads": true,
    "requireApproval": false,
    "autoRecord": true,
    "autoSummarize": true
  }
}
FieldTypeRequiredDescription
titlestringrequiredSession title (max 120 chars)
modeenumrequiredask-session private-room public-convo ama workshop
categoryenumoptionalexhibitor speaker community sponsor or custom
statusenumoptionaldraft scheduled live ended — defaults to draft
scheduledAtISO 8601optionalWhen the session goes live
durationnumberoptionalMinutes. Default from community config
maxParticipantsnumberoptionalCap. 0 = unlimited
meetLinkurloptionalExternal meeting URL (Meet, Zoom, Teams)
hostsstring[]optionalUser IDs of session hosts
preCreatedThreadsobject[]optionalSeed threads created with the session
tagsstring[]optionalTopic tags
settingsobjectoptionalSession-level overrides

Requires session.create

Pre-seeding: Use preCreatedThreads to set up an AMA with starter questions, a workshop with exercise prompts, or an exhibitor booth with FAQ threads — all in a single API call.

GET /communities/{id}/sessions List sessions

Query Parameters

ParamTypeDefaultDescription
statusenumallFilter: draft scheduled live ended
modeenumallFilter by session mode
categoryenumallFilter by category
hoststringFilter by host user ID
tagstringFilter by tag
limitnumber20Page size (max 100)
startAfterstringCursor for pagination

Requires session.join or thread.read

GET /communities/{id}/sessions/{sessionId} Get session detail

Returns session with threads, participant count, hosts, and meeting link. Includes userPermissions block showing what the authenticated user can do in this session.

{
  "id": "ses_abc123",
  "title": "Building Products That Scale",
  "mode": "ama",
  "category": "speaker",
  "status": "live",
  "participantCount": 34,
  "threads": [ ... ],
  "userPermissions": {
    "canPost": true,
    "canReply": true,
    "canManage": false,
    "canJoinCall": true
  }
}
PATCH /communities/{id}/sessions/{sessionId} Update session

Partial update. Only send fields to change. Hosts can update their own sessions; session.manage can update any.

{ "status": "live", "meetLink": "https://zoom.us/j/123456" }

Requires session.create (own) or session.manage (any)

POST /communities/{id}/sessions/{sessionId}/join Join / reserve spot

Registers the authenticated user as a participant. For scheduled sessions, reserves a spot. For live sessions, joins immediately.

Requires session.join

POST /communities/{id}/sessions/batch Bulk create sessions

Create up to 50 sessions in one call. Perfect for importing an entire conference schedule.

{
  "sessions": [
    { "title": "...", "mode": "ama", ... },
    { "title": "...", "mode": "workshop", ... }
  ],
  "defaults": {
    "category": "exhibitor",
    "visibility": "public",
    "maxParticipants": 30
  }
}

Requires session.manage

Threads

Threads are the core unit — a structured question that can attract answers, spawn rooms, and generate knowledge.

POST /communities/{id}/threads Create a thread
{
  "title": "How to handle stakeholder misalignment?",
  "body": "Our leadership team has conflicting priorities...",
  "askType": "ask-session",
  "sessionId": "ses_abc123",
  "tags": ["stakeholders","alignment"],
  "visibility": "community",
  "meetLink": "https://meet.google.com/xyz",
  "matchCriteria": {
    "expertise": ["product-strategy","leadership"],
    "minTrust": 70
  }
}
FieldTypeRequiredDescription
titlestringrequiredThe question (max 200 chars)
askTypeenumoptionalMatches session modes. Defaults to public-convo
sessionIdstringoptionalAttach to an existing session
tagsstring[]optionalTopic tags
visibilityenumoptionalpublic community private
meetLinkurloptionalExternal call link
matchCriteriaobjectoptionalAuto-match people by expertise/trust

Requires thread.create

GET /communities/{id}/threads List threads

Filterable by status, askType, sessionId, tag, authorId. Supports sort=recent|popular|unanswered.

Requires thread.read

POST /communities/{id}/threads/{threadId}/replies Reply to a thread
{ "body": "In my experience at Stripe, we solved this by...", "parentId": null }

Nested replies use parentId. Top-level answers leave it null.

Requires thread.reply

POST /communities/{id}/threads/{threadId}/room Spin up a room from thread
{ "meetLink": "https://teams.microsoft.com/l/meetup/...", "maxParticipants": 8 }

Creates a live room linked to the thread. The thread pipeline: Ask → Match → Room → Summary → Knowledge.

Requires room.create

Rooms

Live conversation spaces. Always linked to a thread or session.

GET /communities/{id}/rooms List active rooms

Returns rooms with status=active by default. Each room includes participant list with online status.

Requires room.join

POST /communities/{id}/rooms/{roomId}/messages Send room message
{ "body": "Great point — I think the key insight is...", "type": "text" }

Requires room.message + must be a room participant

POST /communities/{id}/rooms/{roomId}/end End room & trigger summary

Closes the room, generates an auto-summary from the conversation, and promotes key takeaways back to the parent thread.

Requires Room host or session.manage

Members

Manage community members, their roles, and per-user capability overrides.

GET /communities/{id}/members List members

Query Parameters

ParamTypeDescription
statusenumonline in-room offline all
rolestringFilter by role name
expertisestringFilter by expertise tag
searchstringSearch name/bio

Requires member.list

POST /communities/{id}/members Add / invite member
{
  "email": "[email protected]",
  "role": "speaker",
  "customCapabilities": {
    "tag.create": true
  },
  "sessionAccess": ["ses_abc123", "ses_def456"],
  "sendInvite": true
}

Adds a member with a specific role. Use customCapabilities for per-user overrides. sessionAccess restricts which sessions they can see (omit for all).

Requires member.invite

PATCH /communities/{id}/members/{userId} Update member role / capabilities
{
  "role": "exhibitor",
  "customCapabilities": {
    "session.create": true,
    "tag.create": true,
    "member.invite": true
  }
}

Change a user's role or toggle individual capability flags. The final permission is: role.capabilities[flag] OR customCapabilities[flag].

Requires member.manage

POST /communities/{id}/members/batch Bulk import members
{
  "members": [
    { "email": "[email protected]", "role": "exhibitor", "name": "Acme Corp" },
    { "email": "[email protected]", "role": "speaker", "name": "Jane Doe" }
  ],
  "defaults": { "sendInvite": true }
}

Import up to 200 members. Ideal for conference pre-registration.

Requires member.manage

Tags

Community taxonomy for organizing threads and sessions. Tags can be hierarchical.

POST /communities/{id}/tags Create a tag
{ "name": "product-strategy", "parentId": "tag_product", "color": "#6366f1" }

Requires tag.create

GET /communities/{id}/tags List tags (tree)

Returns tags as a flat list with parentId references, or ?format=tree for nested structure.

Requires thread.read

POST /communities/{id}/tags/{tagId}/merge Merge tags
{ "mergeInto": "tag_product_strategy" }

Merges all references of this tag into the target. Useful for cleaning up duplicates.

Requires tag.manage

Knowledge

Auto-generated summaries from resolved threads and completed rooms. The end product of ASQ's pipeline: Question → Room → Summary → Knowledge.

GET /communities/{id}/knowledge Search knowledge base

Query Parameters

ParamTypeDescription
qstringFull-text search query
tagstringFilter by tag
sessionIdstringKnowledge from a specific session
statusenumapproved pending rejected

Requires knowledge.read

PATCH /communities/{id}/knowledge/{knowledgeId} Curate knowledge entry
{ "status": "approved", "editedSummary": "Refined summary text..." }

Approve, reject, or edit auto-generated summaries before they become permanent knowledge.

Requires knowledge.curate

Widget Embed

Drop the ASQ widget into any website with 3 lines of code. The widget inherits the community's permission model — users see only what their role allows.

Quick Start

<!-- 1. Load ASQ -->
<script src="https://cdn.asq.ai/v1/asq.js"></script>
<link rel="stylesheet" href="https://cdn.asq.ai/v1/asq.css">

<!-- 2. Initialize -->
<script>
  ASQ.init({
    communityId: 'expo-2026',
    firebaseConfig: { /* your config */ },
    theme: 'light',
    position: 'bottom-right',
    features: {
      sessions: true,
      people: true,
      knowledge: true
    }
  });
</script>

Configuration Options

OptionTypeDefaultDescription
communityIdstringrequiredYour community identifier
firebaseConfigobjectrequiredFirebase project config
themestringlightlight or dark
positionstringbottom-rightWidget position: bottom-right bottom-left
featuresobjectall onToggle widget features
localestringenLanguage code
ssoTokenstringPre-auth with your SSO provider
defaultViewstringhomeInitial screen: home sessions people
sessionFilterobjectPre-filter sessions shown (e.g. by category)

SSO Integration

For platforms that have their own auth, pass a signed JWT to auto-login users:

ASQ.init({
  communityId: 'expo-2026',
  firebaseConfig: { ... },
  ssoToken: 'eyJhbG...',          // JWT signed with your ASQ API secret
  ssoProvider: 'custom',
  userMapping: {
    id: 'sub',                     // JWT claim → ASQ user ID
    name: 'name',
    email: 'email',
    role: 'asq_role'               // optional: auto-assign role from JWT
  }
});

JavaScript API

// Open/close widget programmatically
ASQ.open();
ASQ.close();
ASQ.toggle();

// Navigate to a specific session
ASQ.openSession('ses_abc123');

// Listen for events
ASQ.on('thread.created', (thread) => { ... });
ASQ.on('room.joined', (room) => { ... });
ASQ.on('session.started', (session) => { ... });

// Pre-fill a new thread
ASQ.createThread({
  title: 'Question from the audience',
  sessionId: 'ses_abc123',
  tags: ['live-qa']
});

Webhooks

Get notified when things happen in your community. Configure webhooks in the dashboard or via API.

POST /communities/{id}/webhooks Create webhook
{
  "url": "https://yoursite.com/asq-webhook",
  "secret": "whsec_...",
  "events": [
    "session.created",
    "session.started",
    "session.ended",
    "thread.created",
    "thread.solved",
    "room.started",
    "room.ended",
    "member.joined",
    "knowledge.generated"
  ]
}

Requires community.configure

Webhook Payload

{
  "event": "session.started",
  "timestamp": "2026-04-15T14:00:00Z",
  "communityId": "expo-2026",
  "data": {
    "sessionId": "ses_abc123",
    "title": "Building Products That Scale",
    "mode": "ama",
    "hostIds": ["usr_sarah"],
    "participantCount": 34
  }
}
Hub · Widget Demo · Page App · API Reference