snapwonders-com Convert API

**Convert images, videos, and PDFs to different formats.** Supports format conversion, quality control, image resize, video resolution cap, metadata stripping, and PDF-to-image rendering. All endpoints require `X-Api-Key`. **Workflow — 6 steps:** **Step 1 — Create a session** `POST /api/convert/session` Returns `upload_uid` — include it in every upload for this session. **Step 2 — Upload files to convert** `POST /api/upload` · headers `X-Upload-Uid`, `X-Filename`, `Content-Type`, file as the body. One request per file. Large files or unreliable connections: TUS `POST /api/tus` with `Upload-Metadata: upload_uid ,step MQ==` instead. Supported types: images (JPEG, PNG, WebP, AVIF, HEIC, JXL), videos (MP4, MKV, WebM, MOV), PDFs. **Step 3 — Verify all uploads are complete** `GET /api/convert/session/{uid}/files` All files must show `"status":"completed"` before proceeding. **Step 4 — Start the conversion job** `POST /api/convert/job` · Required: `upload_uid` Optional: `image_format`, `video_format`, `image_quality`, `video_crf`, `video_max_dimension`, `strip_metadata`, `image_resize_width`, `image_resize_height`, `pdf_dpi`, `pdf_page_from`, `pdf_page_to`, `expiry` Returns `{"status":"queued", "job_uid": "..."}`. **Step 5 — Poll until done** `GET /api/convert/job/{uid}` — repeat every few seconds. Watch `status`: `queued` → `processing` → `completed` (or `partial` / `failed`). **Step 6 — Download converted files** `GET /api/convert/job/{uid}/results` Returns `result_items` with a `download_url` for each completed item. `GET /api/convert/download/{itemUid}` — streams the output file (requires same `X-Api-Key`).

Operations 6

POST /api/convert/session Create a media convert session #
GET /api/convert/session/{uid}/files List uploaded files for a convert session #
POST /api/convert/job Start a media conversion job #
GET /api/convert/job/{uid} Get convert job status #
GET /api/convert/job/{uid}/results Get convert job results #
GET /api/convert/download/{assetId} Download a converted output file #

Work with this as data

Every API here is available over the APIs.io API and to AI agents over MCP.

MCP server

One button, every client — Claude, Cursor, VS Code and the rest.

https://apis.io/mcp

Tools for apis

7 MCP tools reach this
  • find_apisBrowse and filter every API in the catalog.
  • get_api_artifactsOne API's artifacts, grouped by type.
  • get_openapiThe primary OpenAPI for this API.
  • find_similar_apisAPIs that look like this one.
  • apis_io_searchSTART HERE — APIs, providers and tags for one query, each with its total.
  • resolveTurn a domain, URL or GitHub org into the provider it belongs to.
  • find_cohortsEvery scored population of providers in the catalog.
All 92 tools →

Call it yourself

curl for this page
This API
curl "https://apis.io/api/v1/apis/snapwonders-com:snapwonders-com-convert-api"
All apis
curl "https://apis.io/api/v1/apis?limit=25"

Discovery needs no key. Ratings and market analysis are Pro.

Get an API key

Free tier, no form to fill in. Signing in shares your email address with us — we store it to create your key and to recognise you if you sign in with another provider. See our Privacy Policy and Terms.

A second provider on the same verified email joins the account you already have.

OpenAPI Specification

