Quick Start

The Attention Factory API is rentals-and-actions first. You rent a real, verified social account for a whole month, then submit actions (posts, comments, likes, follows, branding changes) against it. This guide walks through your first rental in five steps.

1. Sign up and get your API key

Create your account on the dashboard, then generate an API key from the API Keys page. Every request below requires it in theAuthorization header.

2. Create a rental

Pick a platform and a duration (in whole months). Optionally supply filters, a branding preset, or an opt-in warming niche. The response is always 202 Accepted — the rental may be active immediately, orwarming while the account is prepared.

POST /v1/rentals
curl -X POST https://api.attentionfactory.com/v1/rentals \
  -H "Authorization: Bearer af_live_sk_..." \
  -H "Content-Type: application/json" \
  -d '{
    "platform": "instagram",
    "months": 1,
    "auto_renew": true
  }'
Response
{
  "id": "4e1a5c98-1d23-4c9e-b3a7-0fdbc2a6e1b3",
  "anonymized_id": null,
  "platform": "instagram",
  "rental_start": null,
  "rental_end": null,
  "monthly_rate": "99.00",
  "credits_charged": "99.00",
  "auto_renew": true,
  "status": "warming",
  "expires_pending_at": "2026-05-02T12:00:00Z",
  "branding_preset": null,
  "created_at": "2026-04-18T12:00:00Z",
  "profile": null
}

3. Wait for activation

Poll the rental or register a webhook for rental.active. Once status flips toactive with a non-null anonymized_id, the account is yours for the rental window. On active rentals, the response includes a live profile object with the account's real username, display name, avatar, and follower counts.

GET /v1/rentals/{id}
curl https://api.attentionfactory.com/v1/rentals/4e1a5c98-1d23-4c9e-b3a7-0fdbc2a6e1b3 \
  -H "Authorization: Bearer af_live_sk_..."
Response (active rental)
{
  "id": "4e1a5c98-1d23-4c9e-b3a7-0fdbc2a6e1b3",
  "anonymized_id": "7c2d9f5b-e48a-4c11-8b3f-91c2e4d8a6b7",
  "platform": "instagram",
  "rental_start": "2026-04-18T12:30:00Z",
  "rental_end": "2026-05-18T12:30:00Z",
  "monthly_rate": "99.00",
  "credits_charged": "99.00",
  "auto_renew": true,
  "status": "active",
  "expires_pending_at": null,
  "branding_preset": null,
  "created_at": "2026-04-18T12:00:00Z",
  "profile": {
    "username": "launchpad_labs",
    "display_name": "Launchpad",
    "avatar_url": "https://cdn.example.com/avatars/launchpad.jpg",
    "follower_count": 2340,
    "following_count": 180,
    "post_count": 47
  }
}

4. Submit an action

Actions are scoped to a rental + platform. The body carries atype (e.g.post.image) and action-specificparams. The rental must beactive.

POST /v1/rentals/{rental_id}/{platform}/actions
curl -X POST https://api.attentionfactory.com/v1/rentals/$RENTAL_ID/instagram/actions \
  -H "Authorization: Bearer af_live_sk_..." \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: launch-post-001" \
  -d '{
    "type": "post.image",
    "params": {
      "caption": "Our new launch is live.",
      "media_url": "https://cdn.example.com/launch.jpg"
    }
  }'

5. Track completion via webhook

Register a webhook once and receive action status transitions (action.assigned, action.submitted, action.verified, etc.) in near-real-time.

POST /v1/webhooks
curl -X POST https://api.attentionfactory.com/v1/webhooks \
  -H "Authorization: Bearer af_live_sk_..." \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://acme.com/webhooks/af",
    "events": ["rental.active", "action.verified", "action.failed"],
    "secret": "whsec_your_signing_secret"
  }'

Authentication

All API requests require an API key passed in the Authorization header.

Authorization: Bearer af_live_sk_...

API Key Format

API keys follow the format af_live_sk_... for production and af_test_sk_... for testing. Keys are generated and revoked from the API Keys page in the dashboard.

Platforms

Discovery endpoints for supported platforms, the actions they expose, and the niches available for opt-in warming. Call these before creating a rental to validate input client-side.

