Connect your agent
Amnetic is agent-native. Your coding agent — Claude Code, Cursor, or any
MCP-capable client — connects to the marketplace over the
Model Context Protocol and gets the 13 core
MCP tools (the buyer loop enter_market / purchase, the ownership_* and
balance / list_images helpers, and the six seller tools) — plus the three
buyer-posting request tools where that surface is enabled. This page is the
deep per-client connection reference; the tools themselves — every parameter and
return shape — are single-sourced in the
MCP tools reference.
When your agent hits a knowledge or data gap, enter_market clones its
conversation context into a forgetful inner agent that runs inside our
walled exchange, evaluates real seller data, and returns a buy recommendation —
each suggested listing enriched with its public title, description, and price.
Your agent decides, then purchase buys exactly those listings and returns
ownership metadata. ownership_download retrieves the owned bytes, and the two
ownership_* tools let your agent re-access anything it already bought, in any
later session; balance checks your credit and
list_images lists the inner-agent images you can run. Everything the inner
agent saw is destroyed when the session ends; the only thing that crosses the
wall is the recommendation. You pay only for what you buy.
Hosted Seller's Agent
The hosted Seller's Agent answers buyer requests and prepares the subsets they ask for on a seller's behalf. It runs as two narrowly scoped roles rather than one over-privileged seller key: one reads the seller's catalog, talks with buyers, and drafts what's being asked for as a three-part Spec; the other executes the approved Spec and stages the resulting subset. Nothing goes out to a buyer, and nothing publishes, without the seller's approval.
The fastest path is the portal — one click, no keys. Sign in at the portal, open AI Agents → Seller's Agent, and click Start Seller's Agent. That single click registers and turns on every hosted role the agent needs; there's nothing to configure. The same button is also available from the Agents panel elsewhere in the portal.
This capability is enabled in production. It is not a pending deployment
gate: routes and tools 404 / are absent from tools/list only if the
recovery kill-switch (SELLER_TXN_ENABLED) is off (rollback:
.github/workflows/flag-rollout.yml).
The platform is the price authority: quote_dataset is the only price read
either role can use, and neither role chooses, invents, or silently changes a
number. A prepared subset stays pending until the seller reviews and approves
it in the portal; neither role can approve, accept payment, or claim delivery
on its own.
For the full REST state machine and seller review routes, see API, and for the seller-facing approval/subset flow see Selling derived listings. The MCP input/output contracts are in the MCP tools reference.
Advanced: manual registration
Most sellers never need this section — the portal's one-click Start Seller's Agent above does the same thing. Use manual registration only if you're integrating your own agent host in place of the hosted one, or scripting provisioning outside the portal.
Both roles (seller-front, the buyer-facing role, and seller-worker, the
role that builds the subset) can be registered and enrolled directly.
Registration and enrollment require the seller's Cognito ID token; an amn_
account key or an ephemeral amn_agent_ key cannot create, list, change, or
disable an enrollment.
First create or reuse the hosted registration at
https://hosted-agent.amnetic.ai:
GET /api/v1/agents
Authorization: Bearer COGNITO_ID_TOKEN
POST /api/v1/agents
Authorization: Bearer COGNITO_ID_TOKEN
Content-Type: application/json
{"role":"seller-worker"}
Use the returned registration id as agent_id on the marketplace edge:
GET /api/v1/accounts/agent-enrollments
Authorization: Bearer COGNITO_ID_TOKEN
POST /api/v1/accounts/agent-enrollments
Authorization: Bearer COGNITO_ID_TOKEN
Content-Type: application/json
{"agent_id":"RETURNED_HOSTED_REGISTRATION_ID","role":"seller-worker"}
Re-enrolling the same registration is idempotent and revokes its existing
episode credentials before future work. Disable an enrollment with
DELETE /api/v1/accounts/agent-enrollments/{enrollment_id}. Registration and
enrollment grant no independent authority to publish, approve, accept
payment, or enable the hosted Seller's Agent; the relevant product gate and
human review still apply.
The fastest path for buying with an agent is Claude Code — mint an
amn_ API key in the
portal, then register the server with one command:
claude mcp add --transport http amnetic \
https://market.amnetic.ai/mcp \
--header "Authorization: Bearer amn_YOURKEY"
After it finishes, Claude Code already has the marketplace tools — skip to The loop below. The rest of this page documents the endpoint and the per-client registration for Cursor, Claude Desktop, the claude.ai browser connector, and hand-rolled streamable-HTTP consumers. For the full list of tools and their shapes, see the MCP tools reference.
The endpoint
The MCP server lives on the same host, port (443), and TLS certificate as
the REST API — there is no special port to remember. It speaks two MCP
transports, so every client can use its native one:
- Streamable HTTP at
/mcp— the recommended transport for every client (Claude Code, Cursor, the claude.ai browser connector, ChatGPT, and other current MCP clients). - HTTP+SSE at
/sse— the original transport, kept only as a legacy fallback for older SDK-only clients (andmeno-research); new setups use/mcp.
| Environment | Host | Streamable HTTP (recommended) | HTTP+SSE (legacy fallback) |
|---|---|---|---|
| Production | https://market.amnetic.ai |
…/mcp |
…/sse |
| Staging (design-partner access) | https://market.staging.amnetic.ai |
…/mcp |
…/sse |
| Local dev | http://localhost:8081 |
…/mcp |
…/sse |
Pick the row for your environment and the recommended
/mcpcolumn — e.g.https://market.amnetic.ai/mcp. The older:8443port still answers for clients configured before the move, but the port-less URL is canonical.
Reading responses: Streamable HTTP tool calls can stream multiple frames
If you use a standard MCP client library (Claude Code, Cursor, Claude
Desktop, the official MCP SDKs for Python/TypeScript/Go,
mcp-remote, the claude.ai browser connector), you don't need to think about
this — your client handles it for you. This section is only for integrators
who hand-roll their own Streamable HTTP consumer against /mcp.
The /mcp endpoint uses the standard MCP Streamable HTTP wire format (the
server is built on the official
modelcontextprotocol/go-sdk),
so a single tool call's response can arrive as multiple SSE frames on one
streamed HTTP response, not just a single JSON body:
- Each frame is a standard SSE
event: messageblock whosedata:line is one JSON-RPC 2.0 message. - Intermediate frames are progress notifications (
method: "notifications/progress", noid). A long-running tool likeenter_market— which spins up an inner agent — emits these while it works. - The terminal frame is the JSON-RPC response: the object whose
idmatches your requestidand that carriesresult(orerror). This is the frame with the actual payload.
A correct consumer reads the stream to completion and uses the frame whose
id matches the request (equivalently: the frame carrying result/error).
A naive consumer that stops after the first data: frame silently gets a
progress notification — incomplete or empty data, with no error raised. This
is the one and only trap, and it only bites hand-rolled parsers.
Do not use this one-shot POST pattern against legacy /sse. The HTTP+SSE
transport is stateful: a raw client must first open the SSE GET, read the
server's endpoint event, POST initialize, POST
notifications/initialized, and only then send tools/list or tools/call to
that session endpoint. If tools/call is the first message on a fresh /sse
session, the server correctly rejects it as a call during session
initialization. Use an MCP SDK for /sse unless you implement that full
handshake.
Minimal correct consumer (Python, stdlib only — pick the matching JSON-RPC response, don't stop at frame one):
import json, urllib.request
def call_tool(endpoint, api_key, name, arguments, req_id=1):
body = json.dumps({
"jsonrpc": "2.0", "id": req_id,
"method": "tools/call",
"params": {"name": name, "arguments": arguments},
}).encode()
req = urllib.request.Request(endpoint, data=body, method="POST", headers={
"Authorization": f"Bearer {api_key}",
"Content-Type": "application/json",
# Accept BOTH: the server may answer with a bare JSON body or an SSE stream.
"Accept": "application/json, text/event-stream",
})
resp = urllib.request.urlopen(req, timeout=180)
raw = resp.read().decode()
# Bare-JSON answer (no streaming): use it directly.
if raw.lstrip().startswith("{"):
return json.loads(raw)
# SSE answer: scan every `data:` frame and return the JSON-RPC RESPONSE —
# the frame whose id matches our request (it carries result/error).
# Intermediate frames are progress notifications; do NOT stop at the first.
response = None
for line in raw.splitlines():
if not line.startswith("data:"):
continue
try:
msg = json.loads(line[len("data:"):].strip())
except json.JSONDecodeError:
continue
if isinstance(msg, dict) and msg.get("id") == req_id and (
"result" in msg or "error" in msg
):
response = msg
if response is None:
raise RuntimeError("stream closed without a matching JSON-RPC response")
return response
The rule of thumb: read until the stream closes, then pick the JSON-RPC message whose
idmatches your request. SendAccept: application/json, text/event-streamso you handle both a single JSON body and a multi-frame SSE stream. If you reach for an MCP client SDK instead of hand-parsing, all of this is handled for you.
Which surface are you connecting from?
| You use… | How it authenticates | Section |
|---|---|---|
| claude.ai (web browser) | OAuth — log in with your Amnetic account | claude.ai (browser) |
| Claude Desktop (Mac/Windows app) | Your amn_… API key, via a small bridge |
Claude Desktop |
| Claude Code (CLI / IDE) | Your amn_… API key as a header |
Claude Code |
| Cursor / other MCP client | Your amn_… API key as a header |
Cursor / generic MCP JSON |
Authenticate
MCP clients authenticate by sending your account API key as a standard bearer token on the transport:
Authorization: Bearer amn_YOURKEY
The server verifies the key once, when the connection is established. The key
never travels as a tool argument — it stays out of your agent's model
context, out of MCP client logs, and out of tool-call transcripts. A missing or
invalid bearer fails the connection with 401 before any tool runs.
To mint a key, see How to get an API key below.
Claude Code
Register the server with claude mcp add and the --header flag (re-run it with
a different URL to target another environment):
# Production
claude mcp add --transport http amnetic \
https://market.amnetic.ai/mcp \
--header "Authorization: Bearer amn_YOURKEY"
# Staging
claude mcp add --transport http amnetic \
https://market.staging.amnetic.ai/mcp \
--header "Authorization: Bearer amn_YOURKEY"
# Local dev
claude mcp add --transport http amnetic \
http://localhost:8081/mcp \
--header "Authorization: Bearer amn_YOURKEY"
Your agent now has the marketplace tools available — see the MCP tools reference for the full set.
Legacy SSE fallback. If you run an older client that predates streamable HTTP, the
/ssetransport still answers: swap--transport httpfor--transport sseand/mcpfor/sse(e.g.claude mcp add --transport sse amnetic https://market.amnetic.ai/sse --header "Authorization: Bearer amn_YOURKEY"). Prefer/mcpfor anything new —/sseis deprecated upstream and slated for removal.
amnetic CLI (optional)
The amnetic solution commands are a scriptable CLI wrapper around the same MCP
buyer tools. They use Streamable HTTP by default: pass the MCP base URL with
--mcp, and the CLI calls <base>/mcp for solution request,
solution purchase, solution ownership-list, and
solution ownership-download.
amnetic solution --mcp https://market.amnetic.ai request \
--api-key amn_YOURKEY \
--goal "Find a dataset of US retail foot traffic under $50"
amnetic solution --mcp https://market.amnetic.ai purchase \
--api-key amn_YOURKEY \
--listing-id LISTING_UUID \
--offer-id OFFER_UUID
amnetic solution --mcp https://market.amnetic.ai purchase \
--api-key amn_YOURKEY \
--listing-id LISTING_UUID \
--offer-id OFFER_UUID \
--renew-of GRANT_UUID
If you have old scripts that pass https://market.amnetic.ai/sse, the CLI
normalizes that legacy URL to https://market.amnetic.ai/mcp. The API key is
still sent only as Authorization: Bearer on the MCP transport; it is never a
tool argument.
solution ownership-download prints the download handle and fetches no
bytes — it is for scripting against the URL, size, digest and expiry yourself.
To actually move the object, use amnetic buyer download <listing-id>, which
transfers it as resumable ranged chunks and re-mints the URL when it expires
mid-transfer (see the API reference).
Cursor / generic MCP JSON
Add the server to .cursor/mcp.json (project) or ~/.cursor/mcp.json (global) —
the same url + headers shape works for any client that reads MCP JSON config:
{
"mcpServers": {
"amnetic": {
"url": "https://market.amnetic.ai/mcp",
"headers": { "Authorization": "Bearer amn_YOURKEY" }
}
}
}
Cursor supports environment interpolation in this file — use
"Authorization": "Bearer ${env:AMNETIC_KEY}" to keep the key out of a committed
config.
Claude Desktop
The Claude Desktop app (Mac/Windows) reaches a header-authenticated remote MCP
server through the mcp-remote
bridge. Open your Claude Desktop config —
~/Library/Application Support/Claude/claude_desktop_config.json (macOS) or
%APPDATA%\Claude\claude_desktop_config.json (Windows) — and add Amnetic under
mcpServers, then fully quit and reopen Claude Desktop:
{
"mcpServers": {
"amnetic": {
"command": "npx",
"args": [
"-y", "mcp-remote",
"https://market.amnetic.ai/mcp",
"--header", "Authorization:${AMNETIC_AUTH}"
],
"env": { "AMNETIC_AUTH": "Bearer amn_YOURKEY" }
}
}
}
Why the
envindirection: Claude Desktop on some platforms splitsargson spaces, which would mangleAuthorization: Bearer amn_…. Passing the header value through an environment variable (Authorization:${AMNETIC_AUTH}, no space) sidesteps that.mcp-remoteneeds Node.js (npx) on your PATH.
Once it reconnects, the Amnetic tools are available in Claude Desktop —
including inside Research. Ask Claude to research something and it can call
enter_market, show you the recommended listings and prices, and (with
your go-ahead) purchase the ones you want, then use ownership_download to
cite their contents.
claude.ai (web browser) — custom connector
In the browser app you add Amnetic as a custom connector and authenticate by logging in with your Amnetic account (OAuth) — no API key to paste, no config file. This is the path that lets Amnetic show up in claude.ai's Research.
- In claude.ai go to Settings → Connectors → Add custom connector.
- Paste the Streamable HTTP URL for your environment:
- Production:
https://market.amnetic.ai/mcp - Staging:
https://market.staging.amnetic.ai/mcp
- Production:
- Click Add. Claude auto-registers with the server and opens the Amnetic sign-in page — nothing to paste. Log in with the same Amnetic account you use for the marketplace and approve access. (If a Claude build asks for an OAuth client ID under Advanced settings, get it from your portal operator; leave the secret blank.)
- Back in claude.ai, enable the Amnetic connector for your chat (and for
Research). The tools —
enter_market,purchase,ownership_list,ownership_download,balance,list_images— are now available.
There's no separate key step: the connector is bound to the account you logged in as, and identity is derived from that login (never from a request field). Your account still needs credit to consult and buy — see Credits.
Funding & accounts. The browser connector signs you into an existing Amnetic account; if you don't have one yet, sign up first (the marketplace is invite-gated). Consults and purchases draw on that account's balance exactly like every other surface.
How to get an API key
API keys (the amn_… keys) are scoped to your account; identity is derived from
the key, never from a request body. Mint one in the portal
API-key panel — sign in with your Amnetic account and create a key. The
plaintext is shown exactly once — store it now. The server keeps only a
hash and the 8-character prefix. There is no MCP tool that mints keys.
Advanced integrators who can't use the portal can mint the same key over REST (it requires a Cognito ID token from your account sign-in):
curl -sS -X POST https://market.amnetic.ai/api/v1/accounts/api-keys \
-H "Authorization: Bearer <cognito-id-token>" \
-H 'Content-Type: application/json' \
-d '{"name":"my-agent"}'
# → { "id": "...", "prefix": "amn_xxxx", "name": "my-agent", "plaintext": "amn_…" }
Revoke a key over REST with DELETE /api/v1/accounts/api-keys/{id}, or manage
keys in the portal. See Authentication.
The claude.ai browser connector needs no key — it authenticates with Cognito OAuth when you add the connector and log in. The API key is only for header-authenticated clients (Claude Code, Cursor, Claude Desktop).
The loop: enter_market → purchase
Once connected, enter_market and purchase form the whole buyer loop;
the ownership_* pair covers re-access afterwards.
1. enter_market
Hand your agent's working context into the wall. You pass the conversation
messages (the standard chat-message stream every model already produces); the
inner forgetful agent clones that context, runs against the real catalog, and
returns a recommendation — each suggested listing enriched with its public
catalog metadata, no free-form inner-agent text.
Input:
{
"messages": [
{ "role": "system", "content": "You are helping a retail analytics team." },
{ "role": "user", "content": "Find a dataset of US retail foot-traffic, weekly granularity, under $50. At least 200 locations, covers 2025-2026. Public census data is too coarse." }
],
"llm_model": "claude-opus-4-6",
"image_id": "sha256:…",
"required_rights": {
"use": "commercial"
}
}
Only messages is required, and it must include at least one user message.
llm_model (optional) picks the LLM the inner agent runs on and must exactly
match a supported Claude model ID such as claude-opus-4-6 (the default),
claude-sonnet-4-6, or claude-haiku-4-5; all supported models run through
AWS Bedrock. Omit it for the platform default. image_id (optional) picks the inner-agent image — call
list_images to see what's available, or omit it for the default image.
required_rights is optional and accepts minimums for use,
redistribution_scope, derived_display, training, training_serve,
training_weights, term, and attribution. It is enum-only; omitted
dimensions mean “don't care.” Omitted, null, and {} preserve the legacy
behavior. While licensing remains production-dark, the live enter_market
schema omits this argument entirely—inspect tools/list instead of sending it
optimistically.
Pre-ratification boundary. The
menublock in the example below is always-on pre-purchase metadata, including in production. The optionalrequired_rightscomparison and operative exact-text surface remain gated pending counsel ratification. A menu is not operative license text, a grant, or acceptance.
Output:
{
"decision": "buy",
"recommended_listings": [
{
"listing_id": "9dad1234-5678-90ab-cdef-1234567890ab",
"document_type": "data",
"title": "US Retail Foot-Traffic — Weekly, 500 locations",
"description": "Store-level weekly visit counts for 500 US retail locations, 2025–2026.",
"category": "retail",
"price_cents": 4500,
"currency": "usd",
"seller_name": "Mobility Metrics Lab",
"data_format": "text/plain",
"data_size_bytes": 18432,
"tags": ["retail", "foot-traffic", "weekly"],
"status": "active",
"created_at": "2026-06-01T14:23:11Z",
"updated_at": "2026-07-10T09:41:02Z",
"menu": [
{"offer_id": "7ecb1234-5678-90ab-cdef-1234567890ab", "offer_key": "standard", "price_cents": 4500, "currency": "usd", "sellable": true}
],
"rights_fit": {
"band": "fit",
"best_offer": {
"offer_id": "7ecb1234-5678-90ab-cdef-1234567890ab",
"offer_key": "standard",
"terms": { "use": "commercial", "redistribution_scope": "entity", "derived_display": "none", "training": "none", "training_serve": "none", "training_weights": "none", "term": "perpetual", "exclusivity": "none", "attribution": "not_required" },
"price_cents": 4500,
"currency": "usd"
}
}
}
],
"recommended_total_cents": 4500
}
Each recommended listing carries its public catalog metadata — title,
description, category, price, seller display name, tags, format, size, status,
and timestamps — looked up platform-side, so the recommendation is decidable on
its face. It also carries the always-on menu: in the current slice, the
materialized base rung's terms, price, currency, and immutable offer id.
The separate exact-text and rights-fit surfaces are not part of this phase and
remain unavailable in production; do not treat the menu's enum metadata as
operative terms or purchase from it alone. After reviewing the operative
terms through an available exact-text surface, use those selectors in a later
explicit purchase. The recommendation does not buy anything, grant rights, or
record acceptance. With the non-empty required_rights shown above, the
platform compares each visible ladder mechanically and adds rights_fit.
band is one of fit, partial, no_fit, or unknown; only fit has a
best_offer. The base-rung summary is copied from the materialized menu with
its offer id. It is a
provisional comparison, not legal advice, a compliance finding, permission, a
reservation, or a grant.
In active rights-fit mode, recommended_total_cents is the sum of fitting
best_offer prices—the $45 base rung above therefore produces a $45 total.
Rows without a fit contribute zero, and an all-no-fit response emits the field
explicitly as 0. If required_rights is omitted, null, or {}, the legacy
standard-price sum remains unchanged (including historical omission of an
all-zero total). Both meanings are advisory snapshot arithmetic. The
response does not include raw seller ids, document body,
data_ref, data_dictionary, inner-agent reason, or confidence scores. The
inner agent cannot send prose back across the wall; everything free-form it
learned dies with the session. decision: "buy" means the inner agent found a
content match; it is not a rights verdict. In active rights-fit mode a buy may
therefore contain zero full fits—inspect every rights_fit and do not purchase a
partial/no-fit/unknown row. decision: "no_match" means no content match and the
recommended list is empty; you pay nothing. A no-match result may include a
class-only gap_report:
Inside the wall, the forgetful agent can compare the listing's license menu as
well as its data. Its internal get_listing response always carries a non-empty
top-level menu: currently the materialized base rung with its enum-only terms,
price, currency, and offer id. The platform re-reads the same current
listing/offer records after the wall returns and attaches the menu shown above
to each outer recommendation. The inner agent still returns only listing ids;
it cannot author or alter these fields.
After reviewing the operative exact text, copy best_offer.offer_id into the
later purchase. Do not infer rights from the
recommendation. Purchase re-resolves the quote, and only the returned grant is
license evidence.
Large listings: bounded windows inside the wall
A listing can be larger than the platform renders whole. Inside the wall the
forgetful agent then reads it in bounded windows — a byte range for a text
document, one row group for a dataset — through the same internal
get_listing call it already uses. There is no separate tool and nothing changes
on the surface you call. Two consequences show up in your outcomes:
- An oversized body no longer fails the examination. Where ranged reads are
enabled it previews from targeted reads instead; where it defeats even that, it
comes back as a
too_large_to_previewblock naming the ceiling it exceeded. Either way the agent gets a usable answer, and re-reading a listing it has already examined costs nothing further against the session's examination ceiling. - Windowed reading is metered by bytes, per session. Once that budget is
spent, further windows are refused and the agent is told to decide with what it
has already examined. The session is not killed — it finishes and returns
its recommendation or
no_matchnormally. If an agent settles earlier than you expected on a very large listing, this is the most likely reason.
Windows are a sampling primitive: large non-columnar bodies are sample-only in the wall today, and opaque uploaded files (PDF, DOCX, zip, a raw CSV file) are metadata-only at any size. Inside the wall is the full per-format picture.
Daily enter_market session quota follows that same final response boundary:
only decision: "buy" with at least one recommended_listings entry consumes
the daily quota. no_match, rejected requests, setup failures, timeouts, and
platform faults do not consume daily session quota; concurrency limits still
apply while the session is active.
{
"decision": "no_match",
"gap_report": {
"unmet": [
{ "class": "freshness" },
{ "class": "granularity" },
{ "class": "price" }
]
}
}
gap_report.unmet[].class is closed vocabulary (coverage, freshness,
granularity, format, price, trust, rights). It never carries notes, reasons, or
other inner-agent prose.
If enter_market fails, treat it as a tool error with sanitized text. Use the
structured error_code when present (insufficient_credit, rate_limited,
buyer_context_invalid, platform_terminated, platform_error, and related
bounded codes) rather than parsing raw prose. Error responses do not expose
seller content, inner-agent reasoning, raw stream details, tokens, URLs, or stack
traces. A debug_id, when present, is safe to share with support.
2. purchase
You decide. Buy exactly the listings you want. The debit is atomic
(all-or-nothing), and the response confirms the ownership handles you can
re-access with ownership_download.
The MCP purchase tool spends wallet credit by default. For a single item, set
funding_mode to card to start hosted card checkout
and receive checkout_url, session_id, status, and card funding fields.
Input:
{
"items": [{
"listing_id": "9dad1234-5678-90ab-cdef-1234567890ab",
"offer_id": "7ecb1234-5678-90ab-cdef-1234567890ab"
}]
}
Offer-aware purchases use items instead:
{
"items": [
{
"listing_id": "9dad1234-5678-90ab-cdef-1234567890ab",
"offer_id": "immutable offer UUID",
"renew_of_grant_id": "optional grant UUID to renew"
}
]
}
Output:
{
"purchases": [
{
"listing_id": "9dad1234-5678-90ab-cdef-1234567890ab",
"seller_id": "b1c2d3e4-…",
"title": "US Retail Foot-Traffic — Weekly, 500 locations",
"price_cents": 4500,
"data_format": "text/plain",
"data_size_bytes": 52418,
"outcome": "purchased",
"offer_id": "7ecb1234-5678-90ab-cdef-1234567890ab",
"offer_key": "standard",
"terms_hash": "sha256:…",
"grant_id": "grant UUID"
}
],
"total_cents": 4500,
"balance_cents_after": 500
}
Your credit balance is debited by total_cents. A retry for rights you already
hold returns outcome: "already_licensed" instead of charging again. If the
balance can't cover the order, nothing is purchased and nothing is debited.
Card modes are single-listing checkout starts: the purchase settles after the
payment webhook. card charges the full listing price by card and preserves
existing wallet credit; ownership is granted when settlement completes.
Offer-level conflicts return structured error_code, listing_id, and detail
fields (offer_unavailable, price_changed, or renewal_invalid).
offer_unavailable.detail.live_offers includes replacement offers with terms,
terms schema version, DLS version, and price.
Arbitrary uploaded-file listings must have a clean malware scan before purchase;
files still pending scan, infected, or failed closed are treated as unavailable.
3. Re-access what you bought: ownership_list + ownership_download
A purchase creates durable ownership/download access for the listing. Usage rights
are governed by the license grant returned by purchase and may expire or require
renewal. When a purchase result has left your agent's context (a later session,
a different machine), the two ownership tools recover the owned listing without
buying again:
ownership_list(no arguments) — every listing your account owns, enriched with title, description, and the price you paid:{ "owned": [ { "listing_id": "9dad1234-…", "title": "US Retail Foot-Traffic — Weekly, 500 locations", "description": "…", "category": "datasets", "price_paid_cents": 4500, "currency": "usd", "acquired_at": "2026-06-04T18:21:09Z" } ] }ownership_download({ "listing_id": "…" }) — a short-lived presigned download URL for a listing you own. Fortext/plainpayloads up to 256 KiB, the response also includesbodyinline:{ "download_url": "https://…", "data_format": "text/plain", "data_size_bytes": 52418, "expires_at": "2026-06-04T18:26:09Z", "total_size_bytes": 52418, "resumable": true, "body": "location_id,week,visits\nSAT-001,2026-W01,1843\n…" }Read
expires_atfor the URL's deadline instead of assuming one, and usetotal_size_bytes(the exact object being served) to plan a large transfer. The handle is re-mintable: if the URL expires mid-download, call the tool again and resume with an HTTPRangerequest. The exception isresumable: false— a delivery-enforced listing, where every call mints a fresh signed bundle behind a rate limiter, so use the URL you were given rather than polling.Refuses anything your account hasn't bought, or any arbitrary uploaded file whose latest malware scan is not clean.
The same surface exists over REST if you're outside an agent: GET /api/v1/ownership and GET /api/v1/ownership/{listingId}/download. Both
paths are ownership-checked and identity comes from your bearer credential. See
the API reference for the full handle, and use amnetic buyer download <listing-id> if you'd rather not implement the ranged-resume loop yourself — it
already does the chunking, re-minting and checksum verification.
Helpers: balance + list_images
Two read-only tools support the loop:
balance(no arguments) — your spendable credit, e.g.{ "balance_cents": 4200, "currency": "USD" }. Check it beforepurchaseinstead of discovering an unaffordable bundle through a failed buy.list_images(no arguments) — the inner-agent images you can run viaenter_market'simage_id. Each entry carries itsimage_id(a sha256 digest), aname, adescription, anddefault: truefor the one used when you omitimage_id:{ "images": [ { "image_id": "sha256:…", "name": "default-buyer-agent", "description": "The default Amnetic buyer agent.", "default": true } ] }
Credits
New accounts start with a $0 balance. Your account has one
balance, and everything an enter_market run needs draws on it:
- the
enter_marketpre-run affordability check, - the forgetful inner-agent session itself (compute + LLM run-cost, gated by the orchestrator's credit-cap check), and
- the final
purchasedebit when your agent finds a match.
Fund it in the portal with a Stripe top-up, or have the
exchange grant credit during onboarding / design-partner setup. The balance
MCP tool is read-only — it reports your credit but cannot add to it, so funding
is always a portal action. A single top-up is enough to run the whole loop —
exploring (run-cost) and buying draw down the same balance, so a long
exploration reduces the buying power left for purchases.
Next
The tools your client now has — every parameter and return shape — are in the MCP tools reference. For the flows that have no MCP tool (custom buyer-image push, buyer request posting, the signed audit record, dataset intake), see the advanced API reference.