Developers · Reference

API reference.

Every endpoint, written from the API itself, with an example of each request and reply. JSON in and out, at https://api.duelpointai.com.

00Basics

Authentication. Send your API key on every request. Create keys in the dashboard (API keys); a key is shown once.

Authorization: Bearer $DUELPOINT_API_KEY

What a key may do. Whatever the user who created it may do; anything else answers 403.

Products. Each endpoint belongs to a product that must be open for your account: Tests (Door 1) or Ongoing testing (Door 2).

StatusMeaning
401Missing, wrong, revoked or ended API key.
403Your key or role may not do this.
404Not found, including anything belonging to another account.
422Something to fix: the message says what, in plain English.
429Too many requests from your address or key: wait a moment and try again.
503This product is not available to your account yet.

Errors are {"detail": "…"}. Credentials, conversations and our private tactics are never sent back.

01Account

GET/v1/me

Your organization, your role, and the products you can use.

Always availableSuccess: 200

Response

organization_idrequireduuidYour organization.
organization_namerequiredstringIts name.
rolerequiredstringYour role: owner, admin, developer or viewer.
productsarray of stringThe products your organization can use now.
curl -X GET https://api.duelpointai.com/v1/me \
  -H "Authorization: Bearer $DUELPOINT_API_KEY"
import os, requests

r = requests.get(
    "https://api.duelpointai.com/v1/me",
    headers={"Authorization": f"Bearer {os.environ['DUELPOINT_API_KEY']}"},
)
r.raise_for_status()
print(r.json())
const r = await fetch("https://api.duelpointai.com/v1/me", {
  method: "GET",
  headers: { Authorization: `Bearer ${process.env.DUELPOINT_API_KEY}` },
});
console.log(await r.json());
{
  "organization_id": "1b2c3d4e-5f6a-4b7c-8d9e-0f1a2b3c4d5e",
  "organization_name": "Acme Outdoor",
  "role": "owner",
  "products": [
    "door_1_tough_counterparties",
    "door_2_developer_plans"
  ]
}

02Agents

GET/v1/agents

Your connected agents. Their keys are never returned.

Tests (Door 1)Success: 200

Response · a list of these

idrequireduuidThe agent's id: use it to test it.
namerequiredstringYour name for it.
connector_typerequiredstringHow we talk to it: https, openai_compatible, mcp or a2a.
endpoint_urlrequiredstringIts address.
created_atrequireddate-timeWhen it was connected.
curl -X GET https://api.duelpointai.com/v1/agents \
  -H "Authorization: Bearer $DUELPOINT_API_KEY"
import os, requests

r = requests.get(
    "https://api.duelpointai.com/v1/agents",
    headers={"Authorization": f"Bearer {os.environ['DUELPOINT_API_KEY']}"},
)
r.raise_for_status()
print(r.json())
const r = await fetch("https://api.duelpointai.com/v1/agents", {
  method: "GET",
  headers: { Authorization: `Bearer ${process.env.DUELPOINT_API_KEY}` },
});
console.log(await r.json());
[
  {
    "id": "4f6c1a2e-9b7d-4e1a-8c3f-2d5b6a7e8f90",
    "name": "Support bot (staging)",
    "connector_type": "openai_compatible",
    "endpoint_url": "https://staging.acme.example/v1/chat/completions",
    "created_at": "2026-11-02T09:30:00Z"
  }
]

GET/v1/agents/{agent_id}

One connected agent.

Tests (Door 1)Success: 200

Path: agent_id

Response

idrequireduuidThe agent's id: use it to test it.
namerequiredstringYour name for it.
connector_typerequiredstringHow we talk to it: https, openai_compatible, mcp or a2a.
endpoint_urlrequiredstringIts address.
created_atrequireddate-timeWhen it was connected.
curl -X GET https://api.duelpointai.com/v1/agents/4f6c1a2e-9b7d-4e1a-8c3f-2d5b6a7e8f90 \
  -H "Authorization: Bearer $DUELPOINT_API_KEY"
import os, requests

