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

# Remove a watermark

> Submits an image for watermark removal. This is the endpoint most integrations should use — it validates the request, runs the generation, writes a generation log, and deducts credits in one call.

**This call blocks until the image is ready.** Fast models return almost immediately. Slower models are polled server-side on your behalf, so the response still arrives as a completed `200` — but it can take up to four minutes, and the request is cut off at five. Set your client's HTTP timeout accordingly; the default in most HTTP libraries is far too short.

You never need to poll this endpoint's result yourself, and there is no fire-and-forget mode — the call always holds the connection until the generation finishes, and the completed `200` body is returned either way. A `webhook_url` gets you a second copy of that same result payload `POST`ed to your server; it does not shorten the request.

On the `lite` tier that webhook is delivered once, on success only. On the async tiers (`pro`, `advance`) it can also arrive with `status: "failed"` and an `error` field when the provider reports a failure — alongside the HTTP error response — and a completed job may be delivered more than once. Treat deliveries as idempotent and key them on `job_id`; do not assume `output_urls` are byte-identical across two deliveries of the same job.

If an async job (`pro` / `advance`) is accepted by the provider and is later reported failed, the response is `500 internal_error`, not `502`. The generation is still marked failed and the credits reserved for it are refunded. Handle all `5xx` responses uniformly rather than matching on a specific status.

Allowed callers: `user`. An internal service token passes the auth gate but carries no user context, so it cannot submit a generation here.




## OpenAPI

````yaml /openapi.yaml post /api/v2/apps/watermark-remover
openapi: 3.0.3
info:
  title: GoStudio Watermark Remover API
  version: 2.0.0
  description: >
    The Watermark Remover endpoints of the GoStudio v2 REST API. Every response
    uses a standard envelope: successes return `{ status, data }`; errors return
    `{ status, error: { type, code, dev, message } }`.


    Every endpoint here takes a **Supabase user JWT** as a Bearer token. An
    `internal` service token is accepted by the auth layer but carries no user
    identity, so it cannot be used to generate or look up a job. The one
    exception is the provider callback, which is authenticated by signature
    rather than by a caller token.
servers:
  - url: https://www.gostudio.ai
    description: Production
security:
  - bearerAuth: []
tags:
  - name: Watermark Remover
    description: AI watermark removal — orchestration, model metadata, and job polling.
  - name: Webhooks
    description: Endpoints called by external services, not by your application.
paths:
  /api/v2/apps/watermark-remover:
    post:
      tags:
        - Watermark Remover
      summary: Remove a watermark
      description: >
        Submits an image for watermark removal. This is the endpoint most
        integrations should use — it validates the request, runs the generation,
        writes a generation log, and deducts credits in one call.


        **This call blocks until the image is ready.** Fast models return almost
        immediately. Slower models are polled server-side on your behalf, so the
        response still arrives as a completed `200` — but it can take up to four
        minutes, and the request is cut off at five. Set your client's HTTP
        timeout accordingly; the default in most HTTP libraries is far too
        short.


        You never need to poll this endpoint's result yourself, and there is no
        fire-and-forget mode — the call always holds the connection until the
        generation finishes, and the completed `200` body is returned either
        way. A `webhook_url` gets you a second copy of that same result payload
        `POST`ed to your server; it does not shorten the request.


        On the `lite` tier that webhook is delivered once, on success only. On
        the async tiers (`pro`, `advance`) it can also arrive with `status:
        "failed"` and an `error` field when the provider reports a failure —
        alongside the HTTP error response — and a completed job may be delivered
        more than once. Treat deliveries as idempotent and key them on `job_id`;
        do not assume `output_urls` are byte-identical across two deliveries of
        the same job.


        If an async job (`pro` / `advance`) is accepted by the provider and is
        later reported failed, the response is `500 internal_error`, not `502`.
        The generation is still marked failed and the credits reserved for it
        are refunded. Handle all `5xx` responses uniformly rather than matching
        on a specific status.


        Allowed callers: `user`. An internal service token passes the auth gate
        but carries no user context, so it cannot submit a generation here.
      operationId: removeWatermark
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/WatermarkRequest'
            examples:
              lite:
                summary: Default model
                value:
                  image_url: https://example.com/watermarked.jpg
              tier:
                summary: Named tier with webhook
                value:
                  image_url: https://example.com/watermarked.jpg
                  model_id: pro
                  webhook_url: https://your-app.com/webhooks/gostudio
      responses:
        '200':
          description: Generation completed synchronously.
          content:
            application/json:
              schema:
                type: object
                properties:
                  status:
                    type: integer
                    example: 200
                  data:
                    $ref: '#/components/schemas/WatermarkSyncResult'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '402':
          $ref: '#/components/responses/PaymentRequired'
        '403':
          $ref: '#/components/responses/Forbidden'
        '422':
          $ref: '#/components/responses/UnprocessableContent'
        '429':
          $ref: '#/components/responses/RateLimited'
        '500':
          $ref: '#/components/responses/ServerError'
        '502':
          $ref: '#/components/responses/BadGateway'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
        '504':
          $ref: '#/components/responses/GatewayTimeout'
