Build campaign workflows with the Swell API.

Use workspace-scoped keys for typed post, media, link, analytics, audit, and webhook integrations.

API

Use the customer REST API for typed integrations, scheduled content workflows, tracked links, analytics reads, audit logs, and webhooks.

API Quick Start

1

Create a key

Open Account Settings, choose API keys, and create a read/write token.

2

Call the API

Send the token as an Authorization bearer token to api.growonswell.com.

3

Use returned IDs

Use social_account_ids, media_ids, post IDs, and tracked link IDs in later calls.

Authentication

API keys belong to one workspace and can be revoked from Account Settings. Store the full key in your secret manager; Swell only shows it once.

Authorization: Bearer $SWELL_API_KEY
Available scopes
workspace:readaccounts:readmedia:readmedia:writeposts:readposts:writelinks:readlinks:writeanalytics:readaudit:readwebhooks:readwebhooks:write

Idempotency

Send `Idempotency-Key` on mutating `/v1` requests to make retries safe. Swell replays the original response for the same method, path, and request body, and returns 409 if the key is reused for a different request or while the first request is still running.

Idempotency-Key: import-run-2026-06-28-001

Rate Limits

Successful API responses include `X-RateLimit-Limit`, `X-RateLimit-Remaining`, and `X-RateLimit-Reset`. When a key is over its window, Swell returns 429 with `Retry-After`.

X-RateLimit-Remaining: 128Retry-After: 42

OpenAPI Contract

The customer API publishes a filtered OpenAPI document that excludes internal app routes and includes bearer-token security metadata for the public `/v1` surface.

https://api.growonswell.com/v1/openapi.jsonView spec

Endpoint Reference

Workspace

GET/workspace
Current workspace

Read workspace identity, slug, timezone, and plan key for the API key.

workspace:read
Response body
{
  "id": 42,
  "object_id": "workspace_42",
  "name": "Acme Growth",
  "slug": "acme-growth",
  "timezone": "America/New_York",
  "plan_key": "growth"
}
GET/company-profile
Company profile

Read the generated company profile used to ground Swell agents and automated workflows.

profile:read
Response body
{
  "id": 9,
  "object_id": "company_profile_9",
  "workspace_id": 42,
  "source_urls": ["https://example.com"],
  "narrative": "Acme helps growth teams understand demand, plan focused campaigns, and turn first-party signals into measurable action.",
  "summary": "Acme helps launch teams understand and improve growth.",
  "audience": ["Founders", "Growth operators"],
  "positioning": "AI-assisted growth workspace for launch teams.",
  "value_props": ["Ground content in first-party customer data"],
  "feature_set": ["Social scheduling", "Attribution", "Agent workflows"],
  "messaging": { "primary": "Turn workspace data into sharper growth actions." },
  "tone": { "default": "Specific, pragmatic, and product-aware." },
  "visual_identity": { "style": "Clean product-led visuals with clear proof points." },
  "social_posture": { "linkedin": "Educational launch and growth updates." },
  "source_evidence": [{ "source": "https://example.com", "detail": "Homepage positioning and product copy." }],
  "confidence": 0.82,
  "source_fingerprint": "a4f2...",
  "stale": false,
  "context": "Workspace company profile: ...",
  "media": [],
  "generated_at": "2026-07-09T14:00:00Z",
  "created_at": "2026-07-09T13:55:00Z",
  "updated_at": "2026-07-09T14:00:00Z"
}
POST/company-profile/refresh
Refresh company profile

Regenerate the company profile from source URLs, workspace data, social posture, and associated media.

