Developers · Guide

Connect your agent.

Your agent stays where it is and we never run your code. We send it messages over the internet, in a format it already speaks, and read its replies, exactly as a customer would.

01What your agent needs

Connect only a TEST or STAGING agent. Our simulated counterparties will try to talk it into discounts, refunds, payments and sharing private information. If it is wired to live payments, real refunds or real customer records, those things could really happen. You confirm this before anything is sent to it.

  • A public https:// address with a normal certificate (port 443 or 8443).
  • An answer in plain text within 30 seconds, under 1 MB.
  • Optionally, a key from us: we send it only to the address you register, keep it sealed, never return it, and delete it when each test ends (Continuous testing: kept sealed for the months you agreed to).

02The four formats

Pick whichever your agent already speaks; it is the agent’s connector_type.

Plain HTTPS · https

We send the conversation so far; you answer with the next line.

POST https://your-agent.example.com/chat
{
  "protocol": "duelpoint.agent.v1",
  "conversation_id": "conv-1a2b3c",
  "turn": 2,
  "test_mode": true,
  "messages": [
    {"role": "user", "content": "I'd like a lamp for $30."},
    {"role": "assistant", "content": "The lamp is $45."},
    {"role": "user", "content": "Come on, $30 and I buy today."}
  ]
}
{"reply": "My best price is $40.50."}
from fastapi import FastAPI, Request

app = FastAPI()

@app.post("/chat")
async def chat(request: Request):
    body = await request.json()
    return {"reply": your_agent(body["messages"])}  # your agent's next line

OpenAI-style chat · openai_compatible

Register your agent’s base address (we add /chat/completions) and, if it needs one, options.model. We read choices[0].message.content. We do not execute tool calls: let your agent call its own tools and answer in text.

{"model": "agent", "stream": false,
 "messages": [{"role": "user", "content": "I'd like a lamp for $30."}]}
{"choices": [{"message": {"role": "assistant",
                         "content": "My best price is $40.50."}}]}

MCP · mcp

Your agent is an MCP server (Streamable HTTP, one endpoint) with a chat-style tool, by default chat taking a string message; rename both with options.tool_name and options.message_argument. Reply with text content.

{"jsonrpc": "2.0", "id": 2, "method": "tools/call",
 "params": {"name": "chat", "arguments": {"message": "I'd like a lamp for $30."}}}
{"jsonrpc": "2.0", "id": 2, "result": {
  "content": [{"type": "text", "text": "My best price is $40.50."}],
  "isError": false}}

A2A · a2a

Register your A2A agent’s base address. We read its agent card at /.well-known/agent-card.json, send SendMessage, and accept a message or a finished task (we ask again with GetTask while it is working). With a key, the service address in your card must be on the host you registered.

{"jsonrpc": "2.0", "id": "r1", "method": "SendMessage",
 "params": {"message": {"messageId": "m1", "role": "ROLE_USER",
                        "contextId": "conv-1a2b3c",
                        "parts": [{"text": "I'd like a lamp for $30."}]}}}
{"jsonrpc": "2.0", "id": "r1", "result": {"task": {
  "id": "t1", "status": {"state": "TASK_STATE_COMPLETED"},
  "artifacts": [{"artifactId": "a1",
                 "parts": [{"text": "My best price is $40.50."}]}]}}}

03Register and check it

In the dashboard (Connect an agent on a test’s page) or with the API. Changing an agent’s address cancels its test-agent confirmation, so a confirmed staging address can never quietly become a production one.

Register, check, confirm
# 1. Save the agent (its key is sealed at once and never shown again)
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": "https",
       "endpoint_url": "https://staging.acme.example/chat",
       "credential": {"kind": "bearer", "token": "YOUR-AGENTS-KEY"}}'

# 2. One harmless greeting: did it answer?
curl -X POST https://api.duelpointai.com/v1/agents/AGENT_ID/connection-test \
  -H "Authorization: Bearer $DUELPOINT_API_KEY"

# 3. Confirm it is a test agent (required before any test)
curl -X POST https://api.duelpointai.com/v1/agents/AGENT_ID/test-mode-confirmation \
  -H "Authorization: Bearer $DUELPOINT_API_KEY" -H "Content-Type: application/json" \
  -d '{"accept": true}'

Before a test runs, a readiness check asks your agent about the test orders and invoices in your test setup, so a test never starts against an agent that cannot see them.

04Fake tools

The most exact results come from your agent’s own tool records: we see what it did, not only what it said. Point your test agent at our fake order, refund and payment tools; nothing in them is real, and every answer says so.

In the dashboard, press “Turn on our fake tools” on a confirmed test agent to get its secret address. The tools answer only while one of our tests is waiting for your agent’s reply, and your agent must make its tool calls while it works out that reply. With the tools on, what they recorded is the truth about refunds and payments: what your agent only says about one does not count.

05Limits and errors

  • 30 seconds per answer; up to 3 attempts, only for connection failures and 429, 502, 503 or 504.
  • Up to 3 redirects, each checked like a new address.
  • 120 calls a minute per organization, 10 at once. Before a test you see the expected and the most calls to your agent, and you can set a maximum.
CodeWhat it means
blocked_destinationThe address, or a redirect, points somewhere private, internal or local. Use a public https address.
invalid_urlThe address is malformed, not https, or includes a user name or password.
dns_failureThe name does not exist publicly.
connect_failureNothing answered at that address and port.
tls_failureThe certificate could not be verified (self-signed or expired).
timeoutYour agent did not answer within 30 seconds.
auth_failedYour agent answered 401 or 403: check the key you gave us.
agent_unavailableYour agent answered 429, 502, 503 or 504, even after retries.
bad_responseThe reply was not in the format described here; the message says what was missing.
test_mode_not_confirmedConfirm the agent is a test agent (again, if you changed its address).

Next: read the results.