Skip to content

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 statusUrl

Endpoints

The canonical shape names the network and the service:

/api/{network}/{service}?{parameter}=...&amount=N

Readable 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 path

A 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.

ParameterMeaning
amountHow many units to buy. Aliases: quantity, winners, count.
urlThe post link, for services that act on one piece of content.
handleThe account name, for services that act on a profile.
joinA public t.me link, for Telegram membership.
actionSet to view to read an existing order. No payment needed.
secretThe order token. Can also be sent as an X-Secret header.
networkPicks 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

ServiceKeyParameterPriceRange
X Likesxlikesurl$0.02510 to 10000
X Repostsxrepostsurl$0.02510 to 10000
X Commentsxcommentsurl$0.035 to 1000
X Viewsxviewsurl$0.003100 to 500000
X Followersxfollowershandle$0.0310 to 20000

Instagram

ServiceKeyParameterPriceRange
Instagram Likesinstalikesurl$0.02510 to 10000
Instagram Commentsinstacommentsurl$0.035 to 1000
Instagram Viewsinstaviewsurl$0.003100 to 500000
Instagram Repostsinstarepostsurl$0.02510 to 5000
Instagram Post Savesinstasavesurl$0.02510 to 10000
Instagram Followersinstafollowershandle$0.0310 to 20000

TikTok

ServiceKeyParameterPriceRange
TikTok Likestiktoklikesurl$0.02510 to 10000
TikTok Commentstiktokcommentsurl$0.035 to 1000
TikTok Viewstiktokviewsurl$0.002100 to 1000000
TikTok Sharestiktoksharesurl$0.02510 to 10000
TikTok Post Savestiktoksavesurl$0.02510 to 10000
TikTok Followerstiktokfollowershandle$0.0310 to 20000

YouTube

ServiceKeyParameterPriceRange
YouTube Likesytlikesurl$0.02510 to 10000
YouTube Commentsytcommentsurl$0.0355 to 1000
YouTube Viewsytviewsurl$0.004100 to 500000
YouTube Subscribersytsubscribershandle$0.03510 to 10000

Telegram

ServiceKeyParameterPriceRange
Telegram Channel Memberstgmembersjoin$0.0310 to 50000

Spotify

ServiceKeyParameterPriceRange
Spotify Playsspotifyplaysurl$0.004100 to 500000
Spotify Savesspotifysavesurl$0.0210 to 20000
Spotify Followersspotifyfollowersurl$0.0210 to 50000
Spotify Monthly Listenersspotifylistenersurl$0.01100 to 100000

Facebook

ServiceKeyParameterPriceRange
Facebook Likesfblikesurl$0.02510 to 10000
Facebook Commentsfbcommentsurl$0.035 to 1000
Facebook Viewsfbviewsurl$0.003100 to 500000
Facebook Sharesfbsharesurl$0.02510 to 10000
Facebook Post Savesfbsavesurl$0.02510 to 10000
Facebook Followersfbfollowershandle$0.0310 to 20000
Facebook Group Membersfbgroupmembersurl$0.03510 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.

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.

UNKNOWN_SERVICESERVICE_UNAVAILABLENETWORK_DISABLEDMISSING_TARGETINVALID_TARGETINVALID_AMOUNTAMOUNT_BELOW_MINAMOUNT_ABOVE_MAXNOT_PRICEABLEINVALID_SECRETRATE_LIMITEDPAYMENT_REQUIREDPAYMENT_FAILEDSERVER_ERROR

Something unclear or missing? Tell us.