profile:write
Response body
{
  "id": 9,
  "object_id": "company_profile_9",
  "workspace_id": 42,
  "source_urls": ["https://example.com"],
  "narrative": "Acme helps growth teams understand demand, plan focused campaigns, and turn first-party signals into measurable action.",
  "summary": "Acme helps launch teams understand and improve growth.",
  "audience": ["Founders", "Growth operators"],
  "positioning": "AI-assisted growth workspace for launch teams.",
  "value_props": ["Ground content in first-party customer data"],
  "feature_set": ["Social scheduling", "Attribution", "Agent workflows"],
  "messaging": { "primary": "Turn workspace data into sharper growth actions." },
  "tone": { "default": "Specific, pragmatic, and product-aware." },
  "visual_identity": { "style": "Clean product-led visuals with clear proof points." },
  "social_posture": { "linkedin": "Educational launch and growth updates." },
  "source_evidence": [{ "source": "https://example.com", "detail": "Homepage positioning and product copy." }],
  "confidence": 0.82,
  "source_fingerprint": "a4f2...",
  "stale": false,
  "context": "Workspace company profile: ...",
  "media": [],
  "generated_at": "2026-07-09T14:00:00Z",
  "created_at": "2026-07-09T13:55:00Z",
  "updated_at": "2026-07-09T14:00:00Z"
}
PATCH/company-profile/sources
Update company profile sources

Replace source URLs used for profile construction, then regenerate the profile.

profile:write
Response body
{
  "id": 9,
  "object_id": "company_profile_9",
  "workspace_id": 42,
  "source_urls": ["https://example.com"],
  "narrative": "Acme helps growth teams understand demand, plan focused campaigns, and turn first-party signals into measurable action.",
  "summary": "Acme helps launch teams understand and improve growth.",
  "audience": ["Founders", "Growth operators"],
  "positioning": "AI-assisted growth workspace for launch teams.",
  "value_props": ["Ground content in first-party customer data"],
  "feature_set": ["Social scheduling", "Attribution", "Agent workflows"],
  "messaging": { "primary": "Turn workspace data into sharper growth actions." },
  "tone": { "default": "Specific, pragmatic, and product-aware." },
  "visual_identity": { "style": "Clean product-led visuals with clear proof points." },
  "social_posture": { "linkedin": "Educational launch and growth updates." },
  "source_evidence": [{ "source": "https://example.com", "detail": "Homepage positioning and product copy." }],
  "confidence": 0.82,
  "source_fingerprint": "a4f2...",
  "stale": false,
  "context": "Workspace company profile: ...",
  "media": [],
  "generated_at": "2026-07-09T14:00:00Z",
  "created_at": "2026-07-09T13:55:00Z",
  "updated_at": "2026-07-09T14:00:00Z"
}
POST/company-profile/media
Associate company profile media

Associate an existing workspace image or video with the profile as a logo, screenshot, demo, or brand reference.

profile:write
Response body
{
  "id": 9,
  "object_id": "company_profile_9",
  "workspace_id": 42,
  "source_urls": ["https://example.com"],
  "narrative": "Acme helps growth teams understand demand, plan focused campaigns, and turn first-party signals into measurable action.",
  "summary": "Acme helps launch teams understand and improve growth.",
  "audience": ["Founders", "Growth operators"],
  "positioning": "AI-assisted growth workspace for launch teams.",
  "value_props": ["Ground content in first-party customer data"],
  "feature_set": ["Social scheduling", "Attribution", "Agent workflows"],
  "messaging": { "primary": "Turn workspace data into sharper growth actions." },
  "tone": { "default": "Specific, pragmatic, and product-aware." },
  "visual_identity": { "style": "Clean product-led visuals with clear proof points." },
  "social_posture": { "linkedin": "Educational launch and growth updates." },
  "source_evidence": [{ "source": "https://example.com", "detail": "Homepage positioning and product copy." }],
  "confidence": 0.82,
  "source_fingerprint": "a4f2...",
  "stale": false,
  "context": "Workspace company profile: ...",
  "media": [],
  "generated_at": "2026-07-09T14:00:00Z",
  "created_at": "2026-07-09T13:55:00Z",
  "updated_at": "2026-07-09T14:00:00Z"
}
DELETE/company-profile/media/{media_id}
Remove company profile media

