Easy2257 Hosted Attestation API

Hand the attestation form to Easy2257 and build no compliance UI.

Operations 1

POST /api/v1/upload-sessions Start a hosted attestation session #

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/easy2257-com:easy2257-com-hosted-attestation-api"
All apis
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.

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

easy2257-com-hosted-attestation-api-openapi.yml Raw ↑
openapi: 3.2.0
info:
  title: Easy2257 Partner Hosted Attestation API
  version: '2026-07-27'
  description: 'The Easy2257 Partner API lets your platform outsource 18 U.S.C. § 2257 compliance in a single integration: performer ID verification, per-depiction content logging, and 7-year record retention, with Easy2257 named Custodian of Records. No endpoint in this API returns a performer''s legal name, date of birth, government ID image, or Easy2257 user id. A platform integrating it never touches a government ID, so it cannot leak one. There is no sandbox: only `ez_live_` keys are accepted, and every call writes a production record.'
  contact:
    name: Easy2257 Developer Support
    email: api@easy2257.com
    url: https://docs.easy2257.com
servers:
- url: https://easy2257.com
  description: Production, and the only environment. There is no sandbox host.
tags:
- name: Hosted Attestation
  description: Hand the attestation form to Easy2257 and build no compliance UI.
paths:
  /api/v1/upload-sessions:
    post:
      summary: Start a hosted attestation session
      description: Hands the whole attestation step to Easy2257. You post the content facts, redirect the uploader to `hostedUrl`, and Easy2257 renders the form, captures the producer attestation with IP, user agent and timestamp, and tells you when it is done. Your platform builds no compliance UI. `contentOrigin` and `detectedFaceCount` choose the path. For captured content (the default), 1 face records a solo attestation and fires `upload_session.solo_completed`; 2 or more opens a collab scene from the collaborators the uploader names, emails them, and fires `collab_scene.created` carrying `uploadSessionId` so you can correlate it back to the content row. AI-generated content (`synthetic`, or `mixed` with no other real person named) records a single attestation and fires `upload_session.synthetic_completed`; `contentSha256` is required for both. The uploader must already have an active solo account under your partner account. Sessions last 24 hours, and each call creates a new one.
      tags:
      - Hosted Attestation
      security:
      - BearerAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateUploadSessionBody'
      responses:
        '201':
          description: Session created. Redirect the uploader to `hostedUrl`.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UploadSessionResponse'
        '400':
          description: Validation failure. `code` is `missing_field` or `invalid_field`, and `field` names the offender.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '401':
          description: 'No `Authorization: Bearer` header, or a key that is unknown, revoked, or expired. The body carries only `error`, never a `code`.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: 'Rejected before the handler: a test-mode key (`TEST_MODE_UNAVAILABLE`) or a partner account that is not ACTIVE. Never used for cross-partner access, which returns 404.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '409':
          description: The uploader has no active Easy2257 solo account under your partner account. `code` is `uploader_not_solo_active`. Run them through solo onboarding first.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          description: 'Rate limit exceeded: 300 requests per 60 seconds per API key, shared across all `/api/v1` endpoints (requests without a `Bearer` key fall back to 60 per 60 seconds per client IP, and a per-address flood ceiling of 1200 per 60 seconds also applies). Honor `Retry-After`.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/RateLimitError'
        '500':
          description: Server error. Retry with exponential backoff.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
      operationId: postApiV1UploadSessions
      x-operation-id-source: derived
