snapwonders-com Reveal API

**Extract hidden content from a stego image.** Requires the same password used when the content was originally hidden. All endpoints require `X-Api-Key`. **Workflow — 6 steps:** **Step 1 — Create a session** `POST /api/session` · body: `{"type":"reveal"}` Returns `upload_uid` — include it in every upload for this session. **Step 2 — Upload the stego image** `POST /api/upload` · headers `X-Upload-Uid`, `X-Filename`, `Content-Type`, file as the body. This is the carrier image that contains the hidden content. Large files or unreliable connections: TUS `POST /api/tus` with `Upload-Metadata: upload_uid ,step MQ==`, `POST` to create then `PATCH` the raw binary. **Step 3 — Verify the upload is complete** `GET /api/session/{uid}/files` The file must show `"status":"completed"` before proceeding. **Step 4 — Start the extraction job** `POST /api/job` · Required: `upload_uid`, `password`, `expiry` Encoding options (`output_format`, etc.) are accepted but ignored for reveal jobs. Returns `{"status":"queued", ...}`. **Step 5 — Poll until done** `GET /api/job/{uid}` — repeat every few seconds. Watch `status`: `queued` → `processing` → `completed` (or `partial` / `failed`). **Step 6 — Download the extracted content** `GET /api/job/{uid}/results` Returns `result_files` with a `download_url` for each file that was extracted from the stego image.

Operations 6

POST /api/session Create an upload session #
GET /api/session/{uid}/files List uploaded files for a session #
POST /api/job Start a processing job #
GET /api/job/{uid} Get job status #
GET /api/job/{uid}/results Get job result files #
GET /api/job/download/{assetId} Download a hide/reveal result 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-reveal-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-reveal-api-openapi.yml Raw ↑
openapi: 3.2.0
info:
  title: snapWONDERS API / MCP Reveal 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: Reveal
  description: '**Extract hidden content from a stego image.** Requires the same password used when the content was originally hidden. All endpoints require `X-Api-Key`.


    **Workflow — 6 steps:**


    **Step 1 — Create a session**

    `POST /api/session` · body: `{"type":"reveal"}`

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


    **Step 2 — Upload the stego image**

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

    This is the carrier image that contains the hidden content.

    Large files or unreliable connections: TUS `POST /api/tus` with `Upload-Metadata: upload_uid ,step MQ==`, `POST` to create then `PATCH` the raw binary.


    **Step 3 — Verify the upload is complete**

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

    The file must show `"status":"completed"` before proceeding.


    **Step 4 — Start the extraction job**

    `POST /api/job` · Required: `upload_uid`, `password`, `expiry`

    Encoding options (`output_format`, etc.) are accepted but ignored for reveal jobs.

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


    **Step 5 — Poll until done**

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

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


    **Step 6 — Download the extracted content**

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

    Returns `result_files` with a `download_url` for each file that was extracted from the stego image.'
