---
title: "Create a collab scene"
method: POST
path: "/api/v1/collab-scenes"
tags: ["Collab Scenes"]
---

# Create a collab scene

`POST /api/v1/collab-scenes`

## Request

- Base URL: `https://easy2257.com`
- URL: `https://easy2257.com/api/v1/collab-scenes`
- Auth: HTTP bearer

Opens a multi-performer scene and emails every performer a magic link. Identify the uploader with exactly one of `uploaderAccountId` or `uploaderExternalUserId`; either must resolve to an active solo account under your partner account. The scene record costs $5 (500 cents), plus $25 (2500 cents) for each performer who does not already have an active Easy2257 solo account; performers who do sign at no extra charge. The response reports that split only as a scene-level aggregate, and performer entries never say which path an individual is on. Not idempotent. Every call creates a new scene, sends fresh invitation emails, and charges fees, so guard it behind your own dedupe. Content stays on your platform until the `collab_scene.greenlit` webhook fires. The uploader's attestation is the producer attestation of record, so capture it from a real click event.

## Request body

- CreateCollabSceneBody: Identify the uploader with exactly one of `uploaderAccountId` or `uploaderExternalUserId`: zero is `400` / `missing_field`, more than one is `400` / `invalid_field`. Both are values you already hold; no endpoint ever returns an Easy2257 user id, so there is nothing else to send. (A legacy `uploaderUserId` field exists for Easy2257-internal callers only and is not usable by partners.)
  - `uploaderAccountId` string: The `accountId` Easy2257 issued when you provisioned the uploader's solo account. Send exactly one of `uploaderAccountId` or `uploaderExternalUserId`. Either must resolve to an active solo account under your partner account, otherwise the call returns `400` with code `uploader_not_solo_active`.
  - `uploaderExternalUserId` string: Your own user id for the uploader, exactly as you supplied it as `externalUserId` at provisioning. Alternative to `uploaderAccountId`; send one or the other, never both.
  - `title` string, required
  - `shootDate` string, date-time
  - `performers` object[], required: 1 to 10 performers, addresses unique within the request. Easy2257 emails each one a magic link. A performer who already has an active Easy2257 solo account signs and is done at no extra charge; anyone else completes registration and ID verification inside the same link at 2500 cents. The response never says which path an individual performer is on.
    - `email` string, email, required
  - `uploaderAttestation` object, required: All four fields required. Capture them from a real click event in your UI: this is the producer attestation, and a synthesized one is worth nothing in an inspection.
    - `ip` string, required: Uploader's IP at the moment they clicked.
    - `ua` string, required
    - `clickedAt` string, date-time, required
    - `attestationText` string, required: The exact statement the uploader confirmed. Stored verbatim with IP and user agent as the 18 U.S.C. § 2257(b)(1) producer attestation.
  - `callbackUrl` string, uri, required: Required, and stored for your reference only. Scene events go to the endpoints registered in the partner portal.

## Response `201`

Scene created and invitation emails sent.

- CollabSceneResponse
  - `sceneId` string, required
  - `status` 'pending_signatures' | 'greenlit' | 'blocked' | 'cancelled', required: `pending_signatures`: waiting on performers. `greenlit`: everyone signed and every new performer passed ID verification. This is the only status that permits publication. `blocked`: a performer refused, or the 14-day window lapsed. `cancelled`: cancelled through the API. No refund.
  - `performers` object[], required
    - `email` string, email, required
    - `status` 'pending_consent' | 'consented' | 'refused', required: `pending_consent`: invited, has not yet signed. This one value covers every unsigned performer, whether or not the address already had an Easy2257 account: registration and ID verification, when needed, happen inside the magic-link flow and are never visible here, so performer status cannot be used to probe whether an email is already on Easy2257. `consented`: release signed and consent recorded. `refused`: performer declined, which blocks the scene. When the signing window lapses, the scene flips to `blocked` while unsigned performers stay `pending_consent`.
  - `fees` object, required
    - `sceneFeeCents` integer, required: Base scene record fee, 500 cents.
    - `onboardingFeeCents` integer, required: 2500 cents for each performer who did not already have an active Easy2257 solo account. Performers who already hold one add nothing. The split is an aggregate for the whole scene; it is not itemized per performer.
    - `totalCents` integer, required
    - `charged` boolean, required: true once a Stripe charge id is on the record. The scene is created either way: a billing failure does not block consent collection, so check this rather than assuming payment succeeded. On `billedTo: platform_invoice` it stays false: the fees are collected with your monthly platform invoice.
    - `stripeChargeId` string, nullable, required: Despite the field name this holds the Stripe PaymentIntent id, charged off-session against the uploader's saved payment method. null when `billedTo` is `platform_invoice`.
    - `billedTo` 'uploader_card' | 'platform_invoice', required: Who pays the fees. `uploader_card`: charged off-session to the uploading creator's saved card. `platform_invoice`: a platform-funded account with collab scenes switched on; the fees are added to your platform's next monthly invoice, so `charged` stays false and `stripeChargeId` null.
    - `chargeError` string, nullable, required: null when the immediate off-session charge succeeded or nothing was due. Otherwise a free-form failure code, not a fixed enum: for example `no_payment_method`, `card_declined`, or `payment_requires_action`. The scene is still created and consent collection proceeds; the fee is settled on the billing side. On `billedTo: platform_invoice` it reports a failure to add the fees to your invoice: the scene still stands and Easy2257 is alerted to add them by hand.
  - `expiresAt` string, date-time, required: 14 days from creation. Unsigned at that point and the scene is blocked.

## Other responses

- `400`: Validation failure. `code` is one of `missing_field` (no uploader identifier, or another required field missing), `invalid_field` (more than one uploader identifier, or a non-string one), `invalid_email`, `duplicate_emails`, `too_many_performers` (more than 10), or `uploader_not_solo_active` (the identifier does not resolve to an active solo account under your partner account).
- `401`: No `Authorization: Bearer` header, or a key that is unknown, revoked, or expired. The body carries only `error`, never a `code`.
- `403`: 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.
- `429`: 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`.
- `500`: Server error. Retry with exponential backoff.

---

[API](https://skmtc.dev/easy2257/apis/easy2257-partner-api.md) · [All operations](https://skmtc.dev/easy2257/apis/easy2257-partner-api/llms.txt) · [OpenAPI document](https://skmtc.dev/easy2257/apis/easy2257-partner-api/revisions/f880026c1f04?raw)
