{
  "schemaVersion": "1.0",
  "item": {
    "slug": "fanvue",
    "name": "Fanvue",
    "source": "tencent",
    "type": "skill",
    "category": "开发工具",
    "sourceUrl": "https://clawhub.ai/igorls/fanvue",
    "canonicalUrl": "https://clawhub.ai/igorls/fanvue",
    "targetPlatform": "OpenClaw"
  },
  "install": {
    "downloadMode": "redirect",
    "downloadUrl": "/downloads/fanvue",
    "sourceDownloadUrl": "https://wry-manatee-359.convex.site/api/v1/download?slug=fanvue",
    "sourcePlatform": "tencent",
    "targetPlatform": "OpenClaw",
    "installMethod": "Manual import",
    "extraction": "Extract archive",
    "prerequisites": [
      "OpenClaw"
    ],
    "packageFormat": "ZIP package",
    "includedAssets": [
      "api-reference.md",
      "SKILL.md",
      "examples/chat-operations.ts",
      "examples/auth.ts",
      "examples/post-operations.ts",
      "examples/insights.ts"
    ],
    "primaryDoc": "SKILL.md",
    "quickSetup": [
      "Download the package from Yavira.",
      "Extract the archive and review SKILL.md first.",
      "Import or place the package into your OpenClaw setup."
    ],
    "agentAssist": {
      "summary": "Hand the extracted package to your coding agent with a concrete install brief instead of figuring it out manually.",
      "steps": [
        "Download the package from Yavira.",
        "Extract it into a folder your agent can access.",
        "Paste one of the prompts below and point your agent at the extracted folder."
      ],
      "prompts": [
        {
          "label": "New install",
          "body": "I downloaded a skill package from Yavira. Read SKILL.md from the extracted folder and install it by following the included instructions. Tell me what you changed and call out any manual steps you could not complete."
        },
        {
          "label": "Upgrade existing",
          "body": "I downloaded an updated skill package from Yavira. Read SKILL.md from the extracted folder, compare it with my current installation, and upgrade it while preserving any custom configuration unless the package docs explicitly say otherwise. Summarize what changed and any follow-up checks I should run."
        }
      ]
    },
    "sourceHealth": {
      "source": "tencent",
      "status": "healthy",
      "reason": "direct_download_ok",
      "recommendedAction": "download",
      "checkedAt": "2026-04-30T16:55:25.780Z",
      "expiresAt": "2026-05-07T16:55:25.780Z",
      "httpStatus": 200,
      "finalUrl": "https://wry-manatee-359.convex.site/api/v1/download?slug=network",
      "contentType": "application/zip",
      "probeMethod": "head",
      "details": {
        "probeUrl": "https://wry-manatee-359.convex.site/api/v1/download?slug=network",
        "contentDisposition": "attachment; filename=\"network-1.0.0.zip\"",
        "redirectLocation": null,
        "bodySnippet": null
      },
      "scope": "source",
      "summary": "Source download looks usable.",
      "detail": "Yavira can redirect you to the upstream package for this source.",
      "primaryActionLabel": "Download for OpenClaw",
      "primaryActionHref": "/downloads/fanvue"
    },
    "validation": {
      "installChecklist": [
        "Use the Yavira download entry.",
        "Review SKILL.md after the package is downloaded.",
        "Confirm the extracted package contains the expected setup assets."
      ],
      "postInstallChecks": [
        "Confirm the extracted package includes the expected docs or setup files.",
        "Validate the skill or prompts are available in your target agent workspace.",
        "Capture any manual follow-up steps the agent could not complete."
      ]
    },
    "downloadPageUrl": "https://openagent3.xyz/downloads/fanvue",
    "agentPageUrl": "https://openagent3.xyz/skills/fanvue/agent",
    "manifestUrl": "https://openagent3.xyz/skills/fanvue/agent.json",
    "briefUrl": "https://openagent3.xyz/skills/fanvue/agent.md"
  },
  "agentAssist": {
    "summary": "Hand the extracted package to your coding agent with a concrete install brief instead of figuring it out manually.",
    "steps": [
      "Download the package from Yavira.",
      "Extract it into a folder your agent can access.",
      "Paste one of the prompts below and point your agent at the extracted folder."
    ],
    "prompts": [
      {
        "label": "New install",
        "body": "I downloaded a skill package from Yavira. Read SKILL.md from the extracted folder and install it by following the included instructions. Tell me what you changed and call out any manual steps you could not complete."
      },
      {
        "label": "Upgrade existing",
        "body": "I downloaded an updated skill package from Yavira. Read SKILL.md from the extracted folder, compare it with my current installation, and upgrade it while preserving any custom configuration unless the package docs explicitly say otherwise. Summarize what changed and any follow-up checks I should run."
      }
    ]
  },
  "documentation": {
    "source": "clawhub",
    "primaryDoc": "SKILL.md",
    "sections": [
      {
        "title": "Fanvue API Skill",
        "body": "Integrate with the Fanvue creator platform to manage chats, posts, subscribers, earnings insights, and media content."
      },
      {
        "title": "1. Create an OAuth Application",
        "body": "Go to the Fanvue Developer Portal\nCreate a new OAuth application\nNote your Client ID and Client Secret\nConfigure your Redirect URI (e.g., https://your-app.com/callback)"
      },
      {
        "title": "2. Environment Variables",
        "body": "Set these environment variables:\n\nFANVUE_CLIENT_ID=your_client_id\nFANVUE_CLIENT_SECRET=your_client_secret\nFANVUE_REDIRECT_URI=https://your-app.com/callback"
      },
      {
        "title": "Authentication",
        "body": "Fanvue uses OAuth 2.0 with PKCE (Proof Key for Code Exchange). All API requests require:\n\nAuthorization Header: Bearer <access_token>\nAPI Version Header: X-Fanvue-API-Version: 2025-06-26"
      },
      {
        "title": "OAuth Scopes",
        "body": "Request these scopes based on your needs:\n\nScopeAccessopenidOpenID Connect authenticationoffline_accessRefresh token supportofflineOffline accessread:selfRead authenticated user profileread:chatRead chat conversationswrite:chatSend messages, update chatsread:postRead postswrite:postCreate postsread:creatorRead subscriber/follower dataread:mediaRead media vaultwrite:tracking_linksManage campaign linksread:insightsRead earnings/analytics (creator accounts)read:subscribersRead subscriber lists (creator accounts)\n\nNote: Some endpoints (subscribers, insights, earnings) require a creator account and may need additional scopes not listed in the public documentation."
      },
      {
        "title": "Quick Auth Flow",
        "body": "import { randomBytes, createHash } from 'crypto';\n\n// 1. Generate PKCE parameters\nconst codeVerifier = randomBytes(32).toString('base64url');\nconst codeChallenge = createHash('sha256')\n  .update(codeVerifier)\n  .digest('base64url');\n\n// 2. Build authorization URL\nconst authUrl = new URL('https://auth.fanvue.com/oauth2/auth');\nauthUrl.searchParams.set('client_id', process.env.FANVUE_CLIENT_ID);\nauthUrl.searchParams.set('redirect_uri', process.env.FANVUE_REDIRECT_URI);\nauthUrl.searchParams.set('response_type', 'code');\nauthUrl.searchParams.set('scope', 'openid offline_access read:self read:chat write:chat read:post');\nauthUrl.searchParams.set('state', randomBytes(32).toString('hex'));\nauthUrl.searchParams.set('code_challenge', codeChallenge);\nauthUrl.searchParams.set('code_challenge_method', 'S256');\n\n// Redirect user to: authUrl.toString()\n\n// 3. Exchange authorization code for tokens\nconst tokenResponse = await fetch('https://auth.fanvue.com/oauth2/token', {\n  method: 'POST',\n  headers: { 'Content-Type': 'application/x-www-form-urlencoded' },\n  body: new URLSearchParams({\n    grant_type: 'authorization_code',\n    client_id: process.env.FANVUE_CLIENT_ID,\n    client_secret: process.env.FANVUE_CLIENT_SECRET,\n    code: authorizationCode,\n    redirect_uri: process.env.FANVUE_REDIRECT_URI,\n    code_verifier: codeVerifier,\n  }),\n});\n\nconst tokens = await tokenResponse.json();\n// tokens.access_token, tokens.refresh_token"
      },
      {
        "title": "API Base URL",
        "body": "All API requests go to: https://api.fanvue.com"
      },
      {
        "title": "Standard Request Headers",
        "body": "const headers = {\n  'Authorization': `Bearer ${accessToken}`,\n  'X-Fanvue-API-Version': '2025-06-26',\n  'Content-Type': 'application/json',\n};"
      },
      {
        "title": "Agent Automation",
        "body": "These workflows are designed for AI agents automating Fanvue creator accounts."
      },
      {
        "title": "Accessing Images (with Signed URLs)",
        "body": "The basic /media endpoint only returns metadata. To get actual viewable URLs, use the variants query parameter:\n\n// Step 1: List all media\nconst list = await fetch('https://api.fanvue.com/media', { headers });\nconst { data } = await list.json();\n\n// Step 2: Get signed URLs for a specific media item\nconst media = await fetch(\n  `https://api.fanvue.com/media/${uuid}?variants=main,thumbnail,blurred`, \n  { headers }\n);\nconst { variants } = await media.json();\n\n// variants = [\n//   { variantType: 'main', url: 'https://media.fanvue.com/private/...' },\n//   { variantType: 'thumbnail', url: '...' },\n//   { variantType: 'blurred', url: '...' }\n// ]\n\nVariant Types:\n\nmain - Full resolution original\nthumbnail - Optimized preview (smaller)\nblurred - Censored version for teasers"
      },
      {
        "title": "Creating a Post with Media",
        "body": "// Step 1: Have existing media UUIDs from vault\nconst mediaIds = ['media-uuid-1', 'media-uuid-2'];\n\n// Step 2: Create post\nconst response = await fetch('https://api.fanvue.com/posts', {\n  method: 'POST',\n  headers,\n  body: JSON.stringify({\n    text: 'Check out my new content! 🔥',\n    mediaIds,\n    audience: 'subscribers',  // or 'followers-and-subscribers'\n    // Optional:\n    price: null,              // Set for pay-per-view\n    publishAt: null,          // Set for scheduled posts\n  }),\n});\n\nAudience Options:\n\nValueWho Can SeesubscribersPaid subscribers onlyfollowers-and-subscribersBoth free followers and subscribers"
      },
      {
        "title": "Sending Messages with Media",
        "body": "// Get subscriber list for decision making\nconst subs = await fetch('https://api.fanvue.com/creators/list-subscribers', { headers });\nconst { data: subscribers } = await subs.json();\n\n// Get top spenders for VIP targeting\nconst vips = await fetch('https://api.fanvue.com/insights/get-top-spenders', { headers });\nconst { data: topSpenders } = await vips.json();\n\n// Send personalized message with media\nawait fetch('https://api.fanvue.com/chat-messages', {\n  method: 'POST',\n  headers,\n  body: JSON.stringify({\n    recipientUuid: subscribers[0].userUuid,\n    content: 'Thanks for being a subscriber! Here\\'s something special for you 💕',\n    mediaIds: ['vault-media-uuid'],  // Attach media from vault\n  }),\n});\n\n// Or send to multiple subscribers at once\nawait fetch('https://api.fanvue.com/chat-messages/mass', {\n  method: 'POST',\n  headers,\n  body: JSON.stringify({\n    recipientUuids: subscribers.map(s => s.userUuid),\n    content: 'New exclusive content just dropped! 🎉',\n    mediaIds: ['vault-media-uuid'],\n  }),\n});"
      },
      {
        "title": "Agent Decision Context",
        "body": "For effective automation, gather this context:\n\ninterface AutomationContext {\n  // Current media in vault\n  media: {\n    uuid: string;\n    name: string;\n    type: 'image' | 'video';\n    description: string;  // AI-generated caption\n    signedUrl: string;    // From variants query\n  }[];\n  \n  // Audience data\n  subscribers: {\n    uuid: string;\n    name: string;\n    subscribedAt: string;\n    tier: string;\n  }[];\n  \n  // Engagement signals\n  topSpenders: {\n    uuid: string;\n    totalSpent: number;\n  }[];\n  \n  // Recent earnings for trend analysis\n  earnings: {\n    period: string;\n    total: number;\n    breakdown: { type: string; amount: number }[];\n  };\n}"
      },
      {
        "title": "Get Current User",
        "body": "const response = await fetch('https://api.fanvue.com/users/me', { headers });\nconst user = await response.json();"
      },
      {
        "title": "List Chats",
        "body": "const response = await fetch('https://api.fanvue.com/chats', { headers });\nconst { data, pagination } = await response.json();"
      },
      {
        "title": "Send a Message",
        "body": "const response = await fetch('https://api.fanvue.com/chat-messages', {\n  method: 'POST',\n  headers,\n  body: JSON.stringify({\n    recipientUuid: 'user-uuid-here',\n    content: 'Hello! Thanks for subscribing!',\n  }),\n});"
      },
      {
        "title": "Create a Post",
        "body": "const response = await fetch('https://api.fanvue.com/posts', {\n  method: 'POST',\n  headers,\n  body: JSON.stringify({\n    content: 'New content available!',\n    // Add media IDs, pricing, etc.\n  }),\n});"
      },
      {
        "title": "Get Earnings",
        "body": "const response = await fetch('https://api.fanvue.com/insights/get-earnings', { headers });\nconst earnings = await response.json();"
      },
      {
        "title": "List Subscribers",
        "body": "const response = await fetch('https://api.fanvue.com/creators/list-subscribers', { headers });\nconst { data } = await response.json();"
      },
      {
        "title": "API Reference",
        "body": "See api-reference.md for the complete endpoint documentation."
      },
      {
        "title": "Token Refresh",
        "body": "Access tokens expire. Use the refresh token to get new ones:\n\nconst response = await fetch('https://auth.fanvue.com/oauth2/token', {\n  method: 'POST',\n  headers: { 'Content-Type': 'application/x-www-form-urlencoded' },\n  body: new URLSearchParams({\n    grant_type: 'refresh_token',\n    client_id: process.env.FANVUE_CLIENT_ID,\n    client_secret: process.env.FANVUE_CLIENT_SECRET,\n    refresh_token: currentRefreshToken,\n  }),\n});\n\nconst newTokens = await response.json();"
      },
      {
        "title": "Error Handling",
        "body": "Common HTTP status codes:\n\nStatusMeaning200Success400Bad request - check your parameters401Unauthorized - token expired or invalid403Forbidden - missing required scope404Resource not found429Rate limited - slow down requests"
      },
      {
        "title": "Resources",
        "body": "Fanvue API Documentation\nOAuth 2.0 Guide\nDeveloper Portal\nFanvue App Starter Kit"
      }
    ],
    "body": "Fanvue API Skill\n\nIntegrate with the Fanvue creator platform to manage chats, posts, subscribers, earnings insights, and media content.\n\nPrerequisites\n1. Create an OAuth Application\nGo to the Fanvue Developer Portal\nCreate a new OAuth application\nNote your Client ID and Client Secret\nConfigure your Redirect URI (e.g., https://your-app.com/callback)\n2. Environment Variables\n\nSet these environment variables:\n\nFANVUE_CLIENT_ID=your_client_id\nFANVUE_CLIENT_SECRET=your_client_secret\nFANVUE_REDIRECT_URI=https://your-app.com/callback\n\nAuthentication\n\nFanvue uses OAuth 2.0 with PKCE (Proof Key for Code Exchange). All API requests require:\n\nAuthorization Header: Bearer <access_token>\nAPI Version Header: X-Fanvue-API-Version: 2025-06-26\nOAuth Scopes\n\nRequest these scopes based on your needs:\n\nScope\tAccess\nopenid\tOpenID Connect authentication\noffline_access\tRefresh token support\noffline\tOffline access\nread:self\tRead authenticated user profile\nread:chat\tRead chat conversations\nwrite:chat\tSend messages, update chats\nread:post\tRead posts\nwrite:post\tCreate posts\nread:creator\tRead subscriber/follower data\nread:media\tRead media vault\nwrite:tracking_links\tManage campaign links\nread:insights\tRead earnings/analytics (creator accounts)\nread:subscribers\tRead subscriber lists (creator accounts)\n\nNote: Some endpoints (subscribers, insights, earnings) require a creator account and may need additional scopes not listed in the public documentation.\n\nQuick Auth Flow\nimport { randomBytes, createHash } from 'crypto';\n\n// 1. Generate PKCE parameters\nconst codeVerifier = randomBytes(32).toString('base64url');\nconst codeChallenge = createHash('sha256')\n  .update(codeVerifier)\n  .digest('base64url');\n\n// 2. Build authorization URL\nconst authUrl = new URL('https://auth.fanvue.com/oauth2/auth');\nauthUrl.searchParams.set('client_id', process.env.FANVUE_CLIENT_ID);\nauthUrl.searchParams.set('redirect_uri', process.env.FANVUE_REDIRECT_URI);\nauthUrl.searchParams.set('response_type', 'code');\nauthUrl.searchParams.set('scope', 'openid offline_access read:self read:chat write:chat read:post');\nauthUrl.searchParams.set('state', randomBytes(32).toString('hex'));\nauthUrl.searchParams.set('code_challenge', codeChallenge);\nauthUrl.searchParams.set('code_challenge_method', 'S256');\n\n// Redirect user to: authUrl.toString()\n\n// 3. Exchange authorization code for tokens\nconst tokenResponse = await fetch('https://auth.fanvue.com/oauth2/token', {\n  method: 'POST',\n  headers: { 'Content-Type': 'application/x-www-form-urlencoded' },\n  body: new URLSearchParams({\n    grant_type: 'authorization_code',\n    client_id: process.env.FANVUE_CLIENT_ID,\n    client_secret: process.env.FANVUE_CLIENT_SECRET,\n    code: authorizationCode,\n    redirect_uri: process.env.FANVUE_REDIRECT_URI,\n    code_verifier: codeVerifier,\n  }),\n});\n\nconst tokens = await tokenResponse.json();\n// tokens.access_token, tokens.refresh_token\n\nAPI Base URL\n\nAll API requests go to: https://api.fanvue.com\n\nStandard Request Headers\nconst headers = {\n  'Authorization': `Bearer ${accessToken}`,\n  'X-Fanvue-API-Version': '2025-06-26',\n  'Content-Type': 'application/json',\n};\n\nAgent Automation\n\nThese workflows are designed for AI agents automating Fanvue creator accounts.\n\nAccessing Images (with Signed URLs)\n\nThe basic /media endpoint only returns metadata. To get actual viewable URLs, use the variants query parameter:\n\n// Step 1: List all media\nconst list = await fetch('https://api.fanvue.com/media', { headers });\nconst { data } = await list.json();\n\n// Step 2: Get signed URLs for a specific media item\nconst media = await fetch(\n  `https://api.fanvue.com/media/${uuid}?variants=main,thumbnail,blurred`, \n  { headers }\n);\nconst { variants } = await media.json();\n\n// variants = [\n//   { variantType: 'main', url: 'https://media.fanvue.com/private/...' },\n//   { variantType: 'thumbnail', url: '...' },\n//   { variantType: 'blurred', url: '...' }\n// ]\n\n\nVariant Types:\n\nmain - Full resolution original\nthumbnail - Optimized preview (smaller)\nblurred - Censored version for teasers\nCreating a Post with Media\n// Step 1: Have existing media UUIDs from vault\nconst mediaIds = ['media-uuid-1', 'media-uuid-2'];\n\n// Step 2: Create post\nconst response = await fetch('https://api.fanvue.com/posts', {\n  method: 'POST',\n  headers,\n  body: JSON.stringify({\n    text: 'Check out my new content! 🔥',\n    mediaIds,\n    audience: 'subscribers',  // or 'followers-and-subscribers'\n    // Optional:\n    price: null,              // Set for pay-per-view\n    publishAt: null,          // Set for scheduled posts\n  }),\n});\n\n\nAudience Options:\n\nValue\tWho Can See\nsubscribers\tPaid subscribers only\nfollowers-and-subscribers\tBoth free followers and subscribers\nSending Messages with Media\n// Get subscriber list for decision making\nconst subs = await fetch('https://api.fanvue.com/creators/list-subscribers', { headers });\nconst { data: subscribers } = await subs.json();\n\n// Get top spenders for VIP targeting\nconst vips = await fetch('https://api.fanvue.com/insights/get-top-spenders', { headers });\nconst { data: topSpenders } = await vips.json();\n\n// Send personalized message with media\nawait fetch('https://api.fanvue.com/chat-messages', {\n  method: 'POST',\n  headers,\n  body: JSON.stringify({\n    recipientUuid: subscribers[0].userUuid,\n    content: 'Thanks for being a subscriber! Here\\'s something special for you 💕',\n    mediaIds: ['vault-media-uuid'],  // Attach media from vault\n  }),\n});\n\n// Or send to multiple subscribers at once\nawait fetch('https://api.fanvue.com/chat-messages/mass', {\n  method: 'POST',\n  headers,\n  body: JSON.stringify({\n    recipientUuids: subscribers.map(s => s.userUuid),\n    content: 'New exclusive content just dropped! 🎉',\n    mediaIds: ['vault-media-uuid'],\n  }),\n});\n\nAgent Decision Context\n\nFor effective automation, gather this context:\n\ninterface AutomationContext {\n  // Current media in vault\n  media: {\n    uuid: string;\n    name: string;\n    type: 'image' | 'video';\n    description: string;  // AI-generated caption\n    signedUrl: string;    // From variants query\n  }[];\n  \n  // Audience data\n  subscribers: {\n    uuid: string;\n    name: string;\n    subscribedAt: string;\n    tier: string;\n  }[];\n  \n  // Engagement signals\n  topSpenders: {\n    uuid: string;\n    totalSpent: number;\n  }[];\n  \n  // Recent earnings for trend analysis\n  earnings: {\n    period: string;\n    total: number;\n    breakdown: { type: string; amount: number }[];\n  };\n}\n\nCore Operations\nGet Current User\nconst response = await fetch('https://api.fanvue.com/users/me', { headers });\nconst user = await response.json();\n\nList Chats\nconst response = await fetch('https://api.fanvue.com/chats', { headers });\nconst { data, pagination } = await response.json();\n\nSend a Message\nconst response = await fetch('https://api.fanvue.com/chat-messages', {\n  method: 'POST',\n  headers,\n  body: JSON.stringify({\n    recipientUuid: 'user-uuid-here',\n    content: 'Hello! Thanks for subscribing!',\n  }),\n});\n\nCreate a Post\nconst response = await fetch('https://api.fanvue.com/posts', {\n  method: 'POST',\n  headers,\n  body: JSON.stringify({\n    content: 'New content available!',\n    // Add media IDs, pricing, etc.\n  }),\n});\n\nGet Earnings\nconst response = await fetch('https://api.fanvue.com/insights/get-earnings', { headers });\nconst earnings = await response.json();\n\nList Subscribers\nconst response = await fetch('https://api.fanvue.com/creators/list-subscribers', { headers });\nconst { data } = await response.json();\n\nAPI Reference\n\nSee api-reference.md for the complete endpoint documentation.\n\nToken Refresh\n\nAccess tokens expire. Use the refresh token to get new ones:\n\nconst response = await fetch('https://auth.fanvue.com/oauth2/token', {\n  method: 'POST',\n  headers: { 'Content-Type': 'application/x-www-form-urlencoded' },\n  body: new URLSearchParams({\n    grant_type: 'refresh_token',\n    client_id: process.env.FANVUE_CLIENT_ID,\n    client_secret: process.env.FANVUE_CLIENT_SECRET,\n    refresh_token: currentRefreshToken,\n  }),\n});\n\nconst newTokens = await response.json();\n\nError Handling\n\nCommon HTTP status codes:\n\nStatus\tMeaning\n200\tSuccess\n400\tBad request - check your parameters\n401\tUnauthorized - token expired or invalid\n403\tForbidden - missing required scope\n404\tResource not found\n429\tRate limited - slow down requests\nResources\nFanvue API Documentation\nOAuth 2.0 Guide\nDeveloper Portal\nFanvue App Starter Kit"
  },
  "trust": {
    "sourceLabel": "tencent",
    "provenanceUrl": "https://clawhub.ai/igorls/fanvue",
    "publisherUrl": "https://clawhub.ai/igorls/fanvue",
    "owner": "igorls",
    "version": "1.0.0",
    "license": null,
    "verificationStatus": "Indexed source record"
  },
  "links": {
    "detailUrl": "https://openagent3.xyz/skills/fanvue",
    "downloadUrl": "https://openagent3.xyz/downloads/fanvue",
    "agentUrl": "https://openagent3.xyz/skills/fanvue/agent",
    "manifestUrl": "https://openagent3.xyz/skills/fanvue/agent.json",
    "briefUrl": "https://openagent3.xyz/skills/fanvue/agent.md"
  }
}