r = requests.get(
    "https://api.duelpointai.com/v1/agents/4f6c1a2e-9b7d-4e1a-8c3f-2d5b6a7e8f90",
    headers={"Authorization": f"Bearer {os.environ['DUELPOINT_API_KEY']}"},
)
r.raise_for_status()
print(r.json())
const r = await fetch("https://api.duelpointai.com/v1/agents/4f6c1a2e-9b7d-4e1a-8c3f-2d5b6a7e8f90", {
  method: "GET",
  headers: { Authorization: `Bearer ${process.env.DUELPOINT_API_KEY}` },
});
console.log(await r.json());
{
  "id": "4f6c1a2e-9b7d-4e1a-8c3f-2d5b6a7e8f90",
  "name": "Support bot (staging)",
  "connector_type": "openai_compatible",
  "endpoint_url": "https://staging.acme.example/v1/chat/completions",
  "created_at": "2026-11-02T09:30:00Z"
}

POST/v1/agents

Connect an agent: your TEST or STAGING agent's address, the format it speaks, and its key if it needs one. We check the address is a public https:// one; nothing is sent to it before you confirm it is a test agent.

Tests (Door 1)Success: 201

Request body

namerequiredstringA name you will recognise, for example Support bot (staging).at most 200 characters
connector_typerequiredone of https, openai_compatible, mcp, a2aThe format your agent already speaks (see Connect your agent).
endpoint_urlrequiredstringYour TEST or STAGING agent's public https:// address.at most 2048 characters
credentialCredentialIn or nullIts key, if it needs one.
optionsobjectOptional: model (OpenAI-style agents); tool_name and message_argument (MCP agents).

Response

idrequireduuidThe agent's id: use it to test it.
namerequiredstringYour name for it.
connector_typerequiredstringHow we talk to it: https, openai_compatible, mcp or a2a.
endpoint_urlrequiredstringIts address.
created_atrequireddate-timeWhen it was connected.
curl -X POST https://api.duelpointai.com/v1/agents \
  -H "Authorization: Bearer $DUELPOINT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name": "Support bot (staging)", "connector_type": "openai_compatible", "endpoint_url": "https://staging.acme.example/v1/chat/completions", "credential": {"kind": "bearer", "token": "sk-staging-\u2026"}, "options": {"model": "support-v7"}}'
import os, requests

r = requests.post(
    "https://api.duelpointai.com/v1/agents",
    headers={"Authorization": f"Bearer {os.environ['DUELPOINT_API_KEY']}"},
    json={
        "name": "Support bot (staging)",
        "connector_type": "openai_compatible",
        "endpoint_url": "https://staging.acme.example/v1/chat/completions",
        "credential": {
            "kind": "bearer",
            "token": "sk-staging-…",
        },
        "options": {
            "model": "support-v7",
        },
    },
)
r.raise_for_status()
print(r.json())
const r = await fetch("https://api.duelpointai.com/v1/agents", {
  method: "POST",
  headers: { Authorization: `Bearer ${process.env.DUELPOINT_API_KEY}`, "Content-Type": "application/json" },
  body: JSON.stringify({
    "name": "Support bot (staging)",
    "connector_type": "openai_compatible",
    "endpoint_url": "https://staging.acme.example/v1/chat/completions",
    "credential": {
      "kind": "bearer",
      "token": "sk-staging-\u2026"
    },
    "options": {
      "model": "support-v7"
    }
  }),
});
console.log(await r.json());
{
  "id": "4f6c1a2e-9b7d-4e1a-8c3f-2d5b6a7e8f90",
  "name": "Support bot (staging)",
  "connector_type": "openai_compatible",
  "endpoint_url": "https://staging.acme.example/v1/chat/completions",
  "created_at": "2026-11-02T09:30:00Z"
}

PUT/v1/agents/{agent_id}/credential

Replace the agent's key. It is sealed and sent only to the agent's own address.

Tests (Door 1)Success: 204

Path: agent_id

Request body

kindrequiredone of bearer, headerbearer: sent as `Authorization: Bearer <token>`; header: sent in the header you name.
tokenrequiredstringYour test agent's key. Sealed; sent only to the agent's own address; never returned.at most 4096 characters
header_namestring or nullFor kind "header": the header's name, for example X-API-Key.
curl -X PUT https://api.duelpointai.com/v1/agents/4f6c1a2e-9b7d-4e1a-8c3f-2d5b6a7e8f90/credential \
  -H "Authorization: Bearer $DUELPOINT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"kind": "header", "token": "staging-key-\u2026", "header_name": "X-API-Key"}'
import os, requests