Endpoints

GET
/v1/platforms

List supported platforms

GET
/v1/platforms/{platform}/capabilities

Action types and per-rental rate caps for a platform

GET
/v1/platforms/{platform}/niches

Valid warming_niche values for opt-in warming

List Platforms

GET /v1/platforms
curl https://api.attentionfactory.com/v1/platforms \
  -H "Authorization: Bearer af_live_sk_..."
Response
{
  "platforms": ["instagram", "tiktok", "reddit", "facebook", "x", "linkedin"]
}

Platform Capabilities

Returns the action types available on a platform and the rate caps applied per rental. Use this to know which type values are valid inPOST .../actions.

GET /v1/platforms/{platform}/capabilities
curl https://api.attentionfactory.com/v1/platforms/instagram/capabilities \
  -H "Authorization: Bearer af_live_sk_..."

Niche Catalog

Opt-in warming pre-primes a rented account for a specific audience over a 7-day pre-activation window. Use one of these values as warming_niche when creating a rental. Unknown values are rejected with a 400 before any credits are charged.

GET /v1/platforms/{platform}/niches
curl https://api.attentionfactory.com/v1/platforms/instagram/niches \
  -H "Authorization: Bearer af_live_sk_..."
Response
{
  "platform": "instagram",
  "niches": ["fitness", "food", "tech-reviews", "travel"]
}

Rent an Account

Reserve a verified social account for a whole month. Pricing is monthly; actions incur no per-call charges. Every rental is charged upfront; if warming doesn't complete within 14 days the rental auto-refunds.

Endpoints

POST
/v1/rentals

Create a rental (returns 202)

GET
/v1/rentals

List your rentals (supports ?status=)

GET
/v1/rentals/{id}

Get rental detail

PATCH
/v1/rentals/{id}

Update auto_renew (and other mutable fields)

DELETE
/v1/rentals/{id}

Release early or cancel a pending rental

POST
/v1/rentals/{id}/extend

Extend an active rental by N months

POST
/v1/rentals/{id}/renew

Renew an active or recently-expired rental

Create Rental

POST /v1/rentals
curl -X POST https://api.attentionfactory.com/v1/rentals \
  -H "Authorization: Bearer af_live_sk_..." \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: my-rental-001" \
  -d '{
    "platform": "instagram",
    "months": 1,
    "auto_renew": true,
    "warming_niche": "tech-reviews",
    "branding": {
      "bio": "Builder. Coffee. Code.",
      "display_name": "Launchpad"
    }
  }'

Request Body

FieldTypeRequiredDescription
platformstringYesOne of: instagram, tiktok, reddit, facebook, x, linkedin
monthsintegerNo1–12. Defaults to 1
auto_renewboolNoAuto-renew when the rental window closes. Defaults to true
warming_nichestringNoOpt in to 7-day pre-warming on this niche. Must be in the platform's niche catalog
brandingobjectNoBranding preset applied automatically on activation

The branding object accepts any subset ofbio,display_name,avatar_url,banner_url, andusername. Each field is applied as a queued action the moment the rental activates.

Rental Status Values

StatusMeaning
warmingPre-activation. The account is being prepared and actions cannot be submitted yet. expires_pending_at indicates when the rental auto-refunds if warming doesn't complete
activeRental is live. Submit actions against the rental
expiredRental window closed naturally (auto-renew disabled or failed)
refundedCredits returned. Warming did not complete within the 14-day guarantee window
releasedCustomer released the rental early. No refund (month-committal)
cancelledCustomer cancelled while still pre-activation. Credits refunded

Extend / Renew

POST /v1/rentals/{id}/extend
curl -X POST https://api.attentionfactory.com/v1/rentals/$RENTAL_ID/extend \
  -H "Authorization: Bearer af_live_sk_..." \
  -H "Content-Type: application/json" \
  -d '{"months": 2}'

POST /renew has the same body shape. Use it to re-start a recently expired rental on the same account (same anonymized id).

Toggle Auto-Renew

PATCH /v1/rentals/{id} updates mutable rental fields. Today the only customer-controllable field is auto_renew; flip it any time before the rental window closes. Returns the updated rental.

