# Varmply Backend API

Varmply API for authentication, onboarding, creator and sponsor profiles, campaign management, marketplace participation, analytics, and wallet operations.
Unless otherwise noted, money amounts are returned in minor units and authenticated endpoints require a bearer token.
Field naming is consistent by response style: camelCase surfaces use names such as `profileImageUrl`, while snake_case surfaces use names such as `profile_image_url`.
## Error Messages
Common error codes: - `NOT_FOUND` - Resource not found (404) - `VALIDATION_ERROR` - Input validation failed (400) - `PERMISSION_DENIED` - User lacks permission (403) - `CONFLICT` - Resource conflict (409) - `UNAUTHORIZED` - Authentication required (401) - `INTERNAL_SERVER_ERROR` - Unexpected server error (500)


Version: 0.1.0

## Servers

Local development server
```
http://localhost:3000
```

Staging environment
```
https://api-staging.varmply.com
```

Production environment
```
https://api.varmply.com
```

## Security

### bearerAuth

JWT access token obtained from /auth/signup/create-password or /auth/login

Type: http
Scheme: bearer
Bearer Format: JWT

## Download OpenAPI description

[Varmply Backend API](https://docs-staging.varmply.com/_bundle/openapi.yaml)

## Health

Health check endpoints

### Health check

 - [GET /health](https://docs-staging.varmply.com/openapi/health/gethealthstatus.md): Returns the health status of the API service

### Readiness probe

 - [GET /health/ready](https://docs-staging.varmply.com/openapi/health/getreadinessstatus.md): Checks if the API service is ready to serve traffic by verifying database connectivity. Returns 200 if healthy, 503 if the database is unavailable.

## Authentication

User registration, authentication, and email verification

### Start a staged signup

 - [POST /auth/signup/start](https://docs-staging.varmply.com/openapi/authentication/startsignup.md): Canonical creator signup entrypoint.
Creates or refreshes a provisional signup keyed by pendingSignupId and sends a 6-digit OTP.
This step does not create a real user, does not issue tokens, and must be followed by
/auth/signup/verify-code and /auth/signup/create-password.

### Resend staged signup code

 - [POST /auth/signup/resend-code](https://docs-staging.varmply.com/openapi/authentication/resendsignupcode.md): Resend a fresh 6-digit OTP for an existing provisional signup.
Uses the same pendingSignupId; clients must not assume a new signup record is created.

### Verify staged signup code

 - [POST /auth/signup/verify-code](https://docs-staging.varmply.com/openapi/authentication/verifysignupcode.md): Verify a provisional signup with a 6-digit numeric OTP and no authenticated session.
The request body contains only pendingSignupId and code; there is no hidden userId
or authenticated-email verification variant in this staged signup flow.

### Complete staged signup

 - [POST /auth/signup/create-password](https://docs-staging.varmply.com/openapi/authentication/createsignuppassword.md): Complete the canonical staged signup after OTP verification succeeds.
Creates the real user, marks the email verified, and issues the normal access and refresh tokens.
This replaces any stale immediate-password registration assumptions.

### Login with email and password

 - [POST /auth/login](https://docs-staging.varmply.com/openapi/authentication/loginuserwithemailandpassword.md): Authenticate an existing user and receive JWT tokens

### Refresh an access token

 - [POST /auth/refresh](https://docs-staging.varmply.com/openapi/authentication/refreshsessionfromrefreshtoken.md): Exchange a valid refresh token for a new access/refresh token pair.

### Request email verification

 - [POST /auth/verify-email/request](https://docs-staging.varmply.com/openapi/authentication/requestemailverification.md): Request a 6-digit OTP verification code to be sent to the authenticated user's email address.
Returns success even if the email is already verified.

### Confirm email verification

 - [POST /auth/verify-email/confirm](https://docs-staging.varmply.com/openapi/authentication/confirmemailverification.md): Confirm email verification using a 6-digit OTP code received via email.
Uses the authenticated user context and does not require a request-body userId.
Returns generic error to avoid leaking whether an email exists.

### Request password reset

 - [POST /auth/password-reset/request](https://docs-staging.varmply.com/openapi/authentication/requestpasswordreset.md): Request a password reset link/code to be sent to the given email address.
Always returns 200 with ok true (no body) to avoid leaking whether the email exists.
If the address has an account with a password, a reset email is sent (subject to rate limit).

### Confirm password reset

 - [POST /auth/password-reset/confirm](https://docs-staging.varmply.com/openapi/authentication/confirmpasswordreset.md): Confirm password reset using the token received via email and set a new password.
Invalid or expired token returns 400. On success, all refresh sessions for the user are revoked.

## Waitlist

Public waitlist capture and invite exchange for closed-access signup

### Join the waitlist

 - [POST /waitlist/entries](https://docs-staging.varmply.com/openapi/waitlist/joinwaitlist.md): Public landing-page entrypoint for joining the Varmply waitlist.
Re-submitting the same email updates the stored profile intent without queuing duplicate welcome emails.

### Read waitlist rollout status

 - [GET /internal/waitlist/status](https://docs-staging.varmply.com/openapi/waitlist/getinternalwaitliststatus.md): Internal automation endpoint for operational waitlist monitoring.
Requires x-waitlist-automation-token.

### Issue a waitlist invite batch

 - [POST /internal/waitlist/invites/issue](https://docs-staging.varmply.com/openapi/waitlist/issueinternalwaitlistinvites.md): Internal automation endpoint that selects FIFO waitlist entries by role quota,
creates invite records, and queues access email deliveries without sending them inline.
Requires x-waitlist-automation-token.

### Send pending waitlist emails

 - [POST /internal/waitlist/emails/send](https://docs-staging.varmply.com/openapi/waitlist/sendinternalwaitlistemails.md): Internal automation endpoint that sends pending or retryable waitlist email deliveries.
Requires x-waitlist-automation-token.

### Run a waitlist invite batch

 - [POST /internal/waitlist/invite-batches/run](https://docs-staging.varmply.com/openapi/waitlist/runinternalwaitlistinvitebatch.md): Canonical internal automation endpoint that runs a scheduled waitlist invite batch using absolute role quotas.
The endpoint derives its idempotency key from automationName and scheduledForTimestamp,
creates invite records, and queues access email deliveries without sending them inline.
Requires x-waitlist-automation-token.

### Send pending waitlist emails

 - [POST /internal/waitlist/emails/send-pending](https://docs-staging.varmply.com/openapi/waitlist/sendpendinginternalwaitlistemails.md): Canonical internal automation endpoint that sends pending or retryable waitlist email deliveries.
Callers may limit the run by waitlist email type. Requires x-waitlist-automation-token.

### Suppress a waitlist entry

 - [POST /internal/waitlist/entries/{waitlistEntryId}/suppress](https://docs-staging.varmply.com/openapi/waitlist/suppressinternalwaitlistentry.md): Internal repair endpoint that suppresses a waitlist entry, revokes active invites,
and suppresses pending or retryable waitlist emails. Requires x-waitlist-automation-token.

### Restore a suppressed waitlist entry

 - [POST /internal/waitlist/entries/{waitlistEntryId}/restore](https://docs-staging.varmply.com/openapi/waitlist/restoreinternalwaitlistentry.md): Internal repair endpoint that restores a suppressed waitlist entry to the waiting queue.
Suppressed email deliveries remain suppressed. Requires x-waitlist-automation-token.

### Remove and anonymize a waitlist entry

 - [POST /internal/waitlist/entries/{waitlistEntryId}/remove](https://docs-staging.varmply.com/openapi/waitlist/removeinternalwaitlistentry.md): Internal repair endpoint that removes a waitlist entry, revokes active invites,
suppresses pending or retryable waitlist emails, and anonymizes stored waitlist PII
while preserving aggregate invite and batch history. Requires x-waitlist-automation-token.

### Update waitlist role intent

 - [PATCH /internal/waitlist/entries/{waitlistEntryId}/role-intent](https://docs-staging.varmply.com/openapi/waitlist/updateinternalwaitlistroleintent.md): Internal repair endpoint that updates role intent only while an entry is still waiting.
Requires x-waitlist-automation-token.

### Reissue a waitlist invite

 - [POST /internal/waitlist/entries/{waitlistEntryId}/reissue-invite](https://docs-staging.varmply.com/openapi/waitlist/reissueinternalwaitlistinvite.md): Internal repair endpoint that revokes any active invite for an eligible entry, creates a new invite,
and queues a new access email. Callers must provide a unique idempotency key for each intended reissue.
Requires x-waitlist-automation-token.

### Exchange a waitlist invite for signup access

 - [POST /auth/invitations/exchange](https://docs-staging.varmply.com/openapi/waitlist/exchangewaitlistinvitation.md): Validates a private waitlist invite token and returns a short-lived signup access token.
Clients use the returned token with /auth/signup/start in closed-access mode.

## Onboarding

User onboarding and readiness flows, including role assignment and initial profile setup

### Get authenticated user snapshot

 - [GET /me](https://docs-staging.varmply.com/openapi/onboarding/getauthenticatedusersnapshot.md): Returns the canonical authenticated-user bootstrap snapshot used by auth and onboarding flows.
This response is intentionally broad: it includes identity, assigned roles, onboarding readiness,
creator app-access state, next-step routing, and normalized platform connection capability state.

GET /me is the source of truth for bootstrap routing decisions. Dedicated profile/settings helpers
should not be treated as alternate bootstrap contracts.

### Acknowledge the current dashboard milestone banner

 - [POST /me/milestones/{milestoneEventId}/surfaced](https://docs-staging.varmply.com/openapi/onboarding/markmilestonesurfaced.md): Acknowledges the authenticated user's current dashboard milestone banner by marking the
referenced milestone event as surfaced. Dashboard is the canonical banner owner; analytics
does not expose a parallel milestone banner payload.

### Assign roles to user

 - [POST /me/roles/assign](https://docs-staging.varmply.com/openapi/onboarding/assignuserroles.md): Assigns roles to the authenticated user. Users may self-assign CREATOR and/or SPONSOR. ADMIN may only be assigned by an already-admin user. This operation is idempotent - adding an already-present role is a no-op. Returns the updated /me response.

## Dashboard

Canonical authenticated dashboard surface with backend-owned banner resolution

### Get the authenticated dashboard

 - [GET /dashboard](https://docs-staging.varmply.com/openapi/dashboard/getdashboard.md): Returns the canonical role-scoped dashboard for the authenticated user.
Users with both SPONSOR and CREATOR roles must provide role=sponsor or role=creator.
Banner ownership, copy, semantic primary action refs, and acknowledgement policy are fully
backend-resolved. Exactly one banner is returned on the dashboard surface.

## Creator

Creator-facing profile and account-management surfaces outside the campaign workspace

### Get my private creator profile

 - [GET /me/profile](https://docs-staging.varmply.com/openapi/creator/getmycreatorprofile.md): Returns the authenticated creator's editable profile surface.
Includes creator identity fields, campaign-derived credibility metrics, and connected platform state.
Canonical onboarding and bootstrap routing state lives on GET /me, not this helper surface.
This endpoint is only available to users with the CREATOR role.

### Update my creator profile

 - [PATCH /me/profile](https://docs-staging.varmply.com/openapi/creator/updatemycreatorprofile.md): Updates the authenticated creator's editable identity fields.
This endpoint is only available to users with the CREATOR role.

Validation rules:
- displayName: 2-40 characters, trimmed, cannot be only whitespace
- handle: 3-30 characters, letters/numbers/dots/underscores/hyphens only
- bio: 280 characters max
- profileImageAssetId and bannerImageAssetId must reference existing READY media assets owned by the authenticated user
- handle must be unique if provided

Profile updates do not affect campaign-derived analytics.

### Get public creator profile

 - [GET /creators/{creatorId}](https://docs-staging.varmply.com/openapi/creator/getcreatorprofile.md): Returns the public creator profile for a CREATOR user.
Only campaign-derived credibility signals are exposed. Wallet balances, earnings, payouts,
CEI, account settings, and integration secrets are never returned here.

## Settings

Authenticated user settings and account preferences

### Get account settings

 - [GET /me/settings](https://docs-staging.varmply.com/openapi/settings/getusersettings.md): Returns the authenticated user's dedicated settings surface.

### Update notification preferences

 - [PATCH /me/settings/notifications](https://docs-staging.varmply.com/openapi/settings/updatenotificationpreferences.md): Partially updates notification delivery preferences for the authenticated user.

## Security

Authenticated session management and password change surfaces

### List active sessions

 - [GET /me/security/sessions](https://docs-staging.varmply.com/openapi/security/listsecuritysessions.md)

### Revoke one session

 - [DELETE /me/security/sessions/{sessionId}](https://docs-staging.varmply.com/openapi/security/revokesecuritysession.md)

### Revoke all other sessions

 - [POST /me/security/sessions/revoke-others](https://docs-staging.varmply.com/openapi/security/revokeothersecuritysessions.md)

### Change password

 - [POST /me/security/change-password](https://docs-staging.varmply.com/openapi/security/changepassword.md)

## Notifications

Authenticated user notification inbox and read state management

### Get my notifications

 - [GET /me/notifications](https://docs-staging.varmply.com/openapi/notifications/getusernotifications.md): Returns a paginated list of notifications for the authenticated user.
Notifications are returned in descending order by creation timestamp (most recent first).
Supports cursor-based pagination via the cursor query parameter.

### Mark my notification as read

 - [POST /me/notifications/{id}/read](https://docs-staging.varmply.com/openapi/notifications/marknotificationasread.md): Marks a specific notification as read for the authenticated user.
Returns the updated notification. If the notification is already read or doesn't exist, returns 404.

### Mark all my notifications as read

 - [POST /me/notifications/read-all](https://docs-staging.varmply.com/openapi/notifications/markallnotificationsasread.md): Marks all unread notifications as read for the authenticated user.
Returns the count of notifications that were marked as read.

## Connections

Authenticated social account connection status and capability management

### Get my TikTok connection

 - [GET /me/tiktok-connection](https://docs-staging.varmply.com/openapi/connections/gettiktokconnectionstatus.md): Returns the current TikTok connection status and capabilities for the authenticated user.
Returns null if no connection exists. The response includes normalized capability status,
available capabilities, and any error codes.

### Disconnect my TikTok connection

 - [DELETE /me/tiktok-connection](https://docs-staging.varmply.com/openapi/connections/disconnecttiktokconnection.md): Disconnects the authenticated user's TikTok integration. This removes the stored TikTok
connection and marks the active TikTok social account as disconnected without resetting
existing submission state.

### Get my Instagram connection

 - [GET /me/instagram-connection](https://docs-staging.varmply.com/openapi/connections/getinstagramconnectionstatus.md): Returns the current Instagram connection status and capabilities for the authenticated user.
Returns null if no connection exists. The response includes verification status,
available capabilities (profile, media, insights, comments access), and any error codes.

## OAuth

Social account OAuth connection and callback flows

### Start Instagram OAuth connect flow

 - [POST /oauth/instagram/start](https://docs-staging.varmply.com/openapi/oauth/startinstagramoauth.md): Starts the canonical Instagram connect flow for the authenticated creator.
The request body uses a normalized returnUrl, matching the TikTok start contract.
On success the API returns an authorization URL and the eventual callback redirects back to the exact same returnUrl.

### Handle Instagram OAuth callback

 - [GET /oauth/instagram/callback](https://docs-staging.varmply.com/openapi/oauth/handleinstagramoauthcallback.md): Handles the Instagram OAuth callback after authorization.
Exchanges the authorization code, upserts the connection, and redirects to the same caller-provided
returnUrl supplied to /oauth/instagram/start.

### Start TikTok OAuth connect flow

 - [POST /oauth/tiktok/start](https://docs-staging.varmply.com/openapi/oauth/starttiktokoauth.md): Starts the canonical TikTok connect flow for the authenticated creator.
The request body uses the same normalized returnUrl contract as Instagram.
On success the API returns an authorization URL plus its expiry; the eventual callback redirects to the exact same returnUrl.

### Handle TikTok OAuth callback

 - [GET /oauth/tiktok/callback](https://docs-staging.varmply.com/openapi/oauth/handletiktokoauthcallback.md): Handles the TikTok OAuth callback after authorization.
Exchanges the authorization code, upserts the connection, and redirects to the same caller-provided
returnUrl supplied to /oauth/tiktok/start.

### Verify TikTok connection

 - [POST /oauth/tiktok/verify](https://docs-staging.varmply.com/openapi/oauth/verifytiktokconnection.md): Triggers verification of the current user's TikTok connection.
This endpoint is primarily for dev/admin use to manually verify connections.
It exercises the official TikTok API grant already stored for the connection and updates
the persisted capability status without inventing unsupported capabilities.

Verification steps:
1. Fetch profile - verifies token validity
2. List videos - verifies official video-list access
3. Get video metrics - verifies official metrics access when TikTok allows it

## Sponsor

Sponsor-facing organization identity and profile management

### Get public sponsor profile

 - [GET /sponsors/{sponsorId}](https://docs-staging.varmply.com/openapi/sponsor/getsponsorprofile.md): Returns the public sponsor profile for a sponsor.
Only campaign-derived credibility and representation information are exposed. Wallet balances,
escrow balances, internal payout state, CEI, and unverified follower metrics are never returned here.

### Get my private sponsor profile

 - [GET /me/sponsor-profile](https://docs-staging.varmply.com/openapi/sponsor/getmysponsorprofile.md): Returns the authenticated sponsor's editable sponsor profile surface.
Includes only sponsor identity, representation details, and the explicit editable-field contract.

### Update my sponsor profile

 - [PATCH /me/sponsor-profile](https://docs-staging.varmply.com/openapi/sponsor/updatemysponsorprofile.md): Creates or updates the authenticated sponsor's editable profile surface.
displayName is required. logoImageAssetId, when present, must reference an existing READY media asset
owned by the authenticated user. mode must be one of the supported sponsor representation values.
Unknown fields are rejected so stale private-only fields cannot drift back into the contract.

## Wallet

Authenticated wallet setup and balance retrieval

### Get role-aware wallet surface

 - [GET /me/wallet](https://docs-staging.varmply.com/openapi/wallet/getwalletoverview.md): Returns a role-scoped wallet read model.
- role=creator returns creator earnings buckets (trackingEarnings, pendingPayout) plus shared wallet availability.
- role=sponsor returns sponsor campaign escrow and spend buckets (sponsorEscrow) plus shared wallet availability.
- For dual-role users, role is required to avoid mixed role semantics.
All amounts on this surface are returned in major Naira.

Verification criteria:
- Dual-role users cannot access an ambiguous wallet projection without role.
- Sponsor wallet escrow totals reconcile with sponsor-owned campaign escrow records.
- Creator wallet excludes sponsor-only escrow semantics.

### Get wallet transaction history

 - [GET /me/wallet/transactions](https://docs-staging.varmply.com/openapi/wallet/getwallettransactions.md): Returns the wallet's financial transaction history for balance-affecting events.
Each entry includes amount, direction, and processing status.
This feed is intended for ledger-backed money movement and should not be merged with /me/wallet/activity
unless the client has explicit product rules for doing so.

Verification criteria:
- Funding, withdrawal, withdrawal reversal, refund, escrow allocation, and payout entries are surfaced as distinct type values.
- Sorting is newest-first by createdAt, then transactionId, and pagination remains stable via nextCursor.

### Get wallet activity history

 - [GET /me/wallet/activity](https://docs-staging.varmply.com/openapi/wallet/getwalletactivity.md): Returns the descriptive wallet activity feed derived from the event journal.
This feed explains wallet-related milestones and operational events, but it is not the canonical
money-movement history and does not include normalized debit or credit semantics.
Dual-role users must pass role=creator or role=sponsor; single-role users default to their available role.

Verification criteria:
- Successful funding produces a wallet_funding_succeeded entry with a non-null relatedFundingReference.
- Milestone events surface human-readable milestone descriptions instead of a generic label.

### List payout accounts

 - [GET /me/payout-accounts](https://docs-staging.varmply.com/openapi/wallet/listpayoutaccounts.md): Returns the saved payout accounts for the authenticated user.
Exactly zero or one entries may be marked isDefault; withdrawal initiation still requires the client
to send the chosen payoutAccountId explicitly.

Verification criteria:
- The list returns only payout accounts owned by the authenticated user.
- At most one entry is marked isDefault=true.

### Add payout account

 - [POST /me/payout-accounts](https://docs-staging.varmply.com/openapi/wallet/addpayoutaccount.md): Resolves the bank account with the provider, creates a transfer recipient, and stores the verified payout account.

Verification criteria:
- The first saved payout account is marked isDefault=true.
- Adding a payout account requires a verified email.

### Delete payout account

 - [DELETE /me/payout-accounts/{payoutAccountId}](https://docs-staging.varmply.com/openapi/wallet/deletepayoutaccount.md): Deletes a saved payout account owned by the authenticated user.
A payout account in use by a processing withdrawal cannot be deleted.

Verification criteria:
- Deleting a payout account referenced by a processing withdrawal returns 409.
- Deleting the current default payout account promotes the oldest remaining account to isDefault=true when one exists.

### Set default payout account

 - [POST /me/payout-accounts/{payoutAccountId}/set-default](https://docs-staging.varmply.com/openapi/wallet/setdefaultpayoutaccount.md): Marks the selected payout account as the only default payout account for the authenticated user.

Verification criteria:
- After the call succeeds, the selected payout account is the only entry with isDefault=true.
- Changing the default payout account requires a verified email.

### List supported banks

 - [GET /wallet/banks](https://docs-staging.varmply.com/openapi/wallet/listwalletbanks.md): Returns the supported bank list used by wallet payout-account resolution and creation flows.

Verification criteria:
- The response is a non-empty array.
- Each entry exposes stable bankCode and bankName string fields.

### Resolve bank account

 - [POST /wallet/resolve-account](https://docs-staging.varmply.com/openapi/wallet/resolvewalletaccount.md): Resolves a bank account before it is persisted as a payout account.

Verification criteria:
- A resolvable account returns isResolvable=true.
- accountNumberMasked exposes only the final four digits.
- Invalid bank account input is rejected with 400 before provider resolution is attempted.

### Initiate wallet funding

 - [POST /wallet/fund/initiate](https://docs-staging.varmply.com/openapi/wallet/initiatewalletfunding.md): Creates a pending funding session and returns the same normalized session DTO used by the funding-session
status read. Funding does not credit the wallet until the provider webhook marks the session as completed.

Verification criteria:
- The initiation response always returns status=pending.
- The user's wallet balance remains unchanged until the webhook completes the session.

### Get wallet funding session

 - [GET /wallet/funding-sessions/{paymentReference}](https://docs-staging.varmply.com/openapi/wallet/getwalletfundingsession.md): Returns the current status of a previously initiated wallet funding session.
The session is only visible to the authenticated owner; other users receive 404.

Verification criteria:
- The owner can read the current status, timestamps, and failureMessage for the session.
- A different authenticated user receives 404 for the same paymentReference.

### Verify wallet funding session

 - [POST /wallet/funding-sessions/{paymentReference}/verify](https://docs-staging.varmply.com/openapi/wallet/verifywalletfundingsession.md): Reconciles a returned Paystack checkout callback for an authenticated wallet funding session.
The session is only verifiable by its authenticated owner; other users receive 404.

This endpoint does not trust the browser callback alone. It verifies the paymentReference
against Paystack's transaction verification API, checks that the provider amount matches the
funding session amount, and then reuses the same idempotent wallet ledger completion/failure
path as the Paystack webhook.

Verification criteria:
- A successful Paystack verification completes the funding session and credits the wallet once.
- A provider verification outage or malformed provider response returns the existing pending
  funding session with 202, allowing the client to retry or keep polling.
- A provider amount mismatch returns 409.

### Initiate wallet withdrawal

 - [POST /wallet/withdraw](https://docs-staging.varmply.com/openapi/wallet/initiatewalletwithdrawal.md): Initiates a wallet withdrawal against the explicitly selected payoutAccountId.
The response includes the selected payout account snapshot so the client can render the in-flight withdrawal
without re-deriving bank display details from the payout-account list.

Preconditions:
- Verified email is required.
- payoutAccountId must belong to the authenticated user and be verified.
- amount is a major-unit NGN amount and must be at least 5000.

Verification criteria:
- A newly initiated withdrawal returns status=processing.
- Provider failure restores the wallet balance and the later read returns status=failed.
- Provider success leaves the withdrawal readable as status=completed.

### Get wallet withdrawal

 - [GET /wallet/withdrawals/{withdrawalId}](https://docs-staging.varmply.com/openapi/wallet/getwalletwithdrawal.md): Returns the normalized withdrawal status view.
payoutAccount is a snapshot of the selected payout account when that account record is still available;
clients should use payoutAccountId as the stable identifier.
The withdrawal is only visible to the authenticated owner; other users receive 404.

Verification criteria:
- Failed withdrawals remain readable as status=failed with the original payoutAccountId.
- Completed withdrawals remain readable as status=completed.
- A different authenticated user receives 404 for the same withdrawalId.

## Campaigns

Role-scoped creator and sponsor campaign workspaces plus sponsor campaign detail and lifecycle management

### Get the creator campaign workspace

 - [GET /me/creator-campaigns](https://docs-staging.varmply.com/openapi/campaigns/listcreatorcampaigns.md): Returns the authenticated creator's campaign workspace cards and summary counts using submission-led membership and canonical campaign lifecycle truth.

### Get the sponsor campaign workspace

 - [GET /me/sponsor-campaigns](https://docs-staging.varmply.com/openapi/campaigns/listsponsorcampaigns.md): Returns the authenticated sponsor's ownership-led campaign workspace cards and summary counts. This is the campaign workspace surface and defaults to the draft tab when none is supplied.

### Preview campaign builder budget projection

 - [POST /campaigns/builder/budget-projection](https://docs-staging.varmply.com/openapi/campaigns/previewcampaignbuilderbudgetprojection.md): Non-mutating budget preview endpoint for the campaign builder. The backend derives creator
capacity and sponsor-facing projection ranges from budgetNGN using canonical policy. This
endpoint never creates or updates a campaign draft.

budgetNGN is the creator-distributable campaign budget for MVP. Out-of-policy budgets return
400 with canonical policy limits. Successful responses return total campaign projection ranges
as the primary estimate and per-creator average ranges as secondary explanatory data.

### Create a draft campaign

 - [POST /campaigns](https://docs-staging.varmply.com/openapi/campaigns/createcampaignforauthenticateduser.md): Create a draft campaign for the authenticated user using the canonical builder contract. The backend derives internal campaign constraints from budgetNGN. Returns 201 Created on success. Requires a valid JWT access token.

### Get sponsor campaign detail

 - [GET /campaigns/{campaignId}](https://docs-staging.varmply.com/openapi/campaigns/getsponsorcampaigndetailforauthenticateduser.md): Retrieve the sponsor-authenticated campaign review detail for the authenticated campaign owner. Returns the explicit sponsor review contract with campaign identity, overview, rules, submissions, and creators. Returns 200 OK on success, 404 if not found, and 403 if the user is not the campaign owner or lacks the sponsor role. Requires a valid JWT access token.

### Update a draft campaign

 - [PUT /campaigns/{campaignId}](https://docs-staging.varmply.com/openapi/campaigns/updatecampaignforauthenticateduser.md): Update a draft campaign for the authenticated user using the canonical builder contract. Only campaigns in DRAFT status can be updated, and the backend re-derives internal campaign constraints from budgetNGN. Returns 200 OK on success, 400 for validation errors, 404 if not found, 403 if not owned by user. Requires a valid JWT access token.

### Get creator campaign participation view

 - [GET /campaigns/{campaignId}/creator-view](https://docs-staging.varmply.com/openapi/campaigns/getcreatorcampaignview.md): Retrieve the dedicated creator participation view for a campaign. This surface returns
light campaign context, creator-scoped submission CTA state, and only the authenticated
creator's latest submission card when one exists. Requires a valid JWT access token.

### Get post-campaign summary

 - [GET /campaigns/{campaignId}/summary](https://docs-staging.varmply.com/openapi/campaigns/getcampaignpostsummary.md): Retrieve the canonical role-aware post-campaign summary for the authenticated user.
The endpoint is available when a campaign is COMPLETED and final when a campaign is ARCHIVED.
Campaign owners receive the sponsor summary blocks. Participating creators receive only their creator-scoped summary block.
This closure surface does not include analytics tables, CEI, projection, eligibility, embed state, or raw submission lists.

### Get campaign ledger activity feed

 - [GET /campaigns/{campaignId}/ledger](https://docs-staging.varmply.com/openapi/campaigns/getcampaignledgerevents.md): Retrieve campaign ledger transaction events as an activity feed, showing all financial transactions related to a campaign in chronological order (newest first). Returns 200 OK on success, 404 if campaign not found. Supports optional limit query parameter (default 50). Requires a valid JWT access token.

### Get campaign timeline analytics

 - [GET /campaigns/{campaignId}/timeline](https://docs-staging.varmply.com/openapi/campaigns/getcampaigntimeline.md): Retrieve time-series timeline data for a campaign with daily buckets showing escrow balance, participation counts, and tracking submission counts over time.
Returns 200 OK on success, 404 if campaign not found. Supports optional limitDays query parameter to limit the number of days returned.
Requires a valid JWT access token. All timestamps are in UTC (ISO 8601 format with Z suffix).

### Finalize a campaign

 - [POST /campaigns/{campaignId}/finalize](https://docs-staging.varmply.com/openapi/campaigns/finalizecampaign.md): Finalize a campaign if completion conditions are met. Only the campaign owner can finalize their campaign. Completion requires either: campaign endDate has passed OR escrow balance is zero. Returns 200 OK with updated campaign on success, 400 if not eligible. Requires a valid JWT access token.

### Fund campaign escrow from sponsor wallet

 - [POST /campaigns/{campaignId}/fund](https://docs-staging.varmply.com/openapi/campaigns/fundcampaignescrowforauthenticateduser.md): Allocates confirmed sponsor wallet balance into campaign escrow for a draft campaign. The operation is sponsor-owned, ledger-backed, and should be called with an Idempotency-Key header by clients that may retry. Returns 200 OK on success, 400 for validation or insufficient wallet balance, 403 if not owned by the user, 404 if not found, and 409 if escrow was already allocated through a different request. Requires a valid JWT access token.

### Activate a draft campaign

 - [POST /campaigns/{campaignId}/activate](https://docs-staging.varmply.com/openapi/campaigns/activatecampaignforauthenticateduser.md): Activate a draft campaign, transitioning it to ACTIVE status. The campaign must be in DRAFT status, have all required fields completed, have escrow fully funded to the target budget, and when TikTok is allowed it must have a captured TikTok sound reference. Returns 200 OK on success, 400 for validation errors, 404 if not found, 403 if not owned by user. Requires a valid JWT access token.

### Create a creator submission

 - [POST /campaigns/{campaignId}/submissions](https://docs-staging.varmply.com/openapi/campaigns/submitcampaigncontent.md): Create a new creator submission resource for a campaign.

Submission correction is explicit:
- update the same submission record with PATCH /submissions/{submissionId} while it remains SUBMITTED or VERIFYING
- create a replacement correction with POST /submissions/{submissionId}/retry-or-replace after ACTION_REQUIRED

Public validation output is canonical: nextStatus is limited to TRACKING or ACTION_REQUIRED,
and structured issue codes do not expose legacy temporary verification states.

### Get campaign analytics

 - [GET /campaigns/{campaignId}/analytics](https://docs-staging.varmply.com/openapi/campaigns/getcampaignanalytics.md): Returns sponsor-facing campaign analytics as a descriptive read model.
Supports from, to, and bucket for date range and bucketing (defaults apply when omitted).
Supports metric to choose the primary performance timeline series.
Distributed values are derived from released escrow payouts.
Accessible by the campaign owner only.
All timestamps are in UTC (ISO 8601 format with Z suffix).

### Get creator campaign analytics

 - [GET /campaigns/{campaignId}/creator-analytics](https://docs-staging.varmply.com/openapi/campaigns/getcreatorcampaignanalytics.md): Returns creator-facing campaign analytics scoped to the authenticated creator's participation.
Supports from, to, and bucket for timeline range and bucketing.
Sponsor-only fields, other creators' data, budget utilization, CEI, and private sponsor details are excluded.
Freshness is returned through the canonical analytics freshness block.

### Get participation analytics within campaign

 - [GET /campaigns/{campaignId}/participations/{participationId}/analytics](https://docs-staging.varmply.com/openapi/campaigns/getcampaignparticipationanalytics.md): Returns read-only participation analytics within a campaign context.
Accessible by campaign owner or the participation creator.
Aggregates metrics from TRACKING submissions only and explicitly marks which submissions are counted.
Supports from, to, and bucket for date range and bucketing (defaults apply when omitted).
All timestamps are in UTC (ISO 8601 format with Z suffix).

### Initialize backend-owned media upload

 - [POST /media-assets/init](https://docs-staging.varmply.com/openapi/campaigns/initmediaassetupload.md): Creates a PENDING_UPLOAD media asset, allocates a backend-owned original object key,
and returns temporary upload transport for the client to PUT the original image.

### Create campaign media asset record

 - [POST /media-assets](https://docs-staging.varmply.com/openapi/campaigns/createmediaasset.md): Creates a MediaAsset record owned by the authenticated user.
This endpoint does not upload binary content or generate derived assets.
It records metadata for the original object plus any pre-generated variant metadata supplied by the caller.
originalUrl is persisted as the original-object location only; it is not a promise of backend-signed delivery.
Any thumbhash values are stored as provided variant metadata; the backend does not compute them at request time.

### Get campaign media asset record

 - [GET /media-assets/{assetId}](https://docs-staging.varmply.com/openapi/campaigns/getmediaasset.md)

### Soft-delete media asset

 - [DELETE /media-assets/{assetId}](https://docs-staging.varmply.com/openapi/campaigns/deletemediaasset.md): Soft-deletes an owned media asset. Actively attached assets are rejected unless a detach or replacement
flow handles the reference first.

### Complete media upload

 - [POST /media-assets/{assetId}/complete](https://docs-staging.varmply.com/openapi/campaigns/completemediaassetupload.md): Confirms the original object exists, records upload metadata, and transitions the owned asset to PROCESSING.
This endpoint is idempotent for client retries and does not perform image processing inline.

### Reprocess failed media asset

 - [POST /media-assets/{assetId}/reprocess](https://docs-staging.varmply.com/openapi/campaigns/reprocessmediaasset.md): Retries processing for an owned FAILED asset. Arbitrary user-triggered reprocessing of READY assets is not supported in v1.

### Redirect to presigned URL for a public media object

 - [GET /media-assets/public/{objectKey}](https://docs-staging.varmply.com/openapi/campaigns/getpublicmediaassetredirect.md): Returns a 302 redirect to a short-lived presigned URL for the given object key in the configured object store.
Used to serve public seed and campaign media without exposing storage credentials.
This route only signs reads for object keys intentionally exposed through the public media namespace.
It does not support arbitrary transforms or private asset policy decisions.
If storage is not configured for the current environment, returns 503.

## Marketplace

Creator-facing marketplace for campaign discovery, eligibility, and joining

### Get featured marketplace campaigns

 - [GET /marketplace/featured](https://docs-staging.varmply.com/openapi/marketplace/getfeaturedmarketplacecampaigns.md): Retrieve the backend-ranked featured marketplace campaign cards for the authenticated creator.
Only campaigns that satisfy the canonical featured eligibility gate are returned.
The response includes only the already-ranked campaign cards and does not include scores
or ranking explanations.
Requires a valid JWT access token.

### Get marketplace campaigns

 - [GET /marketplace/campaigns](https://docs-staging.varmply.com/openapi/marketplace/getmarketplacecampaigns.md): Retrieve marketplace campaign cards for the authenticated creator.
Returns the current marketplace projection, escrow summary, slot availability, submission window,
and per-viewer eligibility context for each campaign.
Supports deterministic filtering, sorting, and cursor pagination.
Requires a valid JWT access token.

### Get marketplace campaign detail

 - [GET /marketplace/campaigns/{campaignId}](https://docs-staging.varmply.com/openapi/marketplace/getmarketplacecampaigndetail.md): Retrieve the marketplace discovery detail view for a campaign, including requirements,
sound reference state, projection, slot availability, and the authenticated creator's
submission CTA eligibility without leaking participation detail state.
Requires a valid JWT access token.

## Participation

Creator participation lifecycle, submissions, and participation detail views

### Get participation details with tracking

 - [GET /participations/{participationId}](https://docs-staging.varmply.com/openapi/participation/getparticipationdetailswithtracking.md): Retrieve participation details, campaign context, and derived tracking state for each submission. Requires a valid JWT access token. Accessible to the creator who owns the participation or the campaign owner.

### Get creator submission detail

 - [GET /submissions/{submissionId}](https://docs-staging.varmply.com/openapi/participation/getsubmission.md): Returns the dedicated creator-facing submission read model.
The payload exposes correction-chain identifiers, explicit editability, verified-metrics freshness,
and embed availability without reintroducing participation-slot wording.

### Update an editable pending submission

 - [PATCH /submissions/{submissionId}](https://docs-staging.varmply.com/openapi/participation/patchsubmission.md): Update the same submission record while it is still SUBMITTED or VERIFYING.
Once a submission reaches ACTION_REQUIRED, correction must go through the retry-or-replace route.

### Correct an action-required submission

 - [POST /submissions/{submissionId}/retry-or-replace](https://docs-staging.varmply.com/openapi/participation/retryorreplacesubmission.md): Creates an explicit replacement submission linked to the failed attempt.
The original submission remains addressable through GET /submissions/{submissionId} and exposes
its correction chain through replacedBySubmissionId.

### Get participation analytics

 - [GET /participations/{participationId}/analytics](https://docs-staging.varmply.com/openapi/participation/getparticipationanalytics.md): Returns read-only participation analytics for the authenticated user.
Only accessible by the participation creator.
Aggregates metrics from TRACKING submissions only and explicitly marks which submissions are counted.
Supports from, to, and bucket for date range and bucketing (defaults apply when omitted).
All timestamps are in UTC (ISO 8601 format with Z suffix).

## Analytics

Read-only reporting across campaigns, participations, and submissions; not the campaign workspace surface

### Get portfolio analytics overview

 - [GET /analytics/overview](https://docs-staging.varmply.com/openapi/analytics/getanalyticsoverview.md): Returns the top-level analytics overview for the authenticated user.
Sponsor users receive the sponsor portfolio surface, creator users receive the creator portfolio surface.
Users with both SPONSOR and CREATOR roles must provide role=sponsor or role=creator.
Timeline points are aggregated by UTC day and empty days are zero-filled.
Dashboard remains the sole owner of milestone and dashboard banner interactions; analytics overview
does not return a parallel banner payload.

### Get sponsor campaign analytics list

 - [GET /analytics/campaigns](https://docs-staging.varmply.com/openapi/analytics/getanalyticscampaignperformancelist.md): Returns the sponsor campaign analytics reporting list used by the analytics table screen.
This is an analytics-only reporting surface, not the sponsor campaign workspace.
Use /me/sponsor-campaigns for workspace cards, draft campaigns, and workspace summary counts.
Supports filtering, sorting, cursor pagination, and search.
Metrics and distributed totals are scoped by the selected period, while budget amount remains lifetime campaign budget truth.

### Get campaign analytics summary

 - [GET /analytics/campaigns/{campaignId}/summary](https://docs-staging.varmply.com/openapi/analytics/getcampaignanalyticssummary.md): Returns read-only analytics summary for a campaign, including aggregated metrics totals
and participation-level breakdown. Only the campaign owner can view analytics.
Returns aggregated metrics from the latest snapshot per participation.
All timestamps are in UTC (ISO 8601 format with Z suffix).

### Get submission analytics

 - [GET /submissions/{submissionId}/analytics](https://docs-staging.varmply.com/openapi/analytics/getsubmissionanalytics.md): Returns read-only submission analytics with normalized metrics and money streams.
Only accessible by the submission creator.
Supports from, to, and bucket for date range and bucketing (defaults apply when omitted).
All timestamps are in UTC (ISO 8601 format with Z suffix).

## Metrics

Metrics refresh and ingestion workflows for campaigns and participations

### Refresh metrics for a participation's submitted content

 - [POST /metrics/participations/{participationId}/refresh](https://docs-staging.varmply.com/openapi/metrics/refreshparticipationmetrics.md): Refreshes metrics (impressions, reach, likes, comments, saves, shares) for a participation's submitted content.
Fetches the latest metrics from the social media platform API and creates a snapshot.
Requires the participation to have submitted content and the user to have a connected social account with valid OAuth tokens.
Returns 200 OK with the created metrics snapshot on success.

### Refresh metrics for all eligible participations in a campaign

 - [POST /metrics/campaigns/{campaignId}/refresh](https://docs-staging.varmply.com/openapi/metrics/refreshcampaignmetrics.md): Refreshes metrics for campaign participations once campaign-level settlement checks pass.
Participations without active tracking submissions are included in the run and reported as failed refreshes.
Processes participations sequentially and returns a summary of successful and failed refreshes.
Only the campaign owner can refresh metrics for their campaign.
Returns 200 OK with the refresh summary on success.

## Dev

Development-only endpoints for testing (not available in production)

### Fund wallet (dev-only)

 - [POST /dev/wallets/fund](https://docs-staging.varmply.com/openapi/dev/fundwalletfordev.md): Fund a wallet for the authenticated user. This endpoint is only available in non-production environments.
Returns 403 if called in production. Requires a valid JWT access token.
The wallet must already exist for the user and currency (no auto-create).
Creates a ledger-backed transaction to record the funding.

