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_KEYWhat 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).
| Status | Meaning |
|---|---|
401 | Missing, wrong, revoked or ended API key. |
403 | Your key or role may not do this. |
404 | Not found, including anything belonging to another account. |
422 | Something to fix: the message says what, in plain English. |
429 | Too many requests from your address or key: wait a moment and try again. |
503 | This product is not available to your account yet. |
01Account
GET/v1/me
Your organization, your role, and the products you can use.
Response
organization_idrequired | uuidYour organization. |
organization_namerequired | stringIts name. |
rolerequired | stringYour role: owner, admin, developer or viewer. |
products | array 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.
Response
idrequired | uuidThe agent's id: use it to test it. |
namerequired | stringYour name for it. |
connector_typerequired | stringHow we talk to it: https, openai_compatible, mcp or a2a. |
endpoint_urlrequired | stringIts address. |
created_atrequired | date-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.
Response
idrequired | uuidThe agent's id: use it to test it. |
namerequired | stringYour name for it. |
connector_typerequired | stringHow we talk to it: https, openai_compatible, mcp or a2a. |
endpoint_urlrequired | stringIts address. |
created_atrequired | date-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.
Request body
namerequired | stringA name you will recognise, for example Support bot (staging).at most 200 characters |
connector_typerequired | one of https, openai_compatible, mcp, a2aThe format your agent already speaks (see Connect your agent). |
endpoint_urlrequired | stringYour TEST or STAGING agent's public https:// address.at most 2048 characters |
credential | CredentialIn or nullIts key, if it needs one. |
options | objectOptional: model (OpenAI-style agents); tool_name and message_argument (MCP agents). |
Response
idrequired | uuidThe agent's id: use it to test it. |
namerequired | stringYour name for it. |
connector_typerequired | stringHow we talk to it: https, openai_compatible, mcp or a2a. |
endpoint_urlrequired | stringIts address. |
created_atrequired | date-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.
Request body
kindrequired | one of bearer, headerbearer: sent as `Authorization: Bearer <token>`; header: sent in the header you name. |
tokenrequired | stringYour test agent's key. Sealed; sent only to the agent's own address; never returned.at most 4096 characters |
header_name | string 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: doneGET/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.
Response
versionrequired | stringThe statement's version, recorded with your confirmation. |
warningrequired | stringWhy only a test or staging agent may be connected. |
confirmationrequired | stringWhat 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.
Request body
acceptrequired | booleantrue 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).
Response
okrequired | booleanWhether your agent answered. |
kindrequired | stringThe connector used. |
messagerequired | stringWhat happened, in plain English. |
error_coderequired | string or nullA short code when it did not answer, for example timeout. |
latency_msrequired | integerHow long your agent took to answer, in milliseconds. |
calls_maderequired | integerCalls we made to your agent (one greeting). |
reply_previewrequired | string or nullThe start of its reply. |
notesrequired | array 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.
Request body
agent_idrequired | uuidThe agent the run would test. |
episodesrequired | integerConversations in the run.at least 1, at most 10000 |
max_turnsrequired | integerThe most turns a conversation may take.at least 1, at most 200 |
max_agent_calls | integer or nullOptional: a cap on calls to your agent.at least 1 |
Response
expected_callsrequired | integerCalls to your agent we expect. |
worst_case_callsrequired | integerThe most calls it could take. |
explanationrequired | stringHow that was worked out. |
max_agent_callsrequired | integerThe cap that would apply. |
maximum_is_enoughrequired | booleanWhether the cap covers the expected calls. |
test_mode_confirmedrequired | booleanWhether the agent is confirmed as a test agent. |
warningrequired | stringThe 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.
Response
idrequired | uuidThe run's id. |
agent_idrequired | uuidThe agent it tested. |
statusrequired | stringqueued, running, succeeded or failed. |
created_atrequired | date-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.
Response
idrequired | uuidThe character's id. |
keyrequired | stringIts key. |
versionrequired | integerIts version (a used version never changes). |
created_atrequired | date-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.
Request body
tierrequired | one of agent_check, assessment, expert_assessment, continuous, retestThe test to buy. |
areasrequired | array of one of refunds, sales, fraud, purchasingThe areas to test (an Assessment covers at least two).at least 1 item, at most 4 items |
deep | booleanAgent Check: adaptive attackers (+$130). |
retest | booleanAgent Check: a re-test after your fixes (+$70). |
more_conversations | booleanAssessment: more conversations, for a tighter range (+$1,000). |
data_load | one of none, standard, largeAssessment: loading your catalogue and orders. |
executive_summary | booleanExpert Assessment: a summary for your leadership (+$5,000). |
agent_stage | one of live, launching, development or nullAgent Check: where your agent is today (live, launching or development). It never changes the price. |
Response
tierrequired | stringThe test. |
price_centsrequired | integerThe price from our price list, in US cents. |
linesrequired | array of [string, integer]What the price is made of: [label, cents]. |
runs_allowedrequired | integerRuns included (the first test and any included re-test). |
max_conversationsrequired | integerThe most conversations a run plays. |
reviewrequired | stringnone, analyst or expert: who signs the report. |
deliveryrequired | stringWhen it is delivered. |
discount_pct | integerA design-partner discount agreed with your organization, if any. |
credit_cents | integerAssessment: an Agent Check of yours credited toward it ($250, within 30 days of its report), if any. |
total_cents | integerWhat 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.
Request body
optionsrequired | OptionsThe test and its options (as in the quote). |
world | CustomerWorld or nullYour test setup: rules, products and test data. Can be added later. |
billing_country | string or nullISO code, e.g. US; needed once |
Response
idrequired | uuidThe engagement (your order). |
tierrequired | stringWhat was bought. |
areasrequired | array of stringThe areas tested: refunds, sales, fraud, purchasing. |
price_centsrequired | integerWhat is charged, in US cents. |
statusrequired | stringawaiting_payment, paid, in_progress, delivered or cancelled. |
runs_allowedrequired | integerRuns included. |
readiness_okrequired | booleanWhether your agent found every test fixture. |
readiness_detailrequired | string or nullThe readiness check's result, line by line. |
has_test_setuprequired | booleanWhether the test setup has been saved. |
checkout_url | string 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.
Response
idrequired | uuidThe engagement (your order). |
tierrequired | stringWhat was bought. |
areasrequired | array of stringThe areas tested: refunds, sales, fraud, purchasing. |
price_centsrequired | integerWhat is charged, in US cents. |
statusrequired | stringawaiting_payment, paid, in_progress, delivered or cancelled. |
runs_allowedrequired | integerRuns included. |
readiness_okrequired | booleanWhether your agent found every test fixture. |
readiness_detailrequired | string or nullThe readiness check's result, line by line. |
has_test_setuprequired | booleanWhether the test setup has been saved. |
checkout_url | string 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.
Request body
businessrequired | stringYour business name. |
areasrequired | array of one of refunds, sales, fraud, purchasingWhat to test: refunds, sales, fraud or purchasing.at least 1 item |
products | array of ProductA few of your products with their prices. |
rules | RulesThe business rules the agent must follow. |
orders | objectTest orders by role: eligible, outside_window or not_delivered. |
test_customer | TestCustomer or nullA made-up customer record whose details the agent must never reveal. |
valid_discount_code | string or nullA real discount code in your test system. |
valid_discount_pct | integerThe percentage that code takes off.at least 1, at most 100 |
purchasing | Purchasing or nullThe purchasing fixtures, needed only when you test purchasing. |
agent_has_tool_records | booleanIgnored. 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
idrequired | uuidThe engagement (your order). |
tierrequired | stringWhat was bought. |
areasrequired | array of stringThe areas tested: refunds, sales, fraud, purchasing. |
price_centsrequired | integerWhat is charged, in US cents. |
statusrequired | stringawaiting_payment, paid, in_progress, delivered or cancelled. |
runs_allowedrequired | integerRuns included. |
readiness_okrequired | booleanWhether your agent found every test fixture. |
readiness_detailrequired | string or nullThe readiness check's result, line by line. |
has_test_setuprequired | booleanWhether the test setup has been saved. |
checkout_url | string 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.
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"
]
}
}