{
  "openapi": "3.1.0",
  "info": {
    "title": "GHAN API",
    "version": "1.0.0",
    "summary": "Audited cross-promotion and paid-install network for desktop applications.",
    "description": "GHAN lets macOS and Windows desktop applications promote each other in templated in-app lifecycle slots and settle through a single append-only credit ledger. Attribution is deterministic only: a single-use, 15-minute, ed25519-signed token, countersigned by the receiving SDK. Advertisers are billed per cleared install, meaning an install that was still in use 48 hours later; anything else is refunded automatically. Pricing is a published floor that never rises, with an optional second-price auction for priority above it and 30 percent of each category reserved at floor. This REST surface is what the GHAN MCP server wraps.",
    "termsOfService": "https://ghan.io/terms/",
    "contact": {
      "name": "GHAN",
      "email": "hello@ghan.io",
      "url": "https://ghan.io/contact/"
    },
    "license": {
      "name": "Proprietary",
      "url": "https://ghan.io/terms/"
    }
  },
  "externalDocs": {
    "description": "GHAN documentation",
    "url": "https://ghan.io/docs/"
  },
  "servers": [
    {
      "url": "https://api.ghan.io/v1",
      "description": "Production"
    }
  ],
  "security": [
    {
      "bearerAuth": []
    }
  ],
  "tags": [
    {
      "name": "public",
      "description": "No authentication required."
    },
    {
      "name": "apps",
      "description": "Registration, vetting and scoring."
    },
    {
      "name": "campaigns",
      "description": "Buying cleared installs."
    },
    {
      "name": "money",
      "description": "Wallets, top-ups, payouts."
    },
    {
      "name": "audit",
      "description": "The signed ledger and performance statistics."
    }
  ],
  "paths": {
    "/rate-card": {
      "get": {
        "tags": [
          "public"
        ],
        "operationId": "getRateCard",
        "security": [],
        "summary": "The published fixed price per cleared install, by category",
        "description": "Public and unauthenticated. There is no auction and no negotiated rate; this document is the price.",
        "responses": {
          "200": {
            "description": "The rate card",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RateCard"
                }
              }
            }
          }
        }
      }
    },
    "/network-stats": {
      "get": {
        "tags": [
          "public"
        ],
        "operationId": "getNetworkStats",
        "security": [],
        "summary": "Network-wide clearing rate, fraud percentage and average CPI",
        "description": "Public and unauthenticated. These are the numbers GHAN publishes about itself; per-app data exposed through /apps/{app_id}/ledger is what makes them checkable.",
        "responses": {
          "200": {
            "description": "Network statistics",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/NetworkStats"
                }
              }
            }
          }
        }
      }
    },
    "/integration-guide": {
      "get": {
        "tags": [
          "public"
        ],
        "operationId": "getIntegrationGuide",
        "security": [],
        "summary": "The SDK quickstart as markdown",
        "responses": {
          "200": {
            "description": "Markdown guide",
            "content": {
              "text/markdown": {
                "schema": {
                  "type": "string"
                }
              }
            }
          }
        }
      }
    },
    "/apps": {
      "post": {
        "tags": [
          "apps"
        ],
        "operationId": "registerApp",
        "summary": "Register a desktop application and queue the vetting gate",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RegisterAppRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Registered, pending gate",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RegisterAppResponse"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/apps/{app_id}/score": {
      "get": {
        "tags": [
          "apps"
        ],
        "operationId": "getScore",
        "summary": "Gate result, reputation breakdown, behaviour score and reason codes",
        "parameters": [
          {
            "$ref": "#/components/parameters/AppId"
          }
        ],
        "responses": {
          "200": {
            "description": "Score",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Score"
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/apps/{app_id}/top-up": {
      "post": {
        "tags": [
          "money"
        ],
        "operationId": "topUp",
        "summary": "Fund a credit wallet",
        "description": "Answers HTTP 402 with an x402 challenge when the caller can settle machine-to-machine in USDC on Base. Otherwise returns a Stripe Checkout URL for a person to complete.",
        "parameters": [
          {
            "$ref": "#/components/parameters/AppId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "amount_cents"
                ],
                "properties": {
                  "amount_cents": {
                    "type": "integer",
                    "minimum": 5000,
                    "description": "Credits to purchase. One credit is one euro cent."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Checkout URL for a human",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "checkout_url": {
                      "type": "string",
                      "format": "uri"
                    }
                  }
                }
              }
            }
          },
          "402": {
            "description": "Payment required \u2014 x402 challenge",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/X402Challenge"
                }
              }
            }
          }
        }
      }
    },
    "/campaigns": {
      "post": {
        "tags": [
          "campaigns"
        ],
        "operationId": "createCampaign",
        "summary": "Start buying cleared installs",
        "description": "max_bid_cents is optional. Omit it and the campaign buys at the published category floor, which never rises and is always available. Set it at or above the floor to compete for priority in contested inventory; clearing is second price.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateCampaignRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created, throttled",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Campaign"
                }
              }
            }
          }
        }
      }
    },
    "/campaigns/{campaign_id}/pause": {
      "post": {
        "tags": [
          "campaigns"
        ],
        "operationId": "pauseCampaign",
        "summary": "Pause a campaign",
        "parameters": [
          {
            "name": "campaign_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Paused",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Campaign"
                }
              }
            }
          }
        }
      }
    },
    "/campaigns/{campaign_id}/resume": {
      "post": {
        "tags": [
          "campaigns"
        ],
        "operationId": "resumeCampaign",
        "summary": "Resume a campaign",
        "parameters": [
          {
            "name": "campaign_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Resumed",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Campaign"
                }
              }
            }
          }
        }
      }
    },
    "/apps/{app_id}/ledger": {
      "get": {
        "tags": [
          "audit"
        ],
        "operationId": "getLedger",
        "summary": "Raw append-only ledger lines with event-chain references",
        "description": "The audit tool. Every line carries an event_chain_id which resolves to a chain containing two independent ed25519 signatures, one of which was produced by an SDK inside the caller's own signed binary.",
        "parameters": [
          {
            "$ref": "#/components/parameters/AppId"
          },
          {
            "name": "from",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "date"
            }
          },
          {
            "name": "to",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "date"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Ledger lines",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "lines": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/LedgerLine"
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/apps/{app_id}/stats": {
      "get": {
        "tags": [
          "audit"
        ],
        "operationId": "getStats",
        "summary": "Impressions, clicks, installs, cleared installs, retention and fraud rejections",
        "parameters": [
          {
            "$ref": "#/components/parameters/AppId"
          },
          {
            "name": "period",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "last_7_days",
                "last_30_days",
                "last_90_days"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Statistics",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Stats"
                }
              }
            }
          }
        }
      }
    },
    "/apps/{app_id}/payout": {
      "post": {
        "tags": [
          "money"
        ],
        "operationId": "requestPayout",
        "summary": "Request a Stripe Connect transfer of a balance of at least EUR 50",
        "parameters": [
          {
            "$ref": "#/components/parameters/AppId"
          }
        ],
        "responses": {
          "200": {
            "description": "Transfer created",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "transfer_id": {
                      "type": "string"
                    },
                    "amount_cents": {
                      "type": "integer"
                    }
                  }
                }
              }
            }
          },
          "409": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "description": "API key issued by POST /apps."
      }
    },
    "parameters": {
      "AppId": {
        "name": "app_id",
        "in": "path",
        "required": true,
        "schema": {
          "type": "string"
        },
        "description": "Opaque application identifier. Do not parse."
      }
    },
    "responses": {
      "Error": {
        "description": "Error with a stable machine-readable code",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      }
    },
    "schemas": {
      "Error": {
        "type": "object",
        "properties": {
          "error": {
            "type": "object",
            "properties": {
              "code": {
                "type": "string",
                "description": "Stable code. Build on this, not on message.",
                "examples": [
                  "gate_domain_too_young",
                  "gate_unsigned_binary",
                  "fraud_token_reused",
                  "fraud_datacenter_asn",
                  "below_minimum"
                ]
              },
              "message": {
                "type": "string",
                "description": "Human-readable. May change between versions."
              },
              "retry_after": {
                "type": "string",
                "format": "date-time",
                "nullable": true
              }
            }
          }
        }
      },
      "RateCard": {
        "type": "object",
        "properties": {
          "currency": {
            "type": "string",
            "const": "EUR"
          },
          "take_rate": {
            "type": "number",
            "const": 0.3,
            "description": "Share GHAN keeps of each cleared install."
          },
          "credit_bonus": {
            "type": "number",
            "const": 1.2,
            "description": "Multiplier applied when earnings are taken as credits instead of cash."
          },
          "categories": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "key": {
                  "type": "string",
                  "examples": [
                    "utilities_consumer",
                    "creator_tools",
                    "prosumer_b2b"
                  ]
                },
                "label": {
                  "type": "string"
                },
                "floor_cents_min": {
                  "type": "integer",
                  "examples": [
                    1200,
                    2000,
                    3500
                  ]
                },
                "floor_cents_max": {
                  "type": "integer",
                  "examples": [
                    1800,
                    3000,
                    5000
                  ]
                }
              }
            }
          },
          "reserved_floor_share": {
            "type": "number",
            "const": 0.3,
            "description": "Share of each category's inventory sold only at floor price and never auctioned."
          },
          "pricing_model": {
            "type": "string",
            "const": "floor_plus_second_price",
            "description": "A published floor that never rises, with a second-price auction for priority above it."
          }
        }
      },
      "NetworkStats": {
        "type": "object",
        "properties": {
          "period": {
            "type": "string"
          },
          "clearing_rate": {
            "type": "number",
            "description": "Share of install claims that survive to activated_48h."
          },
          "fraud_pct": {
            "type": "number",
            "description": "Share of chains rejected by a fraud rule."
          },
          "avg_cpi_by_category": {
            "type": "object",
            "additionalProperties": {
              "type": "integer"
            }
          }
        }
      },
      "RegisterAppRequest": {
        "type": "object",
        "required": [
          "name",
          "platform",
          "bundle_id",
          "domain",
          "download_url",
          "contact_email"
        ],
        "properties": {
          "name": {
            "type": "string"
          },
          "platform": {
            "type": "string",
            "enum": [
              "mac",
              "win"
            ]
          },
          "bundle_id": {
            "type": "string",
            "examples": [
              "com.example.app"
            ]
          },
          "domain": {
            "type": "string",
            "description": "Must be at least six months old, checked over RDAP."
          },
          "download_url": {
            "type": "string",
            "format": "uri",
            "description": "Must serve the declared bundle_id."
          },
          "contact_email": {
            "type": "string",
            "format": "email",
            "description": "Must answer a challenge message."
          }
        }
      },
      "RegisterAppResponse": {
        "type": "object",
        "properties": {
          "app_id": {
            "type": "string"
          },
          "api_key": {
            "type": "string"
          },
          "status": {
            "type": "string",
            "const": "pending"
          },
          "scoring_job_id": {
            "type": "string"
          }
        }
      },
      "Score": {
        "type": "object",
        "properties": {
          "status": {
            "type": "string",
            "enum": [
              "pending",
              "approved",
              "throttled",
              "live",
              "suspended",
              "rejected"
            ]
          },
          "gate": {
            "type": "object",
            "properties": {
              "signed": {
                "type": "boolean",
                "description": "macOS notarisation ticket or Windows Authenticode chain."
              },
              "malware_clean": {
                "type": "boolean"
              },
              "domain_age_ok": {
                "type": "boolean"
              },
              "contact_verified": {
                "type": "boolean"
              },
              "bundle_match": {
                "type": "boolean"
              }
            }
          },
          "reputation": {
            "type": "object",
            "description": "0-100. AI visibility and sentiment 50%, release cadence 20%, reviews 20%, coherence 10%.",
            "properties": {
              "total": {
                "type": "integer"
              },
              "ai_visibility": {
                "type": "integer"
              },
              "cadence": {
                "type": "integer"
              },
              "reviews": {
                "type": "integer"
              },
              "coherence": {
                "type": "integer"
              }
            }
          },
          "behavior": {
            "type": [
              "object",
              "null"
            ],
            "description": "Replaces reputation after 500 installs traded.",
            "properties": {
              "retention_48h": {
                "type": "number"
              },
              "uninstall_rate": {
                "type": "number"
              },
              "canary": {
                "type": "boolean"
              },
              "complaints": {
                "type": "number"
              }
            }
          },
          "reasons": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "next_review_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "CreateCampaignRequest": {
        "type": "object",
        "required": [
          "app_id",
          "categories",
          "daily_budget_cents"
        ],
        "properties": {
          "app_id": {
            "type": "string"
          },
          "categories": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "daily_budget_cents": {
            "type": "integer",
            "minimum": 1000
          },
          "max_bid_cents": {
            "type": "integer",
            "description": "Optional. The most you will pay per cleared install in these categories. Must be at or above the category floor. Omit to buy at floor price. Clearing is second price: you pay one cent above the next-highest competing bid, never your maximum."
          }
        }
      },
      "Campaign": {
        "type": "object",
        "properties": {
          "campaign_id": {
            "type": "string"
          },
          "daily_budget_cents": {
            "type": "integer"
          },
          "status": {
            "type": "string",
            "enum": [
              "throttled",
              "active",
              "paused"
            ]
          },
          "floor_cents": {
            "type": "integer",
            "description": "The published floor for the category. Always available to you; never rises."
          },
          "max_bid_cents": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Your priority bid, or null for a floor-price campaign."
          }
        }
      },
      "LedgerLine": {
        "type": "object",
        "description": "Append-only. UPDATE, DELETE and TRUNCATE are blocked by database trigger; corrections are new lines.",
        "properties": {
          "id": {
            "type": "string"
          },
          "ts": {
            "type": "string",
            "format": "date-time"
          },
          "type": {
            "type": "string",
            "enum": [
              "topup",
              "earn",
              "charge",
              "escrow_hold",
              "escrow_release",
              "clawback",
              "payout",
              "adjustment"
            ]
          },
          "amount_cents": {
            "type": "integer"
          },
          "counterparty_app_id": {
            "type": [
              "string",
              "null"
            ]
          },
          "event_chain_id": {
            "type": [
              "string",
              "null"
            ]
          },
          "balance_after": {
            "type": "integer"
          },
          "note": {
            "type": [
              "string",
              "null"
            ]
          }
        }
      },
      "Stats": {
        "type": "object",
        "properties": {
          "impressions": {
            "type": "integer"
          },
          "clicks": {
            "type": "integer"
          },
          "installs": {
            "type": "integer"
          },
          "cleared": {
            "type": "integer"
          },
          "retention_48h": {
            "type": "number"
          },
          "fraud_rejected": {
            "type": "object",
            "additionalProperties": {
              "type": "integer"
            },
            "description": "Keyed by stable reason code."
          },
          "floor_cents": {
            "type": "integer"
          },
          "avg_clearing_price_cents": {
            "type": "integer",
            "description": "What contention actually cost. Equals floor_cents when nothing was contested."
          }
        }
      },
      "X402Challenge": {
        "type": "object",
        "properties": {
          "x402Version": {
            "type": "integer",
            "const": 1
          },
          "accepts": {
            "type": "array",
            "items": {
              "type": "object"
            }
          },
          "resource": {
            "type": "string",
            "format": "uri"
          }
        }
      }
    }
  }
}
