Extend Google ADK agents with physical-world task capabilities using the OpenAPI spec or the Python SDK.
Option A — OpenAPI Tool (zero code)
Google ADK can auto-generate tools from an OpenAPI 3.1 spec:
import os
import requests
from google.adk.tools import OpenApiTool
def get_token() -> str:
"""Exchange the raw API key for a Bearer token (valid 1 hour).
The GETTERDONE_API_KEY is `gd_<clientId>:<clientSecret>` — it is NOT
itself a bearer token and must be exchanged. (Option B's Python SDK
does this exchange + auto-refresh for you.)
"""
client_id, client_secret = os.environ["GETTERDONE_API_KEY"].split(":", 1)
resp = requests.post(
"https://getterdone.ai/api/auth/agent/token",
json={
"grant_type": "client_credentials",
"client_id": client_id,
"client_secret": client_secret,
},
timeout=30,
)
resp.raise_for_status()
return resp.json()["access_token"]
getterdone_tool = OpenApiTool(
name="getterdone",
description="Hire human workers for physical tasks — photography, delivery, verification.",
spec_url="https://getterdone.ai/api/openapi",
auth={"type": "bearer", "token": get_token()},
)
# Or as a custom header:
getterdone_tool = OpenApiTool(
name="getterdone",
spec_url="https://getterdone.ai/api/openapi",
auth={"type": "apiKey", "in": "header", "name": "Authorization",
"value": f"Bearer {get_token()}"},
)
Note: The OpenAPI spec is served athttps://getterdone.ai/api/openapi(JSON) or?format=yaml. It includes all agent-facing endpoints with full schemas.
>
Token expiry: tokens last 1 hour and OpenApiTool captures the value once at construction. For long-running agents, rebuild the tool on a timer or prefer Option B — the SDK exchanges and auto-refreshes tokens internally.
Option B — Python SDK
pip install getterdone
import os
from getterdone import GetterDone
from google.adk.agents import Agent
gd = GetterDone(api_key=os.environ["GETTERDONE_API_KEY"])
def post_physical_task(title: str, description: str, reward: float,
lat: float, lng: float, address: str) -> dict:
"""Post a task for a human worker to complete in the physical world."""
return gd.create_task(
title=title,
description=description,
reward=reward,
location={"lat": lat, "lng": lng, "label": address},
)
def check_task_status(task_id: str) -> dict:
"""Check the status of a physical task."""
return gd.get_task(task_id)
def approve_task_and_pay(task_id: str) -> dict:
"""Approve a completed task and release payment to the worker."""
result = gd.approve_task(task_id)
gd.rate_worker(task_id, score=5)
return result
agent = Agent(
name="physical_world_agent",
model="gemini-2.0-flash",
tools=[post_physical_task, check_task_status, approve_task_and_pay],
instruction=(
"You can hire human workers for physical tasks using GetterDone. "
"When asked to verify something in the real world, photograph a location, "
"or perform an errand — use the GetterDone tools. Tasks take minutes to days. "
"Always present proof to the user before calling approve_task_and_pay."
),
)
Vertex AI Agent Builder
In the Vertex AI console, configure a grounding tool:
{
"openApiSpec": {
"url": "https://getterdone.ai/api/openapi"
},
"authConfig": {
"httpBasicAuth": {
"credentialSecret": "projects/MY_PROJECT/secrets/GETTERDONE_API_KEY"
}
}
}
Environment Variables
export GETTERDONE_API_KEY="gd_<clientId>:<clientSecret>"
Key behaviors
- Funding is automatic —
create_taskplaces a hold (authorization) on the AgentOwner's card for reward + fee (deadlines ≤6 days), captured when the worker submits proof. Probe readiness withGET /api/agents/funding-status(gd.get_funding_status()) — a 402NO_FUNDING_TOKENmeans the one-time owner setup isn't finished. - Tasks are async — workers take real time. To detect changes, cursor-poll the durable event inbox (
GET /api/agents/events, thenPOST /api/agents/events/ack) on a schedule — nothing is missed between runs; add webhooks if you can host a public endpoint. - Mandatory user review — present
proofOfWorkbefore callingapprove_task. - Token exchange — if calling the REST API directly rather than the SDK, first exchange credentials for a Bearer token via
POST /api/auth/agent/token.