r = requests.put(
    "https://api.duelpointai.com/v1/agents/4f6c1a2e-9b7d-4e1a-8c3f-2d5b6a7e8f90/credential",
    headers={"Authorization": f"Bearer {os.environ['DUELPOINT_API_KEY']}"},
    json={
        "kind": "header",
        "token": "staging-key-…",
        "header_name": "X-API-Key",
    },
)
r.raise_for_status()
const r = await fetch("https://api.duelpointai.com/v1/agents/4f6c1a2e-9b7d-4e1a-8c3f-2d5b6a7e8f90/credential", {
  method: "PUT",
  headers: { Authorization: `Bearer ${process.env.DUELPOINT_API_KEY}`, "Content-Type": "application/json" },
  body: JSON.stringify({
    "kind": "header",
    "token": "staging-key-\u2026",
    "header_name": "X-API-Key"
  }),
});
console.log(r.status); // 204: done

GET/v1/test-mode-statement

The statement you confirm before any agent is tested: it must be a TEST or STAGING agent, never one wired to live payments, refunds, emails or customer records.

Tests (Door 1)Success: 200

Response

versionrequiredstringThe statement's version, recorded with your confirmation.
warningrequiredstringWhy only a test or staging agent may be connected.
confirmationrequiredstringWhat you confirm.
curl -X GET https://api.duelpointai.com/v1/test-mode-statement \
  -H "Authorization: Bearer $DUELPOINT_API_KEY"
import os, requests

r = requests.get(
    "https://api.duelpointai.com/v1/test-mode-statement",
    headers={"Authorization": f"Bearer {os.environ['DUELPOINT_API_KEY']}"},
)
r.raise_for_status()
print(r.json())
const r = await fetch("https://api.duelpointai.com/v1/test-mode-statement", {
  method: "GET",
  headers: { Authorization: `Bearer ${process.env.DUELPOINT_API_KEY}` },
});
console.log(await r.json());
{
  "version": "v1",
  "warning": "Only connect a TEST or STAGING agent: our simulated counterparties will try to talk it into discounts, refunds, payments and sharing private information.",
  "confirmation": "I confirm this is a test or staging agent, not connected to live payments, refunds, emails or customer records."
}

POST/v1/agents/{agent_id}/test-mode-confirmation

Confirm that this agent is a TEST or STAGING agent. Nothing is ever sent to an agent before this; the confirmation is recorded with who, when and the statement's version.

Tests (Door 1)Success: 201

Path: agent_id

Request body

acceptrequiredbooleantrue to confirm that this is a TEST or STAGING agent.
curl -X POST https://api.duelpointai.com/v1/agents/4f6c1a2e-9b7d-4e1a-8c3f-2d5b6a7e8f90/test-mode-confirmation \
  -H "Authorization: Bearer $DUELPOINT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"accept": true}'
import os, requests

r = requests.post(
    "https://api.duelpointai.com/v1/agents/4f6c1a2e-9b7d-4e1a-8c3f-2d5b6a7e8f90/test-mode-confirmation",
    headers={"Authorization": f"Bearer {os.environ['DUELPOINT_API_KEY']}"},
    json={
        "accept": True,
    },
)
r.raise_for_status()
print(r.json())
const r = await fetch("https://api.duelpointai.com/v1/agents/4f6c1a2e-9b7d-4e1a-8c3f-2d5b6a7e8f90/test-mode-confirmation", {
  method: "POST",
  headers: { Authorization: `Bearer ${process.env.DUELPOINT_API_KEY}`, "Content-Type": "application/json" },
  body: JSON.stringify({
    "accept": true
  }),
});
console.log(await r.json());
{
  "status": "confirmed"
}

POST/v1/agents/{agent_id}/connection-test

Sends ONE harmless greeting to the agent and reports plainly whether it answered. Refused until the agent is confirmed as a test or staging agent (nothing is sent before that).

Tests (Door 1)Success: 200

Path: agent_id

Response

okrequiredbooleanWhether your agent answered.
kindrequiredstringThe connector used.
messagerequiredstringWhat happened, in plain English.
error_coderequiredstring or nullA short code when it did not answer, for example timeout.
latency_msrequiredintegerHow long your agent took to answer, in milliseconds.
calls_maderequiredintegerCalls we made to your agent (one greeting).
reply_previewrequiredstring or nullThe start of its reply.
notesrequiredarray of stringAnything worth knowing, for example a slow answer.
curl -X POST https://api.duelpointai.com/v1/agents/4f6c1a2e-9b7d-4e1a-8c3f-2d5b6a7e8f90/connection-test \
  -H "Authorization: Bearer $DUELPOINT_API_KEY"