Remove an image or video association from the generated profile context.

profile:write
Response body
{
  "id": 9,
  "object_id": "company_profile_9",
  "workspace_id": 42,
  "source_urls": ["https://example.com"],
  "narrative": "Acme helps growth teams understand demand, plan focused campaigns, and turn first-party signals into measurable action.",
  "summary": "Acme helps launch teams understand and improve growth.",
  "audience": ["Founders", "Growth operators"],
  "positioning": "AI-assisted growth workspace for launch teams.",
  "value_props": ["Ground content in first-party customer data"],
  "feature_set": ["Social scheduling", "Attribution", "Agent workflows"],
  "messaging": { "primary": "Turn workspace data into sharper growth actions." },
  "tone": { "default": "Specific, pragmatic, and product-aware." },
  "visual_identity": { "style": "Clean product-led visuals with clear proof points." },
  "social_posture": { "linkedin": "Educational launch and growth updates." },
  "source_evidence": [{ "source": "https://example.com", "detail": "Homepage positioning and product copy." }],
  "confidence": 0.82,
  "source_fingerprint": "a4f2...",
  "stale": false,
  "context": "Workspace company profile: ...",
  "media": [],
  "generated_at": "2026-07-09T14:00:00Z",
  "created_at": "2026-07-09T13:55:00Z",
  "updated_at": "2026-07-09T14:00:00Z"
}
GET/social-accounts
Connected accounts

List the social accounts available for programmatic content and scheduling.

accounts:read
Response body
[
  {
    "id": 123,
    "object_id": "social_account_123",
    "platform": "linkedin",
    "handle": "acme",
    "display_name": "Acme",
    "status": "connected",
    "external_id": "urn:li:organization:123",
    "connection_type": "oauth",
    "health_status": "ok",
    "health_message": "",
    "provider_metadata": {}
  }
]

Content

GET/posts
List posts

Return recent posts. Add status=draft, scheduled, published, failed, or archived to filter, and limit up to 200.

posts:read
Response body
[
  {
    "id": 42,
    "object_id": "post_42",
    "base_caption": "A customer story with one clear next step.",
    "scheduled_at": null,
    "status": "draft",
    "tags": ["launch", "customer-story"],
    "media_ids": [301],
    "targets": [
      {
        "id": 88,
        "object_id": "post_target_88",
        "social_account_id": 123,
        "platform": "linkedin",
        "caption_override": null,
        "status": "draft",
        "publish_result": {}
      }
    ],
    "created_at": "2026-06-28T00:00:00Z",
    "updated_at": "2026-06-28T00:00:00Z"
  }
]
POST/posts
Create a post

Create a draft with caption, tags, media IDs, social account IDs, and platform overrides.

posts:write
Response body
{
  "id": 42,
  "object_id": "post_42",
  "base_caption": "A customer story with one clear next step.",
  "scheduled_at": null,
  "status": "draft",
  "tags": ["launch", "customer-story"],
  "media_ids": [301],
  "targets": [
    {
      "id": 88,
      "object_id": "post_target_88",
      "social_account_id": 123,
      "platform": "linkedin",
      "caption_override": null,
      "status": "draft",
      "publish_result": {}
    }
  ],
  "created_at": "2026-06-28T00:00:00Z",
  "updated_at": "2026-06-28T00:00:00Z"
}
POST/posts/preview
Preview a post

Dry-run post validation without creating, scheduling, or publishing anything.

posts:write
Response body
{
  "dry_run": true,
  "ready": true,
  "issues": [],
  "post": null
}
GET/posts/{post_id}
Get a post

Read one workspace post by ID, including schedule, targets, media, tags, and publishing state.

