# GHAN REST API

> The MCP server wraps a plain REST API, so anything an agent can do over MCP is also reachable over HTTP with a bearer token. The OpenAPI document is published at /openapi.json and listed in both the API catalog and the AI catalog.

Source: https://ghan.io/docs/api/  
Published: 2026-09-22 · Updated: 2026-09-22  
Publisher: GHAN — the audited cross-promotion network for desktop apps (https://ghan.io)

---

## Base and auth

```
Authorization: Bearer <api_key>
Content-Type: application/json
```

The key is issued by `register_app`. Public endpoints — the rate card, the network statistics, the integration guide — need no key.

## Endpoint map

| Method | Path | MCP equivalent |
|---|---|---|
| POST | `/apps` | `register_app` |
| GET | `/apps/{app_id}/score` | `get_score` |
| GET | `/rate-card` | `get_rate_card` |
| GET | `/network-stats` | `get_network_stats` |
| GET | `/integration-guide` | `get_integration_guide` |
| POST | `/apps/{app_id}/top-up` | `top_up` |
| POST | `/campaigns` | `create_campaign` — optional `max_bid_cents` |
| POST | `/campaigns/{id}/pause` | `pause_campaign` |
| POST | `/campaigns/{id}/resume` | `resume_campaign` |
| GET | `/apps/{app_id}/ledger` | `get_ledger` |
| GET | `/apps/{app_id}/stats` | `get_stats` |
| POST | `/apps/{app_id}/payout` | `request_payout` |

The full schemas are in [`/openapi.json`](/openapi.json).

## Machine payments

```http
POST /apps/app_123/top-up
{ "amount_cents": 50000 }
```

An agent that can settle machine-to-machine receives:

```http
HTTP/1.1 402 Payment Required
```

with an x402 challenge, settled in USDC on Base. A caller that cannot receives `{ "checkout_url": "https://..." }` for a human to complete in Stripe. Either way the wallet is credited and the ledger records a `topup` line.

The x402 descriptor is published at [`/.well-known/x402`](/.well-known/x402).

## Webhooks

Signed with a shared secret. Events:

- `chain.state_changed`
- `chain.cleared`
- `chain.rejected`
- `fraud.flagged`
- `payout.sent`
- `score.updated`

Verify the signature before acting. GHAN's entire argument is that a signature is what turns a claim into a fact; that applies to the claims GHAN sends you as much as the ones it makes about itself.

## Errors

```json
{ "error": { "code": "gate_domain_too_young",
             "message": "Domain registered 2026-07-03; eligible 2027-01-03",
             "retry_after": "2027-01-03" } }
```

Codes are stable. Messages are not. Build on codes.

## Rate limits

Per API key, returned in `RateLimit-*` response headers per RFC 9239 conventions. Read tools are generous; write tools are not.

## Questions people ask about this

### Do I need the MCP server to use GHAN?

No. MCP is the primary interface and the one that ships first, but it is a wrapper. Every capability is available over HTTP with a bearer token, described in the OpenAPI document at /openapi.json.

### What is the x402 path on top-ups?

The top-up endpoint answers HTTP 402 with an x402 challenge when the caller is a machine that can settle in USDC on Base. A human-driven caller gets a Stripe Checkout URL instead. Both credit the same wallet, and the ledger records the same topup line type either way.

### Are there webhooks?

Yes, signed with a shared secret, for chain state changes, clearing, fraud flags and payout events. Verify the signature before acting on a payload - GHAN's whole argument is that signatures are what make claims checkable, and that applies to the ones GHAN sends you.

### What are the error codes?

Stable machine-readable codes rather than prose. Gate failures use codes like gate_unsigned_binary and gate_domain_too_young. Fraud rejections use codes like fraud_token_reused and fraud_datacenter_asn. The human-readable string beside a code may change; the code will not.