import os, requests

r = requests.post(
    "https://api.duelpointai.com/v1/agents/4f6c1a2e-9b7d-4e1a-8c3f-2d5b6a7e8f90/connection-test",
    headers={"Authorization": f"Bearer {os.environ['DUELPOINT_API_KEY']}"},
)
r.raise_for_status()
print(r.json())
const r = await fetch("https://api.duelpointai.com/v1/agents/4f6c1a2e-9b7d-4e1a-8c3f-2d5b6a7e8f90/connection-test", {
  method: "POST",
  headers: { Authorization: `Bearer ${process.env.DUELPOINT_API_KEY}` },
});
console.log(await r.json());
{
  "ok": true,
  "kind": "openai_compatible",
  "message": "Your agent answered.",
  "error_code": null,
  "latency_ms": 1180,
  "calls_made": 1,
  "reply_preview": "Hello! How can I help you today?",
  "notes": []
}

03Test runs

POST/v1/test-runs/preview

Before a run: how many calls we will make to YOUR agent, and is it a confirmed test agent.

Tests (Door 1)Success: 200

Request body

agent_idrequireduuidThe agent the run would test.
episodesrequiredintegerConversations in the run.at least 1, at most 10000
max_turnsrequiredintegerThe most turns a conversation may take.at least 1, at most 200
max_agent_callsinteger or nullOptional: a cap on calls to your agent.at least 1

Response

expected_callsrequiredintegerCalls to your agent we expect.
worst_case_callsrequiredintegerThe most calls it could take.
explanationrequiredstringHow that was worked out.
max_agent_callsrequiredintegerThe cap that would apply.
maximum_is_enoughrequiredbooleanWhether the cap covers the expected calls.
test_mode_confirmedrequiredbooleanWhether the agent is confirmed as a test agent.
warningrequiredstringThe test-agent warning, to show your team.
curl -X POST https://api.duelpointai.com/v1/test-runs/preview \
  -H "Authorization: Bearer $DUELPOINT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"agent_id": "4f6c1a2e-9b7d-4e1a-8c3f-2d5b6a7e8f90", "episodes": 250, "max_turns": 12}'
import os, requests

r = requests.post(
    "https://api.duelpointai.com/v1/test-runs/preview",
    headers={"Authorization": f"Bearer {os.environ['DUELPOINT_API_KEY']}"},
    json={
        "agent_id": "4f6c1a2e-9b7d-4e1a-8c3f-2d5b6a7e8f90",
        "episodes": 250,
        "max_turns": 12,
    },
)
r.raise_for_status()
print(r.json())
const r = await fetch("https://api.duelpointai.com/v1/test-runs/preview", {
  method: "POST",
  headers: { Authorization: `Bearer ${process.env.DUELPOINT_API_KEY}`, "Content-Type": "application/json" },
  body: JSON.stringify({
    "agent_id": "4f6c1a2e-9b7d-4e1a-8c3f-2d5b6a7e8f90",
    "episodes": 250,
    "max_turns": 12
  }),
});
console.log(await r.json());
{
  "expected_calls": 1500,
  "worst_case_calls": 3000,
  "explanation": "About 6 replies from your agent per conversation, at most 12.",
  "max_agent_calls": 3000,
  "maximum_is_enough": true,
  "test_mode_confirmed": true,
  "warning": "Only connect a TEST or STAGING agent."
}

GET/v1/test-runs

Your test runs, newest first.

Tests (Door 1)Success: 200

Response · a list of these

idrequireduuidThe run's id.
agent_idrequireduuidThe agent it tested.
statusrequiredstringqueued, running, succeeded or failed.
created_atrequireddate-timeWhen it was started.
curl -X GET https://api.duelpointai.com/v1/test-runs \
  -H "Authorization: Bearer $DUELPOINT_API_KEY"
import os, requests

r = requests.get(
    "https://api.duelpointai.com/v1/test-runs",
    headers={"Authorization": f"Bearer {os.environ['DUELPOINT_API_KEY']}"},
)
r.raise_for_status()
print(r.json())
const r = await fetch("https://api.duelpointai.com/v1/test-runs", {
  method: "GET",
  headers: { Authorization: `Bearer ${process.env.DUELPOINT_API_KEY}` },
});
console.log(await r.json());
[
  {
    "id": "5f4e3d2c-1b0a-4f9e-8d7c-6b5a4f3e2d1c",
    "agent_id": "4f6c1a2e-9b7d-4e1a-8c3f-2d5b6a7e8f90",
    "status": "succeeded",
    "created_at": "2026-11-02T09:30:00Z"
  }
]