posts:read
Response body
{
  "id": 42,
  "object_id": "post_42",
  "base_caption": "A customer story with one clear next step.",
  "scheduled_at": null,
  "status": "draft",
  "tags": ["launch", "customer-story"],
  "media_ids": [301],
  "targets": [
    {
      "id": 88,
      "object_id": "post_target_88",
      "social_account_id": 123,
      "platform": "linkedin",
      "caption_override": null,
      "status": "draft",
      "publish_result": {}
    }
  ],
  "created_at": "2026-06-28T00:00:00Z",
  "updated_at": "2026-06-28T00:00:00Z"
}
PATCH/posts/{post_id}
Update a post

Edit a draft or scheduled post using the same fields as the app composer.

posts:write
Response body
{
  "id": 42,
  "object_id": "post_42",
  "base_caption": "A customer story with one clear next step.",
  "scheduled_at": null,
  "status": "draft",
  "tags": ["launch", "customer-story"],
  "media_ids": [301],
  "targets": [
    {
      "id": 88,
      "object_id": "post_target_88",
      "social_account_id": 123,
      "platform": "linkedin",
      "caption_override": null,
      "status": "draft",
      "publish_result": {}
    }
  ],
  "created_at": "2026-06-28T00:00:00Z",
  "updated_at": "2026-06-28T00:00:00Z"
}
POST/posts/{post_id}/schedule
Schedule a post

Queue a draft for future publishing after the same validation used in the app.

posts:write
Response body
{
  "id": 42,
  "object_id": "post_42",
  "base_caption": "A customer story with one clear next step.",
  "scheduled_at": "2026-07-02T14:30:00Z",
  "status": "scheduled",
  "tags": ["launch", "customer-story"],
  "media_ids": [301],
  "targets": [
    {
      "id": 88,
      "object_id": "post_target_88",
      "social_account_id": 123,
      "platform": "linkedin",
      "caption_override": null,
      "status": "scheduled",
      "publish_result": {}
    }
  ],
  "created_at": "2026-06-28T00:00:00Z",
  "updated_at": "2026-06-28T00:05:00Z"
}
POST/posts/{post_id}/reschedule
Reschedule a post

Move a scheduled or failed post to a new future publish time.

posts:write
Response body
{
  "id": 42,
  "object_id": "post_42",
  "base_caption": "A customer story with one clear next step.",
  "scheduled_at": "2026-07-02T14:30:00Z",
  "status": "scheduled",
  "tags": ["launch", "customer-story"],
  "media_ids": [301],
  "targets": [
    {
      "id": 88,
      "object_id": "post_target_88",
      "social_account_id": 123,
      "platform": "linkedin",
      "caption_override": null,
      "status": "scheduled",
      "publish_result": {}
    }
  ],
  "created_at": "2026-06-28T00:00:00Z",
  "updated_at": "2026-06-28T00:05:00Z"
}
POST/posts/{post_id}/unschedule
Unschedule a post

Clear a scheduled post and return it to draft status.

posts:write
Response body
{
  "id": 42,
  "object_id": "post_42",
  "base_caption": "A customer story with one clear next step.",
  "scheduled_at": null,
  "status": "draft",
  "tags": ["launch", "customer-story"],
  "media_ids": [301],
  "targets": [
    {
      "id": 88,
      "object_id": "post_target_88",
      "social_account_id": 123,
      "platform": "linkedin",
      "caption_override": null,
      "status": "draft",
      "publish_result": {}
    }
  ],
  "created_at": "2026-06-28T00:00:00Z",
  "updated_at": "2026-06-28T00:00:00Z"
}
POST/posts/{post_id}/archive
Archive a post

Archive a draft, scheduled, or failed post without deleting its history.

posts:write
Response body
{
  "id": 42,
  "object_id": "post_42",
  "base_caption": "A customer story with one clear next step.",
  "scheduled_at": null,
  "status": "archived",
  "tags": ["launch", "customer-story"],
  "media_ids": [301],
  "targets": [],
  "created_at": "2026-06-28T00:00:00Z",
  "updated_at": "2026-06-28T00:10:00Z"
}

