Docs
grov is an HTTP API that charges per call. There is no key to obtain, no account to create and no dashboard. Call an endpoint, pay what the 402 asks for, get an order back.
Quick start
Two calls, no setup.
# The first call tells you what to pay.
curl -i "https://grov.fun/api/base/xlikes?url=https%3A%2F%2Fx.com%2Fgrov%2Fstatus%2F1234567890&amount=50"
# 402 Payment Required
# Sign it and repeat the call.
curl -i "https://grov.fun/api/base/xlikes?url=https%3A%2F%2Fx.com%2Fgrov%2Fstatus%2F1234567890&amount=50" \
-H "PAYMENT-SIGNATURE: <signed-payment>"
# 200 OK, with an orderId, a secret and a statusUrlEndpoints
The canonical shape names the network and the service:
/api/{network}/{service}?{parameter}=...&amount=NReadable aliases resolve to exactly the same handler, so both of these work:
/api/base/xfollowers?handle=grov&amount=100
/api/base/x/follower?handle=grov&amount=100
/api/x/follower?handle=grov&amount=100 # network defaults
/api/base/xfollowers/100?handle=grov # amount in the pathA readable path that names no network uses the first configured one. Add ?network=solana to choose, or use the canonical form to be explicit.
Parameters
Sent as query parameters, or as a JSON body on POST. Query values win on conflict.
| Parameter | Meaning |
|---|---|
| amount | How many units to buy. Aliases: quantity, winners, count. |
| url | The post link, for services that act on one piece of content. |
| handle | The account name, for services that act on a profile. |
| join | A public t.me link, for Telegram membership. |
| action | Set to view to read an existing order. No payment needed. |
| secret | The order token. Can also be sent as an X-Secret header. |
| network | Picks a network when the path does not name one. |
Paying with x402
Call the endpoint without a payment header and you get a 402 carrying the requirement. Sign it and repeat the call with the PAYMENT-SIGNATURE header. X-PAYMENT is the older name and is still accepted.
import { wrapFetchWithPayment } from '@x402/fetch'
import { x402Client } from '@x402/core/client'
import { registerExactEvmScheme } from '@x402/evm/exact/client'
import { toClientEvmSigner } from '@x402/evm'
import { privateKeyToAccount } from 'viem/accounts'
const account = privateKeyToAccount(process.env.EVM_PRIVATE_KEY as `0x${string}`)
const client = new x402Client()
registerExactEvmScheme(client, { signer: toClientEvmSigner(account) })
const paymentFetch = wrapFetchWithPayment(fetch, client)
const response = await paymentFetch('https://grov.fun/api/base/xlikes?url=https%3A%2F%2Fx.com%2Fgrov%2Fstatus%2F1234567890&amount=50')
const order = await response.json()For Solana use @x402/svm/exact/client with an @solana/kit signer. Assets: USDC 0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913 on Base, USDC EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v on Solana.
Paying with MPP
Call without an Authorization header and you get a 402 with a WWW-Authenticate: Payment challenge. Build a credential from that live challenge and repeat the call with Authorization: Payment .... The success response carries a Payment-Receipt header.
Read the amount, recipient, currency and network from the live challenge every time. Never hardcode them from documentation, including this page.
import { Mppx, solana } from '@solana/mpp/client'
const mppx = Mppx.create({ methods: [solana.charge({ signer, rpcUrl })] })
const response = await mppx.fetch('https://grov.fun/api/mpp-solana/xlikes?url=...&amount=100')Responses
Order created
{
"ok": true,
"paid": true,
"rail": "base",
"orderId": "7QK4M2XJ9BTN",
"secret": "keep-this-safe",
"statusUrl": "https://grov.fun/api/base/xlikes?action=view&secret=keep-this-safe",
"service": "xlikes",
"amount": 100,
"unit": "like",
"chargedUsd": 2.5,
"status": "queued"
}Save the secret immediately. It is the only way to read the order afterwards and it cannot be recovered.
Order status
{
"ok": true,
"orderId": "7QK4M2XJ9BTN",
"status": "in_progress",
"amount": 100,
"delivered": 42,
"remaining": 58,
"startCount": 1310,
"completedAt": null
}Statuses: queued, in_progress, partial, completed, canceled, failed. Delivery is carried out by people, so an order builds up over minutes to hours. Queued means accepted and paid for.
Services
Prices are per unit, in USD, settled 1:1 in USDC. The 402 is always authoritative.
X
| Service | Key | Parameter | Price | Range |
|---|---|---|---|---|
| X Likes | xlikes | url | $0.025 | 10 to 10000 |
| X Reposts | xreposts | url | $0.025 | 10 to 10000 |
| X Comments | xcomments | url | $0.03 | 5 to 1000 |
| X Views | xviews | url | $0.003 | 100 to 500000 |
| X Followers | xfollowers | handle | $0.03 | 10 to 20000 |
| Service | Key | Parameter | Price | Range |
|---|---|---|---|---|
| Instagram Likes | instalikes | url | $0.025 | 10 to 10000 |
| Instagram Comments | instacomments | url | $0.03 | 5 to 1000 |
| Instagram Views | instaviews | url | $0.003 | 100 to 500000 |
| Instagram Reposts | instareposts | url | $0.025 | 10 to 5000 |
| Instagram Post Saves | instasaves | url | $0.025 | 10 to 10000 |
| Instagram Followers | instafollowers | handle | $0.03 | 10 to 20000 |
TikTok
| Service | Key | Parameter | Price | Range |
|---|---|---|---|---|
| TikTok Likes | tiktoklikes | url | $0.025 | 10 to 10000 |
| TikTok Comments | tiktokcomments | url | $0.03 | 5 to 1000 |
| TikTok Views | tiktokviews | url | $0.002 | 100 to 1000000 |
| TikTok Shares | tiktokshares | url | $0.025 | 10 to 10000 |
| TikTok Post Saves | tiktoksaves | url | $0.025 | 10 to 10000 |
| TikTok Followers | tiktokfollowers | handle | $0.03 | 10 to 20000 |
YouTube
| Service | Key | Parameter | Price | Range |
|---|---|---|---|---|
| YouTube Likes | ytlikes | url | $0.025 | 10 to 10000 |
| YouTube Comments | ytcomments | url | $0.035 | 5 to 1000 |
| YouTube Views | ytviews | url | $0.004 | 100 to 500000 |
| YouTube Subscribers | ytsubscribers | handle | $0.035 | 10 to 10000 |
Telegram
| Service | Key | Parameter | Price | Range |
|---|---|---|---|---|
| Telegram Channel Members | tgmembers | join | $0.03 | 10 to 50000 |
Spotify
| Service | Key | Parameter | Price | Range |
|---|---|---|---|---|
| Spotify Plays | spotifyplays | url | $0.004 | 100 to 500000 |
| Spotify Saves | spotifysaves | url | $0.02 | 10 to 20000 |
| Spotify Followers | spotifyfollowers | url | $0.02 | 10 to 50000 |
| Spotify Monthly Listeners | spotifylisteners | url | $0.01 | 100 to 100000 |
| Service | Key | Parameter | Price | Range |
|---|---|---|---|---|
| Facebook Likes | fblikes | url | $0.025 | 10 to 10000 |
| Facebook Comments | fbcomments | url | $0.03 | 5 to 1000 |
| Facebook Views | fbviews | url | $0.003 | 100 to 500000 |
| Facebook Shares | fbshares | url | $0.025 | 10 to 10000 |
| Facebook Post Saves | fbsaves | url | $0.025 | 10 to 10000 |
| Facebook Followers | fbfollowers | handle | $0.03 | 10 to 20000 |
| Facebook Group Members | fbgroupmembers | url | $0.035 | 10 to 20000 |
MCP
A streamable HTTP MCP server lives at https://grov.fun/mcp. It exposes four tools: grov_services, grov_buy, grov_order_status and grov_help.
grov_buy prices a purchase and returns the exact call to make. It does not spend anything: MCP has no way to carry a signed payment, and your wallet should stay with your own client anyway.
{
"mcpServers": {
"grov": {
"type": "http",
"url": "https://grov.fun/mcp"
}
}
}Discovery
Every file below is generated from the same live catalog, so none of them can drift from what the API actually does.
- /skill.mdInstallable agent skill
- /best-practices.mdWhich service to pick, and what to expect
- /llms.txtShort overview for agents
- /llms-full.txtEvery service, parameter and limit
- /openapi.jsonOpenAPI 3.1 with x-payment-info
- /.well-known/x402Machine-readable resource list
- /.well-known/agent-card.jsonERC-8004 agent card
Errors
{
"ok": false,
"message": "Minimum amount for this service is 10.",
"errorCode": "AMOUNT_BELOW_MIN",
"details": {
"service": "xlikes",
"minAmount": 10,
"maxAmount": 10000
}
}4xx bodies include the limits and the parameter that was expected, so a client can correct itself without reading this page.
Something unclear or missing? Tell us.