{
  "openapi": "3.1.0",
  "info": {
    "title": "Crank Rewards API",
    "version": "1.0.0",
    "description": "Read API for a signed-in wallet's rewards. Every reward is recorded and settled only in $CRANK -- never USDC or SOL. Before the $CRANK mint an accrual is recorded without a $CRANK amount: no conversion ratio is set or published, and a recorded accrual is not an entitlement to any specific amount. Hand-maintained; see rewards-api.md."
  },
  "servers": [
    {
      "url": "https://api.crank.ing/api/v1"
    }
  ],
  "security": [
    {
      "bearerAuth": []
    }
  ],
  "paths": {
    "/user-rewards/summary/": {
      "get": {
        "operationId": "getRewardsSummary",
        "summary": "$CRANK reward summary across every reward programme",
        "description": "Accrued, pending, claimable (matured) and paid reward state for one wallet, in $CRANK only, per programme and in total. Fee-share accruals carry no $CRANK amount until a post-mint settlement round prices them, so before the mint they count toward `count` but never toward `amount_base_units`. Hive contribution credits are never summed and are omitted from `programs` and `totals`; they appear only as history rows.",
        "tags": [
          "rewards"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/WalletAddress"
          }
        ],
        "responses": {
          "200": {
            "description": "Reward summary.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RewardsSummary"
                }
              }
            }
          },
          "400": {
            "description": "The account has no bound wallet."
          },
          "401": {
            "description": "Not signed in."
          },
          "403": {
            "description": "`wallet_address` is neither your wallet nor an agent wallet you own."
          }
        }
      }
    },
    "/user-rewards/history/": {
      "get": {
        "operationId": "getRewardsHistory",
        "summary": "Newest-first $CRANK reward rows",
        "description": "One row per reward record across every programme, newest first. `amount_base_units` is null for a fee-share accrual that has not been priced yet (always, before the mint).",
        "tags": [
          "rewards"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/WalletAddress"
          },
          {
            "name": "program",
            "in": "query",
            "required": false,
            "description": "Only rows from this programme.",
            "schema": {
              "$ref": "#/components/schemas/RewardProgram"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 200,
              "default": 50
            }
          },
          {
            "name": "offset",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 0,
              "default": 0
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Reward history page.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RewardsHistory"
                }
              }
            }
          },
          "400": {
            "description": "Unknown `program`, or non-integer `limit` / `offset`."
          },
          "401": {
            "description": "Not signed in."
          },
          "403": {
            "description": "`wallet_address` is neither your wallet nor an agent wallet you own."
          }
        }
      }
    },
    "/referrals/claim/": {
      "post": {
        "operationId": "claimReferralRewards",
        "summary": "Request a $CRANK payout of matured referral fee-share",
        "description": "Builds a payout request over matured, priced referral accruals. It moves no funds; the treasury settles on-chain in $CRANK to the wallet. Before the $CRANK mint there is nothing to settle and the request answers 409.",
        "tags": [
          "rewards"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ClaimRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The open $CRANK payout request.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PayoutRequest"
                }
              }
            }
          },
          "404": {
            "description": "Unknown wallet, or nothing priced and matured to settle."
          },
          "409": {
            "description": "Before the $CRANK mint: accruals are recorded, nothing settles yet.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PreMintRefusal"
                }
              }
            }
          }
        }
      }
    },
    "/creators/claim/": {
      "post": {
        "operationId": "claimCloneRewards",
        "summary": "Request a $CRANK payout of matured clone fee-share",
        "description": "Same contract as `/referrals/claim/` for the clone fee-share programme.",
        "tags": [
          "rewards"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ClaimRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The open $CRANK payout request.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PayoutRequest"
                }
              }
            }
          },
          "404": {
            "description": "Unknown wallet, or nothing priced and matured to settle."
          },
          "409": {
            "description": "Before the $CRANK mint: accruals are recorded, nothing settles yet.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PreMintRefusal"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "JWT"
      }
    },
    "parameters": {
      "WalletAddress": {
        "name": "wallet_address",
        "in": "query",
        "required": false,
        "description": "Public wallet address to read. Defaults to the signed-in account's own wallet; may also name an agent wallet the account owns.",
        "schema": {
          "type": "string"
        }
      }
    },
    "schemas": {
      "RewardProgram": {
        "type": "string",
        "enum": [
          "referral",
          "clone",
          "integrator",
          "signup_bonus",
          "hive_contribution",
          "distribution",
          "season"
        ]
      },
      "CrankBucket": {
        "type": "object",
        "required": [
          "count",
          "priced_count",
          "amount_base_units"
        ],
        "properties": {
          "count": {
            "type": "integer",
            "description": "Reward records in this state."
          },
          "priced_count": {
            "type": "integer",
            "description": "How many of those already carry a $CRANK amount."
          },
          "amount_base_units": {
            "type": "integer",
            "description": "Sum of the priced records' $CRANK amounts, in base units (6 decimals). Unpriced records contribute nothing -- no amount is ever estimated."
          }
        }
      },
      "CrankBuckets": {
        "type": "object",
        "required": [
          "accrued",
          "pending",
          "claimable",
          "paid"
        ],
        "properties": {
          "accrued": {
            "$ref": "#/components/schemas/CrankBucket",
            "description": "pending + claimable + paid."
          },
          "pending": {
            "$ref": "#/components/schemas/CrankBucket",
            "description": "Inside the 7-day review window (or held for review)."
          },
          "claimable": {
            "$ref": "#/components/schemas/CrankBucket",
            "description": "Matured. Before the mint this still cannot settle -- see `pre_mint`."
          },
          "paid": {
            "$ref": "#/components/schemas/CrankBucket",
            "description": "Settled on-chain in $CRANK."
          }
        }
      },
      "RewardEnvelope": {
        "type": "object",
        "required": [
          "reward_asset",
          "decimals",
          "pre_mint"
        ],
        "properties": {
          "reward_asset": {
            "type": "string",
            "const": "CRANK"
          },
          "decimals": {
            "type": "integer",
            "const": 6
          },
          "pre_mint": {
            "type": "boolean",
            "description": "True until the $CRANK mint exists. While true, fee-share accruals have no $CRANK amount and nothing settles."
          }
        }
      },
      "RewardsSummary": {
        "allOf": [
          {
            "$ref": "#/components/schemas/RewardEnvelope"
          },
          {
            "type": "object",
            "required": [
              "wallet_address",
              "totals",
              "programs",
              "disclosure",
              "history_only_programs",
              "contribution_disclosure"
            ],
            "properties": {
              "wallet_address": {
                "type": "string"
              },
              "totals": {
                "$ref": "#/components/schemas/CrankBuckets"
              },
              "programs": {
                "type": "object",
                "description": "One entry per summed RewardProgram. `hive_contribution` is never summed and never appears here -- see `history_only_programs`.",
                "additionalProperties": {
                  "$ref": "#/components/schemas/CrankBuckets"
                }
              },
              "disclosure": {
                "type": "string",
                "description": "Standing disclosure to show with any reward figure."
              },
              "history_only_programs": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/RewardProgram"
                },
                "description": "Programmes shown only as individual history rows, never totalled (currently `hive_contribution`)."
              },
              "contribution_disclosure": {
                "type": "string",
                "description": "No-entitlement disclosure for contribution credits. Show on every render, including empty states."
              }
            }
          }
        ]
      },
      "RewardHistoryRow": {
        "type": "object",
        "required": [
          "program",
          "id",
          "status",
          "amount_base_units",
          "created_at",
          "claimable_at",
          "paid_at",
          "tx_signature"
        ],
        "properties": {
          "program": {
            "$ref": "#/components/schemas/RewardProgram"
          },
          "id": {
            "type": "integer"
          },
          "status": {
            "type": "string",
            "enum": [
              "pending",
              "claimable",
              "paid"
            ]
          },
          "amount_base_units": {
            "type": [
              "integer",
              "null"
            ],
            "description": "$CRANK base units (6 decimals); null for an accrual not priced yet."
          },
          "created_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "claimable_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "paid_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "tx_signature": {
            "type": "string"
          }
        }
      },
      "RewardsHistory": {
        "allOf": [
          {
            "$ref": "#/components/schemas/RewardEnvelope"
          },
          {
            "type": "object",
            "required": [
              "wallet_address",
              "limit",
              "offset",
              "results",
              "has_more",
              "disclosure",
              "contribution_disclosure"
            ],
            "properties": {
              "wallet_address": {
                "type": "string"
              },
              "limit": {
                "type": "integer"
              },
              "offset": {
                "type": "integer"
              },
              "has_more": {
                "type": "boolean"
              },
              "results": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/RewardHistoryRow"
                }
              },
              "disclosure": {
                "type": "string",
                "description": "Standing disclosure to show with any reward figure."
              },
              "contribution_disclosure": {
                "type": "string",
                "description": "No-entitlement disclosure for contribution credits. Show on every render, including empty states."
              }
            }
          }
        ]
      },
      "ClaimRequest": {
        "type": "object",
        "required": [
          "wallet_address"
        ],
        "properties": {
          "wallet_address": {
            "type": "string"
          }
        }
      },
      "PayoutRequest": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer"
          },
          "status": {
            "type": "string",
            "enum": [
              "requested",
              "settled",
              "failed"
            ]
          },
          "destination_address": {
            "type": "string"
          },
          "payout_mint": {
            "type": "string",
            "description": "Always the canonical $CRANK mint."
          },
          "crank_amount": {
            "type": [
              "integer",
              "null"
            ],
            "description": "$CRANK base units (6 decimals) this request settles."
          },
          "earning_count": {
            "type": "integer"
          },
          "tx_signature": {
            "type": "string"
          }
        }
      },
      "PreMintRefusal": {
        "type": "object",
        "required": [
          "detail",
          "pre_mint",
          "reward_asset"
        ],
        "properties": {
          "detail": {
            "type": "string"
          },
          "pre_mint": {
            "type": "boolean",
            "const": true
          },
          "reward_asset": {
            "type": "string",
            "const": "CRANK"
          }
        }
      }
    }
  }
}