snapwonders-com-convert-api-openapi.yml Raw ↑
openapi: 3.2.0
info:
  title: snapWONDERS API / MCP Convert API
  description: 'The snapWONDERS API is available over **Clearnet**, **Tor** and **I2P** (dark web). All endpoints and this Swagger UI work identically on all three networks. ---


    ## Authentication


    All endpoints **except `GET /api/status`, `OPTIONS /api/tus` and the no-auth MCP methods (`initialize`, `tools/list`, `status`, `*_get_started`)** require an API key, sent in the `X-Api-Key` request header (or as `Authorization: Bearer `):


    ```

    X-Api-Key:

    ```


    Obtain an API key from your **snapWONDERS account profile** once you have a registered account. Keys begin with `sw_` and are hashed server-side — store the raw key immediately after generation as it cannot be retrieved again. ---


    ## SDKs — skip the choreography


    Everything below this section is the **raw HTTP contract**. You do not have to write it yourself. A full run means: create a session → upload each file → start a job → poll until it finishes → fetch the result URLs → download. Uploading is one `POST /api/upload` per file, so the tedious part is the polling and the plumbing rather than the transfer — unless your files are large enough to need the resumable protocol, which is genuinely fiddly. The **snapWONDERS SDKs** collapse all of it into one call. The first two examples do the **same thing** in each language — hide `secret.pdf` inside `cover.jpg` (Vaultify stego) — and the third shows forensic analysis. Each block is self-contained, so it runs as-is. ### Python — hide a file, then download the result


    ```python

    from snapwonders import Client


    client = Client(api_key="sw_...")


    # The last path is the cover; everything before it is a secret. job = client.stego.hide(["secret.pdf", "cover.jpg"], password="Str0ng!Pass")


    for result in job.results():

    result.download("out/")

    ```


    ### JavaScript / TypeScript — the same hide, then download


    ```javascript

    import { Client } from "@snapwonders/sdk";


    const client = new Client("sw_...");


    // The last path is the cover; everything before it is a secret. const job = await client.stego.hide(["secret.pdf", "cover.jpg"], { password: "Str0ng!Pass" });


    for (const result of await job.results()) {

    await result.download("out/");

    }

    ```


    ### Python — forensic analysis, graded A–F


    ```python

    from snapwonders import Client


    client = Client(api_key="sw_...")


    # Grade each file A–F and collect the overlays the analysis produced. job = client.analyse.run(["photo.jpg"], face_detection=True)


    for item in job.results():

    print(item.filename, item.grade, item.face_count)

    for asset in item.assets: # ELA map, face overlay, …

    asset.download("out/")

    ```


    In JavaScript that is the same call — `await client.analyse.run(["photo.jpg"], { face_detection: true })` — with the result fields in camelCase (`item.faceCount`). Sessions, TUS chunking and resume, polling until the job finishes, retries on transient failures, and typed errors are all handled for you. `client.convert` (media conversion) follows the same shape: one call in, results out. | Language | Package | Install | Source |

    |----------|---------|---------|--------|

    | Python (3.10+) | `snapwonders` | `pip install snapwonders` | GitHub |

    | JavaScript / TypeScript (Node 18+) | `@snapwonders/sdk` | `npm install @snapwonders/sdk` | GitHub |

    | PHP (8.2+) | `snapwonders/sdk` | `composer require snapwonders/sdk` | GitHub |

    | Go (1.21+) | — | `go get github.com/snapWONDERS/snapWONDERS-SDK-Go` | GitHub |

    | Ruby, Java, C#, … | generated from this spec | see the Developers hub | — |


    **Status:** All four are **live**. Python and JavaScript via `pip install snapwonders` / `npm install @snapwonders/sdk`; PHP via `composer require snapwonders/sdk` on Packagist; Go straight from GitHub with `go get`. All four clients are **open source on GitHub** (Python, JavaScript / TypeScript, PHP, Go). See the **Developers hub** for full quickstarts and the generation recipe for other languages. Prefer the raw API — or working in a language without a client? Everything the SDKs do is documented below; nothing is hidden from you.'
  version: 1.0.0
servers:
- url: https://snapwonders.com
  description: Clearnet / Web
- url: http://swonderstzr43aczpcwdoyc25vwxngyromja7pyb5sf26ap3v535sxqd.onion
  description: Tor / Dark Web
- url: http://6ymp5jqysizmejdwaqiehcsgjoyb4s7sbgssquishk66drujomka.b32.i2p
  description: I2P / Dark Web
