Thanks to visit codestin.com
Credit goes to climbx.so

Skip to main content
Reference

ClimbX API docs

A small REST API for AI agents to publish and schedule X posts and read analytics and voice data on behalf of a ClimbX account. JSON in, JSON out. v1 is intentionally minimal.

Authentication

Every request needs a key in the Authorization header. Create one in ClimbX under Settings → API. The full key is shown once at creation - store it somewhere safe. We keep only a hash and cannot show it again.

Authorization: Bearer climbx_sk_your_key

The owning account must be on an active plan or trial. A lapsed subscription returns 402 even if the key is still live. Revoke a key any time from the same screen; it stops working on the next call.

Base URL and limits

https://climbx.so/api/v1
  • Daily post cap: 5 posts per account per day across publish and schedule. Resets at 00:00 UTC. Over the cap returns 429.
  • No links: posts containing a URL are rejected with 400. Link posts cut reach and cost 13x to publish.
  • Content type: send Content-Type: application/json on every POST and PATCH.
  • Media: attach up to 4 images by passing image_urls (public https URLs) on publish or schedule. Video over the API is a work in progress.
  • Read rate limit: GET endpoints allow about 60 requests per minute per key. Over it returns 429 with a Retry-After header.
  • Crawling analytics: the analytics and learnings-history endpoints take a start and end ISO window (default last 30 days, max span 366 days). Every response carries generated_at and as_of (the newest metrics snapshot in the window) - poll on a schedule and dedupe on as_of to build a time series.
  • Freshness: using the API refreshes your data in the background - new posts, metrics, and learnings - the same way opening the app does, so you never have to visit the web app to keep these endpoints current. Refreshes are throttled, so the first call in a window does the work and later calls read the fresh result.

Publish a post now

POST/api/v1/posts

Ships a post to X immediately through the connected account. Attach up to 4 images with image_urls.

FieldTypeDescription
textstringrequiredThe post body. 1 to 10,000 chars. No URLs.
image_urlsstring[]optionalUp to 4 public https image URLs. Each is fetched and attached. Video is not supported yet.
curl -X POST https://climbx.so/api/v1/posts \
  -H "Authorization: Bearer climbx_sk_your_key" \
  -H "Content-Type: application/json" \
  -d '{"text": "shipped something today."}'
Response 200
{
  "ok": true,
  "id": "1799999999999999999",
  "url": "https://x.com/i/web/status/1799999999999999999",
  "record_id": "9f1c...",
  "posts_used_today": 1,
  "daily_cap": 5
}

List recent posts with metrics

GET/api/v1/posts

Returns the account’s recent published posts and their latest metrics snapshot.

FieldTypeDescription
limitnumberoptionalHow many to return. 1 to 100, default 30.
curl https://climbx.so/api/v1/posts?limit=10 \
  -H "Authorization: Bearer climbx_sk_your_key"
Response 200
{
  "posts": [
    {
      "id": "1799...",
      "text": "...",
      "format": "hot_take",
      "posted_at": "2026-05-25T08:30:00Z",
      "is_reply": false,
      "metrics": {
        "impressions": 14200,
        "views": 14200,
        "likes": 180,
        "replies": 24,
        "retweets": 12,
        "quote_tweets": 3
      }
    }
  ]
}

Schedule a post

POST/api/v1/schedule

Queues a post for a future time. ClimbX ships it at the scheduled minute and retries on transient failures. A past time publishes on the next tick.

FieldTypeDescription
textstringrequiredThe post body. 1 to 10,000 chars. No URLs.
scheduled_forstringrequiredISO 8601 datetime, e.g. 2026-06-01T14:00:00Z.
image_urlsstring[]optionalUp to 4 public https image URLs, attached at publish time. No video yet.
curl -X POST https://climbx.so/api/v1/schedule \
  -H "Authorization: Bearer climbx_sk_your_key" \
  -H "Content-Type: application/json" \
  -d '{"text": "morning thought.", "scheduled_for": "2026-06-01T08:00:00Z"}'
Response 200
{
  "ok": true,
  "scheduled": {
    "id": "3a2b...",
    "text": "morning thought.",
    "scheduled_for": "2026-06-01T08:00:00Z",
    "status": "pending"
  },
  "posts_used_today": 2,
  "daily_cap": 5
}

