Checked contract
OpenAPI Reference
The public YAML contract for customer API-key clients. It includes only `/v1/*` score and rewrite job routes.
DraftFilter
OpenAPI 3.1.0 · API 1.0.0Public endpoints
Score and rewrite jobs
20 operations · 44 schemas · https://api.draftfilter.com
GET
/v1/score-jobsList score jobs200, 400, 401, 403, 422POST
/v1/score-jobsCreate a score job202, 401, 402, 403, 409, 422, 429POST
/v1/uploadsCreate a file upload201, 401, 402, 403, 413, 422, 429, 503POST
/v1/uploads/{uploadId}/scanScan an uploaded file200, 401, 402, 403, 413, 422, 429, 503POST
/v1/scansScan text synchronously200, 401, 402, 403, 413, 422, 429, 503GET
/v1/scans/{scanId}/reportDownload a scan report PDF200, 401, 403, 404, 409GET
/v1/shared/{shareId}/reportDownload a shared scan report PDF200, 404GET
/v1/rewrites/{rewriteId}/reportDownload a rewrite report PDF200, 401, 403, 404, 409GET
/v1/shared/{shareId}Get a shared scan200, 404GET
/v1/usageGet account usage200, 401, 403, 404POST
/v1/scans/{scanId}/shareCreate a scan share link201, 401, 402, 403, 404, 409PATCH
/v1/scans/{scanId}/shareUpdate a scan share link200, 401, 402, 403, 404, 422DELETE
/v1/scans/{scanId}/shareRevoke a scan share link204, 401, 403, 404POST
/v1/rewritesRewrite text synchronously200, 401, 402, 403, 413, 422, 429, 503GET
/v1/rewrite-jobsList rewrite jobs200, 400, 401, 403, 422POST
/v1/rewrite-jobsCreate a rewrite job202, 401, 402, 403, 409, 422, 429POST
/v1/score-jobs/{jobId}/cancelCancel a queued score job200, 401, 403, 404, 409POST
/v1/rewrite-jobs/{jobId}/cancelCancel a queued rewrite job200, 401, 403, 404, 409GET
/v1/score-jobs/{jobId}Get a score job200, 401, 403, 404GET
/v1/rewrite-jobs/{jobId}Get a rewrite job200, 401, 403, 404Source
draftfilter-api.v1.yaml
openapi: 3.1.0
info:
title: DraftFilter
version: 1.0.0
servers:
- url: https://api.draftfilter.com
paths:
/v1/score-jobs:
get:
summary: List score jobs
operationId: listScoreJobs
parameters:
- name: limit
in: query
required: false
schema:
type: integer
maximum: 100
minimum: 1
default: 50
title: Limit
- name: cursor
in: query
required: false
schema:
anyOf:
- type: string
minLength: 1
- type: 'null'
title: Cursor
- name: includeResults
in: query
required: false
schema:
type: boolean
description: When true, each succeeded job summary includes its full public
results so a batch can be retrieved in one call.
default: false
title: Includeresults
description: When true, each succeeded job summary includes its full public
results so a batch can be retrieved in one call.
responses:
'200':
description: Cursor-paginated score job summaries for the authenticated
API key.
content:
application/json:
schema:
$ref: '#/components/schemas/ScoreJobListResponse'
'400':
$ref: '#/components/responses/BadRequest'
'401':
$ref: '#/components/responses/Unauthorized'
'403':
$ref: '#/components/responses/Forbidden'
'422':
$ref: '#/components/responses/ValidationError'
security: &id001
- bearerApiKey: []
- apiKeyHeader: []
- firebaseIdToken: []
- firebaseAppCheck: []
post:
summary: Create a score job
operationId: createScoreJob
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/ScoreJobCreateRequest'
responses:
'202':
description: Score job accepted.
content:
application/json:
schema:
$ref: '#/components/schemas/ScoreJobCreateResponse'
'409':
$ref: '#/components/responses/Conflict'
'401':
$ref: '#/components/responses/Unauthorized'
'402':
$ref: '#/components/responses/PaymentRequired'
'403':
$ref: '#/components/responses/Forbidden'
'429':
$ref: '#/components/responses/TooManyRequests'
'422':
$ref: '#/components/responses/ValidationError'
security: *id001
/v1/uploads:
post:
summary: Create a file upload
operationId: createUpload
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/UploadCreateRequest'
responses:
'201':
description: Signed upload URL for one file.
content:
application/json:
schema:
$ref: '#/components/schemas/UploadCreateResponse'
'401':
$ref: '#/components/responses/Unauthorized'
'402':
$ref: '#/components/responses/PaymentRequired'
'403':
$ref: '#/components/responses/Forbidden'
'413':
$ref: '#/components/responses/ContentTooLarge'
'422':
$ref: '#/components/responses/ValidationError'
'429':
$ref: '#/components/responses/TooManyRequests'
'503':
$ref: '#/components/responses/ServiceUnavailable'
security: *id001
/v1/uploads/{uploadId}/scan:
post:
summary: Scan an uploaded file
operationId: scanUpload
parameters:
- name: uploadId
in: path
required: true
schema:
type: string
pattern: ^upl_[A-Za-z0-9][A-Za-z0-9_-]*$
title: Uploadid
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/UploadScanRequest'
default:
forceAsync: false
responses:
'200':
description: Extracted file scan result, or a queued sentence-granularity
score job when the extracted text exceeds the synchronous scan limit.
content:
application/json:
schema:
$ref: '#/components/schemas/UploadScanResponse'
'401':
$ref: '#/components/responses/Unauthorized'
'402':
$ref: '#/components/responses/PaymentRequired'
'403':
$ref: '#/components/responses/Forbidden'
'413':
$ref: '#/components/responses/ContentTooLarge'
'422':
$ref: '#/components/responses/ValidationError'
'429':
$ref: '#/components/responses/TooManyRequests'
'503':
$ref: '#/components/responses/ServiceUnavailable'
security: *id001
/v1/scans:
post:
summary: Scan text synchronously
operationId: createScan
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/ScanCreateRequest'
responses:
'200':
description: Document score, band, confidence, and sentence results in one
response.
content:
application/json:
schema:
$ref: '#/components/schemas/ScanResponse'
'401':
$ref: '#/components/responses/Unauthorized'
'402':
$ref: '#/components/responses/PaymentRequired'
'403':
$ref: '#/components/responses/Forbidden'
'413':
$ref: '#/components/responses/ContentTooLarge'
'422':
$ref: '#/components/responses/ValidationError'
'429':
$ref: '#/components/responses/TooManyRequests'
'503':
$ref: '#/components/responses/ServiceUnavailable'
security: *id001
/v1/scans/{scanId}/report:
get:
summary: Download a scan report PDF
operationId: getScanReport
parameters:
- name: scanId
in: path
required: true
schema:
type: string
pattern: ^scan_[A-Za-z0-9][A-Za-z0-9_-]*$
title: Scanid
responses:
'200':
description: Rendered PDF report.
content:
application/pdf:
schema:
type: string
format: binary
'401':
$ref: '#/components/responses/Unauthorized'
'403':
$ref: '#/components/responses/Forbidden'
'404':
$ref: '#/components/responses/NotFound'
'409':
$ref: '#/components/responses/Conflict'
security: *id001
/v1/shared/{shareId}/report:
get:
summary: Download a shared scan report PDF
operationId: getSharedScanReport
parameters:
- name: shareId
in: path
required: true
schema:
type: string
pattern: ^share_[0-9a-f]{32,}$
title: Shareid
responses:
'200':
description: Rendered PDF report.
content:
application/pdf:
schema:
type: string
format: binary
'404':
$ref: '#/components/responses/NotFound'
security: []
/v1/rewrites/{rewriteId}/report:
get:
summary: Download a rewrite report PDF
operationId: getRewriteReport
parameters:
- name: rewriteId
in: path
required: true
schema:
type: string
pattern: ^rewrite_[A-Za-z0-9][A-Za-z0-9_-]*$
title: Rewriteid
responses:
'200':
description: Rendered PDF report.
content:
application/pdf:
schema:
type: string
format: binary
'401':
$ref: '#/components/responses/Unauthorized'
'403':
$ref: '#/components/responses/Forbidden'
'404':
$ref: '#/components/responses/NotFound'
'409':
$ref: '#/components/responses/Conflict'
security: *id001
/v1/shared/{shareId}:
get:
summary: Get a shared scan
operationId: getSharedScan
parameters:
- name: shareId
in: path
required: true
schema:
type: string
pattern: ^share_[0-9a-f]{32,}$
title: Shareid
responses:
'200':
description: Read-only shared scan result.
content:
application/json:
schema:
$ref: '#/components/schemas/SharedScanResponse'
'404':
$ref: '#/components/responses/NotFound'
security: []
/v1/usage:
get:
summary: Get account usage
operationId: getUsage
responses:
'200':
description: Current-period scan/humanize word usage, allowances, and breakdowns
for the authenticated account.
content:
application/json:
schema:
$ref: '#/components/schemas/UsageResponse'
'401':
$ref: '#/components/responses/Unauthorized'
'403':
$ref: '#/components/responses/Forbidden'
'404':
$ref: '#/components/responses/NotFound'
security: *id001
/v1/scans/{scanId}/share:
post:
summary: Create a scan share link
operationId: createScanShare
parameters:
- name: scanId
in: path
required: true
schema:
type: string
pattern: ^scan_[A-Za-z0-9][A-Za-z0-9_-]*$
title: Scanid
responses:
'201':
description: Share link created (or the existing active share returned).
content:
application/json:
schema:
$ref: '#/components/schemas/ScanShareResponse'
'401':
$ref: '#/components/responses/Unauthorized'
'403':
$ref: '#/components/responses/Forbidden'
'404':
$ref: '#/components/responses/NotFound'
'402':
$ref: '#/components/responses/PaymentRequired'
'409':
$ref: '#/components/responses/Conflict'
security: *id001
patch:
summary: Update a scan share link
operationId: updateScanShare
parameters:
- name: scanId
in: path
required: true
schema:
type: string
pattern: ^scan_[A-Za-z0-9][A-Za-z0-9_-]*$
title: Scanid
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/ScanShareUpdateRequest'
responses:
'200':
description: Share link redaction updated.
content:
application/json:
schema:
$ref: '#/components/schemas/ScanShareResponse'
'401':
$ref: '#/components/responses/Unauthorized'
'403':
$ref: '#/components/responses/Forbidden'
'404':
$ref: '#/components/responses/NotFound'
'402':
$ref: '#/components/responses/PaymentRequired'
'422':
$ref: '#/components/responses/ValidationError'
security: *id001
delete:
summary: Revoke a scan share link
operationId: revokeScanShare
parameters:
- name: scanId
in: path
required: true
schema:
type: string
pattern: ^scan_[A-Za-z0-9][A-Za-z0-9_-]*$
title: Scanid
responses:
'204':
description: Share link revoked.
'401':
$ref: '#/components/responses/Unauthorized'
'403':
$ref: '#/components/responses/Forbidden'
'404':
$ref: '#/components/responses/NotFound'
security: *id001
/v1/rewrites:
post:
summary: Rewrite text synchronously
operationId: createRewrite
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/RewriteCreateRequest'
responses:
'200':
description: 'Original and rewritten document scores plus the ordered segment
diff in one response. Anonymous App Check callers receive a redacted once-a-day
teaser: before/after scores and the single most-improved sentence, never
the full rewritten text.'
content:
application/json:
schema:
anyOf:
- $ref: '#/components/schemas/RewriteResponse'
- $ref: '#/components/schemas/RewriteTeaserResponse'
title: Response Createrewrite
'401':
$ref: '#/components/responses/Unauthorized'
'402':
$ref: '#/components/responses/PaymentRequired'
'403':
$ref: '#/components/responses/Forbidden'
'413':
$ref: '#/components/responses/ContentTooLarge'
'422':
$ref: '#/components/responses/ValidationError'
'429':
$ref: '#/components/responses/TooManyRequests'
'503':
$ref: '#/components/responses/ServiceUnavailable'
security: *id001
/v1/rewrite-jobs:
post:
summary: Create a rewrite job
operationId: createRewriteJob
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/RewriteJobCreateRequest'
responses:
'202':
description: Rewrite job accepted.
content:
application/json:
schema:
$ref: '#/components/schemas/RewriteJobCreateResponse'
'409':
$ref: '#/components/responses/Conflict'
'401':
$ref: '#/components/responses/Unauthorized'
'402':
$ref: '#/components/responses/PaymentRequired'
'403':
$ref: '#/components/responses/Forbidden'
'429':
$ref: '#/components/responses/TooManyRequests'
'422':
$ref: '#/components/responses/ValidationError'
security: &id002
- bearerApiKey: []
- apiKeyHeader: []
- firebaseIdToken: []
get:
summary: List rewrite jobs
operationId: listRewriteJobs
parameters:
- name: limit
in: query
required: false
schema:
type: integer
maximum: 100
minimum: 1
default: 50
title: Limit
- name: cursor
in: query
required: false
schema:
anyOf:
- type: string
minLength: 1
- type: 'null'
title: Cursor
- name: includeResults
in: query
required: false
schema:
type: boolean
description: When true, each succeeded job summary includes its full public
results so a batch can be retrieved in one call.
default: false
title: Includeresults
description: When true, each succeeded job summary includes its full public
results so a batch can be retrieved in one call.
responses:
'200':
description: Cursor-paginated rewrite job summaries for the authenticated
API key.
content:
application/json:
schema:
$ref: '#/components/schemas/RewriteJobListResponse'
'400':
$ref: '#/components/responses/BadRequest'
'401':
$ref: '#/components/responses/Unauthorized'
'403':
$ref: '#/components/responses/Forbidden'
'422':
$ref: '#/components/responses/ValidationError'
security: *id002
/v1/score-jobs/{jobId}/cancel:
post:
summary: Cancel a queued score job
operationId: cancelScoreJob
parameters:
- name: jobId
in: path
required: true
schema:
type: string
pattern: ^job_[A-Za-z0-9][A-Za-z0-9_-]*$
title: Jobid
responses:
'200':
description: Score job cancellation result or current terminal state.
content:
application/json:
schema:
$ref: '#/components/schemas/ScoreJobCancelResponse'
'401':
$ref: '#/components/responses/Unauthorized'
'403':
$ref: '#/components/responses/Forbidden'
'404':
$ref: '#/components/responses/NotFound'
'409':
$ref: '#/components/responses/Conflict'
security: *id001
/v1/rewrite-jobs/{jobId}/cancel:
post:
summary: Cancel a queued rewrite job
operationId: cancelRewriteJob
parameters:
- name: jobId
in: path
required: true
schema:
type: string
pattern: ^job_[A-Za-z0-9][A-Za-z0-9_-]*$
title: Jobid
responses:
'200':
description: Rewrite job cancellation result or current terminal state.
content:
application/json:
schema:
$ref: '#/components/schemas/RewriteJobCancelResponse'
'401':
$ref: '#/components/responses/Unauthorized'
'403':
$ref: '#/components/responses/Forbidden'
'404':
$ref: '#/components/responses/NotFound'
'409':
$ref: '#/components/responses/Conflict'
security: *id002
/v1/score-jobs/{jobId}:
get:
summary: Get a score job
operationId: getScoreJob
parameters:
- name: jobId
in: path
required: true
schema:
type: string
pattern: ^job_[A-Za-z0-9][A-Za-z0-9_-]*$
title: Jobid
responses:
'200':
description: Score job state and public results when complete.
content:
application/json:
schema:
$ref: '#/components/schemas/ScoreJobResponse'
'401':
$ref: '#/components/responses/Unauthorized'
'403':
$ref: '#/components/responses/Forbidden'
'404':
$ref: '#/components/responses/NotFound'
security: *id001
/v1/rewrite-jobs/{jobId}:
get:
summary: Get a rewrite job
operationId: getRewriteJob
parameters:
- name: jobId
in: path
required: true
schema:
type: string
pattern: ^job_[A-Za-z0-9][A-Za-z0-9_-]*$
title: Jobid
responses:
'200':
description: Rewrite job state and public results when complete.
content:
application/json:
schema:
$ref: '#/components/schemas/RewriteJobResponse'
'401':
$ref: '#/components/responses/Unauthorized'
'403':
$ref: '#/components/responses/Forbidden'
'404':
$ref: '#/components/responses/NotFound'
security: *id002
components:
schemas:
DashboardRewriteCreditsModel:
properties:
usedCredits:
type: integer
minimum: 0.0
title: Usedcredits
allowanceCredits:
type: integer
minimum: 0.0
title: Allowancecredits
remainingCredits:
type: integer
minimum: 0.0
title: Remainingcredits
additionalProperties: false
type: object
required:
- usedCredits
- allowanceCredits
- remainingCredits
title: DashboardRewriteCreditsModel
description: 'One-time free rewrite credit balance (issue #82); free plan only.'
ErrorResponse:
properties:
error:
properties:
code:
type: string
title: Code
message:
type: string
title: Message
pool:
anyOf:
- type: string
enum:
- scan
- humanize
- type: 'null'
title: Pool
docs:
anyOf:
- type: string
- type: 'null'
title: Docs
additionalProperties: false
type: object
required:
- code
- message
title: ErrorResponseDetail
additionalProperties: false
type: object
required:
- error
title: ErrorResponse
PublicSentenceScore:
properties:
text:
type: string
minLength: 1
title: Text
start:
type: integer
minimum: 0.0
title: Start
end:
type: integer
exclusiveMinimum: 0.0
title: End
is_ai:
type: integer
maximum: 100.0
minimum: 0.0
title: Is Ai
band:
type: string
enum:
- likely_human
- mixed
- likely_ai
title: Band
additionalProperties: false
type: object
required:
- text
- start
- end
- is_ai
- band
title: PublicSentenceScore
RewriteCreateRequest:
properties:
text:
type: string
minLength: 1
title: Text
description: Single document to rewrite synchronously. Texts over 5000 characters
are rejected with 413 rewrite_input_too_large; use the asynchronous rewrite
job API (POST /v1/rewrite-jobs) for longer documents. Anonymous App Check
callers share the 5000-character anonymous cap and are rejected with 429
anonymous_input_too_large instead.
scope:
type: string
enum:
- flagged
- document
title: Scope
description: Use flagged (default) to rewrite paragraphs containing a detector-flagged
sentence (band != likely_human), or document to rewrite every paragraph.
default: flagged
candidateCount:
type: integer
maximum: 4.0
minimum: 1.0
title: Candidatecount
description: Number of rewrite candidates to generate per target paragraph
before selecting the least AI-like option.
default: 1
additionalProperties: false
type: object
required:
- text
title: RewriteCreateRequest
RewriteJobCancelResponse:
$ref: '#/components/schemas/RewriteJobResponse'
RewriteJobCreateRequest:
properties:
idempotencyKey:
anyOf:
- type: string
maxLength: 128
minLength: 1
- type: 'null'
title: Idempotencykey
description: Reusing the same key with the same rewrite request for the
same API key returns the existing job. Reusing it with a different request
returns 409.
candidateCount:
type: integer
maximum: 4.0
minimum: 1.0
title: Candidatecount
description: Number of rewrite candidates to generate per target paragraph
before selecting the least AI-like option.
default: 1
scope:
type: string
enum:
- flagged
- document
title: Scope
description: Use flagged (default) to rewrite paragraphs containing a detector-flagged
sentence (band != likely_human), or document to rewrite every paragraph.
default: flagged
items:
items:
$ref: '#/components/schemas/RewriteItem'
type: array
maxItems: 100
minItems: 1
title: Items
description: Total text across all items must not exceed 100000 characters.
webhookUrl:
anyOf:
- type: string
maxLength: 2048
minLength: 1
- type: 'null'
title: Webhookurl
description: Optional completion webhook URL (https required). On terminal
success or failure the API posts a signed, metadata-only payload to this
URL; the per-job signing secret is returned once as webhookSecret in this
response. Delivery configuration is not part of the idempotent request
identity.
additionalProperties: false
type: object
required:
- items
title: RewriteJobCreateRequest
RewriteJobCreateResponse:
properties:
jobId:
type: string
title: Jobid
state:
type: string
enum:
- queued
- running
- succeeded
- failed
- cancelled
title: State
webhookSecret:
type: string
title: Webhooksecret
description: Per-job webhook signing secret; present only when the request
registered a webhookUrl and shown only in this response.
additionalProperties: false
type: object
required:
- jobId
- state
title: RewriteJobCreateResponse
RewriteJobListResponse:
properties:
items:
items:
$ref: '#/components/schemas/RewriteJobSummary'
type: array
title: Items
nextCursor:
anyOf:
- type: string
- type: 'null'
title: Nextcursor
additionalProperties: false
type: object
required:
- items
- nextCursor
title: RewriteJobListResponse
RewriteJobResponse:
properties:
jobId:
type: string
title: Jobid
state:
type: string
enum:
- queued
- running
- succeeded
- failed
- cancelled
title: State
results:
items:
$ref: '#/components/schemas/PublicRewriteResult'
type: array
title: Results
error:
$ref: '#/components/schemas/ErrorSummary'
title: Error
additionalProperties: false
type: object
required:
- jobId
- state
title: RewriteJobResponse
RewriteResponse:
properties:
rewriteId:
type: string
title: Rewriteid
segmentsVersion:
type: integer
const: 2
title: Segmentsversion
original:
$ref: '#/components/schemas/DocumentScore'
rewritten:
$ref: '#/components/schemas/DocumentScore'
text:
type: string
title: Text
description: The full rewritten document.
segments:
items:
$ref: '#/components/schemas/RewriteSegment'
type: array
title: Segments
iteration:
type: integer
maximum: 3.0
minimum: 1.0
title: Iteration
createdAt:
type: string
title: Createdat
additionalProperties: false
type: object
required:
- rewriteId
- segmentsVersion
- original
- rewritten
- text
- segments
- iteration
- createdAt
title: RewriteResponse
RewriteTeaserResponse:
properties:
rewriteId:
type: string
title: Rewriteid
teaser:
type: boolean
const: true
title: Teaser
description: 'Marks a redacted anonymous rewrite preview: the full rewritten
text is withheld until the caller signs in.'
default: true
original:
$ref: '#/components/schemas/DocumentScore'
rewritten:
$ref: '#/components/schemas/DocumentScore'
sample:
anyOf:
- $ref: '#/components/schemas/RewriteTeaserSample'
- type: 'null'
description: The single most-improved rewritten paragraph (largest is_ai
drop), or null when the rewrite changed nothing.
createdAt:
type: string
title: Createdat
additionalProperties: false
type: object
required:
- rewriteId
- original
- rewritten
- createdAt
title: RewriteTeaserResponse
description: 'Server-side redacted rewrite result for anonymous App Check callers.
The rewrite runs fully, but anonymous responses carry only the
before/after document scores plus the single most-improved sentence —
the full rewritten text never leaves the server (issue #69).'
ScanCreateRequest:
properties:
text:
type: string
minLength: 1
title: Text
description: Single text to scan synchronously. Texts over the plan's per-scan
character cap (5,000 anonymous, 15,000 free, 50,000 paid) are rejected
with 413 scan_input_too_large; use the asynchronous score job API for
longer documents.
additionalProperties: false
type: object
required:
- text
title: ScanCreateRequest
ScanResponse:
properties:
scanId:
type: string
title: Scanid
is_ai:
type: integer
maximum: 100.0
minimum: 0.0
title: Is Ai
band:
type: string
enum:
- likely_human
- mixed
- likely_ai
title: Band
confidence:
type: number
maximum: 1.0
minimum: 0.0
title: Confidence
description: Document-level confidence from calibration band distance.
sentences:
items:
$ref: '#/components/schemas/PublicSentenceScore'
type: array
title: Sentences
createdAt:
type: string
title: Createdat
additionalProperties: false
type: object
required:
- scanId
- is_ai
- band
- confidence
- sentences
- createdAt
title: ScanResponse
ScanShareResponse:
properties:
share:
$ref: '#/components/schemas/ScanShare'
additionalProperties: false
type: object
required:
- share
title: ScanShareResponse
ScanShareUpdateRequest:
properties:
redactText:
type: boolean
title: Redacttext
additionalProperties: false
type: object
required:
- redactText
title: ScanShareUpdateRequest
ScoreJobCancelResponse:
$ref: '#/components/schemas/ScoreJobResponse'
ScoreJobCreateRequest:
properties:
idempotencyKey:
anyOf:
- type: string
maxLength: 128
minLength: 1
- type: 'null'
title: Idempotencykey
description: Reusing the same key with the same score request for the same
API key returns the existing job. Reusing it with a different request
returns 409.
granularity:
type: string
enum:
- document
- sentence
title: Granularity
description: Use document for one public score per item, or sentence to
include sentence spans scored in document context. Sentence granularity
allows at most 10 items and 50000 total text characters.
default: document
items:
items:
$ref: '#/components/schemas/ScoreItem'
type: array
maxItems: 100
minItems: 1
title: Items
description: Total text across all items must not exceed 100000 characters.
webhookUrl:
anyOf:
- type: string
maxLength: 2048
minLength: 1
- type: 'null'
title: Webhookurl
description: Optional completion webhook URL (https required). On terminal
success or failure the API posts a signed, metadata-only payload to this
URL; the per-job signing secret is returned once as webhookSecret in this
response. Delivery configuration is not part of the idempotent request
identity.
additionalProperties: false
type: object
required:
- items
title: ScoreJobCreateRequest
ScoreJobCreateResponse:
properties:
jobId:
type: string
title: Jobid
state:
type: string
enum:
- queued
- running
- succeeded
- failed
- cancelled
title: State
webhookSecret:
type: string
title: Webhooksecret
description: Per-job webhook signing secret; present only when the request
registered a webhookUrl and shown only in this response.
additionalProperties: false
type: object
required:
- jobId
- state
title: ScoreJobCreateResponse
ScoreJobListResponse:
properties:
items:
items:
$ref: '#/components/schemas/ScoreJobSummary'
type: array
title: Items
nextCursor:
anyOf:
- type: string
- type: 'null'
title: Nextcursor
additionalProperties: false
type: object
required:
- items
- nextCursor
title: ScoreJobListResponse
ScoreJobResponse:
properties:
jobId:
type: string
title: Jobid
state:
type: string
enum:
- queued
- running
- succeeded
- failed
- cancelled
title: State
results:
items:
$ref: '#/components/schemas/PublicScoreResult'
type: array
title: Results
error:
$ref: '#/components/schemas/ErrorSummary'
title: Error
additionalProperties: false
type: object
required:
- jobId
- state
title: ScoreJobResponse
SharedScanResponse:
properties:
shareId:
type: string
title: Shareid
is_ai:
type: integer
maximum: 100.0
minimum: 0.0
title: Is Ai
band:
type: string
enum:
- likely_human
- mixed
- likely_ai
title: Band
confidence:
type: number
maximum: 1.0
minimum: 0.0
title: Confidence
description: Document-level confidence from calibration band distance.
sentences:
items:
$ref: '#/components/schemas/SharedSentenceScore'
type: array
title: Sentences
createdAt:
type: string
title: Createdat
additionalProperties: false
type: object
required:
- shareId
- is_ai
- band
- confidence
- sentences
- createdAt
title: SharedScanResponse
SharedSentenceScore:
properties:
text:
anyOf:
- type: string
minLength: 1
- type: 'null'
title: Text
start:
type: integer
minimum: 0.0
title: Start
end:
type: integer
exclusiveMinimum: 0.0
title: End
is_ai:
type: integer
maximum: 100.0
minimum: 0.0
title: Is Ai
band:
type: string
enum:
- likely_human
- mixed
- likely_ai
title: Band
additionalProperties: false
type: object
required:
- start
- end
- is_ai
- band
title: SharedSentenceScore
UploadCreateRequest:
properties:
filename:
anyOf:
- type: string
maxLength: 255
minLength: 1
- type: 'null'
title: Filename
contentType:
type: string
minLength: 1
title: Contenttype
description: 'MIME type of the file to upload. Supported: PDF, DOCX, TXT.'
sizeBytes:
type: integer
minimum: 1.0
title: Sizebytes
description: Browser-reported file size. Files over 10485760 bytes return
413.
additionalProperties: false
type: object
required:
- contentType
- sizeBytes
title: UploadCreateRequest
UploadCreateResponse:
properties:
uploadId:
type: string
title: Uploadid
signedUrl:
type: string
title: Signedurl
expiresAt:
type: string
title: Expiresat
additionalProperties: false
type: object
required:
- uploadId
- signedUrl
- expiresAt
title: UploadCreateResponse
UploadPageModel:
properties:
page:
type: integer
minimum: 1.0
title: Page
start:
type: integer
minimum: 0.0
title: Start
end:
type: integer
exclusiveMinimum: 0.0
title: End
additionalProperties: false
type: object
required:
- page
- start
- end
title: UploadPageModel
UploadScanRequest:
properties:
forceAsync:
type: boolean
title: Forceasync
description: When true, extracted text is always submitted as a sentence-granularity
score job instead of using the synchronous scan path.
default: false
additionalProperties: false
type: object
title: UploadScanRequest
UploadScanResponse:
properties:
uploadId:
type: string
title: Uploadid
status:
type: string
enum:
- scanned
- queued
title: Status
pages:
items:
$ref: '#/components/schemas/UploadPageModel'
type: array
title: Pages
scanId:
anyOf:
- type: string
- type: 'null'
title: Scanid
jobId:
anyOf:
- type: string
- type: 'null'
title: Jobid
state:
anyOf:
- type: string
enum:
- queued
- running
- succeeded
- failed
- cancelled
- type: 'null'
title: State
is_ai:
anyOf:
- type: integer
maximum: 100.0
minimum: 0.0
- type: 'null'
title: Is Ai
band:
anyOf:
- type: string
enum:
- likely_human
- mixed
- likely_ai
- type: 'null'
title: Band
confidence:
anyOf:
- type: number
maximum: 1.0
minimum: 0.0
- type: 'null'
title: Confidence
sentences:
anyOf:
- items:
$ref: '#/components/schemas/PublicSentenceScore'
type: array
- type: 'null'
title: Sentences
createdAt:
anyOf:
- type: string
- type: 'null'
title: Createdat
additionalProperties: false
type: object
required:
- uploadId
- status
- pages
title: UploadScanResponse
UsageResponse:
properties:
accountId:
type: string
title: Accountid
plan:
type: string
enum:
- free
- plus
- pro
- max
title: Plan
pools:
$ref: '#/components/schemas/UsagePools'
daily:
items:
$ref: '#/components/schemas/UsageDaily'
type: array
title: Daily
perKey:
items:
$ref: '#/components/schemas/UsageKeyBreakdown'
type: array
title: Perkey
rewriteCredits:
anyOf:
- $ref: '#/components/schemas/DashboardRewriteCreditsModel'
- type: 'null'
additionalProperties: false
type: object
required:
- accountId
- plan
- pools
- daily
- perKey
title: UsageResponse
ScoreItem:
properties:
id:
type: string
maxLength: 128
minLength: 1
title: Id
text:
type: string
maxLength: 20000
minLength: 1
title: Text
additionalProperties: false
type: object
required:
- id
- text
title: ScoreItemRequest
RewriteItem:
properties:
id:
type: string
maxLength: 128
minLength: 1
title: Id
text:
type: string
maxLength: 5000
minLength: 1
title: Text
additionalProperties: false
type: object
required:
- id
- text
title: RewriteItemRequest
RewriteSegment:
properties:
start:
type: integer
minimum: 0.0
title: Start
end:
type: integer
exclusiveMinimum: 0.0
title: End
originalText:
type: string
minLength: 1
title: Originaltext
originalIsAi:
anyOf:
- type: integer
maximum: 100.0
minimum: 0.0
- type: 'null'
title: Originalisai
rewrittenText:
type: string
minLength: 1
title: Rewrittentext
rewrittenIsAi:
anyOf:
- type: integer
maximum: 100.0
minimum: 0.0
- type: 'null'
title: Rewrittenisai
changed:
type: boolean
title: Changed
additionalProperties: false
type: object
required:
- start
- end
- originalText
- rewrittenText
- changed
title: RewriteSegmentModel
description: Ordered document slice in the versioned paragraph-segment contract.
DocumentScore:
properties:
is_ai:
type: integer
maximum: 100.0
minimum: 0.0
title: Is Ai
band:
type: string
enum:
- likely_human
- mixed
- likely_ai
title: Band
confidence:
type: number
maximum: 1.0
minimum: 0.0
title: Confidence
description: Document-level confidence from calibration band distance.
additionalProperties: false
type: object
required:
- is_ai
- band
- confidence
title: DocumentScoreModel
ScoreJobSummary:
properties:
jobId:
type: string
title: Jobid
state:
type: string
enum:
- queued
- running
- succeeded
- failed
- cancelled
title: State
createdAt:
type: string
title: Createdat
updatedAt:
type: string
title: Updatedat
completedAt:
anyOf:
- type: string
- type: 'null'
title: Completedat
itemCount:
type: integer
minimum: 0.0
title: Itemcount
inputBytes:
type: integer
minimum: 0.0
title: Inputbytes
resultSummary:
anyOf:
- $ref: '#/components/schemas/ResultSummary'
- type: 'null'
errorSummary:
anyOf:
- $ref: '#/components/schemas/ErrorSummary'
- type: 'null'
results:
items:
$ref: '#/components/schemas/PublicScoreResult'
type: array
title: Results
description: Full public results for succeeded jobs; present only on results-included
listings (includeResults=true).
additionalProperties: false
type: object
required:
- jobId
- state
- createdAt
- updatedAt
- completedAt
- itemCount
- inputBytes
- resultSummary
- errorSummary
title: ScoreJobSummaryModel
RewriteJobSummary:
properties:
jobId:
type: string
title: Jobid
state:
type: string
enum:
- queued
- running
- succeeded
- failed
- cancelled
title: State
createdAt:
type: string
title: Createdat
updatedAt:
type: string
title: Updatedat
completedAt:
anyOf:
- type: string
- type: 'null'
title: Completedat
itemCount:
type: integer
minimum: 0.0
title: Itemcount
inputBytes:
type: integer
minimum: 0.0
title: Inputbytes
resultSummary:
anyOf:
- $ref: '#/components/schemas/ResultSummary'
- type: 'null'
errorSummary:
anyOf:
- $ref: '#/components/schemas/ErrorSummary'
- type: 'null'
results:
items:
$ref: '#/components/schemas/PublicRewriteResult'
type: array
title: Results
description: Full public results for succeeded jobs; present only on results-included
listings (includeResults=true).
additionalProperties: false
type: object
required:
- jobId
- state
- createdAt
- updatedAt
- completedAt
- itemCount
- inputBytes
- resultSummary
- errorSummary
title: RewriteJobSummaryModel
PublicScoreResult:
properties:
id:
type: string
title: Id
is_ai:
type: integer
maximum: 100.0
minimum: 0.0
title: Is Ai
band:
anyOf:
- type: string
enum:
- likely_human
- mixed
- likely_ai
- type: 'null'
title: Band
confidence:
anyOf:
- type: number
maximum: 1.0
minimum: 0.0
- type: 'null'
title: Confidence
description: Document-level confidence from calibration band distance.
sentences:
anyOf:
- items:
$ref: '#/components/schemas/PublicSentenceScore'
type: array
- type: 'null'
title: Sentences
additionalProperties: false
type: object
required:
- id
- is_ai
title: PublicScoreResultModel
PublicRewriteResult:
properties:
id:
type: string
title: Id
segmentsVersion:
type: integer
enum:
- 1
- 2
title: Segmentsversion
original_is_ai:
type: integer
maximum: 100.0
minimum: 0.0
title: Original Is Ai
rewritten_is_ai:
type: integer
maximum: 100.0
minimum: 0.0
title: Rewritten Is Ai
rewrittenText:
type: string
title: Rewrittentext
segments:
anyOf:
- items:
$ref: '#/components/schemas/RewriteSegment'
type: array
- type: 'null'
title: Segments
additionalProperties: false
type: object
required:
- id
- segmentsVersion
- original_is_ai
- rewritten_is_ai
- rewrittenText
title: PublicRewriteResultModel
RewriteTeaserSample:
properties:
originalText:
type: string
minLength: 1
title: Originaltext
originalIsAi:
anyOf:
- type: integer
maximum: 100.0
minimum: 0.0
- type: 'null'
title: Originalisai
rewrittenText:
type: string
minLength: 1
title: Rewrittentext
rewrittenIsAi:
anyOf:
- type: integer
maximum: 100.0
minimum: 0.0
- type: 'null'
title: Rewrittenisai
additionalProperties: false
type: object
required:
- originalText
- rewrittenText
title: RewriteTeaserSampleModel
description: The single most-improved paragraph of an anonymous rewrite teaser.
ErrorSummary:
properties:
code:
type: string
title: Code
message:
type: string
title: Message
retryable:
type: boolean
title: Retryable
additionalProperties: false
type: object
required:
- code
- message
- retryable
title: ErrorSummaryModel
ResultSummary:
properties:
succeededItems:
type: integer
minimum: 0.0
title: Succeededitems
failedItems:
type: integer
minimum: 0.0
title: Faileditems
additionalProperties: false
type: object
required:
- succeededItems
- failedItems
title: ResultSummaryModel
UsagePool:
properties:
usedWords:
type: integer
minimum: 0.0
title: Usedwords
allowanceWords:
type: integer
minimum: 0.0
title: Allowancewords
remainingWords:
type: integer
minimum: 0.0
title: Remainingwords
periodStart:
type: string
title: Periodstart
periodEnd:
type: string
title: Periodend
additionalProperties: false
type: object
required:
- usedWords
- allowanceWords
- remainingWords
- periodStart
- periodEnd
title: UsagePoolModel
UsagePools:
properties:
scan:
$ref: '#/components/schemas/UsagePool'
humanize:
$ref: '#/components/schemas/UsagePool'
additionalProperties: false
type: object
required:
- scan
- humanize
title: UsagePoolsModel
UsageDaily:
properties:
date:
type: string
title: Date
scanWords:
type: integer
minimum: 0.0
title: Scanwords
humanizeWords:
type: integer
minimum: 0.0
title: Humanizewords
additionalProperties: false
type: object
required:
- date
- scanWords
- humanizeWords
title: UsageDailyModel
UsageKeyBreakdown:
properties:
apiKeyId:
anyOf:
- type: string
- type: 'null'
title: Apikeyid
label:
type: string
title: Label
scanWords:
type: integer
minimum: 0.0
title: Scanwords
humanizeWords:
type: integer
minimum: 0.0
title: Humanizewords
additionalProperties: false
type: object
required:
- apiKeyId
- label
- scanWords
- humanizeWords
title: UsageKeyModel
ScanShare:
properties:
shareId:
type: string
title: Shareid
scanId:
type: string
title: Scanid
redactText:
type: boolean
title: Redacttext
revoked:
type: boolean
title: Revoked
createdAt:
type: string
title: Createdat
updatedAt:
type: string
title: Updatedat
additionalProperties: false
type: object
required:
- shareId
- scanId
- redactText
- revoked
- createdAt
- updatedAt
title: ScanShareModel
securitySchemes:
bearerApiKey:
type: http
scheme: bearer
description: 'Customer API key supplied as Authorization: Bearer.'
apiKeyHeader:
type: apiKey
in: header
name: X-Api-Key
firebaseIdToken:
type: http
scheme: bearer
description: 'Firebase ID token supplied as Authorization: Bearer.'
firebaseAppCheck:
type: apiKey
in: header
name: X-Firebase-AppCheck
description: Firebase App Check token for anonymous browser scans.
responses:
BadRequest:
description: Request could not be accepted.
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
Unauthorized:
description: Missing or invalid public credential.
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
Forbidden:
description: API key does not have the required scope.
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
PaymentRequired:
description: Billing is disabled for the account.
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
NotFound:
description: Resource was not found.
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
Conflict:
description: The request conflicts with the current job state or idempotency
key.
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
ValidationError:
description: Request validation failed.
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
TooManyRequests:
description: The request exceeded a rate limit.
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
ContentTooLarge:
description: The text exceeds the synchronous request limit; use the asynchronous
job APIs for longer documents.
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
ServiceUnavailable:
description: The backend is temporarily unavailable; retry shortly.
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
security: *id001