PATCH /v1/rentals/{rental_id}
curl -X PATCH https://api.attentionfactory.com/v1/rentals/$RENTAL_ID \
  -H "Authorization: Bearer af_live_sk_..." \
  -H "Content-Type: application/json" \
  -d '{"auto_renew": false}'

Brand an Account

Change your rented account's bio, display name, avatar, banner, and username in one request. The server fans out to one queued action per field you provide. Rate caps and review modes apply per sub-action.

Endpoint

POST
/v1/rentals/{id}/branding

Apply bio / display name / avatar / banner / username in one batch

Field support differs by platform — the sample below changes as you switch platforms. Fields not supported on the selected platform are simply omitted from the example.

Platform

POST /v1/rentals/{rental_id}/branding (instagram)
curl -X POST https://api.attentionfactory.com/v1/rentals/$RENTAL_ID/branding \
  -H "Authorization: Bearer af_live_sk_..." \
  -H "Content-Type: application/json" \
  -d '{
  "bio": "Builder. Coffee. Code.",
  "display_name": "Launchpad",
  "avatar_url": "https://cdn.example.com/avatar.jpg",
  "username": "launchpad_labs",
  "pronouns": "she/her",
  "category": "Artist"
}'
Response (rental is active — mode: applied)
{
  "rental_id": "4e1a5c98-1d23-4c9e-b3a7-0fdbc2a6e1b3",
  "platform": "instagram",
  "mode": "applied",
  "results": [
    {"field": "bio", "action_type": "branding.bio", "action_id": "9ab72c01-...", "status": "queued"},
    {"field": "display_name", "action_type": "branding.display_name", "action_id": "f2c91e45-...", "status": "queued"}
  ],
  "preset": null
}

If the rental is still warming, the request returnsmode: "preset_stored" instead — the batch is saved and applied automatically when the rental activates. Re-posting while pending REPLACES the previously stored preset. At least one field must be non-null (empty bodies return 400).

Warm an Account

Enroll your rented account in a warming schedule — the app gradually builds authentic engagement over the duration you pick. You can pre-warm at rental creation via the warming_niche field, or enroll post-creation via this endpoint.

Endpoints

POST
/v1/rentals/{id}/warming

Enroll the rental in a warming schedule

DELETE
/v1/rentals/{id}/warming

Cancel a pending warming enrolment

Request Body

FieldTypeDefaultDescription
nichestringOptional, max 50 chars. See GET /v1/platforms/{platform}/niches for the platform's catalog. Pace and duration are managed server-side

Enroll

POST /v1/rentals/{rental_id}/warming
curl -X POST https://api.attentionfactory.com/v1/rentals/$RENTAL_ID/warming \
  -H "Authorization: Bearer af_live_sk_..." \
  -H "Content-Type: application/json" \
  -d '{"niche": "tech-reviews"}'
Response
{
  "rental_id": "4e1a5c98-1d23-4c9e-b3a7-0fdbc2a6e1b3",
  "action_id": "9ab72c01-5d62-4f0b-a8cc-1d4a7b2fc309",
  "status": "queued"
}

Cancel

DELETE /v1/rentals/{rental_id}/warming
curl -X DELETE https://api.attentionfactory.com/v1/rentals/$RENTAL_ID/warming \
  -H "Authorization: Bearer af_live_sk_..."

Cancels the most recent warming enrolment on the rental if it's still queued. 404 if there's no matching active enrolment.

Submit Actions

Actions are the unit of work performed on a rented account. They run asynchronously on real people's devices: the request returns 202 Accepted with a queued status, and the final state arrives via webhook or poll.

Endpoints

POST
/v1/rentals/{rental_id}/{platform}/actions

Submit a new action

GET
/v1/rentals/{rental_id}/actions

List actions on a rental (supports ?status=)

GET
/v1/rentals/{rental_id}/actions/{action_id}

Get action detail

DELETE
/v1/rentals/{rental_id}/actions/{action_id}

Cancel a still-queued action

GET
/v1/rentals/{rental_id}/actions/{action_id}/analytics

Post-level analytics for post-type actions

Submit Action

