openapi: 3.1.1
info:
  title: SecretsBuster API
  version: 1.0.0
  summary: Our automated service for vulnerability scanning
  description: |
    SecretsBuster is a service that scans your website for leaked secrets. It
    crawls your website, looking for sensitive information that may have been
    exposed.

    By using this API, you can leverage the full potential of SecretsBuster by
    automating the process of scanning your assets. This means you can bind it
    to your CI/CD pipelines, schedule scans periodically accross your public
    surface, even create your own monitoring dashboard.

    SecretsBuster API is a REST service that uses JSON as its data format.
    You will need an API key to use it. You can purchase one at
    https://secretsbuster.com/api/subscribe.  
servers:
  - url: https://api.secretsbuster.com/{basePath}    
    variables:
      basePath:
        description: SecretsBuster API version. Currently, only v1 is available.
        enum: [ v1 ]
        default: v1
paths:
  /reports:
    summary: Operations about reports, creating and retrieving them as a list.
    description: |
      Reports are the main resource of SecretsBuster API.

      Reports are the result of a scan, which is the process of crawling a
      target URL and other associated resources in search of leaked secrets.
    get:
      summary: Get all reports for your account
      description: |
        This endpoint returns a list of all reports associated with your account,
        meaning that even if you have multiple API keys, you will see reports
        created by all of them.

        This endpoint is paginated at 100 reports per page. You can navigate
        through the pages by using the `page` query parameter.

        You can also filter reports by:
        - their `scan_result` field, which can be `LEAKY`, `SAFE` or `ERROR`
        - their `reviewed` status, which can be `true` or `false`. See the 'PATCH'
          endpoint of 'report' resource for more information about this field.
      
        You can combine these filters and pagination by using the `&` character
        between them.        
      parameters:
        - name: scan_result
          description: |
            Filter reports by their scan result. Possible values are `LEAKY`,
            `SAFE` or `ERROR`.

            A report is `LEAKY` if at least one secret was found in target URL
            or one of associated resources, otherwise it is `SAFE`. A report has
            an `ERROR` scan result if something went wrong during the crawling of
            the target URL. Errors in associated resources doesn't make a report
            `ERROR` as long as target URL can be scanned. 
          required: false
          allowEmptyValue: false
          in: query
          schema:
            type: string
            enum: [ LEAKY, SAFE, ERROR ]
          example: LEAKY
        - name: reviewed
          description: |
            Filter reports by their reviewed status. Possible values are `true`
            or `false`.

            A report is `reviewed` if you have set a review (comment) through
            the `reports` path `PATCH` endpoint.
          required: false
          allowEmptyValue: false
          in: query
          schema:
            type: boolean
          example: true
        - name: page
          description: |
            The page number to retrieve. This endpoint is paginated at 100
            reports per page.
          required: false
          allowEmptyValue: false
          in: query
          schema:
            type: integer
            minimum: 1
          example: 1
      responses:
        '200':
          description: Your account reports, possibly filtered, paginated at 100 reports per page.
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/Report'
        '400':
          description: |
            One of the optional query parameters is invalid. Check the error and parameter documentation.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '401':
          $ref: '#/components/responses/401'
        '500':
          $ref: '#/components/responses/500'
    post:
      summary: Create a new report
      description: |
        This endpoint creates a new report.
        
        Reports are the result of a scan, which is the process of crawling a
        target URL and other associated resources in search of leaked secrets.

        Creating a report is a limited operation. Your API key is tied to a
        usage plan, which limits the number of reports you can create per period.
        You can use the `/accounts/me` endpoint to check your account status,
        specifically your API key(s) details and remaining requests for the period.

        The report will be in `QUEUED` state until it is processed by our system.
        You should periodically poll the report endpoint until it reaches
        `CRAWLED` or `ERROR` state. **Keep in mind that frequent report polling is
        usless, as the report creation process is asynchronous and may take a
        between 10 and 30 seconds, depending on current load on our system and the
        number of associated resources for target URL**.

        The report creation process is asynchronous, meaning that the response
        will be returned immediately, even if the report is not yet processed.
        The response will contain the report's unique identifier named `publicId`,
        which you can use to poll the `/reports/{publicId}` endpoint.        
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ReportRequest'
        required: true
      responses:
        '201':
          description: |
            Report successfuly created. Note that the report returned by this
            request will probably be in 'QUEUED' state. You should poll the
            report endpoint until it reaches 'CRAWLED' or 'ERROR' state.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Report'
        '400':
          description: |
            Request body doesn't match the 'ReportRequest' schema (a JSON document
            with only one 'url' parameter), or if provided URL is invalid.
            
            Review your JSON document (format, escaping, typos...) and the URL
            you provided.

            Check the error message for more details.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '401':
          $ref: '#/components/responses/401'          
        '403':
          description: |
            Report creation is forbidden if you have reached your maximum request
            per period for given API key.

            Use the `/accounts/me` endpoint to check your account status, specifically
            your API key(s) details and total requests for the period.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '500':
          $ref: '#/components/responses/500'
  /reports/{publicId}:
    summary: Operation about a specific report, retrieving and reviewing it.
    description: |
      Reports are the main resource of SecretsBuster API.

      Reports are the result of a scan, which is the process of crawling a
      target URL and other associated resources in search of leaked secrets.
    get:
      summary: Get a report by its unique identifier
      description: |
        Reports are the result of a scan, which is the process of crawling a
        target URL and other associated resources in search of leaked secrets.

        You should have previously created a report to use this endpoint.
        The `POST` method for `/reports` endpoint will return a `publicId` that
        you can use to retrieve the report.

        The report will be in `QUEUED` state until it is processed by our system.
        You should periodically poll the report endpoint until it reaches
        `CRAWLED` or `ERROR` state. **Keep in mind that frequent report polling is
        usless, as the report creation process is asynchronous and may take a
        between 10 and 30 seconds, depending on current load on our system and the
        number of associated resources for target URL**.

        A `QUEUED` or `CRAWLING` report will have most of its fields empty.
      parameters:
        - name: publicId
          description: |
            The unique identifier of the report, as returned by the `POST` method of the
            `/reports` endpoint.

            This parameter is required and must be a valid UUID string representation.
          in: path
          required: true
          allowEmptyValue: false
          schema:
            type: string
            format: uuid
          example: 123e4567-e89b-12d3-a456-426614174000
      responses:
        '200':
          description: |
            The report object you requested.

            The report will be in `QUEUED` state until it is processed by our system.
            You should periodically poll the report endpoint until it reaches
            `CRAWLED` or `ERROR` state. **Keep in mind that frequent report polling is
            usless, as the report creation process is asynchronous and may take a
            between 10 and 30 seconds, depending on current load on our system and the
            number of associated resources for target URL**.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Report'
        '400':
          description: |
            Absent or invalid `publicId` parameter.

            `publicId` must be provided as a path parameter and must be a valid UUID string representation.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '401':
          $ref: '#/components/responses/401'
        '404':
          description: |
            The report with given `publicId` doesn't exist, or doesn't belong to this key's account.

            Check the `publicId` you provided and make sure it is correct.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '500':
          $ref: '#/components/responses/500'
    patch:
      summary: Review a report
      description: |
        The only modification (`PATCH`) allowed for reports is review.
        
        Review means that you can set a comment on it. This comment will
        be visible in the report object, next to the date of review.

        Report scan must be finished to allow reviewing, meaning that you
        can only review a report that is in `CRAWLED` or `ERROR` state.

        Obviously you can only review an existing report. As for the `GET`
        method of this endpoint, you must use the `publicId` of the report
        you want to review as a path parameter.
      parameters:
        - name: publicId
          description: |
            The unique identifier of the report, as returned by the `POST` method of the
            `/reports` endpoint.

            This parameter is required and must be a valid UUID string representation.
          in: path
          required: true
          allowEmptyValue: false
          schema:
            type: string
            format: uuid
          example: 123e4567-e89b-12d3-a456-426614174000
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ReviewRequest'
      responses:
        '200':
          description: |
            The report object you just reviewed, with the new `reviewedAt` and
            `review`values`.  
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Report'
        '400':
          description: |
            Absent or invalid `publicId` parameter.

            `publicId` must be provided as a path parameter and must be a valid UUID string representation.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '401':
          $ref: '#/components/responses/401'
        '404':
          description: |
            The report with given `publicId` doesn't exist, or doesn't belong to this key's account.

            Check the `publicId` you provided and make sure it is correct.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '409':
          description: |
            The report is still pending scan, so it can't be reviewed.

            You can only review a report that is in `CRAWLED` or `ERROR` state.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '500':
          $ref: '#/components/responses/500'
  /accounts/me:
    summary: Operations about your account, retrieved by your API key
    description: |
      This endpoint is used to retrieve information about your account, specifically
      the API key(s) you have, the total requests you made for the period and the
      remaining requests you can make.
    get:
      summary: Get your account details
      description: |
        This endpoint returns information about your account, specifically the API
        key(s) you have, the total requests you made for the period and the remaining
        requests you can make.

        The total requests you can make for the period is a fixed number, depending
        on the API key you have. You can check your account status by submitting your
        email at https://secretsbuster.com/api/manage.
      responses:
        '200':          
          description: Your account details
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Account'
                type: object
                properties:
                  email:
                    type: string
                    format: email
                    description: Your account email
                  apiKey:
                    type: string
                    description: Your API key
                  totalRequests:
                    type: integer
                    description: The total number of requests you can make for the period
                  remainingRequests:
                    type: integer
                    description: The remaining number of requests you can make for the period
        '401':
          $ref: '#/components/responses/401'
        '500':
          $ref: '#/components/responses/500'
components:
  securitySchemes:
    ApiKeyAuth:
      type: apiKey
      description: |
        An API Key is required in order to use SecretsBuster API. You can
        purchase a key at https://secretsbuster.com/api/subscribe. The key must be
        provided for each API call, using the 'X-API-Key' header.

        **Your API key is tied to a usage plan. This plan defines the number
        of report you can create per period, meaning your quota only decreases
        when you `POST` to `/reports`.** Note that other endpoints
        (getting your reports, report details, report reviewing, account
        details...) don't consume your quota.
      name: X-API-Key
      in: header
  schemas:
    ReportRequest:
      type: object
      description: |
        `ReportRequest` is the payload you must provide when you're requesting
        a new report creation through the `POST` `/reports` endpoint.
        
        This is a JSON object with only one parameter, `url`, which is the
        URL you want to scan for leaked secrets.
      properties:
        url:
          type: string
          format: uri
          description: |
            The URL you want to scan for leaked secrets. It must be a valid URL,
            meaning that it must include the scheme. You may provide path
            components after the domain.
          example: https://mywebsite.com
      required:
        - url
    ReviewRequest:
      description: |
        `ReviewRequest` is the payload you must provide when you're reviewing
        (commenting) an existing report through the `PATCH` `/reports/{publicId}`.

        This is a JSON object with only one parameter, `review`, which is a
        string limited to 1000 characters.

        Reviewing will also set the date of the review, set at the request datetime.
      type: object
      properties:
        review:
          description: |
            The review you want to set on the report. This review will be visible
            in the report object, next to the date of review.

            Limited to 1000 characters, will be truncated if longer.
          type: string
          maxLength: 1000
          example: |
            This secret leak on our website is set to be fixed on the next sprint.
      required:
        - url
    Report:
      type: object
      description: |
        `Report` is SecretsBuster's main resource. It is the result of a scan,
        which is the process of crawling a target URL and other associated
        resources in search of leaked secrets.

        Report content changes as the report is processed.

        All `datetime` fields are in ISO 8601 format and in UTC timezone.
      properties:
        publicId:
          type: string
          format: uuid
          description: |
            The unique identifier of the report. This is the ID you must provide
            when you want to retrieve or update (review) the report.
          example: 123e4567-e89b-12d3-a456-426614174000
        url:
          type: string
          format: uri
          description: |
            The URL submitted when new report request was sent.
          example: https://mywebsite.com
        state:
          type: string
          enum:
            - QUEUED
            - CRAWLING
            - CRAWLED
            - ERROR
          description: |
            The current state of the report. Report in `CRAWLING` state should
            be requested again in a few seconds.

            **Keep in mind that frequent report polling is
            useless, as the report creation process is asynchronous and may take a
            between 10 and 30 seconds, depending on current load on our system and the
            number of associated resources for target URL**.
          example: CRAWLED
        submittedAt:
          type: string
          format: date-time
          description: |
            The date and time when the report was submitted, in ISO 8601
            format and UTC timezone.
          example: 2024-12-21T12:00:00Z
        startedAt:
          type: string
          format: date-time
          description: |
            Optional. The date and time when crawl started. Note that if this
            value is defined, `state` can't be `QUEUED`.

            ISO 8601 format and UTC timezone.
          example: 2024-12-21T12:00:05Z
        crawledAt:
          type: string
          format: date-time
          description: |
            Optional. The date and time when crawl ended. Note that if this
            value is defined, `state` can't be `QUEUED` or `CRAWLING`, i.e.
            `state` is one of `CRAWLED` or `ERROR`, meaning crawling is
            finished.

            ISO 8601 format and UTC timezone.
          example: 2024-12-21T12:00:15Z
        scanResult:
          type: string
          enum:
            - LEAKY
            - SAFE
            - ERROR
          description: |
            Optional. `scanResult` is only defined if `state` is `CRAWLED` or
            `ERROR`, meaning crawling is finished. A `LEAKY` report has at least
            one entry in `secrets` array.
          example: LEAKY
        documentCount:
          type: integer
          description: |
            Optional. The number of documents scanned in search for leaked secrets. Note that
            SecretsBuster doesn't crawl the whole website, but only the documents
            that are linked to the target URL and other relevant resources.

            Only defined if `state` is `CRAWLED` or `ERROR`, meaning crawling is finished.
          example: 42
        secrets:
          type: array
          items:
            $ref: '#/components/schemas/MatchReport'
          description: |
            Optional. The list of secrets found in the documents, as an array of
            `MatchReport`. `secrets` is only defined if `scanResult` is `LEAKY`.
        error:
          type: string
          description: |
            Optional. `error` is only defined if `state` is `ERROR`. This field
            is only used when something went wrong (in an unexpected way) during
            the crawling process.
        targetDocumentError:
          type: string
          description: |
            Optional. 'targetDocumentError' is only defined if 'state' is
            'ERROR'. This is where you can find details about a target URL that
            can't be reached.
      required:
        - publicId
        - url
        - state
        - submittedAt
    MatchReport:
      type: object
      description: |
        The `MatchReport` object contains information about a document scanned
        for leaked secrets. It is part of a `Report` object, specifically in the
        `secrets` array.

        There will be one `MatchReport` for each leaky document found dureing a
        scan. One `MatchReport` can contain multiple `MatchResult` objects,
        i.e. a document may leak multiple secrets.
      properties:
        documentUrl:
          type: string
          format: uri
          description: |
            The URL for this document. This document may belong from a different
            domain that report target's one.
          example: https://cdn.mywebsite.com/myleakyscript.js
        error:
          type: string
          description: |
            Optional. `error` is only defined if there was an error while
            scanning this document.
        matchResults:
          type: array
          items:
            $ref: '#/components/schemas/MatchResult'
      required:
        - documentUrl
        - matchResults
    MatchResult:
      type: object
      description: |
        The `MatchResult` object contains information about a secret found in a
        document. It is part of a `MatchReport` object, specifically in the
        `matchResults` array.

        There will be one `MatchResult` for each secret found in a document, but
        the same secret may appear more than once in this document (repeated).
      properties:
        secretType:
          type: string
          description: |
            The type of secret found in the document. We constantly add new
            detection scheme, so this is not a finite list.
          example: Github App Token
        secretValues:
          type: object
          additionalProperties:
            type: integer
          description: |
            The list of secrets of type `secretType` found in the document. The
            key is the secret value and the value is the number of times it was
            found.
          example:
            'MYSQL_PASSWORD: MySuperSecretPassword': 1
            'ERP_API_KEY: Password1234!': 3
      required:
        - secretType
        - secretValues
    Account:
      type: object
      description: |
        The account object contains information about your account, specifically
        the API key(s) you have, the total requests you made for the period and the
        remaining requests you can make.

        It only shows your current API keys, not the one that has expired.
      properties:
        emailAddress:
          type: string
          format: email
          description: |
            The email address used as a unique ID for your account.

            This is the same address you used to purchase your API key,
            submitted at https://secretsbuster.com/api/subscribe
          example: redteam@mycomp.com
        keys:
          type: array
          description: |
            The active API keys associated with your account.
          items:
            $ref: '#/components/schemas/ApiKey'        
    ApiKey:
      type: object
      description: |
        The API key object contains information about your API key, specifically
        the API usage plan it is tied with and the remaining requests you
        can make for this period.
      properties:
        apiKeyId:
          type: string
          description: |
            The API key ID. This is NOT the value you must provide in the
            'X-API-Key' header.

            This unique identifier is not used during API calls, but can be
            useful for debugging purposes.
        usagePlan:
          $ref: '#/components/schemas/UsagePlan'                      
        remainingRequests:
          type: integer
          description: |
            The remaining number of requests you can make for the period
          minimum: 0
          example: 42
    UsagePlan:
      type: object
      description: |
        The usage plan object contains information about your SecretsBuster API subscription.
      properties:
        name:
          type: string
          description: |
            The commercial name of the usage plan.
          example: Enterprise
        quota:
          type: integer
          description: |
            The total number of requests you can make for the period.          
          example: 100
        periodicity:
          type: string
          description: |
            The periodicity for this plan.

            For example, a 'MONTHLY' plan will reset your quota at the begining of
            each month.
          example: MONTHLY
    Error:
      type: object
      properties:
        message:
          type: string
          description: The error message
      required:
        - error
  responses:
    '401':
      description: |
        Unauthorized, no account for given API key.

        Either: 
        - you failed to provide an API key using the `X-API-Key` header
        - the key you provided is invalid (not found in our database, expired...)
        - there is no SecretsBuster account associated with this key

        You can check your account status by submitting your email at https://secretsbuster.com/api/manage        
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    '500':
      description: |
        Internal server error.

        This error occurs when something unexpected happens on our side. It may be
        temporary but if it lasts, please contact us at https://secretsbuster.com/about#contact
security:
  - ApiKeyAuth: []
