{
  "openapi": "3.1.2",
  "info": {
    "title": "Holyheld Agentic",
    "version": "0.0.1",
    "termsOfService": "https://holyheld.com/legal/terms-and-conditions",
    "contact": {
      "email": "hello@holyheld.com"
    },
    "description": "This API definition is intended for usage with AI agents to interact with Holyheld\n",
    "x-logo": {
      "url": "https://github.com/holyheld/agentic-openapi/blob/main/logo.png",
      "backgroundColor": "#000000",
      "altText": "Holyheld logo",
      "href": "https://github.com/holyheld/agentic-openapi"
    },
    "license": {
      "name": "Apache 2.0",
      "identifier": "Apache-2.0"
    }
  },
  "externalDocs": {
    "description": "Find out how to use Holyheld Agentic API",
    "url": "https://docs.brrr.network"
  },
  "tags": [
    {
      "name": "Read",
      "description": "These operations do not change the state"
    },
    {
      "name": "Write",
      "description": "These operations have side effects and change the state"
    }
  ],
  "servers": [
    {
      "url": "https://apicore.holyheld.com/v4/ai-agents",
      "description": "Production server"
    }
  ],
  "paths": {
    "/balance": {
      "get": {
        "operationId": "get_card_balance",
        "tags": ["Read"],
        "summary": "Get available card balance",
        "description": "Query the available card balance which may be used by the agent\n",
        "responses": {
          "200": {
            "description": "Balance response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BalanceResponse"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedResponse"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenResponse"
          },
          "default": {
            "$ref": "#/components/responses/InternalServerErrorResponse"
          }
        }
      }
    },
    "/card-data": {
      "get": {
        "operationId": "get_card_data",
        "tags": ["Read"],
        "summary": "Get card data",
        "description": "Query the card data (card number, expiration date, cvv, etc.)\n",
        "responses": {
          "200": {
            "description": "Card data response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CardDataResponse"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedResponse"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenResponse"
          },
          "default": {
            "$ref": "#/components/responses/InternalServerErrorResponse"
          }
        }
      }
    },
    "/topup-request": {
      "post": {
        "operationId": "top_up_card",
        "summary": "Top Up card",
        "description": "Creates and executes top up request to increase available balance.\n\nThis operation (if succeeded with 200 OK response) may take some time to reflect balance changes.\nClients may want to use polling for some reasonable time (up to 5 minutes).\n",
        "tags": ["Write"],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/TopUpRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Accepted and executed top up request. The card is topped up.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SuccessResponse"
                }
              }
            },
            "links": {
              "getCardBalance": {
                "operationId": "get_card_balance",
                "description": "After topup is accepted, it may take a while before balance changes are reflected.\nClients may want to use polling for some reasonable time (up to 5 minutes).\n"
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequestResponse"
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedResponse"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenResponse"
          },
          "500": {
            "description": "Operation was not successful\n",
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/InsufficientBalanceResponse"
                    },
                    {
                      "$ref": "#/components/schemas/LimitExceededResponse"
                    }
                  ],
                  "discriminator": {
                    "propertyName": "errorCode"
                  }
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/InternalServerErrorResponse"
          }
        }
      }
    }
  },
  "components": {
    "responses": {
      "UnauthorizedResponse": {
        "description": "Unauthorized.\n\nAPI Key was not provided to the response\n",
        "content": {
          "application/json": {
            "schema": {
              "allOf": [
                {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                {
                  "type": "object",
                  "properties": {
                    "errorCode": {
                      "type": "string",
                      "example": "AI_AUTHORIZATION_INVALID",
                      "enum": ["AI_AUTHORIZATION_INVALID"]
                    },
                    "error": {
                      "type": "string",
                      "example": "Authorization header missing"
                    }
                  }
                }
              ]
            }
          }
        }
      },
      "ForbiddenResponse": {
        "description": "Forbidden.\n\nAPI Key is not valid, or the agent access is disabled\n",
        "content": {
          "application/json": {
            "schema": {
              "allOf": [
                {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                {
                  "type": "object",
                  "properties": {
                    "errorCode": {
                      "type": "string",
                      "example": "AI_AUTHORIZATION_INVALID",
                      "enum": ["AI_AUTHORIZATION_INVALID"]
                    },
                    "error": {
                      "type": "string",
                      "example": "Invalid authorization header"
                    }
                  }
                }
              ]
            }
          }
        }
      },
      "BadRequestResponse": {
        "description": "Bad Request.\n\nProvided request body or the values are malformed.\n",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/BadRequestResponse"
            }
          }
        }
      },
      "InternalServerErrorResponse": {
        "description": "Internal server error",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/InternalServerErrorResponse"
            }
          }
        }
      }
    },
    "schemas": {
      "SuccessResponse": {
        "type": "object",
        "required": ["status"],
        "properties": {
          "status": {
            "type": "string",
            "enum": ["ok"]
          }
        }
      },
      "ErrorResponse": {
        "type": "object",
        "required": ["status", "errorCode", "error"],
        "properties": {
          "status": {
            "type": "string",
            "enum": ["error"]
          },
          "errorCode": {
            "description": "Short, machine-readable, generally unique error code",
            "type": "string",
            "example": "INTERNAL_SERVER_ERROR"
          },
          "error": {
            "description": "Human-readable error description",
            "type": "string"
          }
        }
      },
      "BalanceResponse": {
        "allOf": [
          {
            "$ref": "#/components/schemas/SuccessResponse"
          },
          {
            "type": "object",
            "required": ["payload"],
            "properties": {
              "payload": {
                "type": "object",
                "required": ["balance"],
                "properties": {
                  "balance": {
                    "description": "Available balance in EUR",
                    "type": "string",
                    "example": "42.02"
                  }
                }
              }
            }
          }
        ]
      },
      "CardDataResponse": {
        "allOf": [
          {
            "$ref": "#/components/schemas/SuccessResponse"
          },
          {
            "type": "object",
            "required": ["payload"],
            "properties": {
              "payload": {
                "type": "object",
                "required": [
                  "cardNumber",
                  "expirationDate",
                  "cardholderName",
                  "CVV",
                  "billingAddress"
                ],
                "properties": {
                  "cardNumber": {
                    "description": "Card number in compact format",
                    "type": "string",
                    "example": "5200828282828210"
                  },
                  "expirationDate": {
                    "description": "Expiration date in MM/YY format",
                    "type": "string",
                    "example": "03/29"
                  },
                  "cardholderName": {
                    "description": "Card holder name",
                    "type": "string",
                    "example": "JOHN DOE"
                  },
                  "CVV": {
                    "description": "CVV/CVC",
                    "type": "string",
                    "example": "089"
                  },
                  "billingAddress": {
                    "description": "Billing address",
                    "type": "string",
                    "example": "33 OUDEGRACHT, UTRECHT, 3511 AD, NETHERLANDS"
                  }
                }
              }
            }
          }
        ]
      },
      "TopUpRequest": {
        "type": "object",
        "required": ["amount"],
        "properties": {
          "amount": {
            "type": "string",
            "pattern": "^\\d+(\\.\\d{1,2})?$",
            "example": "42.02",
            "format": "decimal"
          }
        }
      },
      "InsufficientBalanceResponse": {
        "allOf": [
          {
            "$ref": "#/components/schemas/ErrorResponse"
          },
          {
            "type": "object",
            "required": ["errorCode", "error"],
            "properties": {
              "errorCode": {
                "type": "string",
                "enum": ["AI_TOPUP_INSUFFICIENT_BALANCE"],
                "example": "AI_TOPUP_INSUFFICIENT_BALANCE"
              },
              "error": {
                "type": "string",
                "example": "Insufficient balance for top up"
              }
            }
          }
        ],
        "description": "User has no available balance on main account to top up.\n\nMore funds needed to perform this operation, further attemps\nwill fail otherwise.\n"
      },
      "InternalServerErrorResponse": {
        "description": "Some kind of internal error occured, the resource could not be provided\n",
        "allOf": [
          {
            "$ref": "#/components/schemas/ErrorResponse"
          },
          {
            "type": "object",
            "properties": {
              "errorCode": {
                "type": "string",
                "enum": ["INTERNAL_SERVER_ERROR"]
              },
              "error": {
                "type": "string",
                "enum": ["Internal Server Error"]
              },
              "payload": {
                "type": "object",
                "description": "Structured error payload (if defined for that error).\nNot sent most of the times\n"
              }
            }
          }
        ]
      },
      "BadRequestResponse": {
        "description": "Internal request or state validation failed. Request could not be processed\n",
        "allOf": [
          {
            "$ref": "#/components/schemas/ErrorResponse"
          },
          {
            "type": "object",
            "properties": {
              "errorCode": {
                "type": "string",
                "example": "WRONG_REQUEST",
                "enum": ["WRONG_REQUEST"]
              },
              "error": {
                "type": "string",
                "example": "Failed to parse request body"
              }
            }
          }
        ]
      },
      "LimitExceededResponse": {
        "description": "Set limit exceeded. Agent is inable to request top ups anymore.\n\nUser needs to manually reset the limit if that's the intention\nor the further operations will fail.\n",
        "allOf": [
          {
            "$ref": "#/components/schemas/ErrorResponse"
          },
          {
            "type": "object",
            "required": ["errorCode", "error"],
            "properties": {
              "errorCode": {
                "type": "string",
                "enum": ["AI_TOPUP_LIMIT_EXCEEDED"],
                "example": "AI_TOPUP_LIMIT_EXCEEDED"
              },
              "error": {
                "type": "string",
                "example": "Limit exceeded"
              }
            }
          }
        ]
      }
    },
    "securitySchemes": {
      "agents_auth": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "token",
        "description": "API Key issued in Holyheld dashboard"
      }
    }
  },
  "security": [
    {
      "agents_auth": []
    }
  ]
}