The URL carries both the rental and platform; the body carries the actiontype and typedparams. Supply anIdempotency-Key header for retries — submitting twice with the same key returns the existing action instead of creating a duplicate. Availability varies by platform; pick a platform and an action below to see the exact request and response. Rate limits also vary per platform and action — call GET /v1/platforms/{platform}/capabilities for the definitive live list with caps.

Platform

Action

Publish a single image with optional caption. Supported on Instagram, Facebook, X, LinkedIn. All TikTok/IG composition options from the shared PostOptionsMixin apply: sound_name, location, link_url, allow_comments, allow_duet, allow_stitch, ai_generated, allow_visual_search, audience_control. LinkedIn composer options also accepted (ignored on other platforms): `visibility` (anyone / connections_only / group), `group_url` (required when visibility="group"; must be an https://linkedin.com/... URL), `comment_control` (anyone / connections_only / no_one), `brand_partner_url` (LinkedIn company URL — presence enables the Paid Partnership label). Include only the fields you want to set — omit the rest to keep the platform default.

POST /v1/rentals/{rental_id}/instagram/actions
curl -X POST https://api.attentionfactory.com/v1/rentals/$RENTAL_ID/instagram/actions \
  -H "Authorization: Bearer af_live_sk_..." \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: my-action-001" \
  -d '{
  "type": "post.image",
  "params": {
    "media_url": "https://cdn.example.com/hero.jpg",
    "caption": "Launching today.",
    "location": "San Francisco, CA",
    "allow_comments": true,
    "audience_control": "everyone"
  }
}'
Response
{
  "id": "9ab72c01-5d62-4f0b-a8cc-1d4a7b2fc309",
  "rental_id": "4e1a5c98-1d23-4c9e-b3a7-0fdbc2a6e1b3",
  "platform": "instagram",
  "action_type": "post.image",
  "status": "queued",
  "created_at": "2026-04-19T12:05:00Z"
}

Action Status Values

StatusMeaning
queuedAccepted and awaiting a provider
assignedProvider picked up the action
in_progressProvider is working
submittedProvider submitted proof; awaiting verification
verifiedTerminal: action completed successfully
failedTerminal: action failed or was rejected on review
Reviews are automatic. You don't approve actions by hand. Status transitions arrive via your existing action.* webhooks andGET /v1/rentals/{id}/actions — wait forverified or failed.

Analytics

Read account-level and post-level metrics.

Endpoints

GET
/v1/rentals/{id}/analytics

Account-level analytics from the upstream provider (active rentals only)

GET
/v1/rentals/{id}/actions/{action_id}/analytics

Post-level analytics for a single post-type action

GET
/v1/rentals/{id}/capabilities

Action types available for this rental's platform

Account Analytics

GET /v1/rentals/{id}/analytics returns the latest account-level metrics (followers, following, post count, engagement) from the upstream provider. Only available while the rental isactive; other statuses return 400. Coverage varies per platform — TikTok typically returns every metric, Reddit returns few.

GET /v1/rentals/{rental_id}/analytics
curl https://api.attentionfactory.com/v1/rentals/$RENTAL_ID/analytics \
  -H "Authorization: Bearer af_live_sk_..."

Post Analytics

Post-type actions expose upstream post-level analytics (views, likes, comments). Non-post action types return 400. Newly-verified posts may take a few seconds before analytics are populated — retry on 400 with "not yet available".

GET /v1/rentals/{rental_id}/actions/{action_id}/analytics
curl https://api.attentionfactory.com/v1/rentals/$RENTAL_ID/actions/$ACTION_ID/analytics \
  -H "Authorization: Bearer af_live_sk_..."

Profile

GET /v1/rentals/{id} includes a live profile object on active rentals: username,display_name,avatar_url, and follower / following / post counts. Count fields report null if the platform doesn't supply them. The profile object itself is nullbefore activation, on terminal statuses, and on transient fetch failure — the rental itself never fails because the profile fetch did. Not returned on GET /v1/rentals (list); fetch each rental individually for profile data.

Capabilities

GET /v1/rentals/{id}/capabilities is a convenience for your UI — same shape as GET /v1/platforms/{platform}/capabilities, scoped to the rental's platform. Lets you check "what can I do with this rental right now" without mapping rental → platform yourself.

