{
  "openapi": "3.1.0",
  "info": {
    "title": "Okaro Agent API",
    "version": "0.1.0-preview",
    "summary": "Expense tracking, multi-currency FX and AI receipt OCR — exposed to AI agents and automations.",
    "description": "Okaro's public Agent API. The receipt-analysis endpoint is generally available today; transaction, card and FX endpoints are in preview and tracked on https://okaro.harukibox.com/en/agents — submit your agent at support@harukibox.com to be notified when each surfaces.",
    "termsOfService": "https://okaro.harukibox.com/en/terms",
    "contact": {
      "name": "HarukiBox",
      "email": "support@harukibox.com",
      "url": "https://okaro.harukibox.com/en/agents"
    },
    "license": {
      "name": "Proprietary (API) / MIT (clients)",
      "url": "https://okaro.harukibox.com/en/terms"
    }
  },
  "servers": [
    {
      "url": "https://okaro.harukibox.com",
      "description": "Production"
    }
  ],
  "x-ai-plugin": "https://okaro.harukibox.com/.well-known/ai-plugin.json",
  "x-mcp": "https://okaro.harukibox.com/.well-known/mcp.json",
  "x-llms-txt": "https://okaro.harukibox.com/llms.txt",
  "x-developer-portal": "https://okaro.harukibox.com/en/agents",
  "security": [
    { "BearerAuth": [] }
  ],
  "paths": {
    "/api/analyze-receipt": {
      "post": {
        "operationId": "analyzeReceipt",
        "summary": "Analyse a receipt image and return structured JSON.",
        "description": "Sends a receipt image to Gemini 2.5 and returns amount, merchant, date and line items. This endpoint is generally available.",
        "x-status": "stable",
        "requestBody": {
          "required": true,
          "content": {
            "multipart/form-data": {
              "schema": {
                "type": "object",
                "required": ["image"],
                "properties": {
                  "image": {
                    "type": "string",
                    "format": "binary",
                    "description": "Receipt image, max ~5MB. JPEG/PNG/WebP/HEIC."
                  },
                  "locale": {
                    "type": "string",
                    "enum": ["zh", "en", "ja"],
                    "description": "Preferred response language for merchant names / categories.",
                    "default": "en"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Structured receipt JSON.",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/ReceiptAnalysis" }
              }
            }
          },
          "400": { "$ref": "#/components/responses/BadRequest" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "429": { "$ref": "#/components/responses/RateLimited" }
        }
      }
    },
    "/api/v1/transactions": {
      "x-status": "preview",
      "get": {
        "operationId": "listTransactions",
        "summary": "List transactions for the authenticated user.",
        "parameters": [
          { "name": "from", "in": "query", "schema": { "type": "string", "format": "date" }, "description": "Inclusive start date." },
          { "name": "to", "in": "query", "schema": { "type": "string", "format": "date" }, "description": "Inclusive end date." },
          { "name": "merchant", "in": "query", "schema": { "type": "string" } },
          { "name": "categoryId", "in": "query", "schema": { "type": "string" } },
          { "name": "cardId", "in": "query", "schema": { "type": "string" } },
          { "name": "currency", "in": "query", "schema": { "type": "string", "minLength": 3, "maxLength": 3 } },
          { "name": "limit", "in": "query", "schema": { "type": "integer", "default": 50, "maximum": 200 } },
          { "name": "cursor", "in": "query", "schema": { "type": "string" } }
        ],
        "responses": {
          "200": {
            "description": "Paginated list of transactions.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": { "type": "array", "items": { "$ref": "#/components/schemas/Transaction" } },
                    "nextCursor": { "type": "string", "nullable": true }
                  }
                }
              }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" }
        }
      },
      "post": {
        "operationId": "createTransaction",
        "summary": "Create a transaction on behalf of the user.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": { "$ref": "#/components/schemas/NewTransaction" }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Transaction created.",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/Transaction" }
              }
            }
          },
          "400": { "$ref": "#/components/responses/BadRequest" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "429": { "$ref": "#/components/responses/RateLimited" }
        }
      }
    },
    "/api/v1/fx/convert": {
      "x-status": "preview",
      "get": {
        "operationId": "convertCurrency",
        "summary": "Convert an amount between currencies.",
        "parameters": [
          { "name": "amount", "in": "query", "required": true, "schema": { "type": "number" } },
          { "name": "from", "in": "query", "required": true, "schema": { "type": "string", "minLength": 3, "maxLength": 3 } },
          { "name": "to", "in": "query", "required": true, "schema": { "type": "string", "minLength": 3, "maxLength": 3 } },
          { "name": "lockedRate", "in": "query", "schema": { "type": "number" }, "description": "If supplied, use this rate instead of the live mid-market rate (used to lock the actual card swipe rate)." }
        ],
        "responses": {
          "200": {
            "description": "Converted amount.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "amount": { "type": "number" },
                    "from": { "type": "string" },
                    "to": { "type": "string" },
                    "rate": { "type": "number" },
                    "lockedRate": { "type": "boolean" },
                    "asOf": { "type": "string", "format": "date-time" }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/cards": {
      "x-status": "preview",
      "get": {
        "operationId": "listCards",
        "summary": "List the user's payment cards with current-month spend stats.",
        "responses": {
          "200": {
            "description": "Cards array.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": { "$ref": "#/components/schemas/Card" }
                }
              }
            }
          }
        }
      }
    },
    "/api/export": {
      "x-status": "stable",
      "get": {
        "operationId": "exportTransactions",
        "summary": "Export reconciliation CSV / JSON for the user.",
        "parameters": [
          { "name": "format", "in": "query", "required": true, "schema": { "type": "string", "enum": ["csv", "json"] } },
          { "name": "from", "in": "query", "schema": { "type": "string", "format": "date" } },
          { "name": "to", "in": "query", "schema": { "type": "string", "format": "date" } }
        ],
        "responses": {
          "200": {
            "description": "Exported file.",
            "content": {
              "text/csv": { "schema": { "type": "string" } },
              "application/json": { "schema": { "type": "object" } }
            }
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "BearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "sk_okaro_*",
        "description": "Scoped API key issued from Okaro Web → Settings → Agent Keys."
      }
    },
    "responses": {
      "BadRequest": {
        "description": "Invalid input.",
        "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }
      },
      "Unauthorized": {
        "description": "Missing or invalid API key, or scope not granted.",
        "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }
      },
      "RateLimited": {
        "description": "Rate limit exceeded.",
        "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }
      }
    },
    "schemas": {
      "Error": {
        "type": "object",
        "required": ["code", "message"],
        "properties": {
          "code": { "type": "string" },
          "message": { "type": "string" },
          "requestId": { "type": "string" }
        }
      },
      "ReceiptAnalysis": {
        "type": "object",
        "properties": {
          "merchant": { "type": "string" },
          "amount": { "type": "number" },
          "currency": { "type": "string" },
          "date": { "type": "string", "format": "date" },
          "items": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "name": { "type": "string" },
                "quantity": { "type": "number" },
                "price": { "type": "number" }
              }
            }
          },
          "confidence": { "type": "number", "minimum": 0, "maximum": 1 }
        }
      },
      "NewTransaction": {
        "type": "object",
        "required": ["amount", "currency", "date"],
        "properties": {
          "amount": { "type": "number" },
          "currency": { "type": "string", "minLength": 3, "maxLength": 3 },
          "date": { "type": "string", "format": "date" },
          "merchant": { "type": "string" },
          "categoryId": { "type": "string" },
          "cardId": { "type": "string" },
          "notes": { "type": "string" },
          "customerCurrency": { "type": "string", "description": "When set, Okaro records both the supplier-side amount and the customer-side billing amount." },
          "customerAmount": { "type": "number" },
          "lockedRate": { "type": "number", "description": "Lock the actual card swipe rate instead of live FX." },
          "receipt": {
            "oneOf": [
              { "type": "string", "format": "uri", "description": "Signed URL the agent has access to." },
              { "type": "string", "format": "byte", "description": "Base64-encoded image bytes." }
            ]
          }
        }
      },
      "Transaction": {
        "allOf": [
          { "$ref": "#/components/schemas/NewTransaction" },
          {
            "type": "object",
            "required": ["id", "createdAt"],
            "properties": {
              "id": { "type": "string" },
              "createdAt": { "type": "string", "format": "date-time" },
              "agentId": { "type": "string", "description": "ID of the agent that created this transaction, if any." },
              "receiptUrl": { "type": "string", "format": "uri" }
            }
          }
        ]
      },
      "Card": {
        "type": "object",
        "properties": {
          "id": { "type": "string" },
          "name": { "type": "string" },
          "last4": { "type": "string" },
          "isDefault": { "type": "boolean" },
          "monthSpend": { "type": "number" },
          "monthCurrency": { "type": "string" }
        }
      }
    }
  }
}