paths:
  /api/session:
    post:
      tags:
      - Reveal
      summary: Create an upload session
      description: Creates a new upload session for a **hide** (conceal) or **reveal** (extract) 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_stego_session_create
      requestBody:
        required: true
        content:
          application/json:
            schema:
              required:
              - type
              properties:
                type:
                  description: '`hide` to conceal content inside a cover image; `reveal` to extract hidden content from a stego image.'
                  type: string
                  enum:
                  - hide
                  - reveal
                  example: hide
              type: object
      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
                  type:
                    type: string
                    enum:
                    - hide
                    - reveal
                  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: Step-by-step upload instructions. Each key is a step name; value describes what to upload and which TUS metadata to set.
                    type: object
                type: object
        '400':
          description: Invalid `type` value
        '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/session/{uid}/files:
    get:
      tags:
      - Reveal
      summary: List uploaded files for a session
      description: Returns all files currently attached to a session. Use this to verify that all uploads have completed (status `complete`) and that each file is on the correct step before calling `POST /api/job`. **Authentication:** `X-Api-Key` header required.
      operationId: get_api_stego_session_files
      parameters:
      - name: uid
        in: path
        description: The `upload_uid` returned by `POST /api/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
                  type:
                    type: string
                    enum:
                    - hide
                    - reveal
                  session_status:
                    type: string
                    example: uploading
                  files:
                    type: array
                    items:
                      properties:
                        step:
                          description: 1 = secret/content to hide; 2 = cover image (hide sessions only)
                          type: integer
                          example: 1
                        name:
                          type: string
                          example: photo.jpg
                        mime_type:
                          type: string
                          example: image/jpeg
                        file_size:
                          description: File size in bytes
                          type: integer
                        status:
                          description: 'pending: upload in progress; complete: ready for job; staged: job already started'
                          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/job:
    post:
      tags:
      - Reveal
      summary: Start a processing job
      description: 'Submits options and dispatches the steganography job to the worker queue. All files must be fully uploaded via TUS before calling this endpoint — verify with `GET /api/session/{uid}/files`.


        **Hide jobs** accept the full set of encoding options below. **Reveal jobs** only use `upload_uid`, `password`, and `expiry` — all encoding keys are ignored.


        The call is **idempotent**: submitting options 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_stego_job_start
      requestBody:
        required: true
        content:
          application/json:
            schema:
              required:
              - upload_uid
              - password
              - expiry
              properties:
                upload_uid:
                  description: The `upload_uid` returned by `POST /api/session`
                  type: string
                  format: uuid
                  example: 550e8400-e29b-41d4-a716-446655440000
                password:
                  description: Encryption password. Required for both hide and reveal. Must be at least 8 characters with mixed case, a digit, and a symbol.
                  type: string
                  example: Str0ng!Pass
                expiry:
                  description: 'How long the result download link remains 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
                output_format:
                  description: '**Hide only.** Image format for stego output files. All formats are lossless. Default: `avif`.'
                  type: string
                  enum:
                  - avif
                  - heic
                  - jp2
                  - jxl
                  - png
                  - webp
                  example: avif
                packing_strategy:
                  description: '**Hide only.** How secrets are distributed across covers. `spread`: each cover altered as little as possible (default). `tight`: pack multiple secrets per cover to minimise cover count. `quality`: preserve visual quality above all else.'
                  type: string
                  enum:
                  - spread
                  - tight
                  - quality
                  example: spread
                scale_secret_to_fit:
                  description: '**Hide only.** When a secret is too large to hide in its cover, automatically reduce it (resize images, increase video compression) until it fits. Set to `false` to fail instead of degrading quality. Default: `true`.'
                  type: boolean
                  example: true
                strip_cover_metadata:
                  description: '**Hide only.** Remove EXIF, GPS, and all other embedded metadata from the stego output cover. Recommended when privacy matters. Default: `false`.'
                  type: boolean
                  example: false
                strip_secret_metadata:
                  description: '**Hide only.** Remove EXIF, GPS, and embedded metadata from secret files before they are hidden. Reduces payload size. Default: `false`.'
                  type: boolean
                  example: false
                video_output_format:
                  description: '**Hide only, video covers.** Lossless codec and container for stego video output. Default: `ffv1_mkv`.'
                  type: string
                  enum:
                  - ffv1_mkv
                  - huffyuv_avi
                  - lagarith_avi
                  - magicyuv_avi
                  - prores4444_mov
                  - prores4444xq_mov
                  - av1lossless_mkv
                  example: ffv1_mkv
                secret_video_crf:
                  description: '**Hide only, video secrets.** Compression quality for secret videos before hiding (lower = better quality, larger payload). Default: `28`.'
                  type: integer
                  maximum: 40
                  minimum: 18
                  example: 28
                secret_video_codec:
                  description: '**Hide only, video secrets.** Codec used to compress secret videos. `h265` gives ~40% smaller payloads. Default: `h265`.'
                  type: string
                  enum:
                  - h264
                  - h265
                  example: h265
                vault_profile_id:
                  description: '**Pro accounts only, hide jobs only.** ID of a Vault Profile to use as an additional key factor in the steganographic key derivation. Vault profiles are created and managed at `/vault` in the web UI. Providing this on a free account returns HTTP 402.'
                  type: integer
                  example: 1
              type: object
      responses:
        '201':
          description: Job queued
          content:
            application/json:
              schema:
                properties:
                  upload_uid:
                    description: Session UUID — use with `GET /api/job/{uid}` to poll status
                    type: string
                    format: uuid
                    example: 550e8400-e29b-41d4-a716-446655440000
                  job_uid:
                    description: Job UUID — identical to `upload_uid` for stego (1:1 session:job). Provided for SDK consistency across all three pipelines.
                    type: string
                    format: uuid
                    example: 550e8400-e29b-41d4-a716-446655440000
                  reference:
                    description: Short human-readable reference (REF- prefix + first 8 chars)
                    type: string
                    example: REF-550E8400
                  job_type:
                    type: string
                    enum:
                    - hide
                    - reveal
                  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` — weak password, 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`.'
        '402':
          description: Pro account required — `vault_profile_id` is only available on Pro plans
        '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/job/{uid}:
    get:
      tags:
      - Reveal
      summary: Get job status
      description: 'Returns the current status and progress of a steganography processing job. Poll this endpoint until `status` is terminal: `completed`, `partial`, `failed` or `terminated` (there is no `done` status). Once it is, call `GET /api/job/{uid}/results` with the same `X-Api-Key` to retrieve per-file asset IDs. **Authentication:** `X-Api-Key` header required.'
      operationId: get_api_stego_job_status
      parameters:
      - name: uid
        in: path
        description: The `upload_uid` returned by `POST /api/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: Job status
          content:
            application/json:
              schema:
                properties:
                  upload_uid:
                    type: string
                    format: uuid
                  job_uid:
                    description: Job UUID — identical to `upload_uid` for stego (1:1 session:job). Provided for SDK consistency across all three pipelines.
                    type: string
                    format: uuid
                  reference:
                    type: string
                    example: REF-550E8400
                  job_type:
                    type: string
                    enum:
                    - hide
                    - reveal
                  status:
                    type: string
                    enum:
                    - queued
                    - processing
                    - completed
                    - partial
                    - failed
                    - terminated
                  progress_message:
                    description: Human-readable description of the current worker stage, e.g. "Encoding cover 2/5"
                    type:
                    - string
                    - 'null'
                  queued_at:
                    type:
                    - string
                    - 'null'
                    format: date-time
                  started_at:
                    type:
                    - string
                    - 'null'
                    format: date-time
                  completed_at:
                    type:
                    - string
                    - 'null'
                    format: date-time
                  error:
                    description: Error description when `status` is `failed`
                    type:
                    - string
                    - 'null'
                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/job/{uid}/results:
    get:
      tags:
      - Reveal
      summary: Get job result files
      description: Returns download URLs for all result files once a job is complete. If the job is still processing, `result_files` will be an empty array — keep polling `GET /api/job/{uid}` until `status` is terminal (`completed`, `partial`, `failed` or `terminated`). **Authentication:** `X-Api-Key` header required.
      operationId: get_api_stego_job_results
      parameters:
      - name: uid
        in: path
        description: The `upload_uid` returned by `POST /api/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: Job results
          content:
            application/json:
              schema:
                properties:
                  upload_uid:
                    type: string
                    format: uuid
                  job_uid:
                    description: Job UUID — identical to `upload_uid` for stego (1:1 session:job). Provided for SDK consistency across all three pipelines.
                    type: string
                    format: uuid
                  reference:
                    type: string
                    example: REF-550E8400
                  job_type:
                    type: string
                    enum:
                    - hide
                    - reveal
                  status:
                    type: string
                    enum:
                    - queued
                    - processing
                    - completed
                    - partial
                    - failed
                    - terminated
                  result_files:
                    description: Empty while job is still processing; populated once `status` is `complete`
                    type: array
                    items:
                      properties:
                        asset_id:
                          description: Pass to `GET /api/job/download/{assetId}` with the same `X-Api-Key` to download the file.
                          type: string
                          format: uuid
                        name:
                          type: string
                          example: stego-output-1.avif
                        mime_type:
                          type: string
                          example: image/avif
                        file_size:
                          description: File size in bytes
                          type: integer
                      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/job/download/{assetId}:
    get:
      tags:
      - Reveal
      summary: Download a hide/reveal result file
      description: Downloads a single result file from a hide or reveal job. The file must belong to a session created with the same `X-Api-Key`. Returns the raw binary file. **Authentication:** `X-Api-Key` header required.
      operationId: get_api_stego_file_download
      parameters:
      - name: assetId
        in: path
        description: The `asset_id` from a file in `result_files` returned by `GET /api/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 — raw binary. `Content-Disposition: attachment` or `inline` depending on MIME type.'
        '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