> ## Documentation Index
> Fetch the complete documentation index at: https://docs.waffo.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Analytics

> GraphQL query examples for revenue, payment, and customer analytics

## Overview

Analytics queries return pre-aggregated statistics for a single store. Every analytics query takes:

* A store identifier — `storeId` **or** `storeSlug` (top-level argument, at least one required).
* A required `filter` of type `AnalyticsFilterInput!`.

```graphql theme={"system"}
input AnalyticsFilterInput {
  timeRange: TimeRangeInput!   # { startDate, endDate } as ISO 8601 strings — required
  currency: String             # optional, ISO 4217
  status: String               # optional
}
```

Many nested fields take their own arguments, most commonly `granularity` and `currency`. The time-bucket granularity uses the `TimePeriodGranularity` enum: `DAY`, `WEEK`, `MONTH`, `QUARTER`, `YEAR`, `ALL_TIME`.

<Note>
  Each analytics query returns a **structured object**, not scalar totals. Amount fields are returned as display strings. Select the nested fields you need — the examples below show the available shape.
</Note>

***

## Order Statistics

Order counts, dual-source revenue, and buyer metrics.

```graphql theme={"system"}
query($storeId: String!) {
  orderStatistics(
    storeId: $storeId
    filter: { timeRange: { startDate: "2026-01-01T00:00:00Z", endDate: "2026-02-01T00:00:00Z" } }
  ) {
    totalCount
    countsByStatus { status count }
    countsByPeriod(granularity: MONTH) { period count }
    revenueByCurrency { currency pspTotalAmount snapshotTotalAmount mismatchCount paymentCount }
    revenueByPeriod(granularity: MONTH, currency: "usd") { period currency pspTotalAmount snapshotTotalAmount paymentCount }
    buyerMetrics { totalBuyers newBuyers returningBuyers }
    ordersByCountry { country count }
    revenueByCountry(currency: "usd") { country totalAmount paymentCount }
    b2bVsB2cBreakdown(currency: "usd") { isBusiness label totalAmount orderCount }
  }
}
```

<Note>
  `revenueByCurrency` / `revenueByPeriod` are **dual-source**: `pspTotalAmount` is the PSP actual amount, `snapshotTotalAmount` is the snapshot expected amount, and `mismatchCount` counts payments where the two disagree.
</Note>

**Variables:**

```json theme={"system"}
{ "storeId": "STO_3bVzrkD0FJjFdZNLk8Ualx" }
```

***

## Payment Statistics

Success rate, failure reasons, refunds, method distribution, and tax summary.

```graphql theme={"system"}
query($storeId: String!) {
  paymentStatistics(
    storeId: $storeId
    filter: { timeRange: { startDate: "2026-01-01T00:00:00Z", endDate: "2026-02-01T00:00:00Z" } }
  ) {
    successRate { totalAttempts succeeded failed pending successRate }
    failedReasons { reason count percentage }
    refunds {
      totalCount
      succeededCount
      pendingCount
      failedCount
      amountByCurrency { currency totalAmount paymentCount }
      refundRate
    }
    methodDistribution(currency: "usd") { methodType count totalAmount percentage }
    cardBrandDistribution(currency: "usd") { brand count totalAmount percentage }
    successRateByMethod { methodType total succeeded failed successRate }
    taxSummary { currency totalTax totalPreTax totalAmount paymentCount }
  }
}
```

<Note>
  `successRate` is an **object** (`{ totalAttempts, succeeded, failed, pending, successRate }`), not a scalar.
</Note>

***

## Product Statistics

Product counts, top sellers, and revenue contribution.

```graphql theme={"system"}
query($storeId: String!) {
  productStatistics(
    storeId: $storeId
    filter: { timeRange: { startDate: "2026-01-01T00:00:00Z", endDate: "2026-02-01T00:00:00Z" } }
  ) {
    onetimeCountsByStatus { status count }
    subscriptionCountsByStatus { status count }
    onetimeTotalCount
    subscriptionTotalCount
    topByOrderCount(limit: 10) { productId productType productName orderCount totalRevenue currency }
    topByRevenue(limit: 10, currency: "usd") { productId productType productName orderCount totalRevenue currency }
    revenueContribution(currency: "usd") { productId productName revenue contributionPercentage cumulativePercentage }
  }
}
```

***

## Trend Analysis

Period-over-period growth, cumulative revenue, and moving averages.

```graphql theme={"system"}
query($storeId: String!) {
  trendAnalysis(
    storeId: $storeId
    filter: { timeRange: { startDate: "2026-01-01T00:00:00Z", endDate: "2026-02-01T00:00:00Z" } }
  ) {
    orderGrowth(granularity: MONTH) { period currentValue previousValue growthRate }
    revenueGrowth(granularity: MONTH, currency: "usd") { period currentValue previousValue growthRate }
    cumulativeRevenue(granularity: MONTH, currency: "usd") { period periodValue cumulativeValue }
    orderMovingAverage(windowDays: 7) { date dailyValue movingAverage }
  }
}
```

***

## Distribution Analysis

Order amount percentiles, average-order-value trend, and amount buckets.