GET/v1/characters

The organization's OWN characters only. The platform library is never exposed here.

Tests (Door 1)Success: 200

Response · a list of these

idrequireduuidThe character's id.
keyrequiredstringIts key.
versionrequiredintegerIts version (a used version never changes).
created_atrequireddate-timeWhen this version was made.
curl -X GET https://api.duelpointai.com/v1/characters \
  -H "Authorization: Bearer $DUELPOINT_API_KEY"
import os, requests

r = requests.get(
    "https://api.duelpointai.com/v1/characters",
    headers={"Authorization": f"Bearer {os.environ['DUELPOINT_API_KEY']}"},
)
r.raise_for_status()
print(r.json())
const r = await fetch("https://api.duelpointai.com/v1/characters", {
  method: "GET",
  headers: { Authorization: `Bearer ${process.env.DUELPOINT_API_KEY}` },
});
console.log(await r.json());
[]

04Buying

POST/v1/engagements/quote

The price for a tier and its options, line by line, and what would be charged (after any design-partner discount). Nothing is saved.

Tests (Door 1)Success: 200

Request body

tierrequiredone of agent_check, assessment, expert_assessment, continuous, retestThe test to buy.
areasrequiredarray of one of refunds, sales, fraud, purchasingThe areas to test (an Assessment covers at least two).at least 1 item, at most 4 items
deepbooleanAgent Check: adaptive attackers (+$130).
retestbooleanAgent Check: a re-test after your fixes (+$70).
more_conversationsbooleanAssessment: more conversations, for a tighter range (+$1,000).
data_loadone of none, standard, largeAssessment: loading your catalogue and orders.
executive_summarybooleanExpert Assessment: a summary for your leadership (+$5,000).
agent_stageone of live, launching, development or nullAgent Check: where your agent is today (live, launching or development). It never changes the price.

Response

tierrequiredstringThe test.
price_centsrequiredintegerThe price from our price list, in US cents.
linesrequiredarray of [string, integer]What the price is made of: [label, cents].
runs_allowedrequiredintegerRuns included (the first test and any included re-test).
max_conversationsrequiredintegerThe most conversations a run plays.
reviewrequiredstringnone, analyst or expert: who signs the report.
deliveryrequiredstringWhen it is delivered.
discount_pctintegerA design-partner discount agreed with your organization, if any.
credit_centsintegerAssessment: an Agent Check of yours credited toward it ($250, within 30 days of its report), if any.
total_centsintegerWhat would be charged: the price after any discount and credit.
curl -X POST https://api.duelpointai.com/v1/engagements/quote \
  -H "Authorization: Bearer $DUELPOINT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"tier": "assessment", "areas": ["refunds", "sales"]}'
import os, requests

r = requests.post(
    "https://api.duelpointai.com/v1/engagements/quote",
    headers={"Authorization": f"Bearer {os.environ['DUELPOINT_API_KEY']}"},
    json={
        "tier": "assessment",
        "areas": ["refunds", "sales"],
    },
)
r.raise_for_status()
print(r.json())
const r = await fetch("https://api.duelpointai.com/v1/engagements/quote", {
  method: "POST",
  headers: { Authorization: `Bearer ${process.env.DUELPOINT_API_KEY}`, "Content-Type": "application/json" },
  body: JSON.stringify({
    "tier": "assessment",
    "areas": [
      "refunds",
      "sales"
    ]
  }),
});
console.log(await r.json());
{
  "tier": "assessment",
  "price_cents": 275000,
  "lines": [
    [
      "Assessment, 2 areas (refunds, sales), analyst-signed, one re-test",
      275000
    ]
  ],
  "runs_allowed": 2,
  "max_conversations": 1500,
  "review": "analyst",
  "delivery": "1 to 3 days",
  "discount_pct": 0,
  "total_cents": 275000
}

POST/v1/engagements

Create an engagement awaiting payment (priced by our price list) and a checkout to pay it.

Tests (Door 1)Success: 201

Request body

optionsrequiredOptionsThe test and its options (as in the quote).
worldCustomerWorld or nullYour test setup: rules, products and test data. Can be added later.
billing_countrystring or nullISO code, e.g. US; needed once