List scheduled posts

GET/api/v1/schedule

Returns upcoming posts that are still pending or mid-publish.

curl https://climbx.so/api/v1/schedule \
  -H "Authorization: Bearer climbx_sk_your_key"
Response 200
{
  "scheduled": [
    {
      "id": "3a2b...",
      "text": "morning thought.",
      "scheduled_for": "2026-06-01T08:00:00Z",
      "status": "pending"
    }
  ]
}

Reschedule a pending post

PATCH/api/v1/schedule/{id}

Moves a still-pending scheduled post to a new time. Works only while the post is pending; once ClimbX has started publishing it, it can’t be changed (returns 409).

FieldTypeDescription
scheduled_forstringrequiredNew ISO 8601 datetime.
curl -X PATCH https://climbx.so/api/v1/schedule/3a2b... \
  -H "Authorization: Bearer climbx_sk_your_key" \
  -H "Content-Type: application/json" \
  -d '{"scheduled_for": "2026-06-02T09:30:00Z"}'
Response 200
{
  "ok": true,
  "scheduled": {
    "id": "3a2b...",
    "text": "morning thought.",
    "scheduled_for": "2026-06-02T09:30:00Z",
    "status": "pending"
  }
}

Cancel a scheduled post

DELETE/api/v1/schedule/{id}

Cancels a still-pending scheduled post so it won’t publish. Cancelling does not give back a daily-cap slot - the post counted when you created it.

curl -X DELETE https://climbx.so/api/v1/schedule/3a2b... \
  -H "Authorization: Bearer climbx_sk_your_key"
Response 200
{
  "ok": true,
  "cancelled": { "id": "3a2b...", "status": "cancelled" }
}

Performance summary

GET/api/v1/analytics

Headline KPIs plus a per-format breakdown over a window. Replies are excluded.

FieldTypeDescription
daysnumberoptionalLookback window. 1 to 90, default 30.
curl https://climbx.so/api/v1/analytics?days=30 \
  -H "Authorization: Bearer climbx_sk_your_key"
Response 200
{
  "range_days": 30,
  "summary": {
    "posts_published": 42,
    "total_impressions": 512000,
    "avg_impressions": 12190,
    "avg_replies": 18,
    "avg_likes": 140,
    "engagement_rate_pct": 2.8
  },
  "by_format": [
    { "format": "hot_take", "posts": 12, "median_replies": 22, "median_impressions": 15000 }
  ]
}

Format performance

GET/api/v1/analytics/formats

Per-format breakdown over a window: how many posts, their share, and the median replies and impressions, with a trend (up/down/neutral) comparing each format against your typical post in the same window. Mirrors the Format performance table in the app.

FieldTypeDescription
startstringoptionalISO datetime window start. Defaults to 30 days before end.
endstringoptionalISO datetime window end. Defaults to now.

generated_at is when the response was computed; as_of is the newest metrics snapshot in the window (when the numbers last moved). Max span 366 days.

curl "https://climbx.so/api/v1/analytics/formats?start=2026-05-01T00:00:00Z&end=2026-06-01T00:00:00Z" \
  -H "Authorization: Bearer climbx_sk_your_key"
Response 200
{
  "generated_at": "2026-06-01T12:00:00Z",
  "as_of": "2026-05-31T22:10:00Z",
  "window": { "start": "2026-05-01T00:00:00Z", "end": "2026-06-01T00:00:00Z" },
  "posts_analyzed": 42,
  "median_impressions": 12000,
  "rows": [
    {
      "format": "hot_take",
      "posts": 12,
      "share": 29,
      "replies": { "value": 22, "trend": "up" },
      "impressions": { "value": 15000, "trend": "up" }
    }
  ]
}

Niche performance

GET/api/v1/analytics/niches

Same shape as Format performance, bucketed by niche instead of format. Posts with no niche label come back under "__unlabeled__".

FieldTypeDescription
startstringoptionalISO datetime window start. Defaults to 30 days before end.
endstringoptionalISO datetime window end. Defaults to now.
curl "https://climbx.so/api/v1/analytics/niches?start=2026-05-01T00:00:00Z&end=2026-06-01T00:00:00Z" \
  -H "Authorization: Bearer climbx_sk_your_key"
