Track buyer-seller dispute frequency per seller

Per-seller disputes ÷ transactions over 90 days. Surface the top-decile dispute-drivers proactively — proactive review costs less than reactive churn.

Updated · published

markdown for agents →

difficulty intermediate · time to value 5 minutes · execution on demand

Start from this

Per seller, compute dispute_opened events / total_transactions over the last 90 days. Surface sellers in the top decile — review them before customers notice.

Why this matters

Marketplace trust is built on the absence of bad actors. A small percentage of sellers cause a disproportionate share of disputes — fraudulent listings, broken products shipped, post-purchase ghosting. Letting them operate burns trust on the buyer side and reputation across the platform.

The classic mistake is reactive triage: wait for buyers to complain loudly enough that CS escalates a specific seller. By the time that happens, 50 buyers have had bad experiences and your refund liability is real.

The proactive version: rank every seller by dispute rate, review the top decile on a chosen cadence, and let a human decide when intervention is justified. This workflow provides the ranking evidence.

What you get

  • Per-seller dispute rate (disputes ÷ transactions) over a 90-day window
  • Volume threshold so you don’t false-positive on sellers with 3 transactions
  • The top decile flagged for proactive CS review
  • Dashboard rows the trust & safety team can pull up from a server-side panel

Walk through it

You

Per seller, compute dispute_opened ÷ total_transactions over the last 90 days. Surface sellers in the top decile — review them before customers notice.

Agent

One HogQL join, then the percentile cut.

Endpoint: POST /v1/projects/:project_id/analytics/query
Exact shape: /v1/openapi.json?path=%2Fv1%2Fprojects%2F%7Bproject_id%7D%2Fanalytics%2Fquery&method=post
Custom HogQL goes in the OpenAPI-defined `query` field.
Concept fields:
  query: "
    with orders as (
      select properties.seller_id as seller, count() as txns
      from events
      where event = 'order_completed' and timestamp > now() - interval 90 day
      group by seller
    ),
    disputes as (
      select properties.seller_id as seller, count() as disp
      from events
      where event = 'dispute_opened' and timestamp > now() - interval 90 day
      group by seller
    )
    select
      o.seller,
      o.txns,
      coalesce(d.disp, 0) as disputes,
      coalesce(d.disp, 0) / o.txns as dispute_rate
    from orders o
    left join disputes d using (seller)
    where o.txns >= 20
    order by dispute_rate desc
    limit 100
  "
{
  "rows": [
    { "seller": "s_8421", "txns":  142, "disputes": 38, "dispute_rate": 0.268 },
    { "seller": "s_1840", "txns":   62, "disputes": 14, "dispute_rate": 0.226 },
    { "seller": "s_3110", "txns":   84, "disputes": 18, "dispute_rate": 0.214 },
    { "seller": "s_7720", "txns":   42, "disputes":  8, "dispute_rate": 0.190 },
    { "seller": "s_4421", "txns":  220, "disputes": 38, "dispute_rate": 0.173 }
  ]
}
Agent

Aggregate distribution to find where the cliff is.

Endpoint: POST /v1/projects/:project_id/analytics/query
Exact shape: /v1/openapi.json?path=%2Fv1%2Fprojects%2F%7Bproject_id%7D%2Fanalytics%2Fquery&method=post
Custom HogQL goes in the OpenAPI-defined `query` field.
Concept fields:
  query: "
    with rates as (
      select properties.seller_id as seller, coalesce(d, 0) / o as rate
      from (
        select properties.seller_id, count() as o,
          countIf(event = 'dispute_opened') as d
        from events
        where event in ('order_completed', 'dispute_opened')
          and timestamp > now() - interval 90 day
        group by properties.seller_id
        having count() >= 20
      )
    )
    select
      avg(rate)      as avg_rate,
      quantile(0.5)(rate)  as p50,
      quantile(0.9)(rate)  as p90,
      quantile(0.99)(rate) as p99,
      max(rate)      as max_rate,
      count() as n_sellers
    from rates
  "
{
  "rows": [
    { "avg_rate": 0.022, "p50": 0.014, "p90": 0.062, "p99": 0.184, "max_rate": 0.268, "n_sellers": 4280 }
  ]
}
Agent

Distribution:

StatValue
Avg2.2%
Median1.4%
P906.2%
P9918.4%
Max26.8%

The top 1% of sellers (about 42 sellers) have dispute rates of 18%+ — that’s 8× the platform average. Worth proactive review on every one of those.

The five sellers I surfaced earlier are all in the >17% bucket. s_8421 at 26.8% (38 disputes on 142 transactions) is your worst-case — either fraudulent or systemic quality issue.

Let me prepare the dashboard rows.

Endpoint: POST /v1/projects/:project_id/analytics/query
Exact shape: /v1/openapi.json?path=%2Fv1%2Fprojects%2F%7Bproject_id%7D%2Fanalytics%2Fquery&method=post
Custom HogQL goes in the OpenAPI-defined `query` field.
Concept fields:
  query: "<first query above>"
{ "rows": [/* dashboard rows */], "row_count": 50 }
Agent

