{
 "openapi": "3.1.0",
 "info": {
  "title": "Login Vault",
  "version": "1.0.0",
  "description": "Scoped login vault for AI agents. Your bot signs in to sites without ever seeing the password: you save each login encrypted with a scope (which sites, which HTTP methods, a daily cap), hand each bot its own key limited to the logins you granted, and the server fills the password, keeps the cookies and returns an opaque session id. Every use is in the audit log; revoke a bot in one call. Free 500/day; Pro $9/month: https://pay.instaloops.com/b/4gM6oHeG42sv2mHgt983C3E"
 },
 "servers": [
  {
   "url": "https://vault.cloudforbots.com"
  }
 ],
 "components": {
  "securitySchemes": {
   "bearer": {
    "type": "http",
    "scheme": "bearer"
   }
  }
 },
 "paths": {
  "/api/run/save_login": {
   "post": {
    "operationId": "save_login",
    "summary": "Owner only (your Pro key, never a bot key)",
    "description": "Owner only (your Pro key, never a bot key). Store one login sealed with AES-256-GCM, with a scope: allowed hosts, allowed methods, a daily session cap and session TTL. Run it from your own machine, not inside the bot. The password and TOTP secret are never returned by any tool. Free watch-only stores nothing and logs would_use_vault.",
    "security": [
     {},
     {
      "bearer": []
     }
    ],
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "type": "object",
        "properties": {
         "name": {
          "type": "string",
          "description": "Short id, e.g. \"github-bot\" (letters, digits, . _ - @)."
         },
         "domain": {
          "type": "string",
          "description": "Site the login belongs to, e.g. github.com."
         },
         "username": {
          "type": "string"
         },
         "password": {
          "type": "string"
         },
         "totp_secret": {
          "type": "string",
          "description": "Optional base32 TOTP secret, so {{totp}} can fill 2FA codes."
         },
         "scope": {
          "type": "object",
          "description": "Where and how this login may be used.",
          "properties": {
           "allowed_hosts": {
            "type": "array",
            "items": {
             "type": "string"
            },
            "description": "Hosts the session may call (the login domain is always included; subdomains match). Max 10."
           },
           "allowed_methods": {
            "type": "array",
            "items": {
             "type": "string"
            },
            "description": "HTTP methods session_fetch may use. Default [\"GET\",\"POST\"]."
           },
           "max_sessions_per_day": {
            "type": "integer",
            "description": "Daily cap on open_session for this login, 1-500. Default 20."
           },
           "ttl_s": {
            "type": "integer",
            "description": "Session lifetime in seconds, 60-3600. Default 900."
           },
           "bot_label": {
            "type": "string",
            "description": "Optional note: which bot this login is for."
           }
          }
         }
        },
        "required": [
         "name",
         "domain",
         "username",
         "password"
        ]
       }
      }
     }
    },
    "responses": {
     "200": {
      "description": "Result with job, understood, outcome, usage",
      "content": {
       "application/json": {
        "schema": {
         "type": "object"
        }
       }
      }
     },
     "401": {
      "description": "bad_agent_key"
     },
     "429": {
      "description": "free_limit_reached (includes upgrade link)"
     }
    }
   }
  },
  "/api/run/list_logins": {
   "post": {
    "operationId": "list_logins",
    "summary": "List saved logins (name, domain, scope, sessions today; never secrets)",
    "description": "List saved logins (name, domain, scope, sessions today; never secrets). With your owner key it also lists bot keys. A bot key only sees the logins it was granted.",
    "security": [
     {},
     {
      "bearer": []
     }
    ],
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "type": "object",
        "properties": {}
       }
      }
     }
    },
    "responses": {
     "200": {
      "description": "Result with job, understood, outcome, usage",
      "content": {
       "application/json": {
        "schema": {
         "type": "object"
        }
       }
      }
     },
     "401": {
      "description": "bad_agent_key"
     },
     "429": {
      "description": "free_limit_reached (includes upgrade link)"
     }
    }
   }
  },
  "/api/run/delete_login": {
   "post": {
    "operationId": "delete_login",
    "summary": "Owner only",
    "description": "Owner only. Delete a saved login, end its open sessions and remove it from every bot key.",
    "security": [
     {},
     {
      "bearer": []
     }
    ],
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "type": "object",
        "properties": {
         "name": {
          "type": "string"
         }
        },
        "required": [
         "name"
        ]
       }
      }
     }
    },
    "responses": {
     "200": {
      "description": "Result with job, understood, outcome, usage",
      "content": {
       "application/json": {
        "schema": {
         "type": "object"
        }
       }
      }
     },
     "401": {
      "description": "bad_agent_key"
     },
     "429": {
      "description": "free_limit_reached (includes upgrade link)"
     }
    }
   }
  },
  "/api/run/create_bot_key": {
   "post": {
    "operationId": "create_bot_key",
    "summary": "Owner only",
    "description": "Owner only. Make a per-bot key (vk_...) that can only open sessions on the logins you name. Shown once; we store only its hash. Revoke any time with revoke_bot_key.",
    "security": [
     {},
     {
      "bearer": []
     }
    ],
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "type": "object",
        "properties": {
         "label": {
          "type": "string",
          "description": "Which bot, e.g. \"invoice-bot\"."
         },
         "logins": {
          "type": "array",
          "items": {
           "type": "string"
          },
          "description": "Names of saved logins this bot may use."
         }
        },
        "required": [
         "label",
         "logins"
        ]
       }
      }
     }
    },
    "responses": {
     "200": {
      "description": "Result with job, understood, outcome, usage",
      "content": {
       "application/json": {
        "schema": {
         "type": "object"
        }
       }
      }
     },
     "401": {
      "description": "bad_agent_key"
     },
     "429": {
      "description": "free_limit_reached (includes upgrade link)"
     }
    }
   }
  },
  "/api/run/revoke_bot_key": {
   "post": {
    "operationId": "revoke_bot_key",
    "summary": "Owner only",
    "description": "Owner only. Revoke a bot key right away and end every session it opened.",
    "security": [
     {},
     {
      "bearer": []
     }
    ],
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "type": "object",
        "properties": {
         "bot_id": {
          "type": "string"
         }
        },
        "required": [
         "bot_id"
        ]
       }
      }
     }
    },
    "responses": {
     "200": {
      "description": "Result with job, understood, outcome, usage",
      "content": {
       "application/json": {
        "schema": {
         "type": "object"
        }
       }
      }
     },
     "401": {
      "description": "bad_agent_key"
     },
     "429": {
      "description": "free_limit_reached (includes upgrade link)"
     }
    }
   }
  },
  "/api/run/open_session": {
   "post": {
    "operationId": "open_session",
    "summary": "Sign in with a saved login without seeing it",
    "description": "Sign in with a saved login without seeing it. The server fills {{username}}, {{password}} and {{totp}} into your form, posts it to url (https, inside the login's allowed hosts), keeps the cookies encrypted, and returns an opaque session id. Checked against the login's scope and daily cap; logged to the audit log. If the site shows a CAPTCHA or new-device check, the reply suggests next_step request_human (Human Handoff relay). Free watch-only logs would_use_vault and signs in nowhere.",
    "security": [
     {},
     {
      "bearer": []
     }
    ],
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "type": "object",
        "properties": {
         "name": {
          "type": "string",
          "description": "Saved login name."
         },
         "url": {
          "type": "string",
          "description": "The sign-in endpoint, e.g. https://example.com/session."
         },
         "form": {
          "type": "object",
          "description": "Fields to send, values may use {{username}}, {{password}}, {{totp}}. Default {\"username\":\"{{username}}\",\"password\":\"{{password}}\"}."
         },
         "as": {
          "type": "string",
          "enum": [
           "form",
           "json"
          ],
          "description": "Body encoding. Default form."
         },
         "method": {
          "type": "string",
          "enum": [
           "POST",
           "PUT"
          ],
          "description": "Default POST."
         },
         "prefetch": {
          "type": "boolean",
          "description": "GET the url first to pick up CSRF cookies. Default true."
         }
        },
        "required": [
         "name",
         "url"
        ]
       }
      }
     }
    },
    "responses": {
     "200": {
      "description": "Result with job, understood, outcome, usage",
      "content": {
       "application/json": {
        "schema": {
         "type": "object"
        }
       }
      }
     },
     "401": {
      "description": "bad_agent_key"
     },
     "429": {
      "description": "free_limit_reached (includes upgrade link)"
     }
    }
   }
  },
  "/api/run/session_fetch": {
   "post": {
    "operationId": "session_fetch",
    "summary": "Make one request inside an open session",
    "description": "Make one request inside an open session. url must be https inside the login's allowed hosts and the method must be in its allowed methods. The password, TOTP secret and codes are redacted from the reply; cookies never leave the vault.",
    "security": [
     {},
     {
      "bearer": []
     }
    ],
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "type": "object",
        "properties": {
         "session": {
          "type": "string"
         },
         "url": {
          "type": "string"
         },
         "method": {
          "type": "string"
         },
         "headers": {
          "type": "object"
         },
         "body": {
          "description": "String or JSON."
         }
        },
        "required": [
         "session",
         "url"
        ]
       }
      }
     }
    },
    "responses": {
     "200": {
      "description": "Result with job, understood, outcome, usage",
      "content": {
       "application/json": {
        "schema": {
         "type": "object"
        }
       }
      }
     },
     "401": {
      "description": "bad_agent_key"
     },
     "429": {
      "description": "free_limit_reached (includes upgrade link)"
     }
    }
   }
  },
  "/api/run/end_session": {
   "post": {
    "operationId": "end_session",
    "summary": "End a session now and wipe its cookies.",
    "description": "End a session now and wipe its cookies.",
    "security": [
     {},
     {
      "bearer": []
     }
    ],
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "type": "object",
        "properties": {
         "session": {
          "type": "string"
         }
        },
        "required": [
         "session"
        ]
       }
      }
     }
    },
    "responses": {
     "200": {
      "description": "Result with job, understood, outcome, usage",
      "content": {
       "application/json": {
        "schema": {
         "type": "object"
        }
       }
      }
     },
     "401": {
      "description": "bad_agent_key"
     },
     "429": {
      "description": "free_limit_reached (includes upgrade link)"
     }
    }
   }
  },
  "/api/run/audit_log": {
   "post": {
    "operationId": "audit_log",
    "summary": "Owner only",
    "description": "Owner only. The last uses of your vault: who (bot label), which login, which domain, what happened. Never contains secrets.",
    "security": [
     {},
     {
      "bearer": []
     }
    ],
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "type": "object",
        "properties": {
         "limit": {
          "type": "integer",
          "description": "1-200, default 50."
         }
        }
       }
      }
     }
    },
    "responses": {
     "200": {
      "description": "Result with job, understood, outcome, usage",
      "content": {
       "application/json": {
        "schema": {
         "type": "object"
        }
       }
      }
     },
     "401": {
      "description": "bad_agent_key"
     },
     "429": {
      "description": "free_limit_reached (includes upgrade link)"
     }
    }
   }
  },
  "/api/run/weekly_report": {
   "post": {
    "operationId": "weekly_report",
    "summary": "Plain-English summary of the last 7 days: where your bots needed to sign in (by domain), sessions opened, blocked attempts, by bot",
    "description": "Plain-English summary of the last 7 days: where your bots needed to sign in (by domain), sessions opened, blocked attempts, by bot. Read-only. Needs a key.",
    "security": [
     {},
     {
      "bearer": []
     }
    ],
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "type": "object",
        "properties": {}
       }
      }
     }
    },
    "responses": {
     "200": {
      "description": "Result with job, understood, outcome, usage",
      "content": {
       "application/json": {
        "schema": {
         "type": "object"
        }
       }
      }
     },
     "401": {
      "description": "bad_agent_key"
     },
     "429": {
      "description": "free_limit_reached (includes upgrade link)"
     }
    }
   }
  },
  "/api/key": {
   "post": {
    "operationId": "get_free_key",
    "summary": "Get a free API key",
    "responses": {
     "200": {
      "description": "api_key"
     }
    }
   }
  }
 }
}