# GrowVib auth.md

How an AI agent or an automated client authenticates to GrowVib (https://growvib.com), the social growth
storefront, and what it can do at each level of access. Machine-readable versions of everything
below: [OAuth authorization server metadata](https://api.growvib.com/.well-known/oauth-authorization-server),
[OAuth protected resource metadata](https://api.growvib.com/.well-known/oauth-protected-resource),
[MCP server card](https://api.growvib.com/.well-known/mcp/server-card.json), [OpenAPI for the catalog reads](https://api.growvib.com/openapi.json),
[API catalog](https://api.growvib.com/.well-known/api-catalog), and the skills index at
https://growvib.com/.well-known/agent-skills/index.json.

## Who this is for

Agents acting for a person who wants to grow a Telegram, Instagram, TikTok, YouTube or other social
account, and developers integrating the catalog into their own software. Three levels of access
exist. Start at the lowest one that does the job. An agent that has no GrowVib user to act for
but holds an x402-compatible wallet skips straight from level 1 to level 3.

## 1. Anonymous: browse the catalog and get exact quotes

No credentials, no account.

- MCP (Streamable HTTP): `https://api.growvib.com/mcp-public`. Tools: `search_catalog`, `get_service`,
  `recommend_service`, and a list-price `get_quote`. The quote runs the same server-side pricing
  a real order uses, so trust it over arithmetic on catalog prices.
- REST: `GET https://api.growvib.com/v1/services` (paginated) and `GET https://api.growvib.com/v1/services/{id}`.
- Limit: 60 requests per minute per IP. A 429 states the limit and sets `Retry-After`.

Nothing at this level can read or change an account, and nothing here spends an account's money.
The one spend tool on this server, `create_paid_order`, is paid by the CALLING wallet over x402
(level 3), never from anyone's GrowVib balance; an agent that must never spend simply does not
call it. The `get_quote` result's `payment_methods` block says which payment paths are open for
a quote.

## 2. Acting for a GrowVib user: OAuth 2.1 with PKCE (the MCP server)

To quote against a user's balance, place orders paid from their wallet, check order status, or
top the wallet up, connect to `https://api.growvib.com/mcp` on that user's behalf. The flow is standard and
fully automatic for a compliant MCP client; the only human step is the user's approval.

1. Call `https://api.growvib.com/mcp` with no credentials. The 401 carries
   `WWW-Authenticate: Bearer resource_metadata="https://api.growvib.com/.well-known/oauth-protected-resource"`.
2. Read the protected resource metadata, then the authorization server metadata it names
   (issuer `https://api.growvib.com`).
3. Register a public client: `POST https://api.growvib.com/oauth/register` (RFC 7591 dynamic client
   registration; `token_endpoint_auth_method` is `none`, redirect URIs are checked exactly).
4. Send the user to `https://api.growvib.com/oauth/authorize` with `response_type=code`, `scope=mcp`,
   and a PKCE S256 challenge. The user signs in to GrowVib and approves the connection on the
   dashboard consent screen. That approval is the one-click onboarding; nothing else is needed.
5. Exchange the code at `POST https://api.growvib.com/oauth/token` (`authorization_code` with the PKCE
   verifier). Access tokens last one hour; refresh tokens rotate on every use
   (`grant_type=refresh_token`).
6. Call `https://api.growvib.com/mcp` with `Authorization: Bearer <access token>`.

Scope: `mcp` only, bound to that one user. The token can search, quote, place orders funded by
the user's balance (never unfunded), read that user's orders and deposits, and create a hosted
top-up link. It cannot read other accounts, cannot credit a wallet, and cannot change account
settings.

Safety annotations: every tool in the [server card](https://api.growvib.com/.well-known/mcp/server-card.json)
carries MCP tool annotations. readOnlyHint true and idempotentHint true on search_catalog, get_service, recommend_service, get_quote, get_paid_order_status, list_paid_orders, order_status, get_balance, list_payment_methods and deposit_status, so they are safe to call freely and to retry. readOnlyHint false, destructiveHint true and idempotentHint true on place_order and create_paid_order: they spend (place_order from the connected user's wallet, create_paid_order from the calling agent's own wallet over x402), and a retried idempotency_key or a re-sent signed payment returns the same order rather than a second one. Every hint false on add_funds: it creates a pending top-up that charges nothing until the payment is confirmed, and each call starts a new deposit. A client that honours the hints can auto-approve the reads and ask the user before place_order and create_paid_order.

Oversight and revocation: the user sees every connected client, with its name and when it was
authorised, at https://app.growvib.com/connect, and disconnects any of them at any time (the token stops working
immediately). GrowVib can also revoke a client or a grant on its side. Every tool call on this
endpoint is recorded server-side (tool, outcome, error, time, and which connection made it), and
an order placed through it carries that origin, so what an agent did on an account can be audited
after the fact.

Tokens are opaque: `jwks_uri` in the server metadata returns an empty key set because there
is no signature to verify. Present the token, do not decode it.

## 3. No account at all: pay over x402 (USDC on Base or Solana)

For an agent that is not acting for a GrowVib user. It pays for the order itself with an
x402-compatible wallet, and the wallet that signs becomes the account: no signup, no API key, no
OAuth, no deposit. Protocol x402 version 2, USDC on Base (`eip155:8453`) or Solana (`solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp`), endpoint
`POST https://api.growvib.com/v1/agent/orders` (the same handshake is the `create_paid_order` tool on the anonymous MCP
endpoint, with the 402 document returned in the tool result because MCP has no status codes).

1. search_catalog or recommend_service on https://api.growvib.com/mcp-public (or GET https://api.growvib.com/v1/services) to pick the service and option
2. get_quote for the exact price; its payment_methods.x402 block confirms the order is payable with no account
3. POST https://api.growvib.com/v1/agent/orders with {service_id, quantity, link} and no payment header (or call create_paid_order on https://api.growvib.com/mcp-public without a payment argument)
4. receive HTTP 402 with the PAYMENT-REQUIRED header (base64 JSON, the same document in the body): one accepts entry per network (Base first, then Solana when it is offered), each with the exact amount in USDC atomic units, asset, recipient and network, plus the EIP-712 domain (Base) or the facilitator's feePayer (Solana) in extra
5. pick the entry your wallet is on and sign: on Base an EIP-3009 transferWithAuthorization for exactly those requirements; on Solana a USDC transfer of exactly that amount to payTo with extra.feePayer as the transaction fee payer, signed by the paying wallet only and sent base64-encoded as payload.transaction
6. send the identical request again with the signed payload base64-encoded in PAYMENT-SIGNATURE (copy the 402's `extensions` into the payload, as x402 v2 requires)
7. receive 201 with the order (order_id, tracking_code, status, charged_usd, balance_usd, agent_token) and a PAYMENT-RESPONSE header carrying the transaction hash
8. track it: GET https://api.growvib.com/v1/agent/orders/{order_id} with Authorization: Bearer <agent_token>, or get_paid_order_status on the public MCP endpoint
9. spend any remaining balance on the next order with the same bearer token plus an idempotency_key and no payment (nothing on chain); a wallet that comes back later signs in at POST /v1/agent/auth/challenge with ERC-4361 (EVM) or Sign-In With Solana (chain: solana)

What proves who is asking: on the paying request, the signed payment itself, an EIP-3009
authorization on Base or a USDC transfer transaction on Solana (the server verifies and settles it
through an x402 facilitator; it never holds a key). Afterwards, the
`agent_token` the order returned: a bearer credential for that wallet's account, one hour, refreshed
on every order, that can place orders from the balance the wallet already holds and read that
wallet's orders, and nothing else (no withdrawals, no account changes).

The amount is never the client's to state: the server prices the order and the 402 names it, the
payer signs for exactly that figure, and a payment that differs is refused before anything moves.
A 200 or a 202 on the paying request is NOT a failure (paid but order not created, with the funds
in balance; or settlement still being confirmed): do not sign a second payment. Full reference,
with wire examples and every status: https://growvib.com/x402. Machine-readable: the `Agent payments` tag in
https://api.growvib.com/openapi.json and `publicServer.x402` on the server card, both present only while the
channel is enabled.

### Registering with no payment: the wallet sign-in (auth.md `anonymous`)

A payment is not the only way to get that credential, and an agent does not have to spend anything
to register. Signing a message is enough, and the account is created on the first sign-in whether
or not the wallet has ever paid.

1. `POST https://api.growvib.com/v1/agent/auth/challenge` with `{"address": "<your wallet address>", "chain":
   "eip155"}` (`"solana"` for a Solana wallet; `chain` defaults to `eip155`). It returns
   `{"nonce", "message", "expires_at"}`. Creates nothing and reveals nothing about whether the
   address is already known.
2. Sign `message` unchanged: `personal_sign` for an EVM wallet (ERC-4361), `signMessage` for a
   Solana one (Sign-In With Solana). The text says in as many words that signing moves no funds.
3. `POST https://api.growvib.com/v1/agent/auth/token` with `{"nonce", "signature"}`. It returns
   `{"agent_token", "expires_at", "chain", "address", "balance_usd"}`. The nonce is single use,
   and a wrong signature burns it: ask for a new challenge rather than retrying.
4. Send `Authorization: Bearer <agent_token>` to place orders from that wallet's balance
   (`POST https://api.growvib.com/v1/agent/orders` with an `idempotency_key` and no payment) and to read its orders
   (`GET https://api.growvib.com/v1/agent/orders/{order_id}`).

This is auth.md's `anonymous` registration, and the API declares it as one: `agent_auth` in
[the authorization server metadata](https://api.growvib.com/.well-known/oauth-authorization-server) lists
`anonymous` in `identity_types_supported` with `credential_types_supported: ["access_token"]`,
and names both endpoints, whenever the channel is live. Two differences from the profile are worth
knowing before you send anything:

- **Two steps, not one POST**, because the credential is bound to a key you have to prove you
  hold. There is no `{"type": "anonymous"}` body; send the address and sign what comes back.
- **No claim ceremony and no `claim_token`.** The account stays the wallet's, reached by signing
  again. Nothing upgrades it to a human-owned account, so do not wait for a `claim_url`.

The token is the same credential an order returns, with the same limits: it spends the balance that
wallet already holds and reads that wallet's orders, and it cannot withdraw, change account
settings, or read another account.

## What is deliberately not offered

- No registration by assertion: GrowVib verifies no ID-JAG (auth.md `identity_assertion`) and
  runs no verified-email registration (`service_auth`). A person approves every connection to an
  existing GrowVib account, which is level 2. The unattended path is level 3, where a wallet
  signature or a settled payment is the credential and the wallet becomes its own account.
- No claim ceremony, so no `claim_uri`. auth.md makes the ceremony optional for `anonymous`
  registrations and GrowVib does not implement it: an account a wallet created stays that
  wallet's, reached by signing again, and there is no flow that hands it to a human who signs in
  with an email instead.
- No self-service API keys and no key-based REST ordering. That surface is not launched; when it
  is, this file and the OpenAPI document will describe it.
- No agent may credit a GrowVib wallet by assertion. Wallets are credited only by the audited
  payment flow after a payment completes, and an x402 settlement is one of those flows.
- Orders are only ever placed with funds already in the wallet, or settled on chain first. An
  insufficient balance returns a clear handoff (total, balance, shortfall) on level 2 and the
  ordinary 402 on level 3, and places nothing.

## Contract version

Every response carries `X-GrowVib-API-Version`, a date naming the revision of the wire contract
that answered it. Read the value from the header rather than from this page: a copy of it here
would be one more thing to keep in step, and the header is always current. The path says which
MAJOR contract you are on (`/v1`, `/api/v1`) and cannot say more, because changes inside it are
additive: two clients that integrated months apart read the same URL and see different fields. This
is the number that tells them apart. It is on every response including errors, so a request that
failed still says which revision produced it, and it moves only when a client outside GrowVib could
observe a change, never on an ordinary deploy.

## Errors

Every API error is JSON: `{"error": "<message>", "code": <http status>, "details"?: "<what to
fix>", "reason"?: "<stable code>"}`. Branch on `code` and `reason`, never on the message
text. Over MCP, a failed tool call carries the same actionable text in its error result.

## Contact

Site: https://growvib.com. Agent guide: https://growvib.com/llms.txt. MCP page for humans: https://growvib.com/mcp.
