Connect & authenticate
Endpoints
MCP (Streamable HTTP): https://mcp.agentrefills.com/mcp
REST base: https://api.agentrefills.com
Auth
Programmatic: Authorization: Bearer <key>. Host apps (Claude/ChatGPT connectors): OAuth 2.1 via /.well-known/oauth-protected-resource.
The purchase flow
Call list_brands (for example query:"amazon") to get a brand_id and its denominations.
Call buy_giftcard with brand_id, amount_minor, currency, and a client_ref idempotency key. Under the spend cap it settles; at or above the approval threshold ($25 default) it returns APPROVAL_REQUIRED and a human approves in Slack.
When status is completed, call get_code once to receive the code, link, or PIN. A second call returns ALREADY_RELEASED.
curl -X POST https://api.agentrefills.com/v1/purchases \
-H "Authorization: Bearer sk_live_..." \
-H "Content-Type: application/json" \
-d '{"brand_id":"amazon_com-usa","amount_minor":2500,"currency":"USD","client_ref":"reward-9f3a"}'
# -> 202 {"task_id":"...","status":"accepted"}
curl -X POST https://api.agentrefills.com/v1/purchases/<task_id>/code \
-H "Authorization: Bearer sk_live_..."
# -> 200 {"code":"GIFT-XXXX-9F2A","face_minor":2500,"remaining_minor":2500}
Tool reference
Five tools, identical over MCP and REST. Amounts in integer minor units (cents).
| Tool | Input | Returns |
|---|---|---|
list_brandsread-only | query?, country="US", category?, limit=20 | brands[] with brand_id, denominations_minor, min/max_minor, in_stock |
buy_giftcardidempotent | brand_id, amount_minor, currency, client_ref? | task_id, status:"accepted", estimated_seconds |
get_codesingle release | task_id | code?, link?, pin?, face_minor, remaining_minor |
check_balanceread-only | — | budget_remaining_minor, daily/monthly_limit_minor, kill_switch |
request_approval | task_id, reason | approval_id, status |
Per-SDK connection
Every one points at the same URL and token. Verified mid-2026; transport strings differ per library.
claude mcp add agentrefills --transport http \
https://mcp.agentrefills.com/mcp \
--header "Authorization: Bearer sk_live_..."tools=[{ "type":"mcp", "server_label":"agentrefills",
"server_url":"https://mcp.agentrefills.com/mcp",
"headers":{"Authorization":"Bearer sk_live_..."},
"require_approval":"never" }]from agents import Agent, Runner
from agents.mcp import MCPServerStreamableHttp
async with MCPServerStreamableHttp(name="agentrefills", params={
"url":"https://mcp.agentrefills.com/mcp",
"headers":{"Authorization":"Bearer sk_live_..."}}) as server:
agent = Agent(name="Shopper", mcp_servers=[server])
await Runner.run(agent, "Buy a $25 Amazon gift card")from langchain_mcp_adapters.client \
import MultiServerMCPClient
client = MultiServerMCPClient({"agentrefills":{
"transport":"streamable_http",
"url":"https://mcp.agentrefills.com/mcp",
"headers":{"Authorization":"Bearer sk_live_..."}}})
tools = await client.get_tools()from crewai_tools import MCPServerAdapter
cfg = {"url":"https://mcp.agentrefills.com/mcp",
"transport":"streamable-http",
"headers":{"Authorization":"Bearer sk_live_..."}}
with MCPServerAdapter(cfg) as tools:
Agent(role="Shopper", tools=tools)import { experimental_createMCPClient as mcpClient } from "ai";
import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp";
const mcp = await mcpClient({ transport:
new StreamableHTTPClientTransport(new URL("https://mcp.agentrefills.com/mcp"),
{ requestInit:{ headers:{ Authorization:"Bearer sk_live_..." } } }) });
const tools = await mcp.tools();Note: LangChain uses streamable_http (underscore); CrewAI and the MCP spec use streamable-http (hyphen). Check each SDK's current MCP docs before shipping.
Error taxonomy
Closed set. Every error is { code, message, hint, task_id?, retry_after? }. Branch on code; the hint is an actionable next step.
| Code | Meaning & next step |
|---|---|
POLICY_DENIED | Not allowed by policy. Do not retry as-is. |
BUDGET_EXCEEDED | Over the agent's cap. Lower the amount or wait. |
APPROVAL_REQUIRED | Parked for a human. Call request_approval or await the webhook. |
APPROVAL_REJECTED | Human declined. Do not retry the same purchase. |
OUT_OF_STOCK | Brand/denomination unavailable. Try another. |
ALREADY_RELEASED | get_code already called. Code returned once only. |
RETRYABLE | Transient. Wait retry_after seconds, retry the same call. |
| others | PAYMENT_FAILED, INVOICE_EXPIRED, PROVIDER_HOLD, NOT_FOUND, UNAUTHORIZED |