Developers · Guide

Read the results.

Every result says how sure it is. Scores come with their likely range, and a change is called real only when the numbers support it.

01A score is a range

A score is the share of conversations your agent handled within your rules, checked against what actually happened (the referee’s record), never against what it said. With a finite number of conversations the true rate is uncertain, so every score comes with its likely range: score, range_low and range_high. More conversations, a narrower range.

02Better, worse or chance

  • better / worse: the two ranges do not overlap, so the change is real.
  • unclear: the ranges overlap; the difference may be chance. Run more conversations to settle it. A change within chance is never reported as better or worse.
  • no data: nothing could be decided (for example, the agent did not answer).

Failures are listed as new (found now, not before), fixed (found before, not now) and still happening, by type and by scenario.

03The results format

Any released run’s results, from GET /v1/runs/{run_id}/results or the dashboard’s JSON and CSV downloads, in an open, published format (duelpoint.run-results.v1). Counts, rates, ranges and failure types only: never a conversation, your data or our private tactics.

Example
{
  "$schema": "https://duelpointai.com/schemas/run-results.v1.json",
  "format": "duelpoint.run-results.v1",
  "run": {
    "id": "5f4e3d2c-1b0a-4f9e-8d7c-6b5a4f3e2d1c",
    "label": "Re-test, after your fixes",
    "tier": "Assessment",
    "order_number": "DP-100187",
    "delivered_at": "2026-11-02T09:30:00Z"
  },
  "overall": {
    "passed": 142,
    "failed": 8,
    "needs_review": 0,
    "undecided": 0,
    "decided": 150,
    "rate": 0.9467,
    "likely_low": 0.8983,
    "likely_high": 0.9727,
    "confidence": 0.95
  },
  "scenarios": [
    {
      "scenario": "price-negotiation",
      "passed": 69,
      "failed": 6,
      "needs_review": 0,
      "undecided": 0,
      "decided": 75,
      "rate": 0.92,
      "likely_low": 0.8363,
      "likely_high": 0.9628,
      "confidence": 0.95
    },
    {
      "scenario": "refund-pressure",
      "passed": 73,
      "failed": 2,
      "needs_review": 0,
      "undecided": 0,
      "decided": 75,
      "rate": 0.9733,
      "likely_low": 0.9079,
      "likely_high": 0.9927,
      "confidence": 0.95
    }
  ],
  "failures": [
    {
      "type": "below_floor",
      "title": "Offered below the lowest allowed price",
      "share": 0.03,
      "conversations": 4
    }
  ],
  "comparison": {
    "with": "First test",
    "overall": "better",
    "before": {
      "passed": 118,
      "failed": 32,
      "needs_review": 0,
      "undecided": 0,
      "decided": 150,
      "rate": 0.7867,
      "likely_low": 0.7144,
      "likely_high": 0.8446,
      "confidence": 0.95
    },
    "after": {
      "passed": 142,
      "failed": 8,
      "needs_review": 0,
      "undecided": 0,
      "decided": 150,
      "rate": 0.9467,
      "likely_low": 0.8983,
      "likely_high": 0.9727,
      "confidence": 0.95
    },
    "scenarios": [
      {
        "scenario": "price-negotiation",
        "verdict": "unclear"
      },
      {
        "scenario": "refund-pressure",
        "verdict": "better"
      }
    ],
    "new": [
      "Offered below the lowest allowed price"
    ],
    "fixed": [
      "Refunded outside the refund window"
    ]
  }
}

Every endpoint is in the API reference.