openapi: 3.1.0

info:
  title: Airaa API
  version: "1.0.0"
  summary: Read your Airaa communities, campaigns, submissions and payouts over HTTP.
  description: |
    The Airaa API exposes the same twelve tools an AI agent sees over MCP, as plain
    HTTP endpoints you can call with `curl`, `fetch`, or any HTTP client.

    Every endpoint follows one shape:

    ```
    POST /api/ai/mcp/tools/{tool_name}/execute
    Authorization: Bearer airaa_<uuid>
    Content-Type: application/json

    {"args": { ... }}
    ```

    Successful responses return a single `result` key. The type of `result` depends
    on the tool.

    ## Scope

    This API is read only. It reads campaigns, submissions, members, leaderboards,
    tokens and profile data. Launching a campaign, approving content and releasing
    payouts still happen in the Airaa dashboard. Write access is on the way.

    ## Permissions

    A key carries exactly the permissions of the user it belongs to. It can only
    reach communities where that user is an admin or a moderator. Any other
    `projectId` returns `403`.

    When you do not already know a `projectId`, call `list_manageable_projects`
    first and use an id from that response.

    ## Error handling

    Most failures return an HTTP error status with an `{"error": "..."}` body.

    Four cases currently return **HTTP 200** with the error nested inside `result`
    instead, so check for `result.error` as well as the status code:

    * `get_clipping_campaign_detail` on a campaign that is not clipping or UGC
    * `get_clipping_owner_submissions` on a campaign that is not clipping or UGC
    * `get_project_leaderboard` with an unparseable `startDate` or `endDate`
    * any tool whose underlying query fails

    ## Identifiers

    All ids are UUIDs. `projectId` identifies a community, `projectCampaignId`
    identifies a campaign, and `platformId` identifies a social platform such as X
    or Instagram. Platform ids are not fixed constants you should hardcode: read
    them from `supportedPlatforms` on `get_clipping_campaign_detail` or from the
    task rows on `get_campaign_details`.

    ## Pagination

    Paginated tools accept `page` (1-indexed) and `limit` (1 to 100) and return a
    `metadata` object with `page`, `limit`, `totalItems` and `totalPages`.

    `get_project_members_detailed` is the exception: it accepts `page` and `limit`
    but returns a bare array with no `metadata`, so you cannot tell from the
    response alone whether more pages exist.

    ## Examples

    Response examples in this reference use invented community, creator and
    campaign data. Field names, types, statuses and value formats are taken from
    real API responses.
  contact:
    name: Airaa
    url: https://airaa.xyz

servers:
  - url: https://app.airaa.xyz
    description: Production

security:
  - bearerAuth: []

tags:
  - name: Communities
    description: Which communities the key can reach, and their profile data.
  - name: Campaigns
    description: Campaign lists and full campaign detail.
  - name: Submissions
    description: Content creators submitted, with engagement and payout state.
  - name: People
    description: Community roster and earnings leaderboard.
  - name: Account
    description: The key owner, payout tokens, and the server clock.