security:
- ApiKey: []
tags:
- name: Convert
  description: '**Convert images, videos, and PDFs to different formats.** Supports format conversion, quality control, image resize, video resolution cap, metadata stripping, and PDF-to-image rendering. All endpoints require `X-Api-Key`.


    **Workflow — 6 steps:**


    **Step 1 — Create a session**

    `POST /api/convert/session`

    Returns `upload_uid` — include it in every upload for this session.


    **Step 2 — Upload files to convert**

    `POST /api/upload` · headers `X-Upload-Uid`, `X-Filename`, `Content-Type`, file as the body.

    One request per file. Large files or unreliable connections: TUS `POST /api/tus` with `Upload-Metadata: upload_uid ,step MQ==` instead. Supported types: images (JPEG, PNG, WebP, AVIF, HEIC, JXL), videos (MP4, MKV, WebM, MOV), PDFs.


    **Step 3 — Verify all uploads are complete**

    `GET /api/convert/session/{uid}/files`

    All files must show `"status":"completed"` before proceeding.


    **Step 4 — Start the conversion job**

    `POST /api/convert/job` · Required: `upload_uid`

    Optional: `image_format`, `video_format`, `image_quality`, `video_crf`, `video_max_dimension`, `strip_metadata`, `image_resize_width`, `image_resize_height`, `pdf_dpi`, `pdf_page_from`, `pdf_page_to`, `expiry`

    Returns `{"status":"queued", "job_uid": "..."}`.


    **Step 5 — Poll until done**

    `GET /api/convert/job/{uid}` — repeat every few seconds.

    Watch `status`: `queued` → `processing` → `completed` (or `partial` / `failed`).


    **Step 6 — Download converted files**

    `GET /api/convert/job/{uid}/results`

    Returns `result_items` with a `download_url` for each completed item.

    `GET /api/convert/download/{itemUid}` — streams the output file (requires same `X-Api-Key`).'