```graphql theme={"system"}
query($storeId: String!) {
  distributionAnalysis(
    storeId: $storeId
    filter: { timeRange: { startDate: "2026-01-01T00:00:00Z", endDate: "2026-02-01T00:00:00Z" } }
  ) {
    orderAmountPercentiles(currency: "usd") { p10 p25 p50 p75 p90 p95 p99 min max avg stddev count }
    aovTrend(granularity: MONTH, currency: "usd") { period averageOrderValue orderCount totalRevenue }
    orderAmountBuckets(currency: "usd", bucketCount: 10) { rangeMin rangeMax count percentage }
  }
}
```

***

## Customer Analysis

Cohort retention, LTV distribution, purchase frequency, and top customers.

```graphql theme={"system"}
query($storeId: String!) {
  customerAnalysis(
    storeId: $storeId
    filter: { timeRange: { startDate: "2026-01-01T00:00:00Z", endDate: "2026-02-01T00:00:00Z" } }
  ) {
    cohortRetention(granularity: MONTH) {
      cohortPeriod
      cohortSize
      retention { periodOffset activeCustomers retentionRate }
    }
    ltvDistribution(currency: "usd") {
      averageLtv
      medianLtv
      percentiles { p50 p90 p99 min max }
      buckets { rangeMin rangeMax count percentage }
    }
    purchaseFrequency { purchaseCount customerCount percentage }
    topCustomers(limit: 10, currency: "usd") { buyerEmail totalSpent orderCount firstPurchaseDate lastPurchaseDate }
  }
}
```

***

## Tax Analysis

Tax amounts by category, rate group, and country, plus B2B/B2C comparison.

```graphql theme={"system"}
query($storeId: String!) {
  taxAnalysis(
    storeId: $storeId
    filter: { timeRange: { startDate: "2026-01-01T00:00:00Z", endDate: "2026-02-01T00:00:00Z" } }
  ) {
    byCategory(currency: "usd") { taxCategory totalTax totalAmount paymentCount }
    byRateGroup(currency: "usd") { taxRate totalTax totalAmount paymentCount }
    byCountry(currency: "usd") { country totalTax totalAmount paymentCount }
    b2bVsB2c(currency: "usd") { isBusiness label totalTax totalAmount orderCount }
    effectiveTaxRateTrend(granularity: MONTH, currency: "usd") { period avgTaxRate paymentCount }
  }
}
```

***

## Subscription Analysis

Billing period distribution, cancellation stats, trial conversion, and churn.

```graphql theme={"system"}
query($storeId: String!) {
  subscriptionAnalysis(
    storeId: $storeId
    filter: { timeRange: { startDate: "2026-01-01T00:00:00Z", endDate: "2026-02-01T00:00:00Z" } }
  ) {
    billingPeriodDistribution(currency: "usd") { billingPeriod count totalAmount percentage }
    activeCount
    cancellationStats { totalSubscriptions canceledCount cancellationRate avgLifetimeDays medianLifetimeDays }
    trialConversion { totalTrials convertedCount activeTrials conversionRate }
    churnRate(granularity: MONTH) { period startActive churned churnRate }
  }
}
```

***

## Refund Ticket Analysis

Reason distribution, review efficiency, and approval rate.

```graphql theme={"system"}
query($storeId: String!) {
  refundTicketAnalysis(
    storeId: $storeId
    filter: { timeRange: { startDate: "2026-01-01T00:00:00Z", endDate: "2026-02-01T00:00:00Z" } }
  ) {
    reasonDistribution(currency: "usd") { reason count totalAmount percentage }
    statusDistribution { status count percentage }
    reviewEfficiency { avgHours medianHours p90Hours totalReviewed }
    ticketTrend(granularity: MONTH) { period totalCreated resolvedCount approvedCount rejectedCount }
    approvalRate { approved rejected rate }
  }
}
```

***

## Settlement Analysis

Actual settled amounts sourced from settlement files (post-fee, post-refund). This is the ground truth for reconciliation, distinct from `paymentStatistics.settlementRevenueByCurrency` (a PSP projection at payment time).

```graphql theme={"system"}
query($storeId: String!) {
  settlementAnalysis(
    storeId: $storeId
    filter: { timeRange: { startDate: "2026-04-01T00:00:00Z", endDate: "2026-05-01T00:00:00Z" } }
  ) {
    countsByAccountingStatus { status count }
    netSettlementByCurrency { currency totalAmount paymentCount }
    netSettlementByPeriod(granularity: DAY, currency: "usd") { period currency totalAmount paymentCount }
    refundTotalByCurrency { currency totalAmount paymentCount }
    feeTotalByCurrency { currency totalAmount paymentCount }
  }
}
```

<Note>
  `settlementAnalysis` time range is based on the settlement date, not `created_at`. Additional analytics queries are available depending on your role, including `deliveryAnalysis` (webhook/email delivery) and `payoutAnalysis` (payout tickets, scoped to the merchant). Use schema introspection to discover their full field sets.
</Note>

**Variables:**

```json theme={"system"}
{ "storeId": "STO_3bVzrkD0FJjFdZNLk8Ualx" }
```
