{
  "schemaVersion": "1.0",
  "item": {
    "slug": "platform-api-connector",
    "name": "Platform API Connector",
    "source": "tencent",
    "type": "skill",
    "category": "开发工具",
    "sourceUrl": "https://clawhub.ai/brandonwadepackard-cell/platform-api-connector",
    "canonicalUrl": "https://clawhub.ai/brandonwadepackard-cell/platform-api-connector",
    "targetPlatform": "OpenClaw"
  },
  "install": {
    "downloadMode": "redirect",
    "downloadUrl": "/downloads/platform-api-connector",
    "sourceDownloadUrl": "https://wry-manatee-359.convex.site/api/v1/download?slug=platform-api-connector",
    "sourcePlatform": "tencent",
    "targetPlatform": "OpenClaw",
    "installMethod": "Manual import",
    "extraction": "Extract archive",
    "prerequisites": [
      "OpenClaw"
    ],
    "packageFormat": "ZIP package",
    "includedAssets": [
      "SKILL.md",
      "references/oauth-flows.md"
    ],
    "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/platform-api-connector"
    },
    "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/platform-api-connector",
    "agentPageUrl": "https://openagent3.xyz/skills/platform-api-connector/agent",
    "manifestUrl": "https://openagent3.xyz/skills/platform-api-connector/agent.json",
    "briefUrl": "https://openagent3.xyz/skills/platform-api-connector/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": "Platform API Connector",
        "body": "Navigate developer portals and obtain API credentials for social/content platforms. Store credentials in Supabase (or any DB) for reuse."
      },
      {
        "title": "General Pattern",
        "body": "Create developer app on platform's developer portal\nConfigure OAuth redirect URIs and scopes\nComplete OAuth flow (or generate API keys)\nStore credentials in structured format\nTest with a simple API call"
      },
      {
        "title": "Facebook + Instagram",
        "body": "Facebook and Instagram share the same auth system. One Facebook Page Token unlocks both."
      },
      {
        "title": "Setup",
        "body": "Go to developers.facebook.com/apps → Create App → Business type\nAdd \"Facebook Login\" product\nIn Graph API Explorer (developers.facebook.com/tools/explorer/):\n\nSelect your app\nAdd permissions: pages_show_list, pages_read_engagement, pages_manage_posts, instagram_basic, instagram_content_publish\nGenerate User Access Token → authorize\nExchange for long-lived token: GET /oauth/access_token?grant_type=fb_exchange_token&client_id={app_id}&client_secret={secret}&fb_exchange_token={short_token}\n\n\nGet Page Access Token: GET /me/accounts → find page → copy access_token\nGet Instagram Business Account ID: GET /{page_id}?fields=instagram_business_account"
      },
      {
        "title": "Store",
        "body": "{\n  \"platform\": \"facebook\",\n  \"credentials\": {\n    \"app_id\": \"...\",\n    \"app_secret\": \"...\",\n    \"page_id\": \"...\",\n    \"page_access_token\": \"...\",\n    \"ig_user_id\": \"...\"\n  }\n}"
      },
      {
        "title": "Key gotcha",
        "body": "Page Access Tokens from Graph API Explorer are short-lived unless you exchange the User Token for a long-lived one FIRST, then request Page tokens from the long-lived User Token. Page tokens derived from long-lived user tokens are permanent (no expiry)."
      },
      {
        "title": "Setup",
        "body": "Go to console.cloud.google.com → APIs & Services → Credentials\nCreate OAuth 2.0 Client ID (Web application type)\nAdd redirect URI: http://localhost:8422/callback (or your callback URL)\nEnable YouTube Data API v3\nRun local OAuth flow:\n\nfrom google_auth_oauthlib.flow import InstalledAppFlow\n\nflow = InstalledAppFlow.from_client_secrets_file(\n    'credentials.json',\n    scopes=['https://www.googleapis.com/auth/youtube.upload',\n            'https://www.googleapis.com/auth/youtube.readonly']\n)\ncreds = flow.run_local_server(port=8422)\n# creds.token, creds.refresh_token, creds.expiry"
      },
      {
        "title": "Store",
        "body": "{\n  \"platform\": \"youtube\",\n  \"credentials\": {\n    \"client_id\": \"...\",\n    \"client_secret\": \"...\",\n    \"access_token\": \"...\",\n    \"refresh_token\": \"...\",\n    \"token_expiry\": \"...\"\n  }\n}"
      },
      {
        "title": "Key gotcha",
        "body": "If the user previously authorized with limited scopes, the refresh token may not cover youtube.upload. Must re-authorize with prompt='consent' to get a new refresh token with full scopes."
      },
      {
        "title": "Setup",
        "body": "Go to developer.x.com/en/portal/dashboard\nCreate Project + App (Free tier: 100 posts/month)\nUnder Keys and Tokens:\n\nAPI Key + Secret (consumer credentials)\nBearer Token (app-only auth for reading)\nAccess Token + Secret (user auth for posting) — generate with Read & Write permissions\n\n\nIf permissions were Read Only when tokens were generated, regenerate Access Token after changing to Read & Write"
      },
      {
        "title": "Store",
        "body": "{\n  \"platform\": \"twitter\",\n  \"credentials\": {\n    \"api_key\": \"...\",\n    \"api_secret\": \"...\",\n    \"bearer_token\": \"...\",\n    \"access_token\": \"...\",\n    \"access_token_secret\": \"...\"\n  }\n}"
      },
      {
        "title": "Key gotcha",
        "body": "Free tier caps at 100 posts/month (resets on billing date, not calendar month). No delete or analytics on free tier."
      },
      {
        "title": "Setup",
        "body": "Go to developers.tiktok.com → Create App\nAdd products: Login Kit + Content Posting API\nConfigure: app icon (1024x1024), category, ToS URL, Privacy Policy URL, redirect URI\nSubmit for review — TikTok requires demo video showing the app in action\nUntil approved, use Manual mode (generate content but post manually)"
      },
      {
        "title": "Key gotcha",
        "body": "TikTok Content Posting API requires full app review with demo video. This takes days to weeks. Plan for Manual mode as interim solution. Login Kit can work in sandbox mode for development."
      },
      {
        "title": "Credential Storage Pattern",
        "body": "Use a single table with JSONB for flexibility:\n\nCREATE TABLE platform_connections (\n  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),\n  platform TEXT NOT NULL,\n  account_name TEXT,\n  credentials JSONB NOT NULL,\n  scopes TEXT[],\n  status TEXT DEFAULT 'active',\n  created_at TIMESTAMPTZ DEFAULT now(),\n  updated_at TIMESTAMPTZ DEFAULT now()\n);\n\nJSONB accommodates different auth shapes per platform without schema changes."
      },
      {
        "title": "Token Refresh Pattern",
        "body": "async def get_valid_token(platform: str) -> dict:\n    conn = await get_connection(platform)\n    creds = conn['credentials']\n    \n    if platform == 'youtube' and is_expired(creds.get('token_expiry')):\n        new_token = refresh_google_token(creds['refresh_token'], creds['client_id'], creds['client_secret'])\n        creds['access_token'] = new_token\n        await update_connection(conn['id'], creds)\n    \n    # Facebook page tokens don't expire (if derived from long-lived user token)\n    # Twitter tokens don't expire\n    # TikTok tokens expire in 24h — refresh with refresh_token\n    \n    return creds"
      }
    ],
    "body": "Platform API Connector\n\nNavigate developer portals and obtain API credentials for social/content platforms. Store credentials in Supabase (or any DB) for reuse.\n\nGeneral Pattern\nCreate developer app on platform's developer portal\nConfigure OAuth redirect URIs and scopes\nComplete OAuth flow (or generate API keys)\nStore credentials in structured format\nTest with a simple API call\nFacebook + Instagram\n\nFacebook and Instagram share the same auth system. One Facebook Page Token unlocks both.\n\nSetup\nGo to developers.facebook.com/apps → Create App → Business type\nAdd \"Facebook Login\" product\nIn Graph API Explorer (developers.facebook.com/tools/explorer/):\nSelect your app\nAdd permissions: pages_show_list, pages_read_engagement, pages_manage_posts, instagram_basic, instagram_content_publish\nGenerate User Access Token → authorize\nExchange for long-lived token: GET /oauth/access_token?grant_type=fb_exchange_token&client_id={app_id}&client_secret={secret}&fb_exchange_token={short_token}\nGet Page Access Token: GET /me/accounts → find page → copy access_token\nGet Instagram Business Account ID: GET /{page_id}?fields=instagram_business_account\nStore\n{\n  \"platform\": \"facebook\",\n  \"credentials\": {\n    \"app_id\": \"...\",\n    \"app_secret\": \"...\",\n    \"page_id\": \"...\",\n    \"page_access_token\": \"...\",\n    \"ig_user_id\": \"...\"\n  }\n}\n\nKey gotcha\n\nPage Access Tokens from Graph API Explorer are short-lived unless you exchange the User Token for a long-lived one FIRST, then request Page tokens from the long-lived User Token. Page tokens derived from long-lived user tokens are permanent (no expiry).\n\nYouTube\nSetup\nGo to console.cloud.google.com → APIs & Services → Credentials\nCreate OAuth 2.0 Client ID (Web application type)\nAdd redirect URI: http://localhost:8422/callback (or your callback URL)\nEnable YouTube Data API v3\nRun local OAuth flow:\nfrom google_auth_oauthlib.flow import InstalledAppFlow\n\nflow = InstalledAppFlow.from_client_secrets_file(\n    'credentials.json',\n    scopes=['https://www.googleapis.com/auth/youtube.upload',\n            'https://www.googleapis.com/auth/youtube.readonly']\n)\ncreds = flow.run_local_server(port=8422)\n# creds.token, creds.refresh_token, creds.expiry\n\nStore\n{\n  \"platform\": \"youtube\",\n  \"credentials\": {\n    \"client_id\": \"...\",\n    \"client_secret\": \"...\",\n    \"access_token\": \"...\",\n    \"refresh_token\": \"...\",\n    \"token_expiry\": \"...\"\n  }\n}\n\nKey gotcha\n\nIf the user previously authorized with limited scopes, the refresh token may not cover youtube.upload. Must re-authorize with prompt='consent' to get a new refresh token with full scopes.\n\nTwitter/X\nSetup\nGo to developer.x.com/en/portal/dashboard\nCreate Project + App (Free tier: 100 posts/month)\nUnder Keys and Tokens:\nAPI Key + Secret (consumer credentials)\nBearer Token (app-only auth for reading)\nAccess Token + Secret (user auth for posting) — generate with Read & Write permissions\nIf permissions were Read Only when tokens were generated, regenerate Access Token after changing to Read & Write\nStore\n{\n  \"platform\": \"twitter\",\n  \"credentials\": {\n    \"api_key\": \"...\",\n    \"api_secret\": \"...\",\n    \"bearer_token\": \"...\",\n    \"access_token\": \"...\",\n    \"access_token_secret\": \"...\"\n  }\n}\n\nKey gotcha\n\nFree tier caps at 100 posts/month (resets on billing date, not calendar month). No delete or analytics on free tier.\n\nTikTok\nSetup\nGo to developers.tiktok.com → Create App\nAdd products: Login Kit + Content Posting API\nConfigure: app icon (1024x1024), category, ToS URL, Privacy Policy URL, redirect URI\nSubmit for review — TikTok requires demo video showing the app in action\nUntil approved, use Manual mode (generate content but post manually)\nKey gotcha\n\nTikTok Content Posting API requires full app review with demo video. This takes days to weeks. Plan for Manual mode as interim solution. Login Kit can work in sandbox mode for development.\n\nCredential Storage Pattern\n\nUse a single table with JSONB for flexibility:\n\nCREATE TABLE platform_connections (\n  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),\n  platform TEXT NOT NULL,\n  account_name TEXT,\n  credentials JSONB NOT NULL,\n  scopes TEXT[],\n  status TEXT DEFAULT 'active',\n  created_at TIMESTAMPTZ DEFAULT now(),\n  updated_at TIMESTAMPTZ DEFAULT now()\n);\n\n\nJSONB accommodates different auth shapes per platform without schema changes.\n\nToken Refresh Pattern\nasync def get_valid_token(platform: str) -> dict:\n    conn = await get_connection(platform)\n    creds = conn['credentials']\n    \n    if platform == 'youtube' and is_expired(creds.get('token_expiry')):\n        new_token = refresh_google_token(creds['refresh_token'], creds['client_id'], creds['client_secret'])\n        creds['access_token'] = new_token\n        await update_connection(conn['id'], creds)\n    \n    # Facebook page tokens don't expire (if derived from long-lived user token)\n    # Twitter tokens don't expire\n    # TikTok tokens expire in 24h — refresh with refresh_token\n    \n    return creds"
  },
  "trust": {
    "sourceLabel": "tencent",
    "provenanceUrl": "https://clawhub.ai/brandonwadepackard-cell/platform-api-connector",
    "publisherUrl": "https://clawhub.ai/brandonwadepackard-cell/platform-api-connector",
    "owner": "brandonwadepackard-cell",
    "version": "1.0.0",
    "license": null,
    "verificationStatus": "Indexed source record"
  },
  "links": {
    "detailUrl": "https://openagent3.xyz/skills/platform-api-connector",
    "downloadUrl": "https://openagent3.xyz/downloads/platform-api-connector",
    "agentUrl": "https://openagent3.xyz/skills/platform-api-connector/agent",
    "manifestUrl": "https://openagent3.xyz/skills/platform-api-connector/agent.json",
    "briefUrl": "https://openagent3.xyz/skills/platform-api-connector/agent.md"
  }
}