---
title: "Provision a solo creator account"
method: POST
path: "/api/v1/solo-accounts"
tags: ["Solo Accounts"]
---

# Provision a solo creator account

`POST /api/v1/solo-accounts`

## Request

- Base URL: `https://easy2257.com`
- URL: `https://easy2257.com/api/v1/solo-accounts`
- Auth: HTTP bearer

Creates a solo creator account for one of your users, and returns either `active` (grant uploads now) or the pending shape with an `onboardingUrl` to redirect them to. Idempotent on two natural keys, `(partner, externalUserId)` and `(partner, email)`, so a retry after a timeout cannot produce a second account, a second charge, or a second email. There is no idempotency header to send. If the address already belongs to an Easy2257 user, Easy2257 emails that person for approval instead of handing their identity records to your platform. The response is deliberately identical either way, so your integration cannot be used to probe whether one of your users already has an Easy2257 account.

## Request body

- CreateSoloAccountBody
  - `externalUserId` string, required: Your own user id for this creator. Half of the natural idempotency key: a repeat POST with the same `externalUserId` returns the existing account with `200` instead of `201`. Store the `accountId` you get back; every later call needs it.
  - `email` string, email, required: The creator's email address. The second idempotency scope: one account per (partner, exact address), so a creator's consent decision survives a change to your own user id for them. If the address already belongs to an Easy2257 user, Easy2257 emails that user for approval instead of linking them to you.
  - `callbackUrl` string, uri, required: Required. Stored on the account record for your own reference. It does NOT subscribe you to anything: webhook deliveries go only to endpoints you register in the partner portal at partner.easy2257.com/webhooks.
  - `firstName` string: Optional. Used in the email Easy2257 sends the creator. Sanitized and truncated to 100 characters.
  - `lastName` string: Optional. Sanitized and truncated to 100 characters.
  - `redirectUrl` string, uri: Optional. Where Easy2257 sends the creator after they finish onboarding.

## Response `200`

Existing account returned (replay, or an account already provisioned for this address).

- object: Provisioning returns exactly two shapes: `{ accountId, status: "active", createdAt }`, or the pending shape with `onboardingUrl`. Every not-yet-active outcome returns the identical shape and the identical status string by design, whatever happened internally.
  - `accountId` string, required: Easy2257's id for this account. Opaque cuid. Store it: every later call is addressed by it.
  - `status` 'pending_id_verification' | 'subscribed_pending_id' | 'active' | 'suspended', required: The four values a partner can observe. `pending_id_verification`: not finished. This one value covers every pre-active state, including an emailed link request that has not been answered, so account existence and consent decisions are never observable through the API. `subscribed_pending_id`: paid, ID not yet verified. Still not uploadable. `active`: paid and ID verified. This is the only value that unlocks uploads. `suspended`: not in custody right now. Revoke upload access. `suspendReason` says why: the creator's own subscription lapsed, your platform fee lapsed, Easy2257 suspended them, or you deactivated them through `POST .../deactivate`.
  - `onboardingUrl` string, uri: Present on every not-yet-active response, absent when status is `active`. Send the creator here in top-level navigation, not an iframe, because ID verification needs camera access. Tokens last 7 days and are refreshed automatically on later reads, so redirect to whatever the API just returned rather than storing the link.
  - `createdAt` string, date-time, required

## Other responses

- `201`: Account created.
- `400`: `email`, `externalUserId`, or `callbackUrl` missing, or email longer than 255 characters.
- `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)