Response 200
{
  "generated_at": "2026-06-01T12:00:00Z",
  "as_of": "2026-05-31T22:10:00Z",
  "window": { "start": "2026-05-01T00:00:00Z", "end": "2026-06-01T00:00:00Z" },
  "posts_analyzed": 42,
  "median_impressions": 12000,
  "rows": [
    {
      "niche": "saas",
      "posts": 18,
      "share": 43,
      "replies": { "value": 20, "trend": "neutral" },
      "impressions": { "value": 13500, "trend": "up" }
    }
  ]
}

Voice profile

GET/api/v1/voice

The account’s voice persona, evidence-backed learnings, cadence targets, and posting schedule. Use it to draft in the owner’s voice and time posts well.

curl https://climbx.so/api/v1/voice \
  -H "Authorization: Bearer climbx_sk_your_key"
Response 200
{
  "voice": {
    "persona": "lowercase, short lines, founder-to-founder...",
    "mode": "adaptive",
    "learnings": [
      { "text": "open with a contradiction", "polarity": "positive", "evidence": "..." }
    ],
    "cadence": { "phase": "grow", "posts_per_day": 2, "replies_per_day": 5 },
    "schedule": {
      "timezone": "Europe/Copenhagen",
      "active_start_hour": 8,
      "active_end_hour": 22,
      "weekly_slots": { "mon": ["09:00", "17:00"] }
    }
  }
}

Ongoing learnings

GET/api/v1/learnings

The account’s current “Ongoing learnings” - the do-more (positive) and do-less (negative) rules ClimbX derived from the owner’s own posts, each with its evidence. last_derived_at is when the set was last recomputed.

curl https://climbx.so/api/v1/learnings \
  -H "Authorization: Bearer climbx_sk_your_key"
Response 200
{
  "generated_at": "2026-06-01T12:00:00Z",
  "last_derived_at": "2026-05-30T03:00:00Z",
  "learnings": {
    "positive": [
      { "text": "open with a contradiction", "source": "derived", "evidence": "..." }
    ],
    "negative": [
      { "text": "long multi-paragraph posts underperform", "source": "derived", "evidence": "..." }
    ]
  }
}

Learnings history

GET/api/v1/learnings/history

The recorded timeline of the learnings set - one snapshot each time it was re-derived, within the window. Use it to chart how the rules evolved. History accrues going forward from when the feature shipped; there is no retroactive backfill.

FieldTypeDescription
startstringoptionalISO datetime window start. Defaults to 30 days before end.
endstringoptionalISO datetime window end. Defaults to now.
curl "https://climbx.so/api/v1/learnings/history?start=2026-05-01T00:00:00Z&end=2026-06-01T00:00:00Z" \
  -H "Authorization: Bearer climbx_sk_your_key"
Response 200
{
  "generated_at": "2026-06-01T12:00:00Z",
  "window": { "start": "2026-05-01T00:00:00Z", "end": "2026-06-01T00:00:00Z" },
  "snapshots": [
    {
      "captured_at": "2026-05-30T03:00:00Z",
      "learnings": { "positive": [ ... ], "negative": [ ... ] }
    }
  ]
}

Errors

Errors return a JSON body with an error code and a human message.

StatuserrorWhen
400invalid_body / url_posts_not_allowed / invalid_id / invalid_windowBad payload, the text contains a link, a malformed id, or a bad start/end window.
401missing_bearer / invalid_keyNo key, or the key is unknown or revoked.
402subscription_requiredThe owning account is not on a plan or trial.
404not_foundNo scheduled post with that id on this account.
400image_rejectedAn image_url could not be used: bad URL, blocked host, too large, or not an image.
409x_not_connected / x_token_expired / not_pendingReconnect X, or the post is no longer pending (already publishing or published).
429daily_post_cap_reachedHit the 5/day post cap. Resets 00:00 UTC.
429rate_limitedToo many GET requests this minute. Back off per the Retry-After header.
500image_store_failedCould not store a scheduled image; the post was rolled back.
502publish_failed / media_upload_failedX rejected the post or an image.