Billing

Track your credit balance and transaction history. Rentals are charged upfront at the monthly rate for each whole month requested.

Endpoints

GET
/v1/billing/balance

Get current credit balance

GET
/v1/billing/transactions

List transaction history

Balance

GET /v1/billing/balance
curl https://api.attentionfactory.com/v1/billing/balance \
  -H "Authorization: Bearer af_live_sk_..."

Transactions

GET /v1/billing/transactions
curl https://api.attentionfactory.com/v1/billing/transactions \
  -H "Authorization: Bearer af_live_sk_..."

Webhooks

Register HTTPS endpoints to receive real-time notifications when rentals activate, actions progress, or credits move. Deliveries are signed with HMAC-SHA256.

Endpoints

POST
/v1/webhooks

Register a webhook endpoint

GET
/v1/webhooks

List registered webhooks

DELETE
/v1/webhooks/{id}

Remove a webhook

POST
/v1/webhooks/{id}/rotate-secret

Rotate the HMAC signing secret

GET
/v1/webhooks/{id}/deliveries

View delivery log for a webhook

Register Webhook

POST /v1/webhooks
curl -X POST https://api.attentionfactory.com/v1/webhooks \
  -H "Authorization: Bearer af_live_sk_..." \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://acme.com/webhooks/af",
    "events": ["rental.active", "action.verified", "action.failed"],
    "secret": "whsec_your_signing_secret"
  }'

Event Types

Every delivery wraps the event data in an envelope containing the event name, a timestamp, and the event-specificdata object.

Rental events

EventWhen it fires
rental.activeRental transitions from warming to active and can accept actions
rental.cancelledCustomer cancelled a still-pending rental; credits refunded
rental.refundedPending window elapsed or pre-warming could not complete; credits refunded
rental.expiredRental window closed naturally

Action events

Emitted as action.{status} for each status transition. Subscribe only to the ones you need.

EventMeaning
action.queuedAction accepted
action.assignedProvider picked it up
action.in_progressProvider started work
action.submittedProof submitted by provider
action.verifiedTerminal: succeeded
action.failedTerminal: failed or rejected
Example action.verified payload
{
  "event": "action.verified",
  "timestamp": "2026-04-19T12:30:00Z",
  "data": {
    "action_id": "9ab72c01-5d62-4f0b-a8cc-1d4a7b2fc309",
    "rental_id": "4e1a5c98-1d23-4c9e-b3a7-0fdbc2a6e1b3",
    "platform": "instagram",
    "action_type": "post.image",
    "status": "verified"
  }
}

Signature Verification

Each delivery includes an X-Webhook-Signature header with an HMAC-SHA256 signature of the JSON data field (sorted keys). Verify against your webhook secret before trusting the payload.

Signature verification (Node.js)
const crypto = require('crypto');

function verifyWebhook(dataJson, signatureHeader, secret) {
  // signatureHeader looks like: "sha256=<hex>"
  const provided = signatureHeader.replace(/^sha256=/, '');
  const expected = crypto
    .createHmac('sha256', secret)
    .update(dataJson)
    .digest('hex');
  return crypto.timingSafeEqual(
    Buffer.from(provided),
    Buffer.from(expected)
  );
}
Idempotent handlers recommended. Deliveries are retried on non-2xx responses, so the same event may arrive more than once. De-dupe on action_id /rental_id + event name on your side.

Errors

The API uses standard HTTP status codes. All error responses include a detail field with a human-readable message.

Error Response Format

Error response
{
  "detail": "Insufficient credits. Need 99.00, have 12.00"
}

Status Codes

CodeMeaningCommon Cause
400Bad RequestMissing or invalid fields (e.g. unknown warming_niche)
401UnauthorizedMissing or invalid API key
402Payment RequiredInsufficient credit balance
403ForbiddenAction not allowed for your subscription tier
404Not FoundResource does not exist or not owned by your business
409ConflictInvalid state transition (e.g. extending an expired rental)
422Unprocessable EntityAction params failed schema validation
429Too Many RequestsPer-rental rate cap exceeded (see Retry-After header)
500Internal Server ErrorSomething went wrong on our end