Two follow-ups worth doing:

  1. s_8421 deep-dive: pull their last 50 transactions and the 38 dispute messages. Pattern-match — is it “item never arrived” (shipping fraud) or “item not as described” (listing fraud)?
  2. Review threshold crossings on demand: list sellers above 15% with the evidence a CS owner needs to decide what to do.

The output

Seller dispute rates — top decile (90d)

Seller       Txns      Disputes    Rate     Decile    Action
─────────────────────────────────────────────────────────────────
s_8421        142         38       26.8%    P99       ★★★ deep-dive
s_1840         62         14       22.6%    P99       ★★ review
s_3110         84         18       21.4%    P99       ★★ review
s_7720         42          8       19.0%    P99       ★★ review
s_4421        220         38       17.3%    P99       ★ contact

Platform stats:
  Median dispute rate:    1.4%
  P90:                    6.2%
  P99:                   18.4%
  Sellers analyzed:      4,280

Recommended workflow:
  - Daily: review P99 (top ~42 sellers); confirm legitimacy
  - Weekly: outreach to P90-P99 (next ~380 sellers); offer training
  - Human review: surface new sellers above 15% without changing seller state or contacting anyone

Public view:
  Use Agentry's returned public_url after publishing a real query blueprint.

Setting it up

Two events, both with seller_id and order_id:

// On order confirmation
await fetch(`https://api.agentry.sh/v1/analytics/`, {
  method: "POST",
  headers: {
    "Authorization": `Bearer ${process.env.AGENTRY_SERVER_API_KEY}`,
    "Content-Type": "application/json",
    "User-Agent": "marketplace/1.0",  // REQUIRED — Cloudflare 403s default UAs
  },
  body: JSON.stringify({
    event: "order_completed",
    distinct_id: buyer.id,
    properties: {
      order_id: order.id,
      seller_id: listing.seller_id,
      gmv: order.amount,
    },
  }),
});

// In the dispute creation handler
await fetch(`https://api.agentry.sh/v1/analytics/`, {
  method: "POST",
  headers: { /* same */ },
  body: JSON.stringify({
    event: "dispute_opened",
    distinct_id: buyer.id,
    properties: {
      order_id: dispute.order_id,
      seller_id: dispute.seller_id,
      reason: dispute.reason,  // "not_received" | "not_as_described" | "fraudulent" | "other"
      amount: dispute.amount,
    },
  }),
});

The min 20 transactions filter in the query is important — without it, a seller with 2 transactions and 1 dispute shows up as 50% and dominates the ranking with no signal.

Variations

  • “Same query split by dispute reason. ‘Not received’ vs ‘not as described’ point to different bad-actor types.”
  • “Trend per seller — show me sellers whose dispute rate jumped in the last 14 days vs prior 76. Newly-bad actors.”
  • “Cohort the rate by seller tenure — do new sellers dispute more, or seasoned sellers?”
  • “List sellers above 25% dispute rate with sample-size evidence and draft a pause recommendation for CS; do not change seller state automatically.”

Adapt this workflow in your own agent.

Ask your agent to map the starter prompt to your saved signal map, live events, and the current HTTP API before answering.

Agentry gives coding agents production context from errors, product analytics, and deploys through one HTTP API. Fetch and read https://agentry.sh/install.md completely, then install Agentry's full first-time telemetry baseline in this repository. I authorize device-code login, saving the owner key only to ~/.agentry/credentials.json, creating one Agentry project for this repository, and read-only inspection of shipped source plus hidden CI/provider configuration. Deeply analyze the product's business logic and complete value flow before choosing telemetry. Save the complete source-backed plan and show me its exact contents and hash. Until I explicitly approve that plan or request a replacement, do not edit app/CI source, place runtime/CI credentials, commit, exercise product traffic, start proof, push, or deploy. After approval, I authorize only the reviewed targets: place the required scoped browser/server/CI credentials through the established environment or secret mechanism, preserve existing telemetry, implement and test the baseline, commit it, push that reviewed commit when the shipped CI/provider path requires it, exercise safe proof paths with test/non-customer data, and perform one deployment through the reviewed shipped CI/provider path. Ask first if proof would charge money, contact a third party, change real customer data, or require new external access. After the plan is saved, immediately before every onboarding state-changing POST, GET current onboarding state, perform only its single returned next_action, then read state again; do not batch or infer later stages. Continue until status is verified, installation_complete is true, and next_action is null. Keep all secrets, source snapshots, proof markers, and scratch files outside the repository.

+ Full access
5.5 Extra High
  1. 1. Open your repo in Codex, Claude Code, Cursor etc.
  2. 2. Paste the install prompt.
  3. 3. Your agent reads the install doc and shows you an implementation plan for approval.