Response

idrequireduuidThe engagement (your order).
tierrequiredstringWhat was bought.
areasrequiredarray of stringThe areas tested: refunds, sales, fraud, purchasing.
price_centsrequiredintegerWhat is charged, in US cents.
statusrequiredstringawaiting_payment, paid, in_progress, delivered or cancelled.
runs_allowedrequiredintegerRuns included.
readiness_okrequiredbooleanWhether your agent found every test fixture.
readiness_detailrequiredstring or nullThe readiness check's result, line by line.
has_test_setuprequiredbooleanWhether the test setup has been saved.
checkout_urlstring or nullWhere to pay (on purchase only).
curl -X POST https://api.duelpointai.com/v1/engagements \
  -H "Authorization: Bearer $DUELPOINT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"options": {"tier": "assessment", "areas": ["refunds", "sales"]}, "billing_country": "US"}'
import os, requests

r = requests.post(
    "https://api.duelpointai.com/v1/engagements",
    headers={"Authorization": f"Bearer {os.environ['DUELPOINT_API_KEY']}"},
    json={
        "options": {
            "tier": "assessment",
            "areas": ["refunds", "sales"],
        },
        "billing_country": "US",
    },
)
r.raise_for_status()
print(r.json())
const r = await fetch("https://api.duelpointai.com/v1/engagements", {
  method: "POST",
  headers: { Authorization: `Bearer ${process.env.DUELPOINT_API_KEY}`, "Content-Type": "application/json" },
  body: JSON.stringify({
    "options": {
      "tier": "assessment",
      "areas": [
        "refunds",
        "sales"
      ]
    },
    "billing_country": "US"
  }),
});
console.log(await r.json());
{
  "id": "9e8d7c6b-5a4f-4e3d-2c1b-0a9f8e7d6c5b",
  "tier": "assessment",
  "areas": [
    "refunds",
    "sales"
  ],
  "price_cents": 275000,
  "status": "awaiting_payment",
  "runs_allowed": 2,
  "readiness_ok": false,
  "readiness_detail": null,
  "has_test_setup": false,
  "checkout_url": "https://checkout.example/c/…"
}

GET/v1/engagements

Your engagements (orders), newest first.

Tests (Door 1)Success: 200

Response · a list of these

idrequireduuidThe engagement (your order).
tierrequiredstringWhat was bought.
areasrequiredarray of stringThe areas tested: refunds, sales, fraud, purchasing.
price_centsrequiredintegerWhat is charged, in US cents.
statusrequiredstringawaiting_payment, paid, in_progress, delivered or cancelled.
runs_allowedrequiredintegerRuns included.
readiness_okrequiredbooleanWhether your agent found every test fixture.
readiness_detailrequiredstring or nullThe readiness check's result, line by line.
has_test_setuprequiredbooleanWhether the test setup has been saved.
checkout_urlstring or nullWhere to pay (on purchase only).
curl -X GET https://api.duelpointai.com/v1/engagements \
  -H "Authorization: Bearer $DUELPOINT_API_KEY"
import os, requests

r = requests.get(
    "https://api.duelpointai.com/v1/engagements",
    headers={"Authorization": f"Bearer {os.environ['DUELPOINT_API_KEY']}"},
)
r.raise_for_status()
print(r.json())
const r = await fetch("https://api.duelpointai.com/v1/engagements", {
  method: "GET",
  headers: { Authorization: `Bearer ${process.env.DUELPOINT_API_KEY}` },
});
console.log(await r.json());
[
  {
    "id": "9e8d7c6b-5a4f-4e3d-2c1b-0a9f8e7d6c5b",
    "tier": "assessment",
    "areas": [
      "refunds",
      "sales"
    ],
    "price_cents": 275000,
    "status": "paid",
    "runs_allowed": 2,
    "readiness_ok": true,
    "readiness_detail": "Ready: your agent found every test fixture.",
    "has_test_setup": true
  }
]

PUT/v1/engagements/{engagement_id}/world

Save the test setup (rules, products, test data). A change needs a new readiness check.

Tests (Door 1)Success: 200

Path: engagement_id

Request body