paths:
  /api/convert/session:
    post:
      tags:
      - Convert
      summary: Create a media convert session
      description: Creates a new upload session for a media **convert** job. Returns the `upload_uid` you must include in every TUS upload request for this session. **Authentication:** `X-Api-Key` header required.
      operationId: post_api_convert_session_create
      requestBody:
        required: false
        content:
          application/json:
            schema:
              properties: {}
      responses:
        '201':
          description: Session created
          content:
            application/json:
              schema:
                properties:
                  upload_uid:
                    description: UUID to include in every TUS upload for this session
                    type: string
                    format: uuid
                    example: 550e8400-e29b-41d4-a716-446655440000
                  status:
                    type: string
                    example: pending
                  created_at:
                    type: string
                    format: date-time
                  tus_endpoint:
                    description: TUS root endpoint — append the upload ID for PATCH/HEAD requests
                    type: string
                    example: /api/tus
                  instructions:
                    description: Human-readable upload instructions
                    type: string
                type: object
        '401':
          description: 'Not authenticated. `error` names the exact cause: `missing_api_key`, `malformed_api_key`, `invalid_api_key` (key unknown/revoked/expired), or — when the key itself is valid — `account_not_verified` / `account_inactive`.'
        '429':
          description: Too many upload sessions created for this API key inside the sliding window (`api.session_create_hard_limit` per `api.session_create_window_seconds`, default 120 per hour). Body is the same `throttled` shape as job start, with `sessions_created`, `limit` and `window_seconds` in place of `active_jobs`. Wait for the window to pass, then retry.
  /api/convert/session/{uid}/files:
    get:
      tags:
      - Convert
      summary: List uploaded files for a convert session
      description: Returns all files currently attached to a convert session. Use this to verify that all uploads show `"status":"completed"` before calling `POST /api/convert/job`. **Authentication:** `X-Api-Key` header required.
      operationId: get_api_convert_session_files
      parameters:
      - name: uid
        in: path
        description: The `upload_uid` returned by `POST /api/convert/session`
        required: true
        schema:
          type: string
          format: uuid
          pattern: '[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}'
        example: 550e8400-e29b-41d4-a716-446655440000
      responses:
        '200':
          description: File list
          content:
            application/json:
              schema:
                properties:
                  upload_uid:
                    type: string
                    format: uuid
                  session_status:
                    type: string
                    example: pending
                  files:
                    type: array
                    items:
                      properties:
                        name:
                          type: string
                          example: photo.jpg
                        mime_type:
                          type: string
                          example: image/jpeg
                        file_size:
                          description: File size in bytes
                          type: integer
                        status:
                          description: Upload status — must be `completed` before starting job
                          type: string
                          enum:
                          - pending
                          - completed
                          - failed
                          - staged
                      type: object
                type: object
        '401':
          description: 'Not authenticated. `error` names the exact cause: `missing_api_key`, `malformed_api_key`, `invalid_api_key` (key unknown/revoked/expired), or — when the key itself is valid — `account_not_verified` / `account_inactive`.'
        '404':
          description: '`not_found` — What you''re looking for is not here.'
  /api/convert/job:
    post:
      tags:
      - Convert
      summary: Start a media conversion job
      description: 'Submits conversion options and dispatches the job to the worker queue. All files must be fully uploaded via TUS and show `"status":"completed"` (verify with `GET /api/convert/session/{uid}/files`) before calling this endpoint.


        The call is **idempotent**: calling it again for a session that already has a job returns the existing job without creating a duplicate.


        **Authentication:** `X-Api-Key` header required.'
      operationId: post_api_convert_job_start
      requestBody:
        required: true
        content:
          application/json:
            schema:
              required:
              - upload_uid
              properties:
                upload_uid:
                  description: The `upload_uid` returned by `POST /api/convert/session`
                  type: string
                  format: uuid
                  example: 550e8400-e29b-41d4-a716-446655440000
                image_format:
                  description: 'Output format for image files. Default: `jpeg`.'
                  type: string
                  enum:
                  - jpeg
                  - png
                  - webp
                  - avif
                  - heic
                  - jxl
                  example: webp
                video_format:
                  description: 'Output format for video files. Default: `mp4h264`.'
                  type: string
                  enum:
                  - mp4h264
                  - mp4h265
                  - webm
                  - mkv
                  - mov
                  example: mp4h264
                image_quality:
                  description: 'JPEG/WebP output quality 1–100. Default: 85.'
                  type: integer
                  maximum: 100
                  minimum: 1
                  example: 85
                video_crf:
                  description: 'Video CRF value 0–51 (lower = better quality). Default: 23.'
                  type: integer
                  maximum: 51
                  minimum: 0
                  example: 23
                video_max_dimension:
                  description: Cap video resolution to this height in pixels. Omit or set to 0 to keep original resolution.
                  type: integer
                  enum:
                  - 480
                  - 720
                  - 1080
                  example: 1080
                strip_metadata:
                  description: 'Strip EXIF/GPS/encoder metadata from output files. Default: `false`.'
                  type: boolean
                  example: false
                image_resize_width:
                  description: Resize images to fit within this bounding-box width in pixels. Longest-edge fit, aspect ratio preserved, no upscaling. Omit for no resize.
                  type: integer
                  maximum: 10000
                  minimum: 1
                  example: 1920
                image_resize_height:
                  description: Resize images to fit within this bounding-box height in pixels. Longest-edge fit, aspect ratio preserved, no upscaling. Omit for no resize.
                  type: integer
                  maximum: 10000
                  minimum: 1
                  example: 1080
                pdf_dpi:
                  description: '**PDF only.** Render resolution in DPI. Default: 150.'
                  type: integer
                  maximum: 300
                  minimum: 72
                  example: 150
                pdf_page_from:
                  description: '**PDF only.** First page to render, 1-based. Default: 1.'
                  type: integer
                  minimum: 1
                  example: 1
                pdf_page_to:
                  description: '**PDF only.** Last page to render, 1-based. `0` means all pages. Default: 0.'
                  type: integer
                  minimum: 0
                  example: 0
                expiry:
                  description: 'How long the result download links remain accessible after the job completes. `1h` = 1 hour, `12h` = 12 hours, `1d` = 1 day (default), `2d` = 2 days, `1w` = 1 week, `1m` = 1 month. **Free-tier keys are silently clamped** to `upload.free_max_expiry` (default `1d`): the job still succeeds, but anything longer is reduced. Pro accounts get the requested value. No response currently returns the granted expiry, so assume the free maximum unless the owning account is Pro.'
                  type: string
                  enum:
                  - 1h
                  - 12h
                  - 1d
                  - 2d
                  - 1w
                  - 1m
                  example: 1d
              type: object
      responses:
        '201':
          description: Job queued
          content:
            application/json:
              schema:
                properties:
                  upload_uid:
                    type: string
                    format: uuid
                  job_uid:
                    description: Job UUID — use with `GET /api/convert/job/{uid}` to poll status
                    type: string
                    format: uuid
                  status:
                    type: string
                    example: queued
                  queued_at:
                    type: string
                    format: date-time
                  warning:
                    description: Advisory only, and PRESENT ONLY at or above `api.concurrent_job_soft_limit`. The job has already been queued; this is the one warning you get before the hard ceiling starts returning 429. Absent (not null) below the limit, so test for presence.
                    type: string
                type: object
        '200':
          description: Job already exists (idempotent repeat call) — returns existing job
        '400':
          description: 'Validation error, named by `error`: `invalid_json`, `missing_upload_uid`, `invalid_option` (a non-scalar option value, with `option` naming the field; enum values are case-insensitive, and an unknown scalar falls back to its default with an entry in the 201 response `warnings` array), `no_files`, `no_acceptable_files` — no files uploaded, invalid option value, etc.'
        '403':
          description: '`account_blocked` — this account cannot submit jobs. Contact support; do not retry.'
        '401':
          description: 'Not authenticated. `error` names the exact cause: `missing_api_key`, `malformed_api_key`, `invalid_api_key` (key unknown/revoked/expired), or — when the key itself is valid — `account_not_verified` / `account_inactive`.'
        '404':
          description: '`not_found` — What you''re looking for is not here.'
        '429':
          description: Too many active jobs for this API key. Wait for queued/processing jobs to finish, then retry. Response includes `active_jobs` and `limit`.
  /api/convert/job/{uid}:
    get:
      tags:
      - Convert
      summary: Get convert job status
      description: 'Returns the current status and per-item progress of a conversion job. Poll this endpoint until `status` is terminal: `completed`, `partial`, `failed` or `terminated` (there is no `done` status). Once it is, call `GET /api/convert/job/{uid}/results` with the same `X-Api-Key` to retrieve per-item asset IDs. **Authentication:** `X-Api-Key` header required.'
      operationId: get_api_convert_job_status
      parameters:
      - name: uid
        in: path
        description: Either the `upload_uid` returned by `POST /api/convert/session` or the `job_uid` returned by `POST /api/convert/job`. Both identify the job.
        required: true
        schema:
          type: string
          format: uuid
          pattern: '[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}'
        example: 550e8400-e29b-41d4-a716-446655440000
      responses:
        '200':
          description: Job status
          content:
            application/json:
              schema:
                properties:
                  upload_uid:
                    type: string
                    format: uuid
                  job_uid:
                    description: Pass to `GET /api/convert/job/{uid}/results` with the same `X-Api-Key` to retrieve result files once complete.
                    type: string
                    format: uuid
                  status:
                    type: string
                    enum:
                    - queued
                    - processing
                    - completed
                    - partial
                    - failed
                    - terminated
                  total_items:
                    description: Total number of files in this job
                    type: integer
                  completed:
                    description: Number of items successfully converted
                    type: integer
                  failed:
                    description: Number of items that failed
                    type: integer
                  queued_at:
                    type:
                    - string
                    - 'null'
                    format: date-time
                  started_at:
                    type:
                    - string
                    - 'null'
                    format: date-time
                  completed_at:
                    type:
                    - string
                    - 'null'
                    format: date-time
                  items:
                    type: array
                    items:
                      properties:
                        uid:
                          type: string
                          format: uuid
                        name:
                          type: string
                          example: photo.jpg
                        status:
                          type: string
                          enum:
                          - queued
                          - processing
                          - completed
                          - failed
                          - deferred
                        progress_pct:
                          type: integer
                          maximum: 100
                          minimum: 0
                        error:
                          type:
                          - string
                          - 'null'
                      type: object
                type: object
        '401':
          description: 'Not authenticated. `error` names the exact cause: `missing_api_key`, `malformed_api_key`, `invalid_api_key` (key unknown/revoked/expired), or — when the key itself is valid — `account_not_verified` / `account_inactive`.'
        '404':
          description: '`not_found` — What you''re looking for is not here.'
  /api/convert/job/{uid}/results:
    get:
      tags:
      - Convert
      summary: Get convert job results
      description: Returns per-item conversion results with asset IDs once a job has finished (`completed` or `partial`). If the job is still processing, `result_files` will be present but items will have `"status":"queued"` or `"status":"processing"` — keep polling `GET /api/convert/job/{uid}` until `status` is terminal (`completed`, `partial`, `failed` or `terminated`) or `partial`. **Authentication:** `X-Api-Key` header required.
      operationId: get_api_convert_job_results
      parameters:
      - name: uid
        in: path
        description: Either the `upload_uid` returned by `POST /api/convert/session` or the `job_uid` returned by `POST /api/convert/job`. Both identify the job.
        required: true
        schema:
          type: string
          format: uuid
          pattern: '[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}'
        example: 550e8400-e29b-41d4-a716-446655440000
      responses:
        '200':
          description: Job results
          content:
            application/json:
              schema:
                properties:
                  upload_uid:
                    type: string
                    format: uuid
                  job_uid:
                    type: string
                    format: uuid
                  status:
                    type: string
                    enum:
                    - queued
                    - processing
                    - completed
                    - partial
                    - failed
                    - terminated
                  result_files:
                    description: One entry per input file. `asset_id` is present only when `status` is `complete` for that item.
                    type: array
                    items:
                      properties:
                        asset_id:
                          description: Pass to `GET /api/convert/download/{assetId}` with the same `X-Api-Key` to download the file.
                          type: string
                          format: uuid
                        name:
                          description: Original input filename
                          type: string
                          example: photo.jpg
                        output_name:
                          description: Output filename — null until conversion completes
                          type:
                          - string
                          - 'null'
                          example: photo.webp
                        status:
                          type: string
                          enum:
                          - queued
                          - processing
                          - completed
                          - failed
                          - deferred
                        mime_type:
                          type:
                          - string
                          - 'null'
                          example: image/webp
                        file_size:
                          description: Output file size in bytes
                          type:
                          - integer
                          - 'null'
                        error:
                          type:
                          - string
                          - 'null'
                      type: object
                type: object
        '401':
          description: 'Not authenticated. `error` names the exact cause: `missing_api_key`, `malformed_api_key`, `invalid_api_key` (key unknown/revoked/expired), or — when the key itself is valid — `account_not_verified` / `account_inactive`.'
        '404':
          description: '`not_found` — What you''re looking for is not here.'
  /api/convert/download/{assetId}:
    get:
      tags:
      - Convert
      summary: Download a converted output file
      description: Downloads a single converted output file. The item must belong to a session created with the same `X-Api-Key`. Available only once the item `status` is `complete`. **Authentication:** `X-Api-Key` header required.
      operationId: get_api_convert_download
      parameters:
      - name: assetId
        in: path
        description: The `asset_id` from `GET /api/convert/job/{uid}/results`
        required: true
        schema:
          type: string
          format: uuid
          pattern: '[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}'
        example: 550e8400-e29b-41d4-a716-446655440000
      responses:
        '200':
          description: 'File download — `Content-Disposition: attachment`'
        '401':
          description: 'Not authenticated. `error` names the exact cause: `missing_api_key`, `malformed_api_key`, `invalid_api_key` (key unknown/revoked/expired), or — when the key itself is valid — `account_not_verified` / `account_inactive`.'
        '404':
          description: '`not_found` — What you''re looking for is not here.'
components:
  securitySchemes:
    ApiKey:
      type: apiKey
      description: 'API key generated on your snapWONDERS account profile page. Required everywhere except `GET /api/status`, `OPTIONS /api/tus` and the no-auth MCP methods. `Authorization: Bearer <key>` is also accepted.'
      name: X-Api-Key
      in: header