components:
  schemas:
    WatermarkRequest:
      type: object
      required:
        - image_url
      properties:
        image_url:
          type: string
          format: uri
          description: >
            Publicly accessible `http`/`https` URL of the watermarked image. The
            API fetches it server-side, so it must not sit behind authentication
            or a firewall.
          example: https://example.com/watermarked.jpg
        model_id:
          type: string
          description: >
            Model to run. Accepts either a full model ID or one of the friendly
            tier aliases `lite`, `pro`, `advance`. Defaults to
            `dewatermark/watermark-remover-pro` (the `lite` tier). Cost per run:
            `lite` 4 credits, `pro` 4 credits, `advance` 10 credits. Call
            `/info` for the authoritative figures rather than hard-coding these
            — both the model list and the pricing can change.
          default: dewatermark/watermark-remover-pro
          example: pro
        prompt:
          type: string
          description: >
            Optional guidance. Ignored by models whose `requires_prompt` is
            `false` in the info response.
        webhook_url:
          type: string
          format: uri
          description: >
            HTTPS URL to receive the result when the generation finishes. Must
            be HTTPS; an `http://` URL is rejected with `400
            invalid_webhook_url`. Delivery is best-effort and fire-and-forget:
            the `POST` is sent once and never retried, the response status is
            ignored, and there is no signature header. If a delivery is missed,
            reconcile with `GET /api/v2/apps/watermark-remover/{jobId}`.
          example: https://your-app.com/webhooks/gostudio
    WatermarkSyncResult:
      type: object
      properties:
        job_id:
          type: integer
          example: 12345
        status:
          type: string
          enum:
            - completed
        model_id:
          type: string
          example: dewatermark/watermark-remover-pro
        output_urls:
          type: array
          description: CDN URLs for the cleaned images, usable immediately.
          items:
            type: string
            format: uri
        credits_deducted:
          type: number
          example: 4
        credit_balance:
          type: number
          description: Remaining balance after this request.
          example: 38
    ErrorResponse:
      type: object
      properties:
        status:
          type: integer
          example: 400
        error:
          type: object
          properties:
            type:
              type: string
              example: validation_error
            code:
              type: string
              example: invalid_input
            dev:
              type: integer
              example: 40001
            message:
              type: string
              example: Some information is invalid.
  responses:
    BadRequest:
      description: The request was malformed or failed validation.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          example:
            status: 400
            error:
              type: validation_error
              code: invalid_input
              dev: 40001
              message: Some information is invalid.
    Unauthorized:
      description: Missing or invalid Authorization Bearer token.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          example:
            status: 401
            error:
              type: authentication_error
              code: unauthorized
              dev: 40100
              message: Missing or invalid Authorization Bearer token.
    PaymentRequired:
      description: The account does not have enough credits for this request.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          example:
            status: 402
            error:
              type: billing_error
              code: insufficient_credits
              dev: 40200
              message: You don't have enough credits.
    Forbidden:
      description: Caller type not allowed for this endpoint.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          example:
            status: 403
            error:
              type: permission_error
              code: forbidden
              dev: 40300
              message: You don't have permission for this action.
    UnprocessableContent:
      description: >
        The request was well-formed but the content could not be processed — for
        example the image was rejected by the model or flagged as NSFW.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          example:
            status: 422
            error:
              type: provider_error
              code: content_filtered
              dev: 42205
              message: >-
                We couldn't generate this image. Please try a different prompt
                or image.
    RateLimited:
      description: Too many requests.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          example:
            status: 429
            error:
              type: rate_limit_error
              code: rate_limited
              dev: 42900
              message: You're doing that too often. Please wait a moment.
    ServerError:
      description: Unexpected server error.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          example:
            status: 500
            error:
              type: system_error
              code: internal_error
              dev: 50000
              message: Something went wrong on our end.
    BadGateway:
      description: >
        The upstream model provider rejected the submission, was unreachable, or
        returned an unusable response while the job was being submitted or
        checked. The generation is marked failed and the credits reserved for it
        are refunded.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          example:
            status: 502
            error:
              type: provider_error
              code: provider_bad_gateway
              dev: 50200
              message: Generation is having trouble right now. Please try again.
    ServiceUnavailable:
      description: >
        A dependency is temporarily unavailable. Auth-dependent endpoints return
        `service_unavailable` (dev 50300) when the auth provider is down;
        generation endpoints return `model_unavailable` (dev 50301) when the
        model provider is. Both are safe to retry with backoff.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          example:
            status: 503
            error:
              type: system_error
              code: service_unavailable
              dev: 50300
              message: Auth service is temporarily unavailable.
    GatewayTimeout:
      description: >
        The upstream model provider took too long to respond, or server-side
        polling gave up after 240 seconds without a result. The generation is
        marked failed and the credits reserved for it are refunded.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          example:
            status: 504
            error:
              type: provider_error
              code: generation_timeout
              dev: 50400
              message: The request took too long. Please try again.
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      bearerFormat: JWT
      description: >
        Supabase user JWT (or an internal service token). Send as
        `Authorization: Bearer <token>`.

````