> ## Documentation Index
> Fetch the complete documentation index at: https://benchgen.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Create a benchmark from a bundle

> Upload a competition bundle you already have and the platform creates the benchmark from it, in one request. Send `multipart/form-data` with the zip in the `bundle` field (`file` is accepted too). The zip must hold `competition.yaml` in its root; the usual mistake is zipping the folder instead of its contents, and the error says so. The platform refuses a zip that is not an archive, has no title in its manifest, is larger than 512 MB, unpacks to more than 2 GB, holds more than 10000 files, compresses far beyond what real content does, or carries entries that would escape the extract folder. Everything else about the bundle is checked while it is unpacked, and reported through `creation_status`. The benchmark is created unpublished. The web app's three-step presigned upload still exists and is what a browser should use. Requires the `benchmark:create` scope and charges the same creation limits as `create_from_spec` (for API tokens and agents, by default 10 per rolling 24 hours and 3 per minute); a dry run does not count.

A bundle is the full benchmark format, so this is how you create anything a
spec cannot express: several phases, several tasks, your own scoring program
and metrics, custom leaderboard columns, image and code benchmarks, and a
custom Docker image. See [Bundle structure](/docs/eval/bundle-structure) for the
files and [YAML reference](/docs/eval/yaml-reference) for every `competition.yaml`
field.


## OpenAPI

````yaml POST /api/competitions/create_from_bundle/
openapi: 3.0.3
info:
  title: BenchGen Platform API
  version: 1.0.0
  description: >-
    One API for the whole BenchGen platform: model catalogue and serving,
    fine-tuning and benchmarks, datasets (knowledge), and billing.


    ## Authentication

    Every request uses the same credential: a platform API token sent as
    `Authorization: Bearer bgn_...`.

    Create tokens in the web app under Profile Settings > Platform API tokens
    (the secret is shown exactly once), or via `POST /api/tokens/` with an
    interactive session. Revoking a token disables it platform-wide within 60
    seconds.


    ## Scopes

    A token carries scopes chosen at creation; a request outside the token's
    scopes gets `403` with an explanatory message.


    | scope | grants |

    |---|---|

    | `models:read` | read model catalogues, job status, logs, GPU info |

    | `models:write` | deploy, train, merge, stop models and jobs |

    | `benchmark:read` | read benchmark runs and results |

    | `benchmark:run` | launch benchmark runs |

    | `benchmark:create` | create benchmarks in your account (drafts, Excel,
    bundles, specs); counts toward the creation limit |

    | `benchmark:manage` | edit and delete benchmarks you own or collaborate on
    |

    | `benchmark:publish` | publish and unpublish benchmarks you own or
    collaborate on |

    | `knowledge:read` | read your datasets and fine-tuning data |

    | `knowledge:write` | create, edit and delete datasets and fine-tuning data
    |

    | `billing:read` | read your balance and usage |

    | `agents:chat` | chat with your own agents through the API |

    | `agents:manage` | manage your agents, knowledge bases and channels |

    | `admin` | everything the account can do (staff accounts only) |


    ## For agents

    This document plus `/api/llms.txt` are the machine-readable entry points.
    Responses are JSON. Errors use conventional status codes; the body carries
    `error` or `message`. Knowledge endpoints return `[{"data": [...], "meta":
    {...}}]`.


    The complete auto-generated schema of every endpoint (including internal
    ones) lives at `/api/public-docs.json` (Swagger 2.0); this document is the
    curated, stable, supported surface.
  contact:
    url: https://benchgen.com
servers:
  - url: https://api.benchgen.com
security:
  - platformToken: []
tags:
  - name: auth
    description: Token introspection for services and integrations
  - name: tokens
    description: Manage your platform API tokens
  - name: models
    description: Model catalogue and serving
  - name: finetune
    description: Fine-tuning jobs, inference deployments, GPUs
  - name: knowledge
    description: Datasets and fine-tuning data (knowledge API)
  - name: billing
    description: Balance and usage
  - name: agents
    description: Chat with your agents (OpenAI-compatible facade)
  - name: benchmark
    description: Public benchmark (competition) listings.