paths:

  /api/ai/mcp/tools/list_manageable_projects/execute:
    post:
      operationId: listManageableProjects
      summary: List communities you can manage
      tags: [Communities]
      description: |
        Returns the communities where the authenticated user is an admin or a
        moderator, with `projectId`, `slug`, `name` and `role`.

        Call this first whenever you need a `projectId` and do not already have
        one. If it returns nothing, the key cannot reach any community data and
        there is no other lookup that will work.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/EmptyArgsRequest'
            example:
              args: {}
      responses:
        '200':
          description: The communities this key can manage.
          content:
            application/json:
              schema:
                type: object
                required: [result]
                properties:
                  result:
                    type: object
                    required: [projects]
                    properties:
                      projects:
                        type: array
                        items:
                          $ref: '#/components/schemas/ManageableProject'
              example:
                result:
                  projects:
                    - projectId: 3f2a9c7e-1b84-4d5a-9e60-7c1af2b83d41
                      slug: lumenlabs
                      name: Lumen Labs
                      guildEnabled: true
                      role: ADMIN
                      demoMode: false
                      isPersonalProject: false
                      accentColor: "#f5cb42"
                      logo: https://cdn.airaa.xyz/images/projects/logo/3f2a9c7e-1b84-4d5a-9e60-7c1af2b83d41.png
                      pointsToken:
                        id: b81c4d02-5f6a-4e33-a1d7-92e845bc0f16
                        name: Lumen Points
                        symbol: LUM
                        logo: ""
                      campaignCommission: 50
        '401': { $ref: '#/components/responses/Unauthorized' }
        '405': { $ref: '#/components/responses/MethodNotAllowed' }

  /api/ai/mcp/tools/get_project_info/execute:
    post:
      operationId: getProjectInfo
      summary: Get a community profile
      tags: [Communities]
      description: |
        Returns a community overview: metadata, the authenticated user's
        membership status and role, member counts, campaign and rewards totals,
        team members, X follower counts, points token and social links.

        `projectId` is required in practice. The tool schema marks it optional,
        but omitting it returns `400`.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [args]
              properties:
                args:
                  type: object
                  required: [projectId]
                  properties:
                    projectId:
                      $ref: '#/components/schemas/ProjectId'
            example:
              args:
                projectId: 3f2a9c7e-1b84-4d5a-9e60-7c1af2b83d41
      responses:
        '200':
          description: The community profile.
          content:
            application/json:
              schema:
                type: object
                required: [result]
                properties:
                  result:
                    $ref: '#/components/schemas/ProjectInfo'
              example:
                result:
                  id: 3f2a9c7e-1b84-4d5a-9e60-7c1af2b83d41
                  slug: lumenlabs
                  name: Lumen Labs
                  isWhitelabelEnabled: true
                  category: Tech
                  logo: https://cdn.airaa.xyz/images/projects/logo/3f2a9c7e-1b84-4d5a-9e60-7c1af2b83d41.png
                  banner: https://cdn.airaa.xyz/images/projects/banner/3f2a9c7e-1b84-4d5a-9e60-7c1af2b83d41.jpeg
                  description: We see, we create, we earn
                  twitterProfileUrl: https://x.com/lumenlabs
                  totalMemberCount: 10
                  isUserMember: true
                  userMembershipStatus: ACTIVE
                  userRole: ADMIN
                  activeCampaignsCount: 33
                  totalCampaignsCount: 35
                  rewardsDistributed: "371.4"
                  totalPointsDistributed: "53018"
                  erc20Totals:
                    - totalAmount: "371.40000000"
                      symbol: USDC
                      decimals: 18
                  pointsTotals:
                    - totalAmount: "53017.00000000"
                      symbol: LUM
                      decimals: 0
                  activeMembersCount: 10
                  teamMembers:
                    - userId: 8d15b4c7-3e29-4a60-9f81-6b2c7e04d5a3
                      role: ADMIN
                      photoUrl: https://cdn.airaa.xyz/images/user-avatars/8d15b4c7-3e29-4a60-9f81-6b2c7e04d5a3
                      username: alexmorgan
                      name: Alex Morgan
                    - userId: c40f7a15-9e2b-4c86-b1d3-58a90e6f27b4
                      role: MODERATOR
                      photoUrl: https://cdn.airaa.xyz/images/profile-placeholders/image3.webp
                      username: mayaokonkwo
                      name: Maya Okonkwo
                  smartFollowersCount: 1
                  pointsToken:
                    symbol: LUM
                    logo: null
                  twitterFollowersCount: 105
                  demoMode: false
                  checklist:
                    hasAnnouncement: true
                    hasGig: true
                  socials:
                    x: https://x.com/lumenlabs
                    telegram: https://t.me/lumenlabs
                    discord: https://discord.gg/lumenlabs
                    youtube: https://youtube.com/@lumenlabs
                    instagram: https://instagram.com/lumenlabs
                    tiktok: https://tiktok.com/@lumenlabs
        '400':
          description: |
            `projectId` was not supplied.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorEnvelope'
              example:
                error: get_project_info requires a projectId, call list_manageable_projects first
        '401': { $ref: '#/components/responses/Unauthorized' }
        '403': { $ref: '#/components/responses/Forbidden' }
        '405': { $ref: '#/components/responses/MethodNotAllowed' }
        '500': { $ref: '#/components/responses/MalformedUuid' }

  /api/ai/mcp/tools/get_my_campaigns/execute:
    post:
      operationId: getMyCampaigns
      summary: List your campaigns
      tags: [Campaigns]
      description: |
        Returns campaigns the authenticated user owns or moderates. Hidden
        campaigns are excluded.

        Omit `projectId` to list campaigns across every community the key can
        manage. `counts` holds aggregate totals and `projects` lists the
        communities available to filter by.

        This response has no `metadata` object. Use `counts` to judge how many
        campaigns exist and page with `page` and `limit`.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [args]
              properties:
                args:
                  type: object
                  properties:
                    projectId:
                      $ref: '#/components/schemas/ProjectIdNullable'
                    statusBy:
                      type: [string, "null"]
                      enum: [LIVE, ENDED, DRAFT, PAYMENT_PENDING, null]
                      description: Filter by campaign status.
                    campaignType:
                      type: [string, "null"]
                      enum: [all, instant_tasks, clipping, UGC, null]
                      description: Filter by campaign type group.
                    page:
                      $ref: '#/components/schemas/Page'
                    limit:
                      allOf:
                        - $ref: '#/components/schemas/Limit'
                      default: 10
            example:
              args:
                projectId: 3f2a9c7e-1b84-4d5a-9e60-7c1af2b83d41
                page: 1
                limit: 10
      responses:
        '200':
          description: Campaigns, aggregate counts, and filterable communities.
          content:
            application/json:
              schema:
                type: object
                required: [result]
                properties:
                  result:
                    type: object
                    required: [campaigns, counts, projects]
                    properties:
                      campaigns:
                        type: array
                        items:
                          $ref: '#/components/schemas/CampaignListItem'
                      counts:
                        $ref: '#/components/schemas/CampaignCounts'
                      projects:
                        type: array
                        items:
                          $ref: '#/components/schemas/ProjectRefWithRole'
              example:
                result:
                  campaigns:
                    - id: 9c4e1d7a-2f38-4b6c-8e51-0d7a3f96b2c8
                      status: LIVE
                      title: Summer Drop Clips
                      createdAt: "2026-08-06T13:01:54.178Z"
                      campaignType: clipping
                      taskTypes: [CLIP_X, CLIP_INSTAGRAM, CLIP_TIKTOK]
                      totalPool: "100"
                      remainingPool: "100"
                      platform:
                        - id: 1a7d3f5b-8c92-4e06-b4a1-9f27d5c83e60
                          name: X
                          enabled: true
                        - id: 2b8e4a6c-9d03-4f17-c5b2-0a38e6d94f71
                          name: Instagram
                          enabled: true
                      payoutType: FCFS
                      completedUsersCount: 0
                      incompletedUsersCount: 0
                      hasCounterOffer: false
                      tokenType: ERC20
                      tokenSymbol: USDC
                      project:
                        id: 3f2a9c7e-1b84-4d5a-9e60-7c1af2b83d41
                        name: Lumen Labs
                        logo: https://cdn.airaa.xyz/images/projects/logo/3f2a9c7e-1b84-4d5a-9e60-7c1af2b83d41.png
                      usedBudget: "0"
                      approvedClipsCount: 0
                      impressions: 0
                      pendingReviewsCount: 0
                  counts:
                    live: 33
                    draft: 4
                    ended: 2
                    spent: 4345
                  projects:
                    - id: 3f2a9c7e-1b84-4d5a-9e60-7c1af2b83d41
                      name: Lumen Labs
                      logo: https://cdn.airaa.xyz/images/projects/logo/3f2a9c7e-1b84-4d5a-9e60-7c1af2b83d41.png
                      role: ADMIN
        '400': { $ref: '#/components/responses/InvalidArguments' }
        '401': { $ref: '#/components/responses/Unauthorized' }
        '403': { $ref: '#/components/responses/Forbidden' }
        '405': { $ref: '#/components/responses/MethodNotAllowed' }

  /api/ai/mcp/tools/get_campaign_details/execute:
    post:
      operationId: getCampaignDetails
      summary: Get one campaign in full
      tags: [Campaigns]
      description: |
        Returns a campaign's full owner-facing detail: basic info, stats, budget,
        tasks, and for live clipping or UGC campaigns the clipping owner
        analytics payload.

        `detailVariant` tells you which shape came back:

        * `clipping_owner` for CLIPPING and UGC campaigns that are no longer DRAFT.
          `clippingOwner` is populated and `tasks` is empty.
        * `social_owner` for SOCIAL campaigns and for any campaign still in DRAFT.
          `tasks` is populated and `clippingOwner` is `null`.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CampaignIdRequest'
            example:
              args:
                projectCampaignId: 9c4e1d7a-2f38-4b6c-8e51-0d7a3f96b2c8
      responses:
        '200':
          description: The campaign detail, in one of two variants.
          content:
            application/json:
              schema:
                type: object
                required: [result]
                properties:
                  result:
                    oneOf:
                      - $ref: '#/components/schemas/CampaignDetailClippingOwner'
                      - $ref: '#/components/schemas/CampaignDetailSocialOwner'
                    discriminator:
                      propertyName: detailVariant
                      mapping:
                        clipping_owner: '#/components/schemas/CampaignDetailClippingOwner'
                        social_owner: '#/components/schemas/CampaignDetailSocialOwner'
              examples:
                clipping_owner:
                  summary: A live clipping campaign
                  value:
                    result:
                      campaignType: clipping
                      detailVariant: clipping_owner
                      campaign:
                        id: 9c4e1d7a-2f38-4b6c-8e51-0d7a3f96b2c8
                        projectId: 3f2a9c7e-1b84-4d5a-9e60-7c1af2b83d41
                        createdAt: "2026-08-06T13:01:54.178Z"
                        title: Summer Drop Clips
                        imageUrl: null
                        status: LIVE
                        startDate: "2026-08-06T13:01:54.177Z"
                        type: clipping
                        approvalMode: MANUAL
                        userEligibilityCriteria:
                          openToAll: true
                      project:
                        id: 3f2a9c7e-1b84-4d5a-9e60-7c1af2b83d41
                        name: Lumen Labs
                        logo: https://cdn.airaa.xyz/images/projects/logo/3f2a9c7e-1b84-4d5a-9e60-7c1af2b83d41.png
                      stats:
                        creators: 4
                        reach: 12480
                        likes: 316
                        quotes: 12
                        post: 9
                      budget:
                        totalPool: "100.000000"
                        remainingPool: "62.400000"
                        tokenType: ERC20
                        tokenSymbol: USDC
                        tokenAddress: "0x3AF9cB6000b310c909e10f79A9Ec642960eeEe99"
                        chainId: "8453"
                        decimals: 18
                      tasks: []
                      draftConfig: null
                      eligibilityProject: null
                      clippingOwner:
                        eligibilitySummary:
                          mode: open
                          guild: null
                        demographicsRequired: false
                        demographicsAudienceRule: null
                        overview:
                          creatorsCount: 4
                          totalSubmissionsCount: 9
                          submissionsCount: 9
                          pendingSubmissionsCount: 2
                          approvedSubmissionsCount: 6
                          rejectedSubmissionsCount: 1
                          paidSubmissionsCount: 5
                          reach: 12480
                          currentReach: 12495
                          initialReach: 15
                          likes: 316
                          comments: 41
                        budget:
                          label: Estimated Budget
                          totalPool: "100.000000"
                          remainingPool: "62.400000"
                          usedBudget: "37.6"
                          tokenType: ERC20
                          tokenSymbol: USDC
                        tasksTab:
                          requirements:
                            hashtags: ["#lumendrop"]
                            mentions: ["@lumenlabs"]
                            urls: []
                            guidelines: Hook in the first two seconds. No captions over the logo.
                          tasks:
                            - taskId: 4c9a2e78-5b13-4d60-8f27-1a94c6e03b52
                              platformId: 1a7d3f5b-8c92-4e06-b4a1-9f27d5c83e60
                              platformName: X
                              platformSlug: x
                              type: CLIP_X
                              submissionRequirements:
                                urls: { values: [], isEnabled: false, requireAll: false }
                                hashtags: { values: ["#lumendrop"], isEnabled: true, requireAll: true }
                                mentions: { values: ["@lumenlabs"], isEnabled: true, requireAll: false }
                                guidelines: Hook in the first two seconds.
                              submissionCounts:
                                total: 5
                                pending: 1
                                approved: 4
                                rejected: 0
                                paid: 3
                                nonRejected: 5
                        settingsTab:
                          userEligibilityCriteria:
                            openToAll: true
                          platformPayouts:
                            - taskId: 4c9a2e78-5b13-4d60-8f27-1a94c6e03b52
                              platformId: 1a7d3f5b-8c92-4e06-b4a1-9f27d5c83e60
                              platformName: X
                              platformSlug: x
                              claimType: FCFS
                              payoutLogic: FORMULA
                              minViews: null
                              maxPayoutPerClip: 100
                              fixedPayout: null
                              cpm: 2
                              bonusRanges: []
                              tokenType: ERC20
                              tokenSymbol: USDC
                      campaignCommission: 50
                social_owner:
                  summary: A social campaign
                  value:
                    result:
                      campaignType: social
                      detailVariant: social_owner
                      campaign:
                        id: 5d8b3e91-7a24-4f10-b3c6-1e9d4a72f05b
                        projectId: 3f2a9c7e-1b84-4d5a-9e60-7c1af2b83d41
                        createdAt: "2026-08-14T11:02:37.443Z"
                        title: Follow and Post
                        imageUrl: null
                        status: LIVE
                        startDate: "2026-08-14T11:02:37.838Z"
                        type: social
                        approvalMode: MANUAL
                        userEligibilityCriteria:
                          guildId: 3f2a9c7e-1b84-4d5a-9e60-7c1af2b83d41
                      project:
                        id: 3f2a9c7e-1b84-4d5a-9e60-7c1af2b83d41
                        name: Lumen Labs
                        logo: https://cdn.airaa.xyz/images/projects/logo/3f2a9c7e-1b84-4d5a-9e60-7c1af2b83d41.png
                      stats:
                        creators: 3
                        reach: 240
                        likes: 18
                        quotes: 2
                        post: 3
                      budget:
                        totalPool: "1000.000000"
                        remainingPool: "400.000000"
                        tokenType: POINTS
                        tokenSymbol: LUM
                        tokenAddress: null
                        chainId: null
                        decimals: 0
                      tasks:
                        - id: 7e30d9a4-6c81-4b25-9f03-2d5a8e17c46b
                          platformId: 1a7d3f5b-8c92-4e06-b4a1-9f27d5c83e60
                          type: POST
                          url: null
                          submissionRequirements:
                            urls: { values: [], isEnabled: false, requireAll: false }
                            hashtags: { values: [], isEnabled: false, requireAll: false }
                            mentions: { values: [], isEnabled: false, requireAll: false }
                            guidelines: Post about the drop and tag the account.
                          payoutConfig:
                            logic: FIXED
                            tokenId: b81c4d02-5f6a-4e33-a1d7-92e845bc0f16
                            claimType: FCFS
                            fixedPayout: 200
                            auraMultiplier: 3
                          taskCompletedCount: "3"
                          reach: "240"
                          likes: "18"
                          replies: "2"
                          platform:
                            id: 1a7d3f5b-8c92-4e06-b4a1-9f27d5c83e60
                            name: X
                      draftConfig: null
                      eligibilityProject: null
                      clippingOwner: null
                      campaignCommission: 50
        '401': { $ref: '#/components/responses/Unauthorized' }
        '403': { $ref: '#/components/responses/Forbidden' }
        '404': { $ref: '#/components/responses/CampaignNotFound' }
        '405': { $ref: '#/components/responses/MethodNotAllowed' }
        '500': { $ref: '#/components/responses/MalformedUuid' }

  /api/ai/mcp/tools/get_clipping_campaign_detail/execute:
    post:
      operationId: getClippingCampaignDetail
      summary: Get a clipping or UGC campaign
      tags: [Campaigns]
      description: |
        Returns the creator-facing view of a clipping or UGC campaign: stats,
        requirements, budget, per platform tasks and payout rules, plus the
        authenticated user's own submissions in `mySubmissions`.

        If the user is not eligible for the campaign, a slim payload comes back
        with `id`, `title`, `project`, `bannerImageUrl` and a `message` instead of
        the full detail.

        Calling this on a SOCIAL campaign returns **HTTP 200** with
        `{"result": {"error": "Clipping campaign not found"}}`.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CampaignIdRequest'
            example:
              args:
                projectCampaignId: 9c4e1d7a-2f38-4b6c-8e51-0d7a3f96b2c8
      responses:
        '200':
          description: |
            The campaign detail, or a `result.error` if the campaign is not a
            clipping or UGC campaign.
          content:
            application/json:
              schema:
                type: object
                required: [result]
                properties:
                  result:
                    oneOf:
                      - $ref: '#/components/schemas/ClippingCampaignDetail'
                      - $ref: '#/components/schemas/InlineError'
              examples:
                detail:
                  summary: A clipping campaign
                  value:
                    result:
                      id: 9c4e1d7a-2f38-4b6c-8e51-0d7a3f96b2c8
                      title: Summer Drop Clips
                      approvalMode: MANUAL
                      status: LIVE
                      startDate: "2026-08-06T13:01:54.177Z"
                      endDate: null
                      payRateDisplay: $1-2/1K views
                      payRateType: PPV
                      bannerImageUrl: https://cdn.airaa.xyz/images/projects/banner/3f2a9c7e-1b84-4d5a-9e60-7c1af2b83d41.jpeg
                      colorCode: "#FFFFFF"
                      project:
                        id: 3f2a9c7e-1b84-4d5a-9e60-7c1af2b83d41
                        name: Lumen Labs
                        logo: https://cdn.airaa.xyz/images/projects/logo/3f2a9c7e-1b84-4d5a-9e60-7c1af2b83d41.png
                      stats:
                        clipsApprovedCount: 6
                        totalViews: 12480
                        totalCurrentViews: 12495
                        totalInitialViews: 15
                        creatorsCount: 4
                      requirements:
                        hashtags: ["#lumendrop"]
                        mentions: ["@lumenlabs"]
                      contentGuidelinesMarkdown: Hook in the first two seconds. No captions over the logo.
                      budget:
                        totalPool: "100.000000"
                        remainingPool: "62.400000"
                        usedBudget: "37.6"
                        accruedUnpaid: "6.040000"
                        tokenType: ERC20
                        tokenSymbol: USDC
                      platformTasks:
                        - taskId: 4c9a2e78-5b13-4d60-8f27-1a94c6e03b52
                          platformId: 1a7d3f5b-8c92-4e06-b4a1-9f27d5c83e60
                          platformSlug: x
                          platformName: X
                          maxPayoutPerClip: 100
                          minViews: null
                          tokenSymbol: USDC
                          taskSubmissionId: null
                          submissionStatus: null
                          payoutLogic: FORMULA
                          cpm: 2
                          fixedTokenAmount: null
                          bonusRanges: []
                          demographicsRequired: false
                          demographicsAudienceRule: null
                      supportedPlatforms:
                        - platformId: 1a7d3f5b-8c92-4e06-b4a1-9f27d5c83e60
                          platformSlug: x
                          platformName: X
                        - platformId: 2b8e4a6c-9d03-4f17-c5b2-0a38e6d94f71
                          platformSlug: instagram
                          platformName: Instagram
                      mySubmissions: []
                      payoutDisplayMode: estimated
                      isEligible: true
                      isEndingSoon: false
                      poolDepleted: false
                      canSubmit: true
                      hasSubmitted: false
                      brandApproved: false
                      brandStats:
                        campaignCount: 44
                        creatorsPaid: 4
                wrong_campaign_type:
                  summary: Called on a social campaign (note the 200 status)
                  value:
                    result:
                      error: Clipping campaign not found
        '401': { $ref: '#/components/responses/Unauthorized' }
        '403': { $ref: '#/components/responses/Forbidden' }
        '404': { $ref: '#/components/responses/CampaignNotFound' }
        '405': { $ref: '#/components/responses/MethodNotAllowed' }
        '500': { $ref: '#/components/responses/MalformedUuid' }

  /api/ai/mcp/tools/get_campaign_submissions/execute:
    post:
      operationId: getCampaignSubmissions
      summary: List submissions by creator
      tags: [Submissions]
      description: |
        Returns submissions for a campaign, one row per creator, with each of
        their tasks and its status. For clipping and UGC campaigns the rows carry
        initial, current and delta view counts.

        For OFFERS-claim campaigns, creators who were offered a slot but have not
        submitted yet are included.

        This works for every campaign type. For the owner dashboard view of a
        clipping or UGC campaign, with payout accruals and action history, use
        `get_clipping_owner_submissions` instead.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [args]
              properties:
                args:
                  type: object
                  required: [projectCampaignId]
                  properties:
                    projectCampaignId:
                      $ref: '#/components/schemas/CampaignId'
                    page:
                      $ref: '#/components/schemas/Page'
                    limit:
                      allOf:
                        - $ref: '#/components/schemas/Limit'
                      default: 10
                    sortBy:
                      type: [string, "null"]
                      enum: [smart_followers, followers, created_at, null]
                    sortOrder:
                      $ref: '#/components/schemas/SortOrder'
                    statusBy:
                      $ref: '#/components/schemas/SubmissionStatusFilter'
                    userId:
                      type: [string, "null"]
                      format: uuid
                      description: Filter to a single creator.
            example:
              args:
                projectCampaignId: 9c4e1d7a-2f38-4b6c-8e51-0d7a3f96b2c8
                page: 1
                limit: 10
      responses:
        '200':
          description: A page of submissions.
          content:
            application/json:
              schema:
                type: object
                required: [result]
                properties:
                  result:
                    type: object
                    required: [submissions, metadata, campaignType]
                    properties:
                      submissions:
                        type: array
                        items:
                          $ref: '#/components/schemas/CreatorSubmission'
                      metadata:
                        $ref: '#/components/schemas/PaginationMetadata'
                      campaignType:
                        $ref: '#/components/schemas/CampaignType'
              example:
                result:
                  submissions:
                    - submissionId: 6a2c8f04-7b31-4e59-a0d6-3f85b1c92e47
                      userId: 7e91b26c-4d05-48af-9b73-2c6f8e14a3d9
                      username: rivertaylor_x
                      userUsername: rivertaylor
                      name: River Taylor
                      profileImageUrl: https://cdn.airaa.xyz/images/user-avatars/7e91b26c-4d05-48af-9b73-2c6f8e14a3d9
                      followersCount: 4820
                      smartFollowersCount: 96
                      viewCount: 5880
                      initialViewCount: 7
                      currentViewCount: 5887
                      deltaViewCount: 5880
                      tokenAmount: "1.00000000"
                      auraPointsAmount: "0.00"
                      estimatedPayout: "11.76"
                      tasks:
                        - taskId: 4c9a2e78-5b13-4d60-8f27-1a94c6e03b52
                          submissionId: 6a2c8f04-7b31-4e59-a0d6-3f85b1c92e47
                          claimedAt: "2026-07-22T14:27:44.495Z"
                          submittedAt: "2026-07-22T14:27:44.493Z"
                          taskType: CLIP_X
                          taskUrl: null
                          submissionStatus: APPROVED
                          submissionReason: null
                          aiReview: null
                          submissionContent:
                            text: Three days with the Lumen drop
                            viewCount: 5880
                            initialViews: 7
                            currentViews: 5887
                            deltaViews: 5880
                            replyCount: 14
                            favoriteCount: 212
                            externalId: "2079936395192545299"
                            url: https://x.com/rivertaylor_x/status/2079936395192545299
                  metadata:
                    page: 1
                    limit: 10
                    totalItems: 1
                    totalPages: 1
                  campaignType: ugc
        '400': { $ref: '#/components/responses/InvalidArguments' }
        '401': { $ref: '#/components/responses/Unauthorized' }
        '403': { $ref: '#/components/responses/Forbidden' }
        '404': { $ref: '#/components/responses/CampaignNotFound' }
        '405': { $ref: '#/components/responses/MethodNotAllowed' }
        '500': { $ref: '#/components/responses/MalformedUuid' }

  /api/ai/mcp/tools/get_clipping_owner_submissions/execute:
    post:
      operationId: getClippingOwnerSubmissions
      summary: List clips for the owner dashboard
      tags: [Submissions]
      description: |
        Returns clipping and UGC submission rows as the campaign owner sees them:
        content links and thumbnails, live engagement, payout accruals, and the
        full action history of each submission.

        Despite the name this works for UGC campaigns as well as clipping ones.
        Calling it on a SOCIAL campaign returns **HTTP 200** with
        `{"result": {"error": "Clipping submissions are only available for clipping campaigns"}}`.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [args]
              properties:
                args:
                  type: object
                  required: [projectCampaignId]
                  properties:
                    projectCampaignId:
                      $ref: '#/components/schemas/CampaignId'
                    page:
                      $ref: '#/components/schemas/Page'
                    limit:
                      allOf:
                        - $ref: '#/components/schemas/Limit'
                      default: 10
                    platformId:
                      type: [string, "null"]
                      format: uuid
                      description: |
                        Filter to one platform. Read valid ids from
                        `supportedPlatforms` on `get_clipping_campaign_detail`.
                    statusBy:
                      $ref: '#/components/schemas/SubmissionStatusFilter'
                    sortBy:
                      type: [string, "null"]
                      enum: [views, likes, created_at, null]
                    sortOrder:
                      $ref: '#/components/schemas/SortOrder'
            example:
              args:
                projectCampaignId: 9c4e1d7a-2f38-4b6c-8e51-0d7a3f96b2c8
                page: 1
                limit: 10
                sortBy: views
                sortOrder: DESC
      responses:
        '200':
          description: |
            A page of clip rows, or a `result.error` if the campaign is not a
            clipping or UGC campaign.
          content:
            application/json:
              schema:
                type: object
                required: [result]
                properties:
                  result:
                    oneOf:
                      - type: object
                        required: [rows, budget, metadata]
                        properties:
                          rows:
                            type: array
                            items:
                              $ref: '#/components/schemas/ClippingOwnerRow'
                          budget:
                            type: object
                            properties:
                              remainingPool:
                                $ref: '#/components/schemas/DecimalString'
                              accruedUnpaid:
                                $ref: '#/components/schemas/DecimalString'
                          metadata:
                            $ref: '#/components/schemas/PaginationMetadata'
                      - $ref: '#/components/schemas/InlineError'
              example:
                result:
                  rows:
                    - submissionId: e5b74a19-0c26-4d83-9f52-8a1c37e604b9
                      taskId: 4c9a2e78-5b13-4d60-8f27-1a94c6e03b52
                      platformId: 1a7d3f5b-8c92-4e06-b4a1-9f27d5c83e60
                      platformName: X
                      platformSlug: x
                      creatorUserId: 7e91b26c-4d05-48af-9b73-2c6f8e14a3d9
                      creatorUsername: rivertaylor_x
                      creatorPhotoUrl: https://cdn.airaa.xyz/images/user-avatars/7e91b26c-4d05-48af-9b73-2c6f8e14a3d9
                      status: DEMOGRAPHICS_DUE
                      submittedAt: "2026-08-03T09:42:45.710Z"
                      expiresAt: "2099-12-31T23:59:59.999Z"
                      rejectionReason: null
                      contentId: a92f60d4-3e17-4b85-8c09-5d7e2a41f6b3
                      contentUrl: https://x.com/rivertaylor_x/status/2084212353432994088
                      contentTitle: Three days with the Lumen drop
                      thumbnailUrl: https://imagedelivery.net/example/content-thumbnail/a92f60d4-3e17-4b85-8c09-5d7e2a41f6b3/public?format=webp
                      videoUrl: null
                      followersCount: 4820
                      commentCount: 14
                      estimatedPayout: "2.71"
                      tokenReward: "0.00000000"
                      auraPointsReward: "0.000000"
                      engagement:
                        views: 1356
                        initialViews: 1
                        currentViews: 1357
                        deltaViews: 1356
                        likes: 212
                        comments: 14
                      canLoadEngagementHistory: true
                      cumulativePaidAmount: "0.00000000"
                      basePaidAmount: "0"
                      bonusPaidAmount: "0"
                      totalPaidAmount: "0"
                      lastPaidAt: null
                      maxPayoutPerClip: 5
                      accruedUnpaid: "2.71"
                      accruedBaseAmount: "2.71"
                      accruedBonusAmount: "0.00"
                      submissionActions:
                        - actionType: DEMOGRAPHICS_DUE
                          amount: null
                          viewsSnapshot: null
                          deltaViews: null
                          reason: null
                          createdAt: "2026-08-04T15:14:00.810Z"
                        - actionType: FAILED
                          amount: null
                          viewsSnapshot: null
                          deltaViews: null
                          reason: Doesn't meet requirements
                          createdAt: "2026-08-04T15:10:21.411Z"
                        - actionType: PENDING
                          amount: null
                          viewsSnapshot: null
                          deltaViews: null
                          reason: null
                          createdAt: "2026-08-03T09:42:45.807Z"
                      demographicsVideoUrl: null
                      demographicsReviewResult: null
                  budget:
                    remainingPool: "62.400000"
                    accruedUnpaid: "6.040000"
                  metadata:
                    page: 1
                    limit: 10
                    totalItems: 8
                    totalPages: 1
        '400': { $ref: '#/components/responses/InvalidArguments' }
        '401': { $ref: '#/components/responses/Unauthorized' }
        '403': { $ref: '#/components/responses/Forbidden' }
        '404': { $ref: '#/components/responses/CampaignNotFound' }
        '405': { $ref: '#/components/responses/MethodNotAllowed' }
        '500': { $ref: '#/components/responses/MalformedUuid' }

  /api/ai/mcp/tools/get_project_members_detailed/execute:
    post:
      operationId: getProjectMembersDetailed
      summary: List community members
      tags: [People]
      description: |
        Returns a community's members with profile info, connected platforms,
        follower totals and participation stats.

        Defaults to ACTIVE members. Filtering by a non-ACTIVE status requires the
        authenticated user to be an admin or moderator of the community.

        Two things to know:

        * `projectId` is required in practice. The tool schema marks it optional,
          but omitting it returns `400`.
        * The response is a bare array with no `metadata`. `page` and `limit` work,
          but nothing in the response tells you whether more pages exist.

        Omit the optional filters unless you actually need them.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [args]
              properties:
                args:
                  type: object
                  required: [projectId]
                  properties:
                    projectId:
                      $ref: '#/components/schemas/ProjectId'
                    status:
                      type: [string, "null"]
                      enum: [ACTIVE, INACTIVE, PENDING, SUSPENDED, null]
                      description: Defaults to ACTIVE.
                    role:
                      type: [string, "null"]
                      enum: [MEMBER, MODERATOR, ADMIN, null]
                    niche:
                      type: [string, "null"]
                      enum:
                        - Gaming
                        - Lifestyle
                        - Fashion
                        - Beauty
                        - Fitness
                        - Food
                        - Travel
                        - Music
                        - Sports
                        - Tech
                        - Finance
                        - Education
                        - Entertainment
                        - Comedy
                        - Art & Design
                        - Creator
                        - Crypto
                        - Business
                        - null
                    platforms:
                      type: [string, "null"]
                      description: 'Comma separated platform slugs. Valid slugs: x, instagram, youtube.'
                      examples: ["x,instagram"]
                    search:
                      type: [string, "null"]
                      description: Match on name or username.
                    page:
                      $ref: '#/components/schemas/Page'
                    limit:
                      allOf:
                        - $ref: '#/components/schemas/Limit'
                      default: 50
            example:
              args:
                projectId: 3f2a9c7e-1b84-4d5a-9e60-7c1af2b83d41
                page: 1
                limit: 50
      responses:
        '200':
          description: Members, as a bare array with no pagination metadata.
          content:
            application/json:
              schema:
                type: object
                required: [result]
                properties:
                  result:
                    type: array
                    items:
                      $ref: '#/components/schemas/ProjectMember'
              example:
                result:
                  - userId: 7e91b26c-4d05-48af-9b73-2c6f8e14a3d9
                    status: ACTIVE
                    role: MEMBER
                    username: rivertaylor
                    name: River Taylor
                    photoUrl: https://cdn.airaa.xyz/images/user-avatars/7e91b26c-4d05-48af-9b73-2c6f8e14a3d9
                    niche: [Business]
                    locationCountry: United States
                    platforms:
                      - slug: x
                        handle: rivertaylor_x
                        followersCount: 4820
                      - slug: instagram
                        handle: rivertaylor
                        followersCount: 1290
                    totalFollowers: 6110
                    communityCampaignsParticipated: 13
                    totalCommunityImpressions: 9139
                    tags:
                      - id: d73e9b58-1a04-4f62-8c95-7b2d6e03a4f1
                        name: Team
                        color: "#e08a3c"
        '400':
          description: |
            `projectId` was not supplied, or an argument failed validation.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorEnvelope'
              example:
                error: get_project_members_detailed requires a projectId, call list_manageable_projects first
        '401': { $ref: '#/components/responses/Unauthorized' }
        '403': { $ref: '#/components/responses/Forbidden' }
        '405': { $ref: '#/components/responses/MethodNotAllowed' }

  /api/ai/mcp/tools/get_project_leaderboard/execute:
    post:
      operationId: getProjectLeaderboard
      summary: Get the earnings leaderboard
      tags: [People]
      description: |
        Returns a community's leaderboard for a date range.

        `sortBy` only controls row order. Every row always carries `totalViews`,
        `totalCampaigns`, `totalUsdc` and `totalCommunityToken` whichever value you
        sort by. There is no sort-by-views option: to rank creators by views, page
        through the results and sort them yourself.

        `myRank: true` returns only the authenticated user's own row, and comes
        back empty when that user is not ranked in the range.

        `startDate` and `endDate` are not validated. An unparseable date returns
        **HTTP 200** with `{"result": {"error": "Failed to fetch leaderboard"}}`.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [args]
              properties:
                args:
                  type: object
                  required: [startDate, endDate, sortBy]
                  properties:
                    projectId:
                      $ref: '#/components/schemas/ProjectIdNullable'
                    startDate:
                      type: string
                      description: Inclusive start date, YYYY-MM-DD.
                      examples: ["2026-01-01"]
                    endDate:
                      type: string
                      description: Inclusive end date, YYYY-MM-DD. Must be on or after startDate.
                      examples: ["2026-08-16"]
                    sortBy:
                      type: string
                      enum: [USDC, POINTS]
                    page:
                      $ref: '#/components/schemas/PageNullable'
                    myRank:
                      type: [boolean, "null"]
                      description: Return only the authenticated user's row.
            example:
              args:
                projectId: 3f2a9c7e-1b84-4d5a-9e60-7c1af2b83d41
                startDate: "2026-01-01"
                endDate: "2026-08-16"
                sortBy: USDC
                page: 1
      responses:
        '200':
          description: |
            A page of ranked creators, or a `result.error` if the query failed.
          content:
            application/json:
              schema:
                type: object
                required: [result]
                properties:
                  result:
                    oneOf:
                      - type: object
                        required: [data, metadata]
                        properties:
                          data:
                            type: array
                            items:
                              $ref: '#/components/schemas/LeaderboardRow'
                          metadata:
                            $ref: '#/components/schemas/PaginationMetadata'
                      - $ref: '#/components/schemas/InlineError'
              example:
                result:
                  data:
                    - rank: 1
                      name: River Taylor
                      username: rivertaylor
                      photoUrl: https://cdn.airaa.xyz/images/user-avatars/7e91b26c-4d05-48af-9b73-2c6f8e14a3d9
                      socialConnections:
                        - platformId: 1a7d3f5b-8c92-4e06-b4a1-9f27d5c83e60
                          platformName: X
                          externalUsername: rivertaylor_x
                      totalCampaigns: 13
                      totalViews: 9139
                      totalUsdc: "155.40000000"
                      totalCommunityToken: "0"
                    - rank: 2
                      name: Maya Okonkwo
                      username: mayaokonkwo
                      photoUrl: https://cdn.airaa.xyz/images/user-avatars/c40f7a15-9e2b-4c86-b1d3-58a90e6f27b4
                      socialConnections:
                        - platformId: 1a7d3f5b-8c92-4e06-b4a1-9f27d5c83e60
                          platformName: X
                          externalUsername: mayaokonkwo
                        - platformId: 3c9f5b7d-0e14-4a28-d6c3-1b49f7e05a82
                          platformName: TikTok
                          externalUsername: maya.okonkwo
                      totalCampaigns: 8
                      totalViews: 65
                      totalUsdc: "72.00000000"
                      totalCommunityToken: "17017.00000000"
                  metadata:
                    page: 1
                    limit: 100
                    totalItems: 6
                    totalPages: 1
        '400':
          description: A required argument was missing or failed validation.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorEnvelope'
              example:
                error: 'Invalid arguments for get_project_leaderboard: Required; Required'
        '401': { $ref: '#/components/responses/Unauthorized' }
        '403': { $ref: '#/components/responses/Forbidden' }
        '405': { $ref: '#/components/responses/MethodNotAllowed' }

  /api/ai/mcp/tools/get_tokens/execute:
    post:
      operationId: getTokens
      summary: List payout tokens
      tags: [Account]
      description: |
        Returns active payout tokens. Tokens are either `POINTS` (community points,
        no chain) or `ERC20` (onchain, with an address, chain id and decimals).

        Pass `projectId` to get the tokens a specific community pays in. When
        `projectId` is set the `type` filter is ignored.

        With no arguments this returns every active token on the platform, which
        includes the points tokens of communities the key does not manage.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [args]
              properties:
                args:
                  type: object
                  properties:
                    type:
                      type: [string, "null"]
                      enum: [ERC20, POINTS, null]
                      description: Ignored when `projectId` is set.
                    projectId:
                      $ref: '#/components/schemas/ProjectIdNullable'
            example:
              args:
                projectId: 3f2a9c7e-1b84-4d5a-9e60-7c1af2b83d41
      responses:
        '200':
          description: The matching tokens.
          content:
            application/json:
              schema:
                type: object
                required: [result]
                properties:
                  result:
                    type: array
                    items:
                      $ref: '#/components/schemas/Token'
              example:
                result:
                  - id: 4e8c1a95-7d20-4f63-b8a1-06d9e5c34f27
                    symbol: USDC
                    name: USD Coin
                    logo: https://basescan.org/token/images/centre-usdc_28.png
                    address: "0x3AF9cB6000b310c909e10f79A9Ec642960eeEe99"
                    chainId: "8453"
                    decimals: 18
                    status: ACTIVE
                    type: ERC20
                  - id: b81c4d02-5f6a-4e33-a1d7-92e845bc0f16
                    symbol: LUM
                    name: Lumen Points
                    logo: https://cdn.airaa.xyz/images/tokens/lumen.jpg
                    address: null
                    chainId: null
                    decimals: 0
                    status: ACTIVE
                    type: POINTS
        '400': { $ref: '#/components/responses/InvalidArguments' }
        '401': { $ref: '#/components/responses/Unauthorized' }
        '403': { $ref: '#/components/responses/Forbidden' }
        '405': { $ref: '#/components/responses/MethodNotAllowed' }

  /api/ai/mcp/tools/get_user_info/execute:
    post:
      operationId: getUserInfo
      summary: Get the key owner
      tags: [Account]
      description: |
        Returns the profile of the user the key belongs to: account flags, X
        profile, connected social accounts, wallets, aura points and the last
        known request location.

        Useful for confirming which account a key is acting as before you run
        anything else.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/EmptyArgsRequest'
            example:
              args: {}
      responses:
        '200':
          description: The authenticated user.
          content:
            application/json:
              schema:
                type: object
                required: [result]
                properties:
                  result:
                    $ref: '#/components/schemas/UserInfo'
              example:
                result:
                  id: 8d15b4c7-3e29-4a60-9f81-6b2c7e04d5a3
                  email: alex@lumenlabs.example
                  badge: null
                  status: null
                  isActive: true
                  verified: true
                  isScout: false
                  twitterProfileId: f61a2c48-9b73-4d05-8e2f-30c7a95b1e64
                  turnkeyExternalUserId: 5b0d9e37-2a46-4c81-b7f3-89e14d6a02c5
                  telegramId: null
                  telegramUsername: null
                  privacyApproved: false
                  isClaimed: false
                  profile:
                    id: f61a2c48-9b73-4d05-8e2f-30c7a95b1e64
                    externalId: "766921563169959936"
                    name: Alex Morgan
                    username: alexmorgan
                    url: https://twitter.com/alexmorgan
                    description: Building Lumen Labs
                    profileImageUrl: https://pbs.twimg.com/profile_images/example/avatar.jpg
                    followersCount: 2419
                    smartFollowersCount: 6
                    followingCount: 1743
                    profileCreatedAt: "2016-08-20T08:55:24.000Z"
                    contentCount: 4516
                    accountBasedIn: null
                  totalBalance: null
                  totalVolume: null
                  totalDappsInteracted: null
                  totalAuraPoints: 90
                  primaryWalletAddress: "0x7a3f9c21e845bd06f1a2c9e37b508d4a6f2e1c93"
                  primaryWalletBalance: null
                  createdAt: "2026-05-31T11:02:45.414Z"
                  updatedAt: "2026-08-15T20:54:13.718Z"
                  name: Alex
                  photoUrl: https://cdn.airaa.xyz/images/profile-placeholders/image2.webp
                  userNiche: [Creator, Tech, Business]
                  username: alexmorgan
                  bio: Building in public
                  niche: [SOCIAL/CONSUMER]
                  spamMultiplier: 0.01
                  wallets:
                    - updatedAt: "2026-06-18T12:35:44.412Z"
                      address: "0x7a3f9c21e845bd06f1a2c9e37b508d4a6f2e1c93"
                      type: EVM
                      projectSlug: null
                      isPrimary: true
                  isAiraaCreator: true
                  isCampaignCreator: false
                  onboardingCompleted: true
                  accounts:
                    - platformId: 2b8e4a6c-9d03-4f17-c5b2-0a38e6d94f71
                      platformName: Instagram
                      externalId: "2981370973"
                      externalUsername: alexmorgan
                      connectedAt: "2026-07-31T14:51:10.812Z"
                  location:
                    country: United States
                    countryCode: US
                    proxy: false
                    hosting: false
                    lastUpdatedAt: "2026-08-15T16:17:53.558Z"
        '401': { $ref: '#/components/responses/Unauthorized' }
        '405': { $ref: '#/components/responses/MethodNotAllowed' }

  /api/ai/mcp/tools/get_current_datetime/execute:
    post:
      operationId: getCurrentDatetime
      summary: Get the server clock
      tags: [Account]
      description: |
        Returns the current date and time, optionally in a given IANA timezone.
        Mainly useful for agents that need to resolve relative dates such as "this
        month" before calling `get_project_leaderboard`.

        Over HTTP this returns a locale formatted string such as
        `8/16/2026, 2:12:52 AM`. The same tool called over MCP returns an ISO 8601
        timestamp. Parse defensively.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [args]
              properties:
                args:
                  type: object
                  properties:
                    timezone:
                      type: [string, "null"]
                      default: UTC
                      description: IANA timezone name. Defaults to UTC.
                      examples: ["America/New_York"]
            example:
              args:
                timezone: UTC
      responses:
        '200':
          description: The current time.
          content:
            application/json:
              schema:
                type: object
                required: [result]
                properties:
                  result:
                    type: object
                    required: [datetime, timezone]
                    properties:
                      datetime:
                        type: string
                        description: Locale formatted date and time over HTTP.
                      timezone:
                        type: string
              example:
                result:
                  datetime: "8/16/2026, 2:12:52 AM"
                  timezone: Asia/Kolkata
        '400': { $ref: '#/components/responses/InvalidArguments' }
        '401': { $ref: '#/components/responses/Unauthorized' }
        '405': { $ref: '#/components/responses/MethodNotAllowed' }