components:
  schemas:
    CreateUploadSessionBody:
      type: object
      properties:
        contentId:
          type: string
          maxLength: 255
          description: Your content id. Echoed back to you on the completion webhook so you can find the row again.
          example: video_abc123
        contentType:
          type: string
          enum:
          - image
          - video
          - gallery
        contentTitle:
          type: string
          maxLength: 500
          example: April 2026 Scene
        detectedFaceCount:
          type: integer
          minimum: 0
          maximum: 50
          description: 'How many faces your pipeline detected in the upload. For `captured` content this alone chooses the path: 1 collects a solo attestation, 2 or more opens a collab scene and emails every collaborator the uploader names. For `synthetic` content it is stored for the record and routes nothing, and 0 is allowed. Captured and mixed content need at least 1, since the uploader is in it.'
          example: 2
        contentOrigin:
          type: string
          enum:
          - captured
          - synthetic
          - mixed
          description: 'What the content is. `captured` (the default when omitted): real people were filmed or photographed. `synthetic`: generated entirely by AI, no real person depicted; the uploader attests to that, no collaborators are invited, and completion fires `upload_session.synthetic_completed`. `mixed`: the uploader with AI-generated figures; the uploader names any other real people, who go through the normal collab flow, and with none named completion fires `upload_session.synthetic_completed`. The uploader cannot change it on the form: if it is wrong, open a new session.'
          example: captured
        personaName:
          type: string
          maxLength: 100
          description: The persona the content is posted under, such as an AI persona's display name. Shown on the form and kept with the attestation.
          example: Lisa Mays
        contentSha256:
          type: string
          pattern: ^[a-fA-F0-9]{64}$
          description: SHA-256 (hex) of the file the uploader is attesting to. Required when `contentOrigin` is `synthetic` or `mixed`; optional for `captured`. Stored lowercased.
          example: 9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08
        generationTool:
          type: string
          maxLength: 200
          description: 'What generated the content, at whatever detail you have. `synthetic` and `mixed` only; sending it on `captured` is a `400`. Easy2257 does not take prompts, seeds or source files: the creator keeps those.'
          example: Example Gen 3
        uploaderExternalUserId:
          type: string
          maxLength: 450
          description: Your user id for the uploader. Must already map to an active Easy2257 solo account under your partner account.
          example: user_12345
        uploaderEmail:
          type: string
          format: email
          example: creator@example.com
        uploaderFirstName:
          type: string
        uploaderLastName:
          type: string
        callbackUrl:
          type: string
          format: uri
          description: Required, stored for your reference. Events go to your portal-registered endpoints.
          example: https://your-platform.com/webhooks/ez2257
        redirectUrl:
          type: string
          format: uri
          description: Required. Where the hosted form returns the uploader when they are done.
          example: https://your-platform.com/uploads/video_abc123
      required:
      - contentId
      - contentType
      - contentTitle
      - detectedFaceCount
      - uploaderExternalUserId
      - uploaderEmail
      - callbackUrl
      - redirectUrl
    RateLimitError:
      type: object
      properties:
        error:
          type: string
          example: Too many requests. Please slow down.
        retryAfter:
          type: integer
          description: Seconds until the window frees up. Mirrors the `Retry-After` header.
          example: 14
        limit:
          type: integer
          description: Requests allowed per window.
          example: 60
        remaining:
          type: integer
          example: 0
        reset:
          type: integer
          description: Epoch milliseconds at which the sliding window releases the oldest request.
          example: 1714000060000
      required:
      - error
      - limit
      - remaining
      - reset
    UploadSessionResponse:
      type: object
      properties:
        sessionId:
          type: string
          example: cmd6t2p5x0001qz8h7f3d9k4w
        token:
          type: string
          description: '64-character session token. Treat it as a secret: anyone holding it can complete the attestation.'
          example: 3f9c1d...
        hostedUrl:
          type: string
          format: uri
          description: Send the uploader here in top-level navigation. Easy2257 hosts the attestation form, so you build no compliance UI at all.
          example: https://easy2257.com/upload-attestation/3f9c1d...
        status:
          type: string
          enum:
          - created
        contentOrigin:
          type: string
          enum:
          - captured
          - synthetic
          - mixed
          description: The origin the session was created with; `captured` when you omitted it.
          example: captured
        expiresAt:
          type: string
          format: date-time
          description: 24 hours from creation. After that the uploader needs a new session.
          example: '2026-04-25T18:00:00Z'
      required:
      - sessionId
      - token
      - hostedUrl
      - status
      - contentOrigin
      - expiresAt
    Error:
      type: object
      properties:
        error:
          type: string
          description: 'Human-readable message. Switch on HTTP status and on `code`, never on this string: it is not part of the API contract.'
          example: email, externalUserId, and callbackUrl are required
        code:
          type: string
          description: Machine-readable error code. Present on the test-key rejection (`TEST_MODE_UNAVAILABLE`), consent conflicts, and most collab-scene and upload-session validation errors. Never present on `401` authentication rejections, and absent on the inactive-partner `403` and on some older solo-account validation errors, which is why status is the primary signal.
          example: missing_parameter
        field:
          type: string
          description: The offending request field. Present on collab-scene and upload-session validation errors.
          example: contentType
      required:
      - error
  securitySchemes:
    BearerAuth:
      type: http
      scheme: bearer
      description: 'Partner API key from partner.easy2257.com/api-keys. Only `ez_live_` keys are accepted. A key beginning with `ez_test_` is rejected with `403` and code `TEST_MODE_UNAVAILABLE` before any handler runs: there is no sandbox, and every handler writes production records, provisions real users, and sends real email. New partner accounts start with a test key, so create a live key before your first call.'