paths:
  /api/competitions/create_from_bundle/:
    post:
      tags:
        - benchmark
      summary: Create a benchmark from a bundle zip
      description: >-
        Upload a competition bundle you already have and the platform creates
        the benchmark from it, in one request. Send `multipart/form-data` with
        the zip in the `bundle` field (`file` is accepted too). The zip must
        hold `competition.yaml` in its root; the usual mistake is zipping the
        folder instead of its contents, and the error says so. The platform
        refuses a zip that is not an archive, has no title in its manifest, is
        larger than 512 MB, unpacks to more than 2 GB, holds more than 10000
        files, compresses far beyond what real content does, or carries entries
        that would escape the extract folder. Everything else about the bundle
        is checked while it is unpacked, and reported through `creation_status`.
        The benchmark is created unpublished. The web app's three-step presigned
        upload still exists and is what a browser should use. Requires the
        `benchmark:create` scope and charges the same creation limits as
        `create_from_spec` (for API tokens and agents, by default 10 per rolling
        24 hours and 3 per minute); a dry run does not count.
      parameters:
        - name: dry_run
          in: query
          required: false
          schema:
            type: boolean
          description: 'Validate only: answers 200 with a summary and creates nothing'
      requestBody:
        required: true
        content:
          multipart/form-data:
            schema:
              type: object
              required:
                - bundle
              properties:
                bundle:
                  type: string
                  format: binary
                  description: The competition bundle .zip
                file:
                  type: string
                  format: binary
                  description: Accepted as an alias for bundle
      responses:
        '200':
          description: 'dry_run: the bundle is usable; nothing was created'
          content:
            application/json:
              schema:
                type: object
                properties:
                  valid:
                    type: boolean
                  title:
                    type: string
                    description: The title from competition.yaml
                  files:
                    type: integer
                  bytes:
                    type: integer
                  unpacked_bytes:
                    type: integer
                  warnings:
                    type: array
                    items:
                      type: string
                    description: >-
                      Advice that does not block creation: a leaderboard column
                      no scoring program appears to write, placeholder text left
                      in the manifest, an empty image, or a manifest with no
                      pages.
        '201':
          description: Creation queued
          content:
            application/json:
              schema:
                type: object
                properties:
                  valid:
                    type: boolean
                  title:
                    type: string
                  files:
                    type: integer
                  bytes:
                    type: integer
                  unpacked_bytes:
                    type: integer
                  status_id:
                    type: integer
                    description: Poll GET /api/competitions/{status_id}/creation_status/
                  warnings:
                    type: array
                    items:
                      type: string
                    description: >-
                      Advice that does not block creation: a leaderboard column
                      no scoring program appears to write, placeholder text left
                      in the manifest, an empty image, or a manifest with no
                      pages.
        '400':
          description: The bundle is not usable; `errors` lists every problem found
          content:
            application/json:
              schema:
                type: object
                properties:
                  valid:
                    type: boolean
                  errors:
                    type: array
                    items:
                      type: string
        '403':
          description: >-
            The token lacks benchmark:create, or the account role may not create
            benchmarks
        '429':
          description: Creation limit reached; a Retry-After header says when to try again
      security:
        - platformToken: []
        - interactiveToken: []
        - session: []
components:
  securitySchemes:
    platformToken:
      type: http
      scheme: bearer
      bearerFormat: bgn_ opaque token
      description: >-
        Platform API token created under Profile Settings > Platform API tokens.
        Scopes are fixed at creation.
    interactiveToken:
      type: apiKey
      in: header
      name: Authorization
      description: >-
        Interactive token from `POST /api/api-token-auth/`, sent as
        `Authorization: Token <token>`. Unlike a platform `bgn_` token this is a
        full interactive credential (it is minted from your password), so it may
        create and revoke platform tokens. Keep it out of CI; put a scoped
        `bgn_` token there instead.
    session:
      type: apiKey
      in: cookie
      name: sessionid
      description: >-
        Interactive browser session, the `sessionid` cookie Django sets when you
        sign in to the web app (benchgen.com). To script this endpoint, sign in
        in a browser and copy the `sessionid` cookie from DevTools > Application
        > Cookies. The recommended path is simply the web app itself: Profile
        Settings > Platform API tokens. Platform tokens are deliberately refused
        here (403), so a leaked token can never mint successors.

````