components:

  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      description: |
        Your Airaa API key, sent as `Authorization: Bearer airaa_<uuid>`.

        Create one in the Airaa dashboard under Profile then API key. A key acts
        as you: it can only reach the communities you already manage, and you can
        rotate it at any time.

        Never put the key in a URL or commit it to a repository.

  responses:

    Unauthorized:
      description: The key is missing or not valid.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorEnvelope'
          examples:
            missing:
              summary: No Authorization header
              value:
                error: Unauthorized
            invalid:
              summary: Key not recognised
              value:
                error: Invalid MCP key

    Forbidden:
      description: |
        The key is valid but the user does not administer the requested
        community.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorEnvelope'
          example:
            error: "You don’t administer that community. I can’t look it up."

    CampaignNotFound:
      description: No campaign with that id is visible to this key.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorEnvelope'
          example:
            error: Campaign not found

    InvalidArguments:
      description: |
        An argument failed schema validation. The message names the offending
        field and its allowed values.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorEnvelope'
          examples:
            enum:
              summary: Value outside the allowed enum
              value:
                error: "Invalid arguments for get_campaign_submissions: Invalid enum value. Expected 'PENDING' | 'APPROVED' | 'FAILED' | 'PAID' | 'MILESTONE_BONUS_PAID' | 'DEMOGRAPHICS_DUE' | 'DEMOGRAPHICS_REVIEW', received 'BOGUS'"
            range:
              summary: Number outside the allowed range
              value:
                error: "Invalid arguments for get_campaign_submissions: Number must be less than or equal to 100"
            body:
              summary: Body was not valid JSON
              value:
                error: Invalid JSON body

    MethodNotAllowed:
      description: Execute endpoints accept POST only.

    MalformedUuid:
      description: |
        An id argument was not a valid UUID. The API currently surfaces the
        underlying database error rather than a validation message, so validate
        ids before sending them.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorEnvelope'
          example:
            error: 'invalid input syntax for type uuid: "not-a-uuid"'

  schemas:

    EmptyArgsRequest:
      type: object
      required: [args]
      properties:
        args:
          type: object
          description: This tool takes no arguments. Send an empty object.
          additionalProperties: false

    CampaignIdRequest:
      type: object
      required: [args]
      properties:
        args:
          type: object
          required: [projectCampaignId]
          properties:
            projectCampaignId:
              $ref: '#/components/schemas/CampaignId'

    ProjectId:
      type: string
      format: uuid
      description: A community id from `list_manageable_projects`.
      examples: ["3f2a9c7e-1b84-4d5a-9e60-7c1af2b83d41"]

    ProjectIdNullable:
      type: [string, "null"]
      format: uuid
      description: A community id from `list_manageable_projects`.

    CampaignId:
      type: string
      description: |
        A campaign id, from the `id` field of `get_my_campaigns`. Must be a valid
        UUID: the API returns a 500 rather than a 400 when it is not.
      examples: ["9c4e1d7a-2f38-4b6c-8e51-0d7a3f96b2c8"]

    Page:
      type: integer
      minimum: 1
      default: 1
      description: Page number, 1-indexed.

    PageNullable:
      type: [integer, "null"]
      minimum: 1
      description: Page number, 1-indexed.

    Limit:
      type: integer
      minimum: 1
      maximum: 100
      description: Items per page, 1 to 100.

    SortOrder:
      type: [string, "null"]
      enum: [ASC, DESC, null]

    SubmissionStatusFilter:
      type: [string, "null"]
      enum:
        - PENDING
        - APPROVED
        - FAILED
        - PAID
        - MILESTONE_BONUS_PAID
        - DEMOGRAPHICS_DUE
        - DEMOGRAPHICS_REVIEW
        - null
      description: Filter by submission status.

    SubmissionStatus:
      type: string
      enum:
        - PENDING
        - APPROVED
        - FAILED
        - PAID
        - MILESTONE_BONUS_PAID
        - DEMOGRAPHICS_DUE
        - DEMOGRAPHICS_REVIEW

    CampaignType:
      type: string
      enum: [clipping, ugc, social]

    CampaignStatus:
      type: string
      enum: [DRAFT, LIVE, PAUSED, ENDED, PAYMENT_PROCESSING, PAYMENT_PENDING]

    TokenType:
      type: string
      enum: [ERC20, POINTS]

    DecimalString:
      type: string
      description: |
        A fixed point decimal carried as a string so precision is never lost.
        Scale varies by field.
      examples: ["62.400000"]

    ErrorEnvelope:
      type: object
      required: [error]
      properties:
        error:
          type: string

    InlineError:
      type: object
      description: |
        An error returned inside a 200 response. Check for this alongside the
        HTTP status.
      required: [error]
      properties:
        error:
          type: string

    PaginationMetadata:
      type: object
      required: [page, limit, totalItems, totalPages]
      properties:
        page:
          type: integer
        limit:
          type: integer
        totalItems:
          type: integer
        totalPages:
          type: integer

    ProjectRef:
      type: object
      properties:
        id:
          type: string
          format: uuid
        name:
          type: string
        logo:
          type: [string, "null"]

    ProjectRefWithRole:
      allOf:
        - $ref: '#/components/schemas/ProjectRef'
        - type: object
          properties:
            role:
              $ref: '#/components/schemas/MemberRole'

    MemberRole:
      type: string
      enum: [MEMBER, MODERATOR, ADMIN]

    PointsTokenRef:
      type: object
      properties:
        id:
          type: string
          format: uuid
        name:
          type: string
        symbol:
          type: string
        logo:
          type: [string, "null"]

    ManageableProject:
      type: object
      properties:
        projectId:
          type: string
          format: uuid
        slug:
          type: string
        name:
          type: string
        guildEnabled:
          type: boolean
        role:
          $ref: '#/components/schemas/MemberRole'
        demoMode:
          type: boolean
        isPersonalProject:
          type: boolean
        accentColor:
          type: [string, "null"]
        logo:
          type: [string, "null"]
        pointsToken:
          oneOf:
            - $ref: '#/components/schemas/PointsTokenRef'
            - type: "null"
        campaignCommission:
          type: [integer, "null"]
          description: Platform commission on this community's campaigns, as a percentage.

    ProjectInfo:
      type: object
      properties:
        id:
          type: string
          format: uuid
        slug:
          type: string
        name:
          type: string
        isWhitelabelEnabled:
          type: boolean
        category:
          type: [string, "null"]
        logo:
          type: [string, "null"]
        banner:
          type: [string, "null"]
        description:
          type: [string, "null"]
        twitterProfileUrl:
          type: [string, "null"]
        totalMemberCount:
          type: integer
        isUserMember:
          type: boolean
        userMembershipStatus:
          type: [string, "null"]
          enum: [ACTIVE, INACTIVE, PENDING, SUSPENDED, null]
        userRole:
          oneOf:
            - $ref: '#/components/schemas/MemberRole'
            - type: "null"
        activeCampaignsCount:
          type: integer
        totalCampaignsCount:
          type: integer
        rewardsDistributed:
          type: string
          description: Total ERC20 value paid out, as a decimal string.
        totalPointsDistributed:
          type: string
        erc20Totals:
          type: array
          items:
            $ref: '#/components/schemas/TokenTotal'
        pointsTotals:
          type: array
          items:
            $ref: '#/components/schemas/TokenTotal'
        activeMembersCount:
          type: integer
        teamMembers:
          type: array
          items:
            type: object
            properties:
              userId:
                type: string
                format: uuid
              role:
                $ref: '#/components/schemas/MemberRole'
              photoUrl:
                type: [string, "null"]
              username:
                type: string
              name:
                type: [string, "null"]
        smartFollowersCount:
          type: integer
        pointsToken:
          type: object
          properties:
            symbol:
              type: [string, "null"]
            logo:
              type: [string, "null"]
        twitterFollowersCount:
          type: integer
        demoMode:
          type: boolean
        checklist:
          type: object
          properties:
            hasAnnouncement:
              type: boolean
            hasGig:
              type: boolean
        socials:
          type: object
          description: Present keys vary by what the community has connected.
          properties:
            x: { type: [string, "null"] }
            telegram: { type: [string, "null"] }
            discord: { type: [string, "null"] }
            youtube: { type: [string, "null"] }
            instagram: { type: [string, "null"] }
            tiktok: { type: [string, "null"] }

    TokenTotal:
      type: object
      properties:
        totalAmount:
          $ref: '#/components/schemas/DecimalString'
        symbol:
          type: string
        decimals:
          type: integer

    CampaignCounts:
      type: object
      properties:
        live:
          type: integer
        draft:
          type: integer
        ended:
          type: integer
        spent:
          type: integer
          description: Total paid out across this community's campaigns.

    CampaignListItem:
      type: object
      properties:
        id:
          type: string
          format: uuid
          description: Pass this as `projectCampaignId` to the campaign detail tools.
        status:
          $ref: '#/components/schemas/CampaignStatus'
        title:
          type: string
        createdAt:
          type: string
          format: date-time
        campaignType:
          $ref: '#/components/schemas/CampaignType'
        taskTypes:
          type: array
          items:
            type: string
          description: 'Task types on the campaign, for example CLIP_X, POST, FOLLOW.'
        totalPool:
          type: [string, "null"]
        remainingPool:
          type: [string, "null"]
        platform:
          type: array
          items:
            type: object
            properties:
              id:
                type: string
                format: uuid
              name:
                type: string
              enabled:
                type: boolean
        payoutType:
          type: [string, "null"]
          enum: [FCFS, OFFERS, null]
        completedUsersCount:
          type: integer
        incompletedUsersCount:
          type: integer
        hasCounterOffer:
          type: boolean
        tokenType:
          oneOf:
            - $ref: '#/components/schemas/TokenType'
            - type: "null"
        tokenSymbol:
          type: [string, "null"]
        project:
          $ref: '#/components/schemas/ProjectRef'
        usedBudget:
          type: [string, "null"]
        approvedClipsCount:
          type: integer
        impressions:
          type: integer
        pendingReviewsCount:
          type: integer

    CampaignCore:
      type: object
      properties:
        id:
          type: string
          format: uuid
        projectId:
          type: string
          format: uuid
        createdAt:
          type: string
          format: date-time
        title:
          type: string
        imageUrl:
          type: [string, "null"]
        status:
          $ref: '#/components/schemas/CampaignStatus'
        startDate:
          type: [string, "null"]
          format: date-time
        type:
          $ref: '#/components/schemas/CampaignType'
        approvalMode:
          type: [string, "null"]
          enum: [MANUAL, AUTO, null]
        userEligibilityCriteria:
          type: object
          description: |
            Either `{"openToAll": true}` or a community restriction such as
            `{"guildId": "..."}`.
          additionalProperties: true

    CampaignStats:
      type: object
      properties:
        creators: { type: integer }
        reach: { type: integer }
        likes: { type: integer }
        quotes: { type: integer }
        post: { type: integer }

    CampaignBudget:
      type: object
      properties:
        totalPool:
          $ref: '#/components/schemas/DecimalString'
        remainingPool:
          $ref: '#/components/schemas/DecimalString'
        tokenType:
          $ref: '#/components/schemas/TokenType'
        tokenSymbol:
          type: string
        tokenAddress:
          type: [string, "null"]
          description: Null for POINTS tokens.
        chainId:
          type: [string, "null"]
        decimals:
          type: integer

    SubmissionRequirementRule:
      type: object
      properties:
        values:
          type: array
          items:
            type: string
        isEnabled:
          type: boolean
        requireAll:
          type: boolean

    SubmissionRequirements:
      type: object
      properties:
        urls:
          $ref: '#/components/schemas/SubmissionRequirementRule'
        hashtags:
          $ref: '#/components/schemas/SubmissionRequirementRule'
        mentions:
          $ref: '#/components/schemas/SubmissionRequirementRule'
        guidelines:
          type: [string, "null"]

    CampaignDetailSocialOwner:
      type: object
      required: [campaignType, detailVariant]
      properties:
        campaignType:
          $ref: '#/components/schemas/CampaignType'
        detailVariant:
          type: string
          const: social_owner
        campaign:
          $ref: '#/components/schemas/CampaignCore'
        project:
          $ref: '#/components/schemas/ProjectRef'
        stats:
          $ref: '#/components/schemas/CampaignStats'
        budget:
          $ref: '#/components/schemas/CampaignBudget'
        tasks:
          type: array
          items:
            $ref: '#/components/schemas/SocialTask'
        draftConfig:
          type: [object, "null"]
          additionalProperties: true
        eligibilityProject:
          type: [object, "null"]
          additionalProperties: true
        clippingOwner:
          type: "null"
          description: Always null on this variant.
        campaignCommission:
          type: [integer, "null"]

    SocialTask:
      type: object
      properties:
        id:
          type: string
          format: uuid
        platformId:
          type: string
          format: uuid
        type:
          type: string
          description: 'For example POST, FOLLOW, LIKE, QUOTE.'
        url:
          type: [string, "null"]
        submissionRequirements:
          $ref: '#/components/schemas/SubmissionRequirements'
        payoutConfig:
          type: object
          properties:
            logic:
              type: string
              enum: [FIXED, FORMULA]
            tokenId:
              type: [string, "null"]
              format: uuid
            claimType:
              type: string
              enum: [FCFS, OFFERS]
            fixedPayout:
              type: [number, "null"]
            auraMultiplier:
              type: [number, "null"]
        taskCompletedCount:
          type: string
        reach:
          type: string
        likes:
          type: string
        replies:
          type: string
        platform:
          type: object
          properties:
            id:
              type: string
              format: uuid
            name:
              type: string

    CampaignDetailClippingOwner:
      type: object
      required: [campaignType, detailVariant]
      properties:
        campaignType:
          $ref: '#/components/schemas/CampaignType'
        detailVariant:
          type: string
          const: clipping_owner
        campaign:
          $ref: '#/components/schemas/CampaignCore'
        project:
          $ref: '#/components/schemas/ProjectRef'
        stats:
          $ref: '#/components/schemas/CampaignStats'
        budget:
          $ref: '#/components/schemas/CampaignBudget'
        tasks:
          type: array
          description: Always empty on this variant. Read `clippingOwner.tasksTab.tasks`.
          items: {}
        draftConfig:
          type: [object, "null"]
          additionalProperties: true
        eligibilityProject:
          type: [object, "null"]
          additionalProperties: true
        clippingOwner:
          $ref: '#/components/schemas/ClippingOwnerPayload'
        campaignCommission:
          type: [integer, "null"]

    ClippingOwnerPayload:
      type: object
      properties:
        eligibilitySummary:
          type: object
          properties:
            mode:
              type: string
              description: 'For example open, or a community restricted mode.'
            guild:
              type: [object, "null"]
              additionalProperties: true
        demographicsRequired:
          type: boolean
        demographicsAudienceRule:
          type: [string, "null"]
        overview:
          type: object
          properties:
            creatorsCount: { type: integer }
            totalSubmissionsCount: { type: integer }
            submissionsCount: { type: integer }
            pendingSubmissionsCount: { type: integer }
            approvedSubmissionsCount: { type: integer }
            rejectedSubmissionsCount: { type: integer }
            paidSubmissionsCount: { type: integer }
            reach: { type: integer }
            currentReach: { type: integer }
            initialReach: { type: integer }
            likes: { type: integer }
            comments: { type: integer }
        budget:
          type: object
          properties:
            label: { type: string }
            totalPool: { $ref: '#/components/schemas/DecimalString' }
            remainingPool: { $ref: '#/components/schemas/DecimalString' }
            usedBudget: { $ref: '#/components/schemas/DecimalString' }
            tokenType: { $ref: '#/components/schemas/TokenType' }
            tokenSymbol: { type: string }
        tasksTab:
          type: object
          properties:
            requirements:
              type: object
              properties:
                hashtags:
                  type: array
                  items: { type: string }
                mentions:
                  type: array
                  items: { type: string }
                urls:
                  type: array
                  items: { type: string }
                guidelines:
                  type: [string, "null"]
            tasks:
              type: array
              items:
                $ref: '#/components/schemas/ClippingTask'
        settingsTab:
          type: object
          properties:
            userEligibilityCriteria:
              type: object
              additionalProperties: true
            platformPayouts:
              type: array
              items:
                $ref: '#/components/schemas/PlatformPayout'

    ClippingTask:
      type: object
      properties:
        taskId:
          type: string
          format: uuid
        platformId:
          type: string
          format: uuid
        platformName:
          type: string
        platformSlug:
          type: string
        type:
          type: string
          description: 'For example CLIP_X, CLIP_INSTAGRAM, CLIP_TIKTOK.'
        submissionRequirements:
          $ref: '#/components/schemas/SubmissionRequirements'
        submissionCounts:
          type: object
          properties:
            total: { type: integer }
            pending: { type: integer }
            approved: { type: integer }
            rejected: { type: integer }
            paid: { type: integer }
            nonRejected: { type: integer }

    PlatformPayout:
      type: object
      properties:
        taskId:
          type: string
          format: uuid
        platformId:
          type: string
          format: uuid
        platformName:
          type: string
        platformSlug:
          type: string
        claimType:
          type: string
          enum: [FCFS, OFFERS]
        payoutLogic:
          type: string
          enum: [FIXED, FORMULA]
          description: |
            FORMULA pays per thousand views via `cpm`, capped at
            `maxPayoutPerClip`. FIXED pays `fixedPayout` per accepted clip.
        minViews:
          type: [integer, "null"]
        maxPayoutPerClip:
          type: [number, "null"]
        fixedPayout:
          type: [number, "null"]
        cpm:
          type: [number, "null"]
          description: Payout per one thousand views.
        bonusRanges:
          type: array
          items:
            type: object
            additionalProperties: true
        tokenType:
          $ref: '#/components/schemas/TokenType'
        tokenSymbol:
          type: string

    ClippingCampaignDetail:
      type: object
      properties:
        id:
          type: string
          format: uuid
        title:
          type: string
        approvalMode:
          type: [string, "null"]
        status:
          $ref: '#/components/schemas/CampaignStatus'
        startDate:
          type: [string, "null"]
          format: date-time
        endDate:
          type: [string, "null"]
          format: date-time
        payRateDisplay:
          type: [string, "null"]
          description: Human readable pay rate, for example `$1-2/1K views`.
        payRateType:
          type: [string, "null"]
          enum: [PPV, FIXED, null]
        bannerImageUrl:
          type: [string, "null"]
        colorCode:
          type: [string, "null"]
        project:
          $ref: '#/components/schemas/ProjectRef'
        stats:
          type: object
          properties:
            clipsApprovedCount: { type: integer }
            totalViews: { type: integer }
            totalCurrentViews: { type: integer }
            totalInitialViews: { type: integer }
            creatorsCount: { type: integer }
        requirements:
          type: object
          properties:
            hashtags:
              type: array
              items: { type: string }
            mentions:
              type: array
              items: { type: string }
        contentGuidelinesMarkdown:
          type: [string, "null"]
        budget:
          type: object
          properties:
            totalPool: { $ref: '#/components/schemas/DecimalString' }
            remainingPool: { $ref: '#/components/schemas/DecimalString' }
            usedBudget: { $ref: '#/components/schemas/DecimalString' }
            accruedUnpaid:
              allOf:
                - $ref: '#/components/schemas/DecimalString'
              description: Earned by creators but not yet paid out.
            tokenType: { $ref: '#/components/schemas/TokenType' }
            tokenSymbol: { type: string }
        platformTasks:
          type: array
          items:
            type: object
            properties:
              taskId: { type: string, format: uuid }
              platformId: { type: string, format: uuid }
              platformSlug: { type: string }
              platformName: { type: string }
              maxPayoutPerClip: { type: [number, "null"] }
              minViews: { type: [integer, "null"] }
              tokenSymbol: { type: string }
              taskSubmissionId:
                type: [string, "null"]
                format: uuid
                description: The authenticated user's submission for this task, if any.
              submissionStatus:
                oneOf:
                  - $ref: '#/components/schemas/SubmissionStatus'
                  - type: "null"
              payoutLogic: { type: string, enum: [FIXED, FORMULA] }
              cpm: { type: [number, "null"] }
              fixedTokenAmount: { type: [number, "null"] }
              bonusRanges:
                type: array
                items:
                  type: object
                  additionalProperties: true
              demographicsRequired: { type: boolean }
              demographicsAudienceRule: { type: [string, "null"] }
        supportedPlatforms:
          type: array
          description: Use these `platformId` values to filter owner submissions.
          items:
            type: object
            properties:
              platformId: { type: string, format: uuid }
              platformSlug: { type: string }
              platformName: { type: string }
        mySubmissions:
          type: array
          description: The authenticated user's own submissions to this campaign.
          items:
            type: object
            additionalProperties: true
        payoutDisplayMode:
          type: [string, "null"]
          enum: [estimated, fixed, null]
        isEligible:
          type: boolean
        isEndingSoon:
          type: boolean
        poolDepleted:
          type: boolean
        canSubmit:
          type: boolean
        hasSubmitted:
          type: boolean
        brandApproved:
          type: boolean
        brandStats:
          type: object
          properties:
            campaignCount: { type: integer }
            creatorsPaid: { type: integer }

    CreatorSubmission:
      type: object
      properties:
        submissionId:
          type: string
          format: uuid
        userId:
          type: string
          format: uuid
        username:
          type: string
          description: The creator's handle on the submitting platform.
        userUsername:
          type: string
          description: The creator's Airaa username.
        name:
          type: [string, "null"]
        profileImageUrl:
          type: [string, "null"]
        followersCount:
          type: integer
        smartFollowersCount:
          type: integer
        viewCount:
          type: integer
        initialViewCount:
          type: integer
          description: Views at the moment the clip was submitted.
        currentViewCount:
          type: integer
        deltaViewCount:
          type: integer
          description: Views earned since submission. This is what payouts are based on.
        tokenAmount:
          $ref: '#/components/schemas/DecimalString'
        auraPointsAmount:
          $ref: '#/components/schemas/DecimalString'
        estimatedPayout:
          oneOf:
            - $ref: '#/components/schemas/DecimalString'
            - type: "null"
        tasks:
          type: array
          items:
            $ref: '#/components/schemas/SubmissionTask'

    SubmissionTask:
      type: object
      properties:
        taskId:
          type: string
          format: uuid
        submissionId:
          type: string
          format: uuid
        claimedAt:
          type: [string, "null"]
          format: date-time
        submittedAt:
          type: [string, "null"]
          format: date-time
        taskType:
          type: string
        taskUrl:
          type: [string, "null"]
        submissionStatus:
          oneOf:
            - $ref: '#/components/schemas/SubmissionStatus'
            - type: "null"
        submissionReason:
          type: [string, "null"]
          description: Why the submission was rejected, when it was.
        aiReview:
          type: [object, "null"]
          additionalProperties: true
        submissionContent:
          oneOf:
            - type: object
              properties:
                text: { type: [string, "null"] }
                viewCount: { type: integer }
                initialViews: { type: integer }
                currentViews: { type: integer }
                deltaViews: { type: integer }
                replyCount: { type: integer }
                favoriteCount: { type: integer }
                externalId: { type: string }
                url: { type: string }
            - type: "null"
          description: Null for tasks with no posted content, such as FOLLOW.

    ClippingOwnerRow:
      type: object
      properties:
        submissionId:
          type: string
          format: uuid
        taskId:
          type: string
          format: uuid
        platformId:
          type: string
          format: uuid
        platformName:
          type: string
        platformSlug:
          type: string
        creatorUserId:
          type: string
          format: uuid
        creatorUsername:
          type: string
        creatorPhotoUrl:
          type: [string, "null"]
        status:
          $ref: '#/components/schemas/SubmissionStatus'
        submittedAt:
          type: [string, "null"]
          format: date-time
        expiresAt:
          type: [string, "null"]
          format: date-time
        rejectionReason:
          type: [string, "null"]
        contentId:
          type: [string, "null"]
          format: uuid
        contentUrl:
          type: [string, "null"]
        contentTitle:
          type: [string, "null"]
        thumbnailUrl:
          type: [string, "null"]
        videoUrl:
          type: [string, "null"]
        followersCount:
          type: integer
        commentCount:
          type: integer
        estimatedPayout:
          $ref: '#/components/schemas/DecimalString'
        tokenReward:
          $ref: '#/components/schemas/DecimalString'
        auraPointsReward:
          $ref: '#/components/schemas/DecimalString'
        engagement:
          type: object
          properties:
            views: { type: integer }
            initialViews: { type: integer }
            currentViews: { type: integer }
            deltaViews: { type: integer }
            likes: { type: integer }
            comments: { type: integer }
        canLoadEngagementHistory:
          type: boolean
        cumulativePaidAmount:
          $ref: '#/components/schemas/DecimalString'
        basePaidAmount:
          $ref: '#/components/schemas/DecimalString'
        bonusPaidAmount:
          $ref: '#/components/schemas/DecimalString'
        totalPaidAmount:
          $ref: '#/components/schemas/DecimalString'
        lastPaidAt:
          type: [string, "null"]
          format: date-time
        maxPayoutPerClip:
          type: [number, "null"]
        accruedUnpaid:
          allOf:
            - $ref: '#/components/schemas/DecimalString'
          description: Earned on current views but not yet paid.
        accruedBaseAmount:
          $ref: '#/components/schemas/DecimalString'
        accruedBonusAmount:
          $ref: '#/components/schemas/DecimalString'
        submissionActions:
          type: array
          description: Newest first. The full state history of this submission.
          items:
            $ref: '#/components/schemas/SubmissionAction'
        demographicsVideoUrl:
          type: [string, "null"]
        demographicsReviewResult:
          type: [object, "null"]
          additionalProperties: true

    SubmissionAction:
      type: object
      properties:
        actionType:
          type: string
          description: 'For example PENDING, APPROVED, FAILED, PAID, DEMOGRAPHICS_DUE.'
        amount:
          type: [string, "null"]
        viewsSnapshot:
          type: [integer, "null"]
        deltaViews:
          type: [integer, "null"]
        reason:
          type: [string, "null"]
        createdAt:
          type: string
          format: date-time

    ProjectMember:
      type: object
      properties:
        userId:
          type: string
          format: uuid
        status:
          type: string
          enum: [ACTIVE, INACTIVE, PENDING, SUSPENDED]
        role:
          $ref: '#/components/schemas/MemberRole'
        username:
          type: string
        name:
          type: [string, "null"]
        photoUrl:
          type: [string, "null"]
        niche:
          type: array
          items:
            type: string
        locationCountry:
          type: [string, "null"]
        platforms:
          type: array
          items:
            type: object
            properties:
              slug:
                type: string
                enum: [x, instagram, youtube, tiktok]
              handle:
                type: string
              followersCount:
                type: integer
        totalFollowers:
          type: integer
        communityCampaignsParticipated:
          type: integer
        totalCommunityImpressions:
          type: integer
        tags:
          type: array
          description: Labels the community applied to this member.
          items:
            type: object
            properties:
              id:
                type: string
                format: uuid
              name:
                type: string
              color:
                type: string

    LeaderboardRow:
      type: object
      properties:
        rank:
          type: integer
        name:
          type: [string, "null"]
        username:
          type: string
        photoUrl:
          type: [string, "null"]
        socialConnections:
          type: array
          items:
            $ref: '#/components/schemas/SocialConnection'
        totalCampaigns:
          type: integer
        totalViews:
          type: integer
        totalUsdc:
          $ref: '#/components/schemas/DecimalString'
        totalCommunityToken:
          $ref: '#/components/schemas/DecimalString'

    SocialConnection:
      type: object
      properties:
        platformId:
          type: string
          format: uuid
        platformName:
          type: string
        externalUsername:
          type: string

    Token:
      type: object
      properties:
        id:
          type: string
          format: uuid
        symbol:
          type: string
        name:
          type: string
        logo:
          type: [string, "null"]
        address:
          type: [string, "null"]
          description: Contract address. Null for POINTS tokens.
        chainId:
          type: [string, "null"]
        decimals:
          type: integer
        status:
          type: string
          enum: [ACTIVE, INACTIVE]
        type:
          $ref: '#/components/schemas/TokenType'

    UserInfo:
      type: object
      properties:
        id:
          type: string
          format: uuid
        email:
          type: [string, "null"]
        badge:
          type: [string, "null"]
        status:
          type: [string, "null"]
        isActive:
          type: boolean
        verified:
          type: boolean
        isScout:
          type: boolean
        twitterProfileId:
          type: [string, "null"]
          format: uuid
        turnkeyExternalUserId:
          type: [string, "null"]
        telegramId:
          type: [string, "null"]
        telegramUsername:
          type: [string, "null"]
        privacyApproved:
          type: boolean
        isClaimed:
          type: boolean
        profile:
          oneOf:
            - $ref: '#/components/schemas/TwitterProfile'
            - type: "null"
        totalBalance:
          type: [string, "null"]
        totalVolume:
          type: [string, "null"]
        totalDappsInteracted:
          type: [integer, "null"]
        totalAuraPoints:
          type: integer
        primaryWalletAddress:
          type: [string, "null"]
        primaryWalletBalance:
          type: [string, "null"]
        createdAt:
          type: string
          format: date-time
        updatedAt:
          type: string
          format: date-time
        name:
          type: [string, "null"]
        photoUrl:
          type: [string, "null"]
        userNiche:
          type: array
          items:
            type: string
        username:
          type: string
        bio:
          type: [string, "null"]
        niche:
          type: array
          items:
            type: string
        spamMultiplier:
          type: [number, "null"]
        wallets:
          type: array
          items:
            type: object
            properties:
              updatedAt:
                type: string
                format: date-time
              address:
                type: string
              type:
                type: string
                enum: [EVM, SOLANA]
              projectSlug:
                type: [string, "null"]
              isPrimary:
                type: boolean
        isAiraaCreator:
          type: boolean
        isCampaignCreator:
          type: boolean
        onboardingCompleted:
          type: boolean
        accounts:
          type: array
          description: Connected social accounts.
          items:
            type: object
            properties:
              platformId:
                type: string
                format: uuid
              platformName:
                type: string
              externalId:
                type: string
              externalUsername:
                type: string
              connectedAt:
                type: string
                format: date-time
        location:
          type: [object, "null"]
          properties:
            country: { type: [string, "null"] }
            countryCode: { type: [string, "null"] }
            proxy: { type: boolean }
            hosting: { type: boolean }
            lastUpdatedAt:
              type: string
              format: date-time

    TwitterProfile:
      type: object
      properties:
        id:
          type: string
          format: uuid
        externalId:
          type: string
        name:
          type: [string, "null"]
        username:
          type: string
        url:
          type: [string, "null"]
        description:
          type: [string, "null"]
        profileImageUrl:
          type: [string, "null"]
        followersCount:
          type: integer
        smartFollowersCount:
          type: integer
        followingCount:
          type: integer
        profileCreatedAt:
          type: [string, "null"]
          format: date-time
        contentCount:
          type: integer
        accountBasedIn:
          type: [string, "null"]
