Skip to content

Creator Onboarding ​

Endpoints for creator verification and payout setup, plus admin review. For the design and the PII rules behind it, see Creator Onboarding & KYC.

Creator endpoints ​

Mounted at /api/v1/creator-onboarding (apps/api/src/router/creatorOnboardingRoutes.ts). All require authentication. Writes are rate limited to 40 per hour per user.

MethodPathBodyPurpose
GET/creator-onboarding—Current status, used to resume the flow, on the review screen, and by the app's status card. Read-only: a user who never applied gets NOT_STARTED defaults and no profile row is created
POST/creator-onboarding/id-documentmultipart: document (JPEG/PNG ≤ 10 MB), side, documentTypeUpload one side of the government ID
POST/creator-onboarding/payout-account{ accountToken: "accttok_…" }Create or update the Stripe Connect account
POST/creator-onboarding/bank-account{ bankToken: "btok_…" }Attach the payout bank account
POST/creator-onboarding/submit—Hand off for review; sets User.onboarded

documentType is one of license, state_id or passport. side is front or back; a passport has no back.

Status response ​

json
{
  "success": true,
  "data": {
    "verificationStatus": "IN_PROGRESS",
    "idDocumentType": "license",
    "uploadedSides": ["front", "back"],
    "steps": { "idDocument": true, "personalInfo": true, "bankAccount": false },
    "bankLast4": null,
    "bankName": null,
    "payoutsEnabled": false,
    "requirementsDue": [],
    "rejectionReason": null,
    "submittedAt": null
  }
}

verificationStatus moves NOT_STARTED → IN_PROGRESS → SUBMITTED → APPROVED | REJECTED. After a REJECTED, uploading a new ID puts it back to IN_PROGRESS.

Rules ​

  • Tokens only. The payout and bank endpoints reject anything that isn't a Stripe token id, so raw PII can't be posted by mistake.
  • Locked once submitted. ID uploads return 409 while SUBMITTED or APPROVED. Changing payout identity after approval also returns 409 and goes through support.
  • Submit is idempotent. Submitting again while SUBMITTED or APPROVED returns the current status. If a step is missing, the response is 400 with code: "ONBOARDING_INCOMPLETE".
  • Stripe errors are generic. Stripe's message can echo parameters, so it is never returned. Clients get a fixed message plus Stripe's error code, and the server logs only the code and request id.
  • 503 means Stripe or the KYC bucket or key isn't configured. The routes fail closed.

Admin review ​

Mounted at /api/v1/admin/creator-verifications. Every route requires authentication andUser.role = "admin".

MethodPathPurpose
GET/admin/creator-verifications?status=SUBMITTED&limit=20&cursor=Review queue, oldest submission first
GET/admin/creator-verifications/:userIdProfile, payout state, and ID document metadata
GET/admin/creator-verifications/:userId/documents/:assetIdDecrypted ID image. Audited, no-store
POST/admin/creator-verifications/:userId/approveApprove; sets userType = "playpal" and the PlayPal badge, and notifies the user
POST/admin/creator-verifications/:userId/reject{ reason }. Reject, delete the ID images, and notify the user with the reason

Every document view, approval and rejection writes a VerificationAccessLog row with the admin id, the subject, the asset and the request IP.

bash
# Review queue
curl -H "Authorization: Bearer $ADMIN_JWT" \
  https://api.playpalz.com/api/v1/admin/creator-verifications

# View a document (writes an audit row)
curl -H "Authorization: Bearer $ADMIN_JWT" -o /tmp/id-front.jpg \
  https://api.playpalz.com/api/v1/admin/creator-verifications/<userId>/documents/<assetId>

Treat downloaded IDs as live PII

Don't download ID images to shared machines or paste them into tickets or chat. Delete local copies after the review. The audit log records that you viewed the image, not where the copy went.

Stripe webhook ​

POST /api/v1/webhooks/stripe is covered in Webhooks → Stripe.

Internal documentation — PlayPalz platform