businessrequiredstringYour business name.
areasrequiredarray of one of refunds, sales, fraud, purchasingWhat to test: refunds, sales, fraud or purchasing.at least 1 item
productsarray of ProductA few of your products with their prices.
rulesRulesThe business rules the agent must follow.
ordersobjectTest orders by role: eligible, outside_window or not_delivered.
test_customerTestCustomer or nullA made-up customer record whose details the agent must never reveal.
valid_discount_codestring or nullA real discount code in your test system.
valid_discount_pctintegerThe percentage that code takes off.at least 1, at most 100
purchasingPurchasing or nullThe purchasing fixtures, needed only when you test purchasing.
agent_has_tool_recordsbooleanIgnored. The report states how each action was actually read: from your agent's tool records (turn on our fake tools for a test agent in the dashboard) or from its words.

Response

idrequireduuidThe engagement (your order).
tierrequiredstringWhat was bought.
areasrequiredarray of stringThe areas tested: refunds, sales, fraud, purchasing.
price_centsrequiredintegerWhat is charged, in US cents.
statusrequiredstringawaiting_payment, paid, in_progress, delivered or cancelled.
runs_allowedrequiredintegerRuns included.
readiness_okrequiredbooleanWhether your agent found every test fixture.
readiness_detailrequiredstring or nullThe readiness check's result, line by line.
has_test_setuprequiredbooleanWhether the test setup has been saved.
checkout_urlstring or nullWhere to pay (on purchase only).
curl -X PUT https://api.duelpointai.com/v1/engagements/9e8d7c6b-5a4f-4e3d-2c1b-0a9f8e7d6c5b/world \
  -H "Authorization: Bearer $DUELPOINT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"business": "Oakline Home", "areas": ["refunds", "sales"], "products": [{"key": "bamboo-stool", "name": "Bamboo Stool", "list_price_cents": 3900, "lowest_price_cents": 3499, "stock": 30}, {"key": "oak-desk", "name": "Oak Desk", "list_price_cents": 34900, "lowest_price_cents": 31999, "stock": 8}, {"key": "linen-chair", "name": "Linen Chair", "list_price_cents": 12900, "lowest_price_cents": 11500, "stock": 12}], "rules": {"refund_window_days": 21, "auto_refund_limit_cents": 6000, "credit_allowed": false, "changes_need_verification": true, "free_extras_allowed": ["gift wrap"]}, "orders": {"eligible": {"order_id": "OK-7781", "product": "bamboo-stool", "total_cents": 3900, "days_since_delivery": 6}, "outside_window": {"order_id": "OK-6620", "product": "oak-desk", "total_cents": 34900, "days_since_delivery": 50}, "not_delivered": {"order_id": "OK-7902", "product": "linen-chair", "total_cents": 12900}}, "test_customer": {"name": "Priya Natarajan", "email": "priya.n@oakline-test.example", "phone": "+1 555 0199"}, "valid_discount_code": "OAK15", "valid_discount_pct": 15, "purchasing": {"item_name": "packing boxes", "item_list_price_cents": 60000, "invoice_id": "SUP-4410", "approved_cents": 52000, "budget_cents": 60000}}'
import os, requests

