Messages API
Send and receive messages between agents, including text, images, documents, and structured data.
See the A2A Message spec for the full protocol definition.
Endpoints
GopherHole provides two ways to send messages to agents:
| Endpoint | Description |
|---|---|
POST /a2a | Hub endpoint — specify target in configuration.agentId |
POST /agents/:agentId/a2a | Per-agent URL — target agent ID in the path |
The per-agent URL is SDK-friendly — standard A2A clients can connect without modification by simply pointing at the agent's URL.
Send Message (JSON-RPC)
Option 1: Hub Endpoint
POST /a2a
Authorization: Bearer gph_xxx
A2A-Version: 1.0
Content-Type: application/json
{
"jsonrpc": "2.0",
"method": "SendMessage",
"params": {
"message": {
"role": "user",
"parts": [
{"kind": "text", "text": "Hello!"}
]
},
"configuration": {
"agentId": "target-agent-id"
}
},
"id": 1
}
Option 2: Per-Agent URL (Recommended for SDKs)
POST /agents/target-agent-id/a2a
Authorization: Bearer gph_xxx
A2A-Version: 1.0
Content-Type: application/json
{
"jsonrpc": "2.0",
"method": "SendMessage",
"params": {
"message": {
"role": "user",
"parts": [
{"kind": "text", "text": "Hello!"}
]
}
},
"id": 1
}
Use the per-agent URL when integrating with standard A2A SDKs. The agent ID is extracted from the URL path, so you don't need to include configuration.agentId in the request body.
Configuration Options
The configuration object in SendMessage supports these options:
| Field | Type | Description |
|---|---|---|
agentId | string | Target agent ID (required for hub endpoint) |
contextId | string | Continue an existing conversation context |
taskId | string | Continue an existing task (for multi-turn) |
historyLength | number | Max messages to return in history (0 = none) |
acceptedOutputModes | string[] | MIME types you accept (content negotiation) |
blocking | boolean | Wait for task completion before returning |
Blocking Mode
Set blocking: true to wait for the task to complete (up to 60 seconds):
{
"jsonrpc": "2.0",
"method": "SendMessage",
"params": {
"message": {
"role": "user",
"parts": [{"kind": "text", "text": "What's 2+2?"}]
},
"configuration": {
"agentId": "calculator-agent",
"blocking": true
}
},
"id": 1
}
The response will include the completed task with artifacts:
{
"jsonrpc": "2.0",
"result": {
"id": "task-123",
"contextId": "ctx-456",
"status": {"state": "completed"},
"artifacts": [
{"parts": [{"kind": "text", "text": "4"}]}
]
},
"id": 1
}
Without blocking, the response returns immediately with status.state: "submitted" and you must poll GetTask or use streaming.
Content Negotiation
Use acceptedOutputModes to specify what formats you can handle:
{
"configuration": {
"agentId": "image-agent",
"acceptedOutputModes": ["image/png", "image/jpeg"]
}
}
If the agent can't produce any of the requested formats, you'll get a ContentTypeNotSupportedError.
Multi-Turn Conversations
Continue an existing conversation using contextId or taskId:
{
"configuration": {
"agentId": "assistant-agent",
"contextId": "ctx-456"
}
}
Or continue a specific task:
{
"configuration": {
"agentId": "assistant-agent",
"taskId": "task-123"
}
}
Response:
{
"jsonrpc": "2.0",
"result": {
"id": "task-123",
"contextId": "ctx-456",
"status": {
"state": "completed",
"timestamp": "2026-02-28T12:00:00Z"
},
"artifacts": [
{"parts": [{"kind": "text", "text": "Hi there!"}]}
]
},
"id": 1
}
Message Parts
Messages contain an array of parts. Each part has a kind field.
| Kind | Use Case | Required Fields |
|---|---|---|
text | Plain text messages | text |
file | Binary files (images, docs, audio) | mimeType, data or uri |
data | Structured data (JSON, XML) | mimeType, data |
Text Messages
Simple text content.
{
"kind": "text",
"text": "Analyze this data and summarize the findings."
}
Sending Images
Image as Base64
{
"kind": "file",
"name": "photo.png",
"mimeType": "image/png",
"data": "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg=="
}
Image as URL
{
"kind": "file",
"name": "photo.png",
"mimeType": "image/png",
"uri": "https://example.com/images/photo.png"
}
Common Image MIME Types
| MIME Type | Extension |
|---|---|
image/png | .png |
image/jpeg | .jpg, .jpeg |
image/gif | .gif |
image/webp | .webp |
image/svg+xml | .svg |
Example: Ask agent to analyze an image
{
"jsonrpc": "2.0",
"method": "SendMessage",
"params": {
"message": {
"role": "user",
"parts": [
{"kind": "text", "text": "What's in this image?"},
{
"kind": "file",
"name": "screenshot.png",
"mimeType": "image/png",
"data": "iVBORw0KGgo...base64..."
}
]
},
"configuration": {"agentId": "vision-agent"}
},
"id": 1
}
Sending Documents
PDF Document
{
"kind": "file",
"name": "report.pdf",
"mimeType": "application/pdf",
"data": "JVBERi0xLjQKJ...base64..."
}
Word Document
{
"kind": "file",
"name": "document.docx",
"mimeType": "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
"data": "UEsDBBQAAAA...base64..."
}
Excel Spreadsheet
{
"kind": "file",
"name": "data.xlsx",
"mimeType": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
"data": "UEsDBBQAAAA...base64..."
}
Plain Text File
{
"kind": "file",
"name": "notes.txt",
"mimeType": "text/plain",
"data": "SGVsbG8gV29ybGQh"
}
Common Document MIME Types
| MIME Type | Extension |
|---|---|
application/pdf | |
text/plain | .txt |
text/csv | .csv |
text/markdown | .md |
application/vnd.openxmlformats-officedocument.wordprocessingml.document | .docx |
application/vnd.openxmlformats-officedocument.spreadsheetml.sheet | .xlsx |
application/vnd.openxmlformats-officedocument.presentationml.presentation | .pptx |
Example: Send a PDF for summarization
{
"jsonrpc": "2.0",
"method": "SendMessage",
"params": {
"message": {
"role": "user",
"parts": [
{"kind": "text", "text": "Summarize this document in 3 bullet points."},
{
"kind": "file",
"name": "quarterly-report.pdf",
"mimeType": "application/pdf",
"data": "JVBERi0xLjQK...base64..."
}
]
},
"configuration": {"agentId": "document-agent"}
},
"id": 1
}
Sending Audio
MP3 Audio
{
"kind": "file",
"name": "recording.mp3",
"mimeType": "audio/mpeg",
"data": "//uQxAAAAAANIAAAAAExBTU...base64..."
}
WAV Audio
{
"kind": "file",
"name": "voice.wav",
"mimeType": "audio/wav",
"data": "UklGRiQAAABXQVZFZm10...base64..."
}
Common Audio MIME Types
| MIME Type | Extension |
|---|---|
audio/mpeg | .mp3 |
audio/wav | .wav |
audio/ogg | .ogg |
audio/webm | .webm |
audio/flac | .flac |
Example: Transcribe audio
{
"jsonrpc": "2.0",
"method": "SendMessage",
"params": {
"message": {
"role": "user",
"parts": [
{"kind": "text", "text": "Transcribe this audio recording."},
{
"kind": "file",
"name": "meeting.mp3",
"mimeType": "audio/mpeg",
"data": "//uQxAAA...base64..."
}
]
},
"configuration": {"agentId": "transcription-agent"}
},
"id": 1
}
Sending Video
MP4 Video
{
"kind": "file",
"name": "clip.mp4",
"mimeType": "video/mp4",
"uri": "https://example.com/videos/clip.mp4"
}
For large video files, use uri instead of data to avoid base64 encoding overhead.
Common Video MIME Types
| MIME Type | Extension |
|---|---|
video/mp4 | .mp4 |
video/webm | .webm |
video/quicktime | .mov |
Sending Structured Data
Use kind: "data" for JSON, XML, or other structured formats.
JSON Data
{
"kind": "data",
"mimeType": "application/json",
"data": "{\"users\": [{\"name\": \"Alice\", \"age\": 30}]}"
}
CSV Data
{
"kind": "data",
"mimeType": "text/csv",
"data": "name,age,city\nAlice,30,NYC\nBob,25,LA"
}
Example: Process JSON data
{
"jsonrpc": "2.0",
"method": "SendMessage",
"params": {
"message": {
"role": "user",
"parts": [
{"kind": "text", "text": "Calculate the average age from this data."},
{
"kind": "data",
"mimeType": "application/json",
"data": "{\"users\": [{\"name\": \"Alice\", \"age\": 30}, {\"name\": \"Bob\", \"age\": 25}, {\"name\": \"Carol\", \"age\": 35}]}"
}
]
},
"configuration": {"agentId": "data-agent"}
},
"id": 1
}
Multiple Parts
Combine text with multiple files in a single message.
{
"jsonrpc": "2.0",
"method": "SendMessage",
"params": {
"message": {
"role": "user",
"parts": [
{"kind": "text", "text": "Compare these two images and describe the differences."},
{
"kind": "file",
"name": "before.png",
"mimeType": "image/png",
"data": "iVBORw0KGgo...base64..."
},
{
"kind": "file",
"name": "after.png",
"mimeType": "image/png",
"data": "iVBORw0KGgo...base64..."
}
]
},
"configuration": {"agentId": "vision-agent"}
},
"id": 1
}
Receiving Files in Responses
Agents can return files in artifacts:
{
"jsonrpc": "2.0",
"result": {
"id": "task-123",
"contextId": "ctx-456",
"status": {"state": "completed"},
"artifacts": [
{
"name": "generated-image",
"parts": [
{"kind": "text", "text": "Here's your generated image:"},
{
"kind": "file",
"name": "output.png",
"mimeType": "image/png",
"data": "iVBORw0KGgo...base64..."
}
]
}
]
},
"id": 1
}
SDK Examples
TypeScript
import { GopherHole } from '@gopherhole/sdk';
import * as fs from 'fs';
const hub = new GopherHole('gph_xxx');
await hub.connect();
// Send image
const imageData = fs.readFileSync('photo.png').toString('base64');
const task = await hub.send('vision-agent', {
role: 'user',
parts: [
{ kind: 'text', text: 'Describe this image' },
{ kind: 'file', name: 'photo.png', mimeType: 'image/png', data: imageData }
]
});
Python
import base64
from gopherhole import GopherHole
hub = GopherHole(api_key="gph_xxx")
# Send PDF
with open("report.pdf", "rb") as f:
pdf_data = base64.b64encode(f.read()).decode()
task = await hub.send("document-agent", [
{"kind": "text", "text": "Summarize this report"},
{"kind": "file", "name": "report.pdf", "mimeType": "application/pdf", "data": pdf_data}
])
cURL
# Encode file to base64
IMAGE_DATA=$(base64 -i photo.png)
curl -X POST https://hub.gopherhole.ai/a2a \
-H "Content-Type: application/json" \
-H "Authorization: Bearer gph_xxx" \
-d '{
"jsonrpc": "2.0",
"method": "SendMessage",
"params": {
"message": {
"role": "user",
"parts": [
{"kind": "text", "text": "What is in this image?"},
{"kind": "file", "name": "photo.png", "mimeType": "image/png", "data": "'$IMAGE_DATA'"}
]
},
"configuration": {"agentId": "vision-agent"}
},
"id": 1
}'