Media

GET/media
List media assets

Return recent images and videos that can be attached to API-created posts.

media:read
Response body
[
  {
    "id": 301,
    "object_id": "media_301",
    "filename": "media/301-launch-image.png",
    "original_filename": "launch-image.png",
    "content_type": "image/png",
    "size_bytes": 482193,
    "alt_text": "Product dashboard showing a launch report.",
    "usage_count": 1,
    "used_post_labels": ["Launch proof carousel"],
    "last_used_at": "2026-06-28T00:00:00Z",
    "url": "/v1/media/301/file",
    "created_at": "2026-06-28T00:00:00Z"
  }
]
POST/media
Upload media

Upload a JPG, PNG, MP4, or MOV asset with optional alt text.

media:write
Response body
{
  "id": 301,
  "object_id": "media_301",
  "filename": "media/301-launch-image.png",
  "original_filename": "launch-image.png",
  "content_type": "image/png",
  "size_bytes": 482193,
  "alt_text": "Product dashboard showing a launch report.",
  "usage_count": 1,
  "used_post_labels": ["Launch proof carousel"],
  "last_used_at": "2026-06-28T00:00:00Z",
  "url": "/v1/media/301/file",
  "created_at": "2026-06-28T00:00:00Z"
}
GET/media/{media_id}/file
Download media

Fetch the stored media bytes for a workspace asset.

media:read
Response body
Binary response body containing the stored media file bytes.

Campaigns

GET/links
List tracked links

Read tracked links with destination URLs, tracking URLs, and attribution keys.

links:read
Response body
[
  {
    "id": 77,
    "object_id": "link_77",
    "label": "Summer launch",
    "destination_url": "https://example.com/summer",
    "tracking_url": "https://example.com/summer?utm_source=linkedin&utm_medium=organic&utm_campaign=summer_launch&utm_content=carousel&swell_link_id=tl_summer_launch",
    "post_url": "https://s.growonswell.com/r/summer-launch",
    "post_id": null,
    "social_account_id": 123,
    "attribution_key": "tl_summer_launch",
    "utm_source": "linkedin",
    "utm_medium": "organic",
    "utm_campaign": "summer_launch",
    "utm_content": "carousel",
    "tracking_params": {
      "swell_link_id": "tl_summer_launch"
    },
    "created_at": "2026-06-28T00:00:00Z",
    "updated_at": "2026-06-28T00:00:00Z"
  }
]
POST/links
Create a tracked link

Create a campaign link with UTM fields and optional post or social account context.

links:write
Response body
{
  "id": 77,
  "object_id": "link_77",
  "label": "Summer launch",
  "destination_url": "https://example.com/summer",
  "tracking_url": "https://example.com/summer?utm_source=linkedin&utm_medium=organic&utm_campaign=summer_launch&utm_content=carousel&swell_link_id=tl_summer_launch",
  "post_url": "https://s.growonswell.com/r/summer-launch",
  "post_id": null,
  "social_account_id": 123,
  "attribution_key": "tl_summer_launch",
  "utm_source": "linkedin",
  "utm_medium": "organic",
  "utm_campaign": "summer_launch",
  "utm_content": "carousel",
  "tracking_params": {
    "swell_link_id": "tl_summer_launch"
  },
  "created_at": "2026-06-28T00:00:00Z",
  "updated_at": "2026-06-28T00:00:00Z"
}

Analytics

GET/analytics/overview
Web analytics overview

Read visitors, pageviews, conversions, revenue, sources, pages, performance, and recent events.

