openapi: 3.1.0
info:
  title: BetterVideo API
  version: "1.0.0"
  description: |
    Privacy-first video enhancement. Upscale, sharpen, and restore video through a
    single API call. We never train on your data, never sell it, and auto-delete it
    on a schedule you control.

    **Auth:** send your secret key as `Authorization: Bearer bv_live_…` (or
    `bv_test_…` for the sandbox). **Billing** is per minute of processed video; we
    detect the real duration server-side. Jobs are async — poll `/jobs/{id}` or
    provide a `webhook_url`.
  contact:
    name: BetterVideo API Support
    url: https://bettervideo.io/contact
  termsOfService: https://bettervideo.io/terms

servers:
  - url: https://api.bettervideo.io/v1

security:
  - bearerAuth: []

paths:
  /me:
    get:
      summary: Validate key & get account info
      operationId: getMe
      responses:
        "200":
          description: Account info
          content:
            application/json:
              schema: { $ref: "#/components/schemas/Account" }
        "401": { $ref: "#/components/responses/Unauthorized" }

  /jobs:
    post:
      summary: Submit a video for enhancement
      operationId: createJob
      parameters:
        - name: Idempotency-Key
          in: header
          required: false
          schema: { type: string }
          description: Repeat-safe key — a duplicate returns the original job.
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: "#/components/schemas/CreateJobRequest" }
            example:
              video_url: "https://example.com/clip.mp4"
              resolution: "1080p"
              webhook_url: "https://my-app.com/hooks/bettervideo"
      responses:
        "201":
          description: Job created
          content:
            application/json:
              schema: { $ref: "#/components/schemas/Job" }
        "400": { $ref: "#/components/responses/BadRequest" }
        "401": { $ref: "#/components/responses/Unauthorized" }
        "402": { $ref: "#/components/responses/InsufficientCredits" }

  /jobs/{id}:
    get:
      summary: Get job status
      operationId: getJob
      parameters: [{ $ref: "#/components/parameters/JobId" }]
      responses:
        "200":
          description: Job
          content: { application/json: { schema: { $ref: "#/components/schemas/Job" } } }
        "401": { $ref: "#/components/responses/Unauthorized" }
        "404": { $ref: "#/components/responses/NotFound" }
    delete:
      summary: Delete a job's data on demand
      description: Permanently deletes the original + enhanced files. Returns a signed deletion certificate on the Secure tier.
      operationId: deleteJob
      parameters: [{ $ref: "#/components/parameters/JobId" }]
      responses:
        "200":
          description: Deleted
          content:
            application/json:
              schema:
                type: object
                properties:
                  deleted: { type: boolean }
                  job_id: { type: string }
                  deleted_at: { type: string, format: date-time }
                  deletion_certificate: { $ref: "#/components/schemas/DeletionCertificate" }
        "401": { $ref: "#/components/responses/Unauthorized" }
        "404": { $ref: "#/components/responses/NotFound" }

  /jobs/{id}/result:
    get:
      summary: Get a time-limited download URL for the enhanced video
      operationId: getJobResult
      parameters: [{ $ref: "#/components/parameters/JobId" }]
      responses:
        "200":
          description: Signed URL
          content:
            application/json:
              schema:
                type: object
                properties:
                  download_url: { type: string, format: uri }
                  expires_in: { type: integer, example: 3600 }
        "401": { $ref: "#/components/responses/Unauthorized" }
        "404": { $ref: "#/components/responses/NotFound" }
        "409":
          description: Job is not yet `done`.

  /jobs/{id}/deletion-certificate:
    get:
      summary: "Secure tier: signed proof of deletion"
      operationId: getDeletionCertificate
      parameters: [{ $ref: "#/components/parameters/JobId" }]
      responses:
        "200":
          description: Deletion certificate
          content: { application/json: { schema: { $ref: "#/components/schemas/DeletionCertificate" } } }
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/UpgradeRequired" }
        "404": { $ref: "#/components/responses/NotFound" }

  /audit-log:
    get:
      summary: "Secure tier: chain-of-custody event log"
      operationId: getAuditLog
      responses:
        "200":
          description: Recent audit events
          content:
            application/json:
              schema:
                type: object
                properties:
                  events: { type: array, items: { type: object } }
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/UpgradeRequired" }

components:
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      description: "Your API key: `Authorization: Bearer bv_live_…`"

  parameters:
    JobId:
      name: id
      in: path
      required: true
      schema: { type: string }

  schemas:
    Account:
      type: object
      properties:
        org_id: { type: string }
        name: { type: string }
        plan: { type: string, enum: [standard, secure] }
        credit_balance: { type: integer, description: "Credits (1 credit = $0.01)" }
        sandbox: { type: boolean }
        limits:
          type: object
          properties: { max_video_seconds: { type: integer, example: 600 } }
        pricing_per_minute:
          type: object
          example: { "1080p": 1.80, "4k": 3.60 }

    CreateJobRequest:
      type: object
      required: [video_url, resolution]
      properties:
        video_url: { type: string, format: uri, description: "Public http(s) link to the source video" }
        resolution: { type: string, enum: ["1080p", "4k"] }
        duration_seconds:
          type: integer
          description: "Optional hint. We auto-detect the real length and bill on that (max 600s)."
        webhook_url: { type: string, format: uri, description: "We POST a signed job.completed/job.failed event here" }

    Job:
      type: object
      properties:
        id: { type: string }
        status: { type: string, enum: [queued, running, done, error, cancelled, deleted] }
        resolution: { type: string }
        duration_seconds: { type: integer }
        credits_charged: { type: integer }
        created_at: { type: string, format: date-time }
        expires_at: { type: string, format: date-time }
        error: { type: [string, "null"] }

    DeletionCertificate:
      type: object
      properties:
        type: { type: string, example: bettervideo.deletion_certificate }
        org_id: { type: string }
        job_id: { type: string }
        deleted_at: { type: string, format: date-time }
        statement: { type: string }
        signature: { type: string, description: "HMAC-SHA256 of the certificate body" }

    Error:
      type: object
      properties:
        error:
          type: object
          properties:
            code: { type: string }
            message: { type: string }
            type: { type: string }

  responses:
    Unauthorized:
      description: Missing or invalid API key
      content: { application/json: { schema: { $ref: "#/components/schemas/Error" } } }
    BadRequest:
      description: Validation error
      content: { application/json: { schema: { $ref: "#/components/schemas/Error" } } }
    NotFound:
      description: Resource not found
      content: { application/json: { schema: { $ref: "#/components/schemas/Error" } } }
    InsufficientCredits:
      description: Not enough credits (top up or enable auto-recharge)
      content: { application/json: { schema: { $ref: "#/components/schemas/Error" } } }
    UpgradeRequired:
      description: Secure-tier feature on a Standard key
      content: { application/json: { schema: { $ref: "#/components/schemas/Error" } } }