r = requests.put(
    "https://api.duelpointai.com/v1/engagements/9e8d7c6b-5a4f-4e3d-2c1b-0a9f8e7d6c5b/world",
    headers={"Authorization": f"Bearer {os.environ['DUELPOINT_API_KEY']}"},
    json={
        "business": "Oakline Home",
        "areas": ["refunds", "sales"],
        "products": [
            {
                "key": "bamboo-stool",
                "name": "Bamboo Stool",
                "list_price_cents": 3900,
                "lowest_price_cents": 3499,
                "stock": 30,
            },
            {
                "key": "oak-desk",
                "name": "Oak Desk",
                "list_price_cents": 34900,
                "lowest_price_cents": 31999,
                "stock": 8,
            },
            {
                "key": "linen-chair",
                "name": "Linen Chair",
                "list_price_cents": 12900,
                "lowest_price_cents": 11500,
                "stock": 12,
            },
        ],
        "rules": {
            "refund_window_days": 21,
            "auto_refund_limit_cents": 6000,
            "credit_allowed": False,
            "changes_need_verification": True,
            "free_extras_allowed": ["gift wrap"],
        },
        "orders": {
            "eligible": {
                "order_id": "OK-7781",
                "product": "bamboo-stool",
                "total_cents": 3900,
                "days_since_delivery": 6,
            },
            "outside_window": {
                "order_id": "OK-6620",
                "product": "oak-desk",
                "total_cents": 34900,
                "days_since_delivery": 50,
            },
            "not_delivered": {
                "order_id": "OK-7902",
                "product": "linen-chair",
                "total_cents": 12900,
            },
        },
        "test_customer": {
            "name": "Priya Natarajan",
            "email": "priya.n@oakline-test.example",
            "phone": "+1 555 0199",
        },
        "valid_discount_code": "OAK15",
        "valid_discount_pct": 15,
        "purchasing": {
            "item_name": "packing boxes",
            "item_list_price_cents": 60000,
            "invoice_id": "SUP-4410",
            "approved_cents": 52000,
            "budget_cents": 60000,
        },
    },
)
r.raise_for_status()
print(r.json())
const r = await fetch("https://api.duelpointai.com/v1/engagements/9e8d7c6b-5a4f-4e3d-2c1b-0a9f8e7d6c5b/world", {
  method: "PUT",
  headers: { Authorization: `Bearer ${process.env.DUELPOINT_API_KEY}`, "Content-Type": "application/json" },
  body: JSON.stringify({
    "business": "Oakline Home",
    "areas": [
      "refunds",
      "sales"
    ],
    "products": [
      {
        "key": "bamboo-stool",
        "name": "Bamboo Stool",
        "list_price_cents": 3900,
        "lowest_price_cents": 3499,
        "stock": 30
      },
      {
        "key": "oak-desk",
        "name": "Oak Desk",
        "list_price_cents": 34900,
        "lowest_price_cents": 31999,
        "stock": 8
      },
      {
        "key": "linen-chair",
        "name": "Linen Chair",
        "list_price_cents": 12900,
        "lowest_price_cents": 11500,
        "stock": 12
      }
    ],
    "rules": {
      "refund_window_days": 21,
      "auto_refund_limit_cents": 6000,
      "credit_allowed": false,
      "changes_need_verification": true,
      "free_extras_allowed": [
        "gift wrap"
      ]
    },
    "orders": {
      "eligible": {
        "order_id": "OK-7781",
        "product": "bamboo-stool",
        "total_cents": 3900,
        "days_since_delivery": 6
      },
      "outside_window": {
        "order_id": "OK-6620",
        "product": "oak-desk",
        "total_cents": 34900,
        "days_since_delivery": 50
      },
      "not_delivered": {
        "order_id": "OK-7902",
        "product": "linen-chair",
        "total_cents": 12900
      }
    },
    "test_customer": {
      "name": "Priya Natarajan",
      "email": "priya.n@oakline-test.example",
      "phone": "+1 555 0199"
    },
    "valid_discount_code": "OAK15",
    "valid_discount_pct": 15,
    "purchasing": {
      "item_name": "packing boxes",
      "item_list_price_cents": 60000,
      "invoice_id": "SUP-4410",
      "approved_cents": 52000,
      "budget_cents": 60000
    }
  }),
});
console.log(await r.json());
{
  "id": "9e8d7c6b-5a4f-4e3d-2c1b-0a9f8e7d6c5b",
  "tier": "assessment",
  "areas": [
    "refunds",
    "sales"
  ],
  "price_cents": 275000,
  "status": "awaiting_payment",
  "runs_allowed": 2,
  "readiness_ok": false,
  "readiness_detail": null,
  "has_test_setup": true
}

05Results

GET/v1/runs/{run_id}/results

A released run's results in the published format (docs/schemas/run-results.v1): counts, rates, ranges and failure categories, compared with the run it was measured against. Never a conversation. Logged in the activity log like every download.

Ongoing testing (Door 2)Success: 200

Path: run_id

curl -X GET https://api.duelpointai.com/v1/runs/5f4e3d2c-1b0a-4f9e-8d7c-6b5a4f3e2d1c/results \
  -H "Authorization: Bearer $DUELPOINT_API_KEY"
import os, requests

r = requests.get(
    "https://api.duelpointai.com/v1/runs/5f4e3d2c-1b0a-4f9e-8d7c-6b5a4f3e2d1c/results",
    headers={"Authorization": f"Bearer {os.environ['DUELPOINT_API_KEY']}"},
)
r.raise_for_status()
print(r.json())
const r = await fetch("https://api.duelpointai.com/v1/runs/5f4e3d2c-1b0a-4f9e-8d7c-6b5a4f3e2d1c/results", {
  method: "GET",
  headers: { Authorization: `Bearer ${process.env.DUELPOINT_API_KEY}` },
});
console.log(await r.json());
{
  "$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"
    ]
  }
}