duskly-ai Verify API
The Verify API from duskly-ai — 2 operation(s) for verify.
The Verify API from duskly-ai — 2 operation(s) for verify.
Every API here is available over the APIs.io API and to AI agents over MCP.
One button, every client — Claude, Cursor, VS Code and the rest.
https://apis.io/mcp
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.curl "https://apis.io/api/v1/apis/duskly-ai:duskly-ai-verify-api"
curl "https://apis.io/api/v1/apis?limit=25"
Calls without X-API-Key need no key. Calls with it need a paid plan — get a 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: 3.2.0
info:
title: Duskly image verification Verify API
version: 1.0.0
summary: Check an image for provenance marks.
description: 'One public endpoint. It inspects an uploaded image for provenance signals and returns what it found, including on images Duskly did not produce.
The result is a limited inspection report, not a certificate of authenticity or compliance. Absence of a mark is not evidence an image is a camera capture: most AI editors write nothing at all. Do not present a result as proof either way.
No key and no account. Calls without a Turnstile token are served from a smaller hourly allowance counted per IP; exceeding it returns 429 with Retry-After.
## Versioning
The stable path is `/api/v1/verify`. Integrate against it: breaking changes ship as a new path segment (`/api/v2/…`), never in place. `/api/verify` is an unversioned alias kept for links already published, and is not covered by this promise.
A retiring version is announced with a `Deprecation` header and a `Sunset` header carrying the removal date (RFC 8594), served for at least six months before removal.
## Rate limits
No key and no account. Callers without a browser bot-check token get a smaller hourly allowance counted per IP. Every response carries `RateLimit-Limit`, `RateLimit-Remaining`, `RateLimit-Reset` and `RateLimit-Policy`; a 429 adds `Retry-After`. Self-throttle on those rather than by retrying into a refusal.'
contact:
url: https://duskly.ai
email: support@duskly.ai
license:
name: Free to use, rate limited
url: https://duskly.ai/terms
servers:
- url: https://duskly.ai
tags:
- name: Verify
paths:
/api/v1/verify:
post:
summary: Inspect an image for provenance marks
operationId: verifyImage
description: 'Inspects an uploaded image for provenance marks and returns what was found. Absence of a mark is not evidence the image is a camera capture: most AI editors write nothing, and Duskly''s own paid downloads are deliberately unmarked.'
requestBody:
required: true
content:
multipart/form-data:
schema:
type: object
required:
- image
properties:
image:
type: string
format: binary
description: JPEG or PNG, up to 20MB.
responses:
'200':
description: Inspection report.
headers:
RateLimit-Limit:
schema:
type: integer
description: Requests allowed in the window.
RateLimit-Remaining:
schema:
type: integer
description: Requests left in the window.
RateLimit-Reset:
schema:
type: integer
description: Seconds until the window resets.
RateLimit-Policy:
schema:
type: string
description: e.g. 12;w=3600
content:
application/json:
schema:
$ref: '#/components/schemas/VerificationReport'
'400':
description: No image supplied, or the image could not be decoded.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'413':
description: Image larger than 20MB.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'429':
description: Hourly allowance exhausted.
headers:
RateLimit-Limit:
schema:
type: integer
description: Requests allowed in the window.
RateLimit-Remaining:
schema:
type: integer
description: Requests left in the window.
RateLimit-Reset:
schema:
type: integer
description: Seconds until the window resets.
RateLimit-Policy:
schema:
type: string
description: e.g. 12;w=3600
Retry-After:
schema:
type: integer
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'403':
description: Bot check failed. Only reachable when a token was supplied and rejected.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'503':
description: Endpoint temporarily unavailable.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
tags:
- Verify
/api/verify:
post:
summary: Inspect an image (unversioned alias)
operationId: verifyImageUnversioned
description: 'Inspects an uploaded image for provenance marks and returns what was found. Absence of a mark is not evidence the image is a camera capture: most AI editors write nothing, and Duskly''s own paid downloads are deliberately unmarked.'
requestBody:
required: true
content:
multipart/form-data:
schema:
type: object
required:
- image
properties:
image:
type: string
format: binary
description: JPEG or PNG, up to 20MB.
responses:
'200':
description: Inspection report.
headers:
RateLimit-Limit:
schema:
type: integer
description: Requests allowed in the window.
RateLimit-Remaining:
schema:
type: integer
description: Requests left in the window.
RateLimit-Reset:
schema:
type: integer
description: Seconds until the window resets.
RateLimit-Policy:
schema:
type: string
description: e.g. 12;w=3600
content:
application/json:
schema:
$ref: '#/components/schemas/VerificationReport'
'400':
description: No image supplied, or the image could not be decoded.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'413':
description: Image larger than 20MB.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'429':
description: Hourly allowance exhausted.
headers:
RateLimit-Limit:
schema:
type: integer
description: Requests allowed in the window.
RateLimit-Remaining:
schema:
type: integer
description: Requests left in the window.
RateLimit-Reset:
schema:
type: integer
description: Seconds until the window resets.
RateLimit-Policy:
schema:
type: string
description: e.g. 12;w=3600
Retry-After:
schema:
type: integer
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'403':
description: Bot check failed. Only reachable when a token was supplied and rejected.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'503':
description: Endpoint temporarily unavailable.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
tags:
- Verify
components:
schemas:
Error:
type: object
description: Every 4xx and 5xx from this API has this shape.
required:
- error
- code
properties:
error:
type: string
description: Human-readable message.
code:
type: string
description: Stable machine-readable identifier.
enum:
- image_missing
- image_too_large
- image_unreadable
- bot_check_failed
- rate_limited
- unavailable
- not_found
detail:
type: string
description: How to resolve it, where there is a clear answer.
VerificationReport:
type: object
description: What was found. Every field describes evidence, never a verdict. Mirrors VerificationReport in src/domain/marking/verify.ts.
required:
- marked
- watermark
- metadata
- summary
properties:
marked:
type: boolean
description: True when at least one Duskly mark was found. False does not mean the image is unedited — Duskly's own paid downloads carry no mark by design.
watermark:
type: object
required:
- found
- reference
- confidence
properties:
found:
type: boolean
reference:
type:
- string
- 'null'
description: Hex reference, or null when the mark was found but its payload was damaged.
confidence:
type: number
description: 0 to 1.
metadata:
type: object
required:
- digitalSourceType
- transform
- model
- originalUrl
- hasXmp
- hasC2paContainer
properties:
digitalSourceType:
type:
- string
- 'null'
description: IPTC digital source type URI, e.g. http://cv.iptc.org/newscodes/digitalsourcetype/compositeWithTrainedAlgorithmicMedia. JPEG only; null for PNG, which is not inspected.
transform:
type:
- string
- 'null'
description: The edit recorded in metadata, e.g. day-to-dusk.
model:
type:
- string
- 'null'
description: The generating model recorded in metadata.
originalUrl:
type:
- string
- 'null'
description: Public page showing the unaltered original, where one was published.
hasXmp:
type: boolean
hasC2paContainer:
type: boolean
description: 'Whether a C2PA container appears present. NOT validated: this check does not parse manifests, verify signatures or check signer trust, and Duskly does not sign manifests.'
summary:
type: array
items:
type: string
description: Plain-language lines describing the findings and their limits. Prefer repeating these over paraphrasing the fields.