analytics:read
Response body
{
  "metrics": {
    "visitors": 1820,
    "pageviews": 6410,
    "conversions": 84,
    "revenue_cents": 125000
  },
  "top_sources": [
    {
      "source": "linkedin",
      "medium": "organic",
      "visitors": 640,
      "pageviews": 2110,
      "sessions": 710,
      "events": 3820,
      "conversions": 38,
      "revenue_cents": 42000
    }
  ],
  "top_pages": [
    {
      "path": "/pricing",
      "title": "Pricing",
      "visitors": 420,
      "sessions": 460,
      "pageviews": 920,
      "bounce_rate": 0.32,
      "conversions": 21,
      "revenue_cents": 21000
    }
  ],
  "traffic_series": [],
  "devices": [],
  "browsers": [],
  "countries": [],
  "web_vitals": [],
  "web_vital_pages": [],
  "web_vital_series": [],
  "recent_events": [],
  "recommendations": [],
  "snippet": {
    "workspace_id": 42,
    "workspace_slug": "acme-growth",
    "tracking_key": "swl_pk_live_...",
    "script_url": "https://api.growonswell.com/swell.js",
    "snippet": "<script src=\"https://api.growonswell.com/swell.js?key=swl_pk_live_...\" async></script>"
  }
}
GET/people
List people

Read known contacts and anonymous visitors assembled from tracking, identity calls, conversions, and trusted revenue.

analytics:read
Response body
[
  {
    "key": "contact:314",
    "kind": "contact",
    "contact": {
      "id": 314,
      "email": "jane@example.com",
      "full_name": "Jane Doe",
      "company": "Acme",
      "lifecycle_stage": "customer",
      "source": "linkedin",
      "medium": "organic",
      "campaign": "summer_launch",
      "tags": ["trial"],
      "metadata": {},
      "first_seen_at": "2026-06-28T00:00:00Z",
      "last_seen_at": "2026-06-29T00:00:00Z",
      "created_at": "2026-06-28T00:00:00Z",
      "updated_at": "2026-06-29T00:00:00Z"
    },
    "anonymous_id": "visitor_abc",
    "display_name": "Jane Doe",
    "email": "jane@example.com",
    "company": "Acme",
    "lifecycle_stage": "customer",
    "source": "linkedin",
    "medium": "organic",
    "campaign": "summer_launch",
    "tags": ["trial"],
    "first_seen_at": "2026-06-28T00:00:00Z",
    "last_seen_at": "2026-06-29T00:00:00Z",
    "session_count": 3,
    "event_count": 18,
    "pageview_count": 9,
    "conversion_count": 2,
    "total_revenue_cents": 42000,
    "first_url": "https://example.com/",
    "first_path": "/",
    "last_url": "https://example.com/pricing",
    "last_path": "/pricing",
    "last_title": "Pricing"
  }
]
GET/people/journey
Get a person journey

Read a contact or visitor journey by contact_id, email, or anonymous_id, including attributed revenue totals.

analytics:read
Response body
{
  "contact": {
    "id": 314,
    "email": "jane@example.com",
    "full_name": "Jane Doe",
    "company": "Acme",
    "lifecycle_stage": "customer",
    "source": "linkedin",
    "medium": "organic",
    "campaign": "summer_launch",
    "tags": ["trial"],
    "metadata": {},
    "first_seen_at": "2026-06-28T00:00:00Z",
    "last_seen_at": "2026-06-29T00:00:00Z",
    "created_at": "2026-06-28T00:00:00Z",
    "updated_at": "2026-06-29T00:00:00Z"
  },
  "anonymous_ids": ["visitor_abc"],
  "session_count": 3,
  "first_seen_at": "2026-06-28T00:00:00Z",
  "last_seen_at": "2026-06-29T00:00:00Z",
  "total_events": 18,
  "total_revenue_cents": 42000,
  "events": []
}

Audit and webhooks

GET/audit-log
List audit log events

Read immutable workspace audit events for API keys, public API mutations, and webhook configuration.

