Why agents and samples fit.
Most commerce APIs are built around a payment step, and payment is where agents get stuck: someone has to approve a charge. On Handsel there is no charge. Every listing is free, so checkout is only two questions: is this person eligible, and did they consent?
Consent is encoded in the key your human gives you. It says which categories you may claim from, how many claims you get per 30 days, what data a brand may see, and when the key expires. Inside those bounds your agent can act on its own. Humans use the same catalog through the website, and both get the same rules.
Zero-cost checkout
Nothing to pay means nothing to approve. Eligibility and consent are the whole checkout.
Consent-scoped
Keys are capped, scoped to categories, revocable in one tap, and set to expire.
Agents and humans
The same catalog, rules and claim limits whether a person clicks or an agent calls a tool.
Live in three steps.
Mint an agent key
On /me, open Agent keys and choose New key. Pick a monthly cap, the allowed categories, what data to share, and an expiry. The
hsk_…secret is shown once, so copy it somewhere safe.Add the MCP server
Point your MCP client at
https://handsel.co/mcpwith the key as a Bearer token.
Connect your client
claude mcp add --transport http handsel https://handsel.co/mcp \ --header "Authorization: Bearer hsk_..."
Then run /mcp inside Claude Code to confirm handsel is connected and its five tools are listed.
{
"mcpServers": {
"handsel": {
"command": "npx",
"args": [
"-y", "mcp-remote",
"https://handsel.co/mcp",
"--header", "Authorization: Bearer hsk_..."
]
}
}
}Or add it as a custom connector in Settings, under Connectors, using the URL above. Restart Claude Desktop after editing the config file.
{
"mcpServers": {
"handsel": {
"type": "http",
"url": "https://handsel.co/mcp",
"headers": { "Authorization": "Bearer hsk_..." }
}
}
}Works with any client that supports MCP Streamable HTTP. Leave out headers for read-only, anonymous access.
# List the tools curl -s https://handsel.co/mcp \ -H "content-type: application/json" \ -H "Authorization: Bearer hsk_..." \ -d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}' # Search for samples (works without a key) curl -s https://handsel.co/mcp \ -H "content-type: application/json" \ -d '{"jsonrpc":"2.0","id":2,"method":"tools/call", "params":{"name":"search_samples","arguments":{"category":"drink","limit":3}}}'
Five tools, one endpoint.
The server speaks MCP over Streamable HTTP: JSON-RPC 2.0 requests sent with POST /mcp, answered with plain JSON responses. Supported methods are initialize, notifications/initialized, tools/list, tools/call and ping.
Auth: send Authorization: Bearer hsk_…. search_samples and get_sample work without a key. Every other tool acts for a member, so it needs one. Tool results come back as JSON in a text content block.
querystringoptionalFull-text search over title, tagline and brand.categorystringoptionalOne of beauty, food, drink, pet, baby, wellness, home, software, media, services.kindstringoptionalphysical,digitalorservice.limitnumberoptionalMaximum results to return.
{
"samples": [{
"id": "smp_k3v9",
"title": "Cold-brew concentrate",
"category": "drink",
"kind": "physical",
"value_cents": 1400,
"remaining": 212,
"demo": false,
"brand": { "name": "Northbound" }
}]
}idstringA sample id such assmp_k3v9.
{
"sample": {
"id": "smp_k3v9",
"description": "Two 8oz bottles…",
"regions": ["US"],
"subscribe_price_cents": 2400,
"subscribe_interval": "month",
"status": "live"
}
}idstringThe sample to claim. Checked against the key's cap, categories and expiry, and the member's claim rules. Demo listings can't be claimed.
{
"claim": {
"id": "clm_7d2q",
"status": "claimed",
"code": null
}
}
// digital samples may return a redeem "code"- None. Returns the member's claims, newest first, with any feedback already left.
{
"claims": [{
"id": "clm_7d2q",
"status": "shipped",
"via": "agent",
"sample": { "title": "Cold-brew…" },
"feedback": null
}]
}claim_idstringratinginteger, 1 to 5would_buybooleancommentstringoptionalRelay the human's own words. Feedback is never required to be positive.
{
"feedback": {
"claim_id": "clm_7d2q",
"rating": 3,
"would_buy": false,
"comment": "Too sweet for us."
}
}Raw JSON-RPC
{
"jsonrpc": "2.0", "id": 3, "method": "tools/call",
"params": { "name": "claim_sample", "arguments": { "id": "smp_k3v9" } }
}Prefer plain HTTP?
Everything the MCP server does is also available as JSON over HTTP. Errors look like {"error": "message"} with a 4xx status. Authenticate with the same Bearer key, or with the browser session cookie.
{samples}.{sample}.{claim: {id, status, code?}}.{rating, would_buy, comment}. Never gated on positivity.{url}. The human finishes subscribing; agents never sign up for paid plans.Try it
This sends a real request from your browser to this server.
// The response will appear here
DemoShowcase listings come back with "demo": true. They're here to show how Handsel works while real brands onboard, so claiming one returns 409. Skip them when choosing for your human.
Permission, scoped.
An agent key is a standing permission slip from a member. It is the only way an agent can act for someone, and every limit on it is checked on every claim.
| Property | What it means |
|---|---|
| Scoped | Only the categories the member picked, for example beauty and pet. |
| Capped | At most monthly_cap claims (1 to 20) per rolling 30 days. |
| Revocable | The member can revoke a key on /me at any time. Revoked keys fail with 401 right away. |
| Expiring | Every key expires after 1 to 365 days. There are no permanent keys. |
| Minimal sharing | share lists what brands may receive: "postal" (ship-to address) and/or "prefs" (taste profile). Nothing else leaves Handsel. |
Claim rules
These apply to every claim, from a person or an agent:
- One per sample per person. A second claim on the same sample returns 409.
- Six claims per member per 30 days across all keys and the website. Keys can be set lower.
- Physical samples need an address on the member's profile, otherwise 422.
- The sample must be live, with stock remaining, and not a demo listing.
Found by machines.
Agents that land on Handsel without instructions can discover everything from two well-known files.
When the answer is no.
Errors are JSON with a readable message. Over MCP, the same message comes back as a tool error (isError: true), so your agent can explain it to the human.
| Status | Meaning | What to do |
|---|---|---|
| 401 | Missing, invalid, revoked or expired key | Ask the human for a new key. |
| 403 | Category not allowed by this key | Don't retry with another key. Ask the human. |
| 404 | Sample or claim not found | Search again. The listing may have ended. |
| 409 | Already claimed, sold out, or a demo listing | Treat as done, or skip the demo. Suggest an alternative. |
| 422 | Physical sample, but no shipping address | Ask the human to add an address on /me. |
| 429 | The key's monthly cap or the member's 6-per-30-days limit is reached, or you hit the per-IP rate limit | Stop claiming until the window resets. For rate limits, wait a minute and slow down. |
Shop like you mean it.
Brands pay to put real product in real hands. Keep the network worth joining.
Only claim what they'd want
Match the member's stated preferences, allergies and household. Volume is not a goal.
Report honestly
Relay the human's real opinion. Never invent ratings, and never write feedback the human didn't give.
Never resell
Samples are personal gifts. Reselling, bulk claiming or claiming for others gets keys and accounts closed.
Leave money to humans
Hand subscription links to your human. Don't start paid plans or accept terms on their behalf.
Full rules are in the Agent Use Policy.