Grok Bot API
Your own Grok Bot checks your social media accounts and sends the numbers to your Soulfy workspace, where they appear on your iBrand Board. This page is written for you and for your bot.
1. Connect with a one-time code
In your dashboard, open your workspace's Grok Bot Connection page and click Create connect code. Paste the message it gives you into your Grok chat. The code (sfc_…) works once and expires after 15 minutes, so it is safe even if it stays in chat history. Grok exchanges it for its own credential:
POST https://soulfy.com/api/agent/v1/connect
Content-Type: application/json
{"code": "sfc_…"}Reply (HTTP 201). The token is shown only this once:
{
"success": true,
"token": "sfa_…",
"token_type": "Bearer",
"workspace": {
"name": "Your brand",
"site_domain": "yourbrand.com"
},
"scopes": [
"measurements.write"
],
"expires_at": "2027-09-30T00:00:00.000Z",
"endpoints": {
"me": "https://soulfy.com/api/agent/v1/me",
"measurements": "https://soulfy.com/api/agent/v1/measurements",
"dry_run": "https://soulfy.com/api/agent/v1/measurements?dry_run=true"
},
"instructions": [
"…"
]
}The bot must store token as a secret named SOULFY_AGENT_TOKEN and never show it in chat. Lost it? Click Rotate on the connection page for a fresh code.
2. Check the connection
GET https://soulfy.com/api/agent/v1/me
Authorization: Bearer $SOULFY_AGENT_TOKEN
Returns the workspace, granted permissions and when the credential expires. Nothing is saved.
3. Send a snapshot
POST https://soulfy.com/api/agent/v1/measurements
Authorization: Bearer $SOULFY_AGENT_TOKEN
Content-Type: application/json
Idempotency-Key: optional
| Field | Required | Notes |
|---|
platform | yes | One of instagram facebook linkedin tiktok youtube x |
captured_at | yes | ISO 8601 with a timezone, e.g. 2026-09-29T21:10:00+08:00. Up to a year old. |
metrics | yes | Object of lowercase_snake_case names to numbers (up to 50). Use the names below. |
collection_method | no | One of browser_agent platform_export manual_entry other (default browser_agent) |
source, evidence | no | Flat objects of strings, e.g. profile_url, screenshot_url |
workspace | no | Your site domain. Must match the credential. |
Example:
curl -X POST "https://soulfy.com/api/agent/v1/measurements" \
-H "Authorization: Bearer $SOULFY_AGENT_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"platform": "facebook",
"captured_at": "2026-09-29T21:10:00+08:00",
"metrics": {
"estimated_earnings": 125.4,
"content_monetization_earnings": 98.1,
"followers": 5517,
"reach": 4001,
"reactions": 46,
"comments": 15,
"shares": 15
},
"source": {
"currency": "USD",
"earnings_period": "last_28_days"
}
}'Success (HTTP 201):
{
"success": true,
"measurement_id": "5b7f0c1e-…",
"platform": "instagram",
"captured_at": "2026-09-29T13:10:00.000Z",
"received_at": "2026-09-30T00:03:59.858Z",
"idempotent_replay": false,
"warnings": [
{
"code": "unknown_metric",
"metric": "follower_count",
"suggestion": "followers",
"message": "\"follower_count\" isn't a recommended metric name. It was saved under Other reported metrics. Did you mean \"followers\"? …"
}
]
}Test without saving: send the same request to https://soulfy.com/api/agent/v1/measurements?dry_run=true. You get HTTP 200 with dry_run: true, exactly what would be stored, and any warnings.
Monetization earnings (the number owners watch most)
Send every earnings figure a platform shows, in the same snapshot as the other metrics. The iBrand Board shows estimated_earnings as each platform's headline number, in large type at the top. With any earnings, add "source": {"currency": "<ISO code as shown, e.g. USD>", "earnings_period": "<the period the platform shows, e.g. last_28_days or this_month>"}. Amounts are shown exactly as reported: never convert currencies, estimate, or send a figure the platform doesn't show.
| Platform | Where | Platform figure → metric name |
|---|
| Facebook | Professional dashboard or Meta Business Suite, Monetization | - Approximate earnings
estimated_earnings - Content Monetization
content_monetization_earnings - In-stream ads / ads on reels
ad_earnings - Stars
fan_support_earnings - Subscriptions
subscription_earnings - Bonuses
bonus_earnings
|
| Instagram | Professional dashboard, Monetization | - Total or approximate earnings
estimated_earnings - Gifts and badges
fan_support_earnings - Subscriptions
subscription_earnings - Bonuses
bonus_earnings - Ads on reels
ad_earnings
|
| YouTube | YouTube Studio, Analytics, Revenue (or Earn) | - Estimated revenue
estimated_earnings - Ad revenue (watch page and Shorts feed)
ad_earnings - Memberships
subscription_earnings - Supers (Super Chat, Super Stickers, Super Thanks)
fan_support_earnings
|
| TikTok | TikTok Studio, Rewards or Creator Rewards Program | - Estimated rewards
estimated_earnings - LIVE gifts and tips
fan_support_earnings - Subscriptions
subscription_earnings
|
| X | Monetization, Creator Revenue Sharing and Subscriptions | - Creator revenue sharing payout
estimated_earnings - Subscriptions
subscription_earnings
|
| LinkedIn | Usually no creator earnings. Send them only if LinkedIn shows an earnings figure. | - Any earnings figure LinkedIn shows
estimated_earnings
|
If two platforms report the same currency and the same period, the Board also shows their combined total. Otherwise each platform stands on its own.
Recommended metric names
Use these names so each number lands in the right chart. Board overview metrics are also combined across platforms. Any other name is still saved, shown under "Other reported metrics", and the reply includes a warnings entry with the closest recommended name.
| Platform | Metrics |
|---|
| Instagram | estimated_earningsEarningsfan_support_earningsEarningssubscription_earningsEarningsbonus_earningsEarningsad_earningsEarningsfollowersBoard overviewreachBoard overviewimpressionsBoard overviewviewsBoard overviewlikesBoard overviewcommentsBoard overviewsharesBoard overviewsavesBoard overviewpostsBoard overviewprofile_visitsPlatform cardlink_clicksPlatform card
|
| Facebook | estimated_earningsEarningscontent_monetization_earningsEarningsad_earningsEarningsfan_support_earningsEarningssubscription_earningsEarningsbonus_earningsEarningsfollowersBoard overviewreachBoard overviewimpressionsBoard overviewviewsBoard overviewreactionsBoard overviewcommentsBoard overviewsharesBoard overviewpostsBoard overviewprofile_visitsPlatform cardlink_clicksPlatform card
|
| LinkedIn | estimated_earningsEarningsfollowersBoard overviewimpressionsBoard overviewreactionsBoard overviewcommentsBoard overviewsharesBoard overviewpostsBoard overviewprofile_visitsPlatform cardlink_clicksPlatform card
|
| TikTok | estimated_earningsEarningsfan_support_earningsEarningssubscription_earningsEarningsfollowersBoard overviewviewsBoard overviewlikesBoard overviewcommentsBoard overviewsharesBoard overviewsavesBoard overviewvideosBoard overviewprofile_visitsPlatform card
|
| YouTube | estimated_earningsEarningsad_earningsEarningssubscription_earningsEarningsfan_support_earningsEarningssubscribersBoard overviewviewsBoard overviewlikesBoard overviewcommentsBoard overviewsharesBoard overviewvideosBoard overviewlink_clicksPlatform card
|
| X | estimated_earningsEarningssubscription_earningsEarningsfollowersBoard overviewimpressionsBoard overviewviewsBoard overviewlikesBoard overviewcommentsBoard overviewsharesBoard overviewsavesBoard overviewpostsBoard overviewprofile_visitsPlatform cardlink_clicksPlatform card
|
Use only real numbers the bot collected. Never estimate or invent values.
Run Growth Actions (optional)
When the owner clicks Execute on a Growth Action, Soulfy places a job in a queue for your bot. The bot needs the Run Growth Actions permission, which the owner turns on at the Grok Bot Connection page; new connections don't get it automatically. Jobs are pulled by the bot; Soulfy never pushes to it. The bot prepares drafts and checklists only. It never publishes, posts, replies or sends anything, and asks the owner instead of guessing.
- Every 30 seconds or slower:
GET https://soulfy.com/api/agent/v1/growth/jobs. Jobs you're working on come first (claimed_by_you: true), then the queue. - Claim one:
POST https://soulfy.com/api/agent/v1/growth/jobs/{id}/claim. The reply holds instructions, execution_rules, the action, focus, goal, and the owner's niche and the action's topic (each null when not set). Follow the execution rules. If another bot claimed it first you get 409; pick the next. - Add results as you go:
POST …/results with {"result_type": "draft", "data": {"text": "…"}, "summary": "…"}. Types: draft text checklist external_reference artifact status - Need a decision?
POST …/questions with {"input_type": "choice", "prompt": "…", "options": ["A", "B"]}. The job waits; poll GET …/{id} until its status is RUNNING again and read the answer in questions. Never ask for passwords, keys or other credentials. - Working longer than 30 minutes?
POST …/heartbeat keeps the job yours. - Finish with
POST …/complete (optionally {"result": {…}}) or POST …/fail with {"reason": "…"}. If the owner cancels, the job's status becomes CANCELLED and further writes return 409, so stop work.
How often, limits and retries
Cadence. Send one snapshot per platform after each daily stats check. Once a day is plenty; the Board shows change over days and weeks.
Rate limits
- 60 requests per 10 minutes per connection, per endpoint.
- 300 requests per 60 minutes per workspace, per endpoint, across all its connections.
- 20 failed sign-ins (bad credential or connect code) per 10 minutes per IP address.
- Over a limit you get HTTP 429 with a Retry-After header (seconds).
Retries and duplicates
- Send an optional Idempotency-Key header (1-128 characters of A-Z a-z 0-9 . _ : -) to make retries safe.
- Without one, the key is a fingerprint of platform, captured_at, collection_method, metrics, source and evidence, so resending the exact same snapshot never creates a duplicate.
- A repeat with the same key and the same data returns HTTP 200 with the original measurement_id and idempotent_replay: true.
- The same key with different data returns HTTP 409 idempotency_conflict.
Errors
Every error is JSON: {"success": false, "code": "…", "error": "…"}. A GET to https://soulfy.com/api/agent/v1/measurements or https://soulfy.com/api/agent/v1/connect returns the request format instead of an empty 405, and https://soulfy.com/api/agent/v1 lists every endpoint.
| HTTP | code | Meaning |
|---|
| 400 | invalid_json | The body isn't valid JSON. |
| 400 | invalid_platform | platform is missing or not one of instagram, facebook, linkedin, tiktok, youtube, x. |
| 400 | invalid_captured_at | captured_at is missing, has no timezone, is in the future, or is over a year old. |
| 400 | invalid_metrics | metrics isn't an object, a name isn't lowercase snake_case, or a value isn't a finite number. |
| 400 | unknown_field | The body has a top-level field the API doesn't accept. |
| 400 | invalid_request | A Growth Actions body field is missing or invalid, too large, or looks like a credential. |
| 400 | invalid_connect_code | The connect code is wrong, already used, or expired. Ask the owner for a new one. |
| 401 | unauthorized | The Authorization: Bearer header is missing, or the credential is invalid, expired or revoked. |
| 403 | insufficient_scope | The connection doesn't have the permission this endpoint needs. |
| 403 | workspace_mismatch | The body's workspace field names a different site. |
| 403 | custom_domain_required | The site isn't live on its own domain yet. |
| 403 | workspace_inactive | The workspace is suspended or cancelled. |
| 403 | forbidden | Another connection claimed this Growth Actions job. |
| 404 | not_found | No such Growth Actions job for this workspace, or it isn't queued or yours. |
| 405 | method_not_allowed | Wrong HTTP method. The reply lists the allowed methods. |
| 409 | idempotency_conflict | The Idempotency-Key was already used for different data. |
| 409 | invalid_transition | The job's status doesn't allow that, e.g. it was cancelled, already claimed or expired. GET the job to see its status. |
| 409 | conflict | The job changed at the same moment. GET it and try again. |
| 413 | payload_too_large | The body is over 16 KB. |
| 415 | unsupported_media_type | Content-Type isn't application/json. |
| 429 | rate_limited | Too many requests. Wait for Retry-After seconds. |
Standing instructions for your Grok Bot
- Keep the credential secret as SOULFY_AGENT_TOKEN. Never paste it into chat.
- Send it as "Authorization: Bearer <token>" with "Content-Type: application/json".
- Send one snapshot per platform after each daily stats check. Once a day is plenty; the Board shows change over days and weeks. POST to https://soulfy.com/api/agent/v1/measurements.
- Body: {"platform", "captured_at" (ISO 8601 with timezone), "metrics": {name: number}}.
- Use the recommended metric names at https://soulfy.com/docs/grok-bot; unknown names are saved but not charted.
- Include monetization earnings wherever a platform shows them: estimated_earnings for the platform's headline figure (Facebook Approximate earnings, YouTube Estimated revenue, TikTok Estimated rewards, X Creator revenue sharing), plus content_monetization_earnings, ad_earnings, subscription_earnings, fan_support_earnings and bonus_earnings when shown.
- With any earnings, add "source": {"currency": "<ISO code as shown, e.g. USD>", "earnings_period": "<the period the platform shows, e.g. last_28_days or this_month>"}.
- Use only real numbers you collected. Never estimate, convert or invent values.
- Add ?dry_run=true to check a request without saving it.
- If the owner gave you the Run Growth Actions permission: GET https://soulfy.com/api/agent/v1/growth/jobs no more than every 30 seconds, claim a job with POST https://soulfy.com/api/agent/v1/growth/jobs/{id}/claim, and follow its instructions and execution_rules. Post drafts to .../results, ask the owner through .../questions instead of guessing, and finish with .../complete or .../fail. Never publish, post, reply or send anything yourself.