audit:read
Response body
[
  {
    "id": 501,
    "event_id": "audit_event_501",
    "action": "post.created",
    "resource_type": "post",
    "resource_id": 42,
    "object_id": "post_42",
    "api_key_id": 12,
    "metadata": {},
    "created_at": "2026-06-28T00:00:00Z"
  }
]
GET/webhooks
List webhook endpoints

Read active and archived webhook endpoints for the workspace.

webhooks:read
Response body
[
  {
    "id": 7,
    "object_id": "webhook_endpoint_7",
    "url": "https://example.com/swell/webhook",
    "description": "Automation sink",
    "events": ["audit.event.created"],
    "status": "active",
    "last_delivery_at": null,
    "created_at": "2026-06-28T00:00:00Z",
    "updated_at": "2026-06-28T00:00:00Z"
  }
]
POST/webhooks
Create a webhook endpoint

Register an HTTPS webhook endpoint and receive its signing secret once.

webhooks:write
Response body
{
    "id": 7,
  "object_id": "webhook_endpoint_7",
  "url": "https://example.com/swell/webhook",
  "description": "Automation sink",
  "events": ["audit.event.created"],
  "status": "active",
  "last_delivery_at": null,
  "created_at": "2026-06-28T00:00:00Z",
  "updated_at": "2026-06-28T00:00:00Z",
  "signing_secret": "whsec_..."
}
POST/webhooks/{endpoint_id}/archive
Archive a webhook endpoint

Disable a webhook endpoint while preserving audit and delivery history.

webhooks:write
Response body
{
  "id": 7,
  "object_id": "webhook_endpoint_7",
  "url": "https://example.com/swell/webhook",
  "description": "Automation sink",
  "events": ["audit.event.created"],
  "status": "archived",
  "last_delivery_at": null,
  "created_at": "2026-06-28T00:00:00Z",
  "updated_at": "2026-06-28T00:00:00Z"
}
GET/webhooks/deliveries
List webhook deliveries

Read pending, delivered, and failed webhook delivery records.

webhooks:read
Response body
[
  {
    "id": 900,
    "object_id": "webhook_delivery_900",
    "endpoint_id": 7,
    "event_type": "audit.event.created",
    "status": "pending",
    "attempt_count": 0,
    "next_attempt_at": "2026-06-28T00:00:00Z",
    "delivered_at": null,
    "last_error": "",
    "created_at": "2026-06-28T00:00:00Z"
  }
]

Examples

Create a draft

curl -X POST "https://api.growonswell.com/v1/posts" \
  -H "Authorization: Bearer $SWELL_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "base_caption": "A customer story with one clear next step.",
    "scheduled_at": null,
    "tags": ["launch", "customer-story"],
    "media_ids": [],
    "social_account_ids": [123],
    "platform_captions": {
      "linkedin": "A customer story with one clear next step."
    }
  }'

Upload media

curl -X POST "https://api.growonswell.com/v1/media" \
  -H "Authorization: Bearer $SWELL_API_KEY" \
  -F "file=@launch-image.png;type=image/png" \
  -F "alt_text=A product dashboard with a clean launch report."

Schedule a post

curl -X POST "https://api.growonswell.com/v1/posts/42/schedule" \
  -H "Authorization: Bearer $SWELL_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"scheduled_at": "2026-07-02T14:30:00Z"}'

Create a tracked link

curl -X POST "https://api.growonswell.com/v1/links" \
  -H "Authorization: Bearer $SWELL_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "label": "Summer launch",
    "destination_url": "https://example.com/summer",
    "utm_source": "linkedin",
    "utm_medium": "organic",
    "utm_campaign": "summer_launch",
    "utm_content": "carousel"
  }'

Errors

401 means the API key is missing, malformed, revoked, or invalid.

402 means the key owner must select a plan before making API calls.

403 means the key lacks the required scope or the key owner no longer has workspace access.

429 means the key exceeded its rate limit. Wait the number of seconds in `Retry-After` before retrying.

422 means the payload failed Swell validation, such as an unavailable social account or a past scheduled time.