Skip to main content
Learn how to use the Qwairy API with real-world examples, from simple queries to complete integrations.

Quick Start

Get your GEO Score in one command:
curl -s -H "Authorization: Bearer $QWAIRY_API_TOKEN" \
  "https://www.qwairy.co/api/v1/brands/YOUR_BRAND_ID/performance?period=30" \
  | jq '.scores'
Output:
{
  "global": 62,
  "mentionRate": 45.2,
  "sourceRate": 23.9,
  "shareOfVoice": 8.13,
  "sentiment": 78.1
}

API Client

Reusable client with error handling for all guides on this site.
// qwairy-client.js
class QwairyClient {
  constructor(apiToken) {
    this.baseUrl = 'https://www.qwairy.co/api/v1';
    this.headers = {
      'Authorization': `Bearer ${apiToken}`,
      'Content-Type': 'application/json',
    };
  }

  async request(endpoint, params = {}) {
    const url = new URL(`${this.baseUrl}${endpoint}`);
    Object.entries(params).forEach(([key, value]) => {
      if (value !== undefined && value !== null) {
        url.searchParams.append(key, value);
      }
    });

    const response = await fetch(url.toString(), { headers: this.headers });

    if (!response.ok) {
      const error = await response.json().catch(() => ({}));
      const code = error.error?.code || 'UNKNOWN_ERROR';
      const message = error.error?.message || `HTTP ${response.status}`;

      if (response.status === 429) {
        const resetTime = response.headers.get('X-RateLimit-Reset');
        throw new Error(`Rate limited. Retry after: ${resetTime}`);
      }

      throw new Error(`[${code}] ${message}`);
    }

    return response.json();
  }

  async getPerformance(brandId, params = {}) {
    return this.request(`/brands/${brandId}/performance`, params);
  }

  async getCompetitors(brandId, params = {}) {
    return this.request(`/brands/${brandId}/competitors`, params);
  }

  async getSourceDomains(brandId, params = {}) {
    return this.request(`/brands/${brandId}/source-domains`, params);
  }

  async getSourceUrls(brandId, params = {}) {
    return this.request(`/brands/${brandId}/source-urls`, params);
  }

  async getAnswers(brandId, params = {}) {
    return this.request(`/brands/${brandId}/answers`, params);
  }

  async getSearch(brandId, params = {}) {
    return this.request(`/brands/${brandId}/search`, params);
  }

  async getCompetitorEvolution(brandId, competitorId, params = {}) {
    return this.request(`/brands/${brandId}/competitors/${competitorId}/evolution`, params);
  }
}

// Usage
const client = new QwairyClient(process.env.QWAIRY_API_TOKEN);
All guides on this site use this client. Copy it to your project or adapt it to your needs.

TypeScript Types

Type definitions for the API client.
// qwairy-types.ts
interface QwairyScores {
  global: number;
  mentionRate: number;
  sourceRate: number;
  shareOfVoice: number;
  sentiment: number;
}

interface QwairyMethodology {
  promptsCount: number;
  responsesTotal: number;
  providers: string[];
}

interface QwairyPerformance {
  scores: QwairyScores;
  methodology: QwairyMethodology;
  byProvider?: Array<{ provider: string; scores: QwairyScores }>;
  byTopic?: Array<{ topic: string; scores: QwairyScores }>;
  byTag?: Array<{ tag: string; scores: QwairyScores }>;
}

interface QwairyCompetitor {
  id: string;
  name: string;
  relationship: 'SELF' | 'DIRECT' | 'INDIRECT';
  totalMentions: number;
  shareOfVoice: number;
  avgPosition: number;
  avgSentiment: number;
}

interface QwairySource {
  id: string;
  domain: string;
  type: 'INSTITUTIONAL' | 'COMMERCIAL' | 'MEDIA' | 'BLOG' | 'SOCIAL' | 'OTHER';
  isSelf: boolean;
  totalMentions: number;
  rate: number;
  avgPosition: number;
}

interface QwairyPagination {
  total: number;
  count: number;
  limit: number;
  offset: number;
}

interface QwairyCompetitorsResponse {
  success: boolean;
  pagination: QwairyPagination;
  competitors: QwairyCompetitor[];
}

interface QwairySourcesResponse {
  success: boolean;
  pagination: QwairyPagination;
  sources: QwairySource[];
}

interface QwairyAnswer {
  id: string;
  promptId: string;
  promptText: string;
  provider: string;
  model: string;
  textPreview: string;
  hasSelfMention: boolean;
  selfMentionPosition: number | null;
  hasSelfSource: boolean;
  competitorsCount: number;
  sourcesCount: number;
  sentiment: number;
  relevance: number;
  createdAt: string;
}

interface QwairySearchQuery {
  id: string;
  query: string;
  prompt: string;
  provider: string;
  createdAt: string;
}

interface QwairyAnswersResponse {
  success: boolean;
  pagination: QwairyPagination;
  answers: QwairyAnswer[];
}

interface QwairySearchResponse {
  success: boolean;
  pagination: QwairyPagination;
  searches: QwairySearchQuery[];
}

Pagination

Fetch all results when you have more than 100 items.
async function fetchAllCompetitors(client, brandId, period = 30) {
  const allCompetitors = [];
  let offset = 0;
  const limit = 100;

  while (true) {
    const response = await client.getCompetitors(brandId, { period, limit, offset });
    allCompetitors.push(...response.competitors);

    if (response.competitors.length < limit || allCompetitors.length >= response.pagination.total) {
      break;
    }
    offset += limit;
  }

  return allCompetitors;
}

// Usage
const allCompetitors = await fetchAllCompetitors(client, 'your-brand-id', 30);
console.log(`Total competitors: ${allCompetitors.length}`);

Field Reference

Mapping between business metrics and API fields:
Business MetricEndpointFieldDescription
GEO Score/performancescores.globalOverall optimization score (0-100)
Brand Visibility/performancescores.mentionRate% of responses mentioning your brand
Citation Rate/performancescores.sourceRate% of responses citing your content
Share of Voice/competitorsshareOfVoiceYour % of all competitor mentions
Share of Citations/source-domainsrateSource’s % of all citations
Sentiment/performancescores.sentimentAverage sentiment score (0-100)
Average Position/competitorsavgPositionAverage rank in AI responses (1 = first)
Mentioned but not cited/answershasSelfMention + hasSelfSourceResponses where you’re mentioned but not linked
AI search queries/searchqueryWeb queries triggered by AI before responding
Use /performance for aggregated KPIs. Use /competitors and /source-domains for detailed breakdowns. Use /answers and /search for LLM-level diagnostics.