HOLD for AI agents
Beta, invite onlyYour AI assistants,
paid from HOLD.
Connect Claude, ChatGPT or Cursor to your account. Your assistant checks your balance, finds the hotel, lines up the payment and pays for the APIs it needs, inside the limits you set.
Connect in three steps
One address for every assistant:
https://api.hihodl.xyz/mcp
Claude
Add a connector
In Claude, open Settings, then Connectors, and choose Add custom connector.
Paste the address
Name it HOLD and paste https://api.hihodl.xyz/mcp. Then press Connect.
Approve on your phone
A HOLD page opens with a code. Approve it in the HOLD app and you are back in Claude.
Claude Code
Add the server
In a terminal, run:
claude mcp add --transport http hold https://api.hihodl.xyz/mcpSign in
In Claude Code, type /mcp, pick hold and sign in. A HOLD page opens with a code.
Approve on your phone
HOLD shows it as Unverified app, because it signs in through your own computer. That is expected. Approve it in the HOLD app.
ChatGPT
Add a connector
In ChatGPT settings, create a custom connector for a remote MCP server.
Paste the address
Use https://api.hihodl.xyz/mcp and choose OAuth to sign in.
Approve on your phone
The HOLD page shows a code. Approve it in the HOLD app.
Cursor
Open your MCP settings
Add a server to Cursor's mcp.json, globally or for one project.
{
"mcpServers": {
"hold": { "url": "https://api.hihodl.xyz/mcp" }
}
}Log in
Cursor asks you to log in to HOLD. A HOLD page opens with a code.
Approve on your phone
Approve it in the HOLD app and the tools show up in Cursor.
What happens when you connect
A code on screen
Your assistant opens a HOLD page with a 6 character code and a QR. Nobody signs in to HOLD on the web: the page only waits for your phone.
The same code in the app
Scan the QR, or tap the button on a phone, and HOLD opens with the same code and the name of the assistant asking. The request waits 10 minutes.
You choose the permissions
Keep the ones you want, drop the rest, and approve with Face ID. The page sends you back to your assistant, connected. Paying by itself is not on this list: you turn it on later in the app.
What an assistant can do
It never moves your money without your limits or your approval.
Six permissions. You pick five of them when you connect. The sixth, Pay within limits, is never asked for at connect. You turn it on later for each assistant in the HOLD app, under Settings > AI assistants, and it works at once. Turn it off there and payments stop at once.
read
See your money
Your balances, your recent activity and your @handle, name and display currency.
Moves nothing.
search
Search
Hotels for your dates, flights, and paid APIs it could use for you.
Moves nothing.
markets
Markets
Live prices, your portfolio with what you paid, the day's biggest movers, Savings rates and a quote for a conversion.
Reads only. Conversions, investing and taking money out of Savings are proposals, under Propose payments.
request_money
Ask for money
Makes a single use payment link in dollars, paid into your account, for whoever owes you.
Money only comes in.
propose_payments
Propose payments
Lines up a payment to a HOLD @handle, a hotel, a flight, an Amazon or eBay product, a conversion, money into Savings or a stock, or money out of Savings. It lands in your HOLD app and you approve it with Face ID, or decline it.
Nothing moves until you approve. A proposal expires after 24 hours.
pay
Pay within limits
Pays for APIs on the sites you allowed, and sends dollars or euros to the people you allowed, without asking each time. No assistant gets it when it connects: you turn it on later, per assistant, in the HOLD app under Settings > AI assistants. Turn it off there and payments stop at once.
Only inside the limits you set. Over a limit, or to a site or person not on its list, it asks you first.
Limits you set
For an assistant with the pay permission. Two layers: one amount set aside for all of them, and each assistant’s own controls on top.
Money set aside
You set aside between $10 and $500 ($50 unless you change it) once, for every assistant together, in USDC on Base. That is the most they can ever spend, whatever else happens.
Per day
Each assistant has its own daily budget, $5 to start and up to $100. It counts the last 24 hours, so there is no midnight to wait for.
Per payment
The most one payment can be, $1 to start and never above the daily budget. The assistant also names its own maximum on every call; if a site asks for more, nothing is paid.
Sites
An assistant pays by itself only on the sites you list, up to 20, by exact name: allowing api.example.com does not allow example.com. Any other site, it asks you first.
People
Up to 20 @handles it may send to without asking, inside the limits. Any other person, it asks you first.
Every payment, in view
Every payment is in your Activity, and from $1 you get a notification. If a paid call fails, the money comes back to you.
Euros too
Set aside euros as well, in EURC on Base, with their own daily budget and per payment limit, and your assistant can send euros to the people you allowed. Paid sites always charge in dollars.
Over a limit, it asks
A payment over a limit, or to a site or person not on the list, is not refused and not paid: it lands in your HOLD app. Approve it and HOLD pays it once; tap Always allow and that site or person goes on the list.
The limit
Cards and payouts are blocked.
Gift cards, prepaid and virtual cards, push to card, Venmo, PayPal and bank payouts are refused, even on a site you allowed, and even if you approve them. An assistant’s budget pays for services; it never turns into cash somewhere else.
An approval never lifts the money you set aside or your balance either. And HOLD can pause payments by assistants at any time; while paused, nothing is charged.
For developers
The reference
An MCP server over Streamable HTTP at https://api.hihodl.xyz/mcp, with OAuth 2.1. A token sees only the tools its permissions reach. Amounts are decimal strings, never floats.
Rate limits: each assistant gets 60 tool calls and 300 messages a minute. Connecting has its own limits, such as 20 client registrations an hour. Over a limit you get 429 with Retry-After.
Tools
get_balances
Balances · read · read only
get_balances
Balances · read · read only
Your HOLD accounts and what each holds, plus the total in your display currency. Amounts are decimal strings.
No inputs.
get_recent_activity
Recent activity · read · read only
get_recent_activity
Recent activity · read · read only
Recent money movements, newest first: date, what, who, signed amount (negative is money out), currency.
limit?
integer 1 to 20
How many movements (default 10)
days?
integer 1 to 90
How far back, in days (default 30)
get_profile
Profile · read · read only
get_profile
Profile · read · read only
Your HOLD @handle, name and display currency.
No inputs.
search_stays
Search hotels · search · read only
search_stays
Search hotels · search · read only
The 5 best bookable hotels for the dates, with the total for the stay and the price range a night.
city?
string
City, e.g. Lisbon (city or query is needed)
query?
string
An area or a landmark, if not a city
checkIn
YYYY-MM-DD
Check-in date
checkOut
YYYY-MM-DD
After checkIn
adults?
integer 1 to 8
Default 2
currency?
"USD" | "EUR"
Default USD
search_flights
Search flights · search · read only
search_flights
Search flights · search · read only
The 5 cheapest flights, one way or return, with airline, times, stops, bags and the price with HOLD's fee in it. Offers expire about 30 minutes after the search.
from
string
IATA code (MAD) or city
to
string
IATA code (BCN) or city
date
YYYY-MM-DD
Departure
return?
YYYY-MM-DD
Return, for a round trip
adults?
integer 1 to 4
Default 1
find_paid_services
Find paid APIs (x402) · search · read only
find_paid_services
Find paid APIs (x402) · search · read only
Searches Coinbase's x402 Bazaar for paid APIs HOLD can pay (USDC on Base): host, name, price per call, URL, method and an example body when listed.
query
string, 120 max
What you need, e.g. "weather forecast" or "web search"
maxUsdPrice?
USD decimal string ("0.05")
Only services at most this per call
get_prices
Prices · markets · read only
get_prices
Prices · markets · read only
Live prices in USD for tickers (BTC, ETH, SOL, LINK...). Tickers HOLD cannot price are listed in unpriced.
symbols
string[], 1 to 20
Tickers, e.g. ["BTC","ETH","SOL"]
get_portfolio
Portfolio · markets · read only
get_portfolio
Portfolio · markets · read only
What the user holds across their HOLD accounts, by token: amount, price, value in USD and, where HOLD knows it, the average cost and the profit or loss. Also the total in their display currency.
No inputs.
get_market_movers
Market movers · markets · read only
get_market_movers
Market movers · markets · read only
The tokens HOLD lets people buy that moved most in the last 24 hours, gainers and losers, with price and change in percent.
limit?
integer 1 to 9
How many gainers and losers (default 3)
get_savings_rates
Savings rates · markets · read only
get_savings_rates
Savings rates · markets · read only
The live yearly rates of HOLD Savings, per stablecoin: apy is what the user earns, after HOLD's share of the interest; grossApy is the venue's rate. Rates move; they are not promised.
No inputs.
quote_swap
Quote a swap · markets · read only
quote_swap
Quote a swap · markets · read only
A live estimate of converting one token into another in HOLD, on Solana through Jupiter: what the user would get, the least they would get, HOLD's fee and the price impact.
from
SOL | USDC | USDT | EURC
What to sell
to
SOL | USDC | USDT | EURC
What to buy
amount
decimal string ("25", "0.5")
How much of from
create_payment_link
Create a payment link · request_money
create_payment_link
Create a payment link · request_money
A single use HOLD payment link for a fixed amount in USD, paid into the user's account. Never sends the user's money.
amount
decimal string, cents at most ("12.50")
e.g. "25.00"
currency
"USD"
Payment links are priced in dollars
note?
string, 140 max
What it is for; the payer sees it
propose_send
Propose a payment · propose_payments
propose_send
Propose a payment · propose_payments
Proposes paying a HOLD user by @handle, in USD or EUR; the user approves or declines in the app with Face ID. With the pay permission, an amount to a handle the user allowed, inside the limits of its currency, is sent at once (status paid). Over the limits, or to someone not on the list, it returns status waiting_for_approval and an actionId; read the outcome with get_action. Reached by propose_payments or pay. With pay alone, a send that would need approval is refused (not_allowed) instead of becoming a proposal.
toHandle
string
The HOLD @handle to pay: a to z, 0 to 9, _ . -, 2 to 50 characters, @ optional
amount
decimal string, cents at most ("12.50")
e.g. "20.00"
currency
"USD" | "EUR" | "USDC" | "EURC"
USDC and EURC are the same money as USD and EUR
note?
string, 140 max
Short note for the payment
propose_booking
Propose a booking · propose_payments
propose_booking
Propose a booking · propose_payments
Proposes a stay (from search_stays), a flight (from search_flights) or an Amazon or eBay product. Nothing is paid: the user reviews and pays in the app.
kind
"stay" | "flight" | "product"
What to book
hotelId?
string
stay: from search_stays
checkIn?
YYYY-MM-DD
stay
checkOut?
YYYY-MM-DD
stay
adults?
integer 1 to 8
stay: default 2
roomId?
string
stay: a specific room, if known
currency?
"USD" | "EUR"
stay: the currency search_stays priced in
offerId?
string
flight: from search_flights
url?
string
product: an Amazon or eBay product link
propose_swap
Propose a swap · propose_payments
propose_swap
Propose a swap · propose_payments
Proposes converting one token into another. Nothing moves: HOLD opens its own convert screen filled in and the user confirms with Face ID.
from
SOL | USDC | USDT | EURC
What to sell
to
SOL | USDC | USDT | EURC
What to buy
amount
decimal string ("25", "0.5")
How much of from
propose_invest
Propose an investment · propose_payments
propose_invest
Propose an investment · propose_payments
Proposes putting dollars in Savings, or buying a tokenised stock from the user's USDC (HOLD checks the user can buy stocks where they live). Nothing moves until the user confirms in the app.
product
"savings" | "xstock"
Savings to earn interest, or a tokenised stock
symbol?
string
savings: USDC, USDT, USDG, USDS, PYUSD (default USDC). xstock: AAPL, TSLA, NVDA, MSFT, AMZN, GOOGL, META, SPY, QQQ, COIN, MSTR, AMD, NFLX
amount
decimal string, cents at most ("12.50")
Dollars. xstock: 1 to 100
propose_withdraw_savings
Propose taking money out of Savings · propose_payments
propose_withdraw_savings
Propose taking money out of Savings · propose_payments
Proposes moving dollars from Savings back to the main account, from the stablecoin the user holds most of in Savings. Nothing moves until the user confirms in the app.
amount?
decimal string, cents at most ("12.50")
Dollars. Leave it out to take all of that one stablecoin out; other stablecoins in Savings stay
get_action
Check a proposal · propose_payments · read only
get_action
Check a proposal · propose_payments · read only
Reached by propose_payments or pay. The status of a proposal or a payment waiting for approval: pending, approved (HOLD is paying it now), completed (for a payment HOLD made, result has the payment and, for an x402 call, the paid response), failed (result.error says why), declined or expired (24 hours).
id
uuid
The id a propose_* tool returned, or the actionId of a payment waiting for approval
pay_x402
Pay for an API (x402) · pay
pay_x402
Pay for an API (x402) · pay
Fetches an https URL and, if it answers 402 Payment Required, pays it in USDC on Base from the user's HOLD balance: only allowed hostnames, within the per payment limit, the daily budget and maxAmount. Over a limit or on a site not on the list, nothing is paid and it returns status waiting_for_approval with an actionId; once the user approves, HOLD makes the call and pays it once, and get_action returns the response. If the paid call fails, the money goes back.
url
https URL
The paid resource; its hostname must be allowed
method?
"GET" | "POST"
Default GET
body?
string, 16 KB max
POST only: the JSON body as a string
maxAmount
USD decimal string ("0.05")
The most you will pay; if the site asks more, nothing is paid
idempotencyKey?
string 8 to 128
The same key within 60 seconds never pays twice
get_spending
Spending limits · pay · read only
get_spending
Spending limits · pay · read only
paysEnabled, dailyBudget, spentToday (last 24 hours), perPaymentLimit, allowedDomains and remainingOnChain (what is left of the budget for every assistant), in USD. When the user set a euro budget, eur holds the same figures for euro sends.
No inputs.
A name with ? is optional. Permission per tool: read (See your money), search (Search), markets (Markets), request_money (Ask for money), propose_payments (Propose payments), pay (Pay within limits).
Paying APIs with x402
With the pay permission, pay_x402 fetches a URL and, when it answers 402 Payment Required, pays it: scheme exact, USDC on Base, x402 v1 or v2.
It pays only an allowed hostname, over https, within the per payment limit, the daily budget and the maxAmount of the call. The same idempotencyKey within 60 seconds returns the first payment instead of a second one.
find_paid_services searches Coinbase’s x402 Bazaar for APIs HOLD can pay, and get_spending tells the assistant what it has left before it tries.
Over a limit, or on a site not on the list, nothing is paid and the tool returns status: "waiting_for_approval" with an actionId. Once the user approves, HOLD makes the call and pays it once; get_action then returns completed with the paid response, or failed, declined or expired. While payments are paused, the pay tools return paused and nothing is charged; do not retry straight away.
Getting paid with x402
Any agent can pay a HOLD user in USDC on Base, straight to their own address. By @handle, the user’s personal link must be on Base and active. Amounts go from $0.01 to $1,000. Ask without a payment header and you get the 402:
curl -i "https://api.hihodl.xyz/x402/pay/@yourhandle?amount=1.50¬e=Thanks"Sign the EIP-3009 authorization it describes and send the same request again with PAYMENT-SIGNATURE (v2) or X-PAYMENT (v1):
curl -i "https://api.hihodl.xyz/x402/pay/@yourhandle?amount=1.50¬e=Thanks" \
-H "PAYMENT-SIGNATURE: <base64 x402 v2 payment payload>"200 with { paid, to, amount, txHash } once settled, 202 while it is still settling (send the same header again to read the outcome). The money lands in the recipient’s Main Account as income.
GET | POST /x402/pay/@handle?amount=1.50
Pay a HOLD user any amount from $0.01 to $1,000. The handle is a to z, 0 to 9, _ . -, 2 to 50 characters. Optional note (140 max) and ref (64 max).
GET | POST /x402/link/:id
Pay a HOLD payment link by its id or code (USD links on Base).
GET /.well-known/x402
The links their owners chose to list for agents.
A link pays at its own amount, or at the amount you pass when the link leaves it open. Recurring links, group links and euro links cannot be paid by agents. A link its owner chose to list can be listed in Coinbase’s x402 Bazaar. In the beta, only invited HOLD users can be paid this way.
OAuth
HOLD is both the authorization server and the resource. Public clients only (no secret), PKCE with S256 required, dynamic client registration and client ID metadata documents both accepted, tokens bound to the resource https://api.hihodl.xyz/mcp. Access tokens last 60 minutes, refresh tokens 30 days.
GET /.well-known/oauth-protected-resource
Protected resource metadata (RFC 9728), also at /.well-known/oauth-protected-resource/mcp
GET /.well-known/oauth-authorization-server
Authorization server metadata (RFC 8414)
POST /oauth/register
Dynamic client registration (RFC 7591), public clients, no secret
GET /oauth/authorize
The connect page: a 6 character code and a QR the user approves in the app
POST /oauth/token
authorization_code and refresh_token grants
POST /oauth/revoke
Token revocation (RFC 7009)
POST /mcp
MCP over Streamable HTTP, Authorization: Bearer
Every path is on https://api.hihodl.xyz. Scopes: read search markets request_money propose_payments pay. A client never gets pay at connect; the user turns it on in the app, and it applies at once. Proposals expire after 24 hours, and at most 20 wait at once.
Questions
Who can use it?
It is in beta and invite only. Until your account is invited, the HOLD app will not approve a connection. Ask us at hello@hihodl.xyz.
Which assistants work?
Any assistant that speaks MCP with OAuth: Claude, Claude Code, ChatGPT and Cursor among them. They all use the same address and the same approval in the HOLD app.
Can it spend my money without asking?
Only if you turn on the pay permission for it in the HOLD app, under Settings > AI assistants, and then only inside the limits you set: the money you set aside, a daily budget, a per payment limit, and the sites and people you allowed. Everything else waits for you to approve it in the app.
What if it goes over its limit?
Nothing is paid. The payment comes to your HOLD app instead, with the amount and who it is for. Approve it and HOLD pays it once, decline it, or let it expire after 24 hours. Always allow puts that site or person on the list for next time. The money you set aside is a hard ceiling an approval cannot lift.
How do I disconnect an assistant?
From the HOLD app, at any time. Its access ends at once, together with every token it holds.
Does the assistant see my keys or my password?
No. It gets a token for the permissions you approved and nothing else. Approving happens on your phone, with Face ID.
What does it cost?
Connecting is free. What an assistant pays for, an API or a booking, is what you pay, the same as in the app.
Want in? hello@hihodl.xyz. New to HOLD? Start here.