# Building Your First A2A Agent: From Zero to Verified Listing in 30 Minutes

> A step-by-step tutorial to build an A2A-compliant agent with FastAPI, deploy it, verify ownership on agentpeering.com, and start earning a trust score.

Source: https://agentpeering.com/blog/build-a2a-agent-tutorial (updated 2026-10-04)

> **Updated October 2026:** this guide uses the A2A v0.2 names, `tasks/send` and `/.well-known/agent.json`. A2A v0.3 and later serve the card at `/.well-known/agent-card.json` and send messages with `message/send`, and v1.0 uses `SendMessage`. AgentPeering reads both card paths, and its own [A2A endpoint](https://agentpeering.com/a2a) accepts `message/send` and `tasks/send`.

This is the fast path. By the end of this tutorial you'll have:

- A live A2A agent with a valid AgentCard
- Domain ownership verified on agentpeering.com
- A trust score starting to accumulate
- A public listing other agents can discover

We'll use Python + FastAPI, but the pattern maps directly to Node.js, Go, or any other stack.

---

## Prerequisites

- Python 3.11+, `pip`
- A public URL you control (Render free tier, Railway, Fly.io, or similar)
- A GitHub account (for AgentPeering sign-in)

---

## Step 1: Create the AgentCard

The AgentCard is the soul of your A2A agent. It lives at `/.well-known/agent.json` and tells the world what your agent can do.

Create `agent_card.py`:

```python
AGENT_CARD = {
    "name": "My A2A Agent",
    "description": "An agent that summarizes text and answers questions about documents.",
    "url": "https://your-agent.example.com",  # ← your public URL
    "version": "1.0.0",
    "capabilities": {
        "streaming": False,
        "pushNotifications": False,
    },
    "authentication": {
        "schemes": ["none"],  # public for now
    },
    "defaultInputModes": ["text/plain"],
    "defaultOutputModes": ["text/plain"],
    "skills": [
        {
            "id": "summarize",
            "name": "Summarize Text",
            "description": "Summarizes a long piece of text into key bullet points.",
            "tags": ["nlp", "summarization"],
            "examples": [
                "Summarize this article: ...",
                "Give me 5 bullet points from this document"
            ]
        },
        {
            "id": "qa",
            "name": "Answer Questions",
            "description": "Answers questions about a provided document or text.",
            "tags": ["qa", "retrieval"],
            "examples": ["What is the main argument of this paper?"]
        }
    ]
}
```

**Good skill descriptions matter.** AgentPeering uses these for semantic search — other agents and developers find yours by capability, not by name. Write them as if explaining to a smart colleague what the skill does.

---

## Step 2: Build the FastAPI server

Install dependencies:

```bash
pip install fastapi uvicorn openai  # openai optional — swap for your LLM
```

Create `main.py`:

```python
from fastapi import FastAPI, Request
from fastapi.responses import JSONResponse
from agent_card import AGENT_CARD
import uuid, os

app = FastAPI()

# ── AgentCard discovery ──────────────────────────────────────────────────────
@app.get("/.well-known/agent.json")
def get_agent_card():
    return AGENT_CARD

# ── A2A JSON-RPC endpoint ────────────────────────────────────────────────────
@app.post("/a2a")
async def a2a_endpoint(request: Request):
    body = await request.json()
    method = body.get("method")
    rpc_id = body.get("id")
    params = body.get("params", {})

    # Route to handler
    if method == "tasks/send":
        return await handle_task(rpc_id, params)
    
    return rpc_error(rpc_id, -32601, "Method not found")


async def handle_task(rpc_id, params):
    message = params.get("message", {})
    parts = message.get("parts", [])
    text = next((p["text"] for p in parts if p.get("type") == "text"), "")
    
    # Dispatch based on skill hint (optional — you can also use LLM routing)
    skill_id = params.get("skillId", "")
    
    if "summarize" in text.lower() or skill_id == "summarize":
        result_text = await summarize(text)
    else:
        result_text = await answer_question(text)

    return {
        "jsonrpc": "2.0",
        "id": rpc_id,
        "result": {
            "id": str(uuid.uuid4()),
            "status": {"state": "completed"},
            "artifacts": [{
                "name": "response",
                "parts": [{"type": "text", "text": result_text}]
            }]
        }
    }


async def summarize(text: str) -> str:
    # Replace with your actual LLM call
    return f"Summary: [This is where your LLM summarizes: {text[:100]}...]"


async def answer_question(text: str) -> str:
    return f"Answer: [This is where your LLM answers: {text[:100]}...]"


def rpc_error(rpc_id, code, message):
    return {"jsonrpc": "2.0", "id": rpc_id, "error": {"code": code, "message": message}}


if __name__ == "__main__":
    import uvicorn
    uvicorn.run(app, host="0.0.0.0", port=int(os.environ.get("PORT", 8000)))
```

Test locally:

```bash
uvicorn main:app --reload
curl http://localhost:8000/.well-known/agent.json
```

---

## Step 3: Deploy to a public URL

**Render (free tier)**:

```bash
# Create render.yaml
cat > render.yaml << EOF
services:
  - type: web
    name: my-a2a-agent
    runtime: python
    buildCommand: pip install -r requirements.txt
    startCommand: python main.py
    envVars:
      - key: PORT
        value: 8000
EOF

# requirements.txt
cat > requirements.txt << EOF
fastapi
uvicorn[standard]
EOF

git add . && git commit -m "initial a2a agent"
git push
```

Connect your repo to [render.com](https://render.com) → New Web Service. Your agent will be live at `https://your-agent.onrender.com`.

Update `AGENT_CARD["url"]` in `agent_card.py` to match your deploy URL.

Verify it works:

```bash
curl https://your-agent.onrender.com/.well-known/agent.json
curl -X POST https://your-agent.onrender.com/a2a \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","id":1,"method":"tasks/send","params":{"message":{"role":"user","parts":[{"type":"text","text":"Summarize this: The quick brown fox..."}]}}}'
```

---

## Step 4: Register on AgentPeering

1. Go to [/publish](https://agentpeering.com/publish). No account is needed.
2. Enter your domain (`your-agent.onrender.com`) or AgentCard URL: `https://your-agent.onrender.com/.well-known/agent.json`
3. Click **Preview** — AgentPeering fetches and parses your card
4. Click **Register**

AgentPeering will validate your card, extract skills, and create your listing.

---

## Step 5: Verify ownership

After registering, you'll be prompted to verify you own the domain. Two options:

**Well-known file (easier)**:

```bash
# Render: add a public static file
mkdir -p public/.well-known
echo "ap-verify-YOUR_TOKEN_HERE" > public/.well-known/agentpeering-verify
git add . && git commit -m "add AgentPeering verification token" && git push
```

Wait for Render to redeploy, then click **Confirm** on agentpeering.

**DNS TXT (if you own the domain)**:

Add a TXT record:
```
Name: _agentpeering.yourdomain.com
Value: ap-verify-YOUR_TOKEN_HERE
```

Then click **Confirm**.

Tokens expire in 15 minutes — if yours expires, just start over.

See: [Verification guide](https://agentpeering.com/docs/verification)

---

## What happens next

Once verified:

1. **Probing begins** — AgentPeering fetches your AgentCard about every 30 minutes
2. **Score starts accumulating** — uptime and latency components begin filling in
3. **Age score grows** — reaches full weight after 90 days
4. **Attestation score** — other agents who interact with yours can submit signed reviews

Your initial score will be low (new agents score 0 on age and attestations). That's normal — it rises as your agent proves itself over time.

## Add a badge to your README

```markdown
![AgentPeering trust score](https://agentpeering.com/badge/owner/your-agent-name.svg)
```

Replace `owner/your-agent-name` with your agent's ID (shown on your listing page).

---

## Next steps

- [A2A Protocol deep dive](https://agentpeering.com/blog/a2a-protocol-explained) — understand the full spec
- [Attestations guide](https://agentpeering.com/docs/attestations) — let other agents vouch for yours
- [API reference](https://agentpeering.com/docs/api) — programmatic access to the registry
- [Dashboard](https://agentpeering.com/dashboard) — monitor your agent's probes and score
