POST /v1/brands/{brand_id}/cms-connections

Connect a CMS

Connect a WordPress site to this brand so its articles can be published there.

The credentials are verified against the live site before anything is stored: a site that is unreachable, or an application password WordPress rejects, returns 422 validation_error and nothing is saved. Once stored, the application password is encrypted at rest and is never returned by this API.

A brand holds one connection per provider, so posting again for the same provider replaces the stored credentials rather than adding a second connection. That is how you rotate an application password, and the connection keeps its id. Posting a different site replaces the connection with a new one under a new id: the old target_id no longer publishes, and articles already published stay recorded against the site they went to.

Requires OWNER access on the brand.

Path parameters

Query parameters

  • dry_run boolean optional

    Preview the call without executing it. Runs auth, scope, eligibility and body validation, then returns 200 with a dry_run object reporting the request-unit and credit cost plus a non-consuming quota snapshot. Nothing is debited, reserved, dispatched or mutated. An invalid body still returns 422.

    default: false

Header parameters

  • Idempotency-Key string required

    Required with an API key, else 400 idempotency_key_required: a new value per operation (a UUID works). A retry with the same key and body within 24 hours replays the first response instead of running again. Ignored with dry_run=true.

Request body

application/json required
Type: CmsConnectionCreate
  • credentials WordPressCredentials required

    Credentials for the site. Verified against the live site before anything is stored.

    Show fields
    Type: WordPressCredentials
    • application_password string required

      A WordPress application password (Users, then Profile, then Application Passwords), not the account password. Stored encrypted and never returned by this API.

      min length: 1 · max length: 200

    • site_url string required

      Base URL of the WordPress site, for example https://rankprompt.com. Must be https, since the application password is sent on every publish. Hosts that resolve to private, loopback or link-local addresses are rejected.

      min length: 1 · max length: 2000

    • username string required

      WordPress username the application password belongs to.

      min length: 1 · max length: 200

  • provider string

    CMS platform to connect through the API. Only wordpress today; Ghost, Shopify, Webflow, GitHub and webhook destinations are connected from the dashboard, Wix by installing our app on the site from the dashboard and WordPress.com by approving access on WordPress.com from the dashboard, then all are listed here.

    default: `wordpress`

Responses

Connect a CMS application/json
Type: CmsConnection
  • brand_id string required

    Owning brand id (UUID).

  • created_at string required

    When the connection was created.

    format: `date-time`

  • has_credentials boolean required

    True when a secret is stored for this connection. The secret itself is never returned.

  • id string required

    Connection id (UUID). Pass as target_id when publishing.

  • provider string required

    CMS platform, an open set (new values can appear): wordpress, wordpress_com (a site hosted on WordPress.com), ghost, shopify, webflow, wix, github (a connected repository whose blog the article is written into, live once its pull request merges) or a webhook destination.

  • status enum required

    Credential health. connected when we last reached the site, error when a check or publish failed, disconnected when it was never established.

  • updated_at string required

    When the connection was last modified.

    format: `date-time`

  • default_status enum (nullable) nullable

    What the brand's owner chose for every send to this site: draft when each article should land as a draft for someone to review, ask when it is chosen per publish. This API does not apply it for you: publish_status still defaults to publish, so send publish_status: draft when this says draft. Null for a provider without this choice (github, webhook) and for the hosted blog.

  • last_error_at string (nullable) nullable

    When last_error_code was set; null while the connection works.

    format: `date-time`

  • last_error_code string (nullable) nullable

    Why the connection needs its owner, or null when it works. An open set (new values can appear): token_expired, scope_missing, not_selected, auth_failed, permission_missing, site_unreachable, host_moved, app_uninstalled, rate_limited, vendor_down.

  • last_synced_at string (nullable) nullable

    Last time the credentials were confirmed working. Only advances on a successful check.

    format: `date-time`

  • object string

    Always cms_connection.

    default: `cms_connection`

  • settings CmsConnectionSettings

    The owner's other publishing choices for this site, read only. Credentials are never included.

    Show fields
    Type: CmsConnectionSettings
    • author_id integer (nullable) nullable

      wordpress and wordpress_com: the site user posts are credited to, or null for the connected user. Null for other providers.

    • category_ids array of integer | string (nullable) nullable

      wordpress and wordpress_com (numeric ids) and wix (GUIDs): the categories every post goes in, empty for the site's default category. Null for other providers.

    • primary_tag string (nullable) nullable

      ghost: the tag every post leads with, or null for the article's first tag. Null for other providers.

  • site_url string (nullable) nullable

    Where the connection publishes: the site, the Shopify blog or the Webflow collection. For a webhook only its host, since the full URL works as a credential. For github, the repository.

  • username string (nullable) nullable

    Username the stored credential belongs to.

Request validation failed application/json
Type: ApiError
  • error object required
    Show fields
    • code string required

      Stable machine-readable error code from the catalog.

    • message string required

      Human-readable description suitable for logging.

    • details object

      Optional, code-specific context (e.g. errors array for validation_error, retry_after for service_unavailable). Shape depends on error.code; treat as opaque otherwise.

      Show fields

      Empty object (no properties).

  • Server-generated correlation id for the request. Mirrors the X-Correlation-ID response header. Include this when contacting support.

    format: `uuid`

Example response
{
  "error": {
    "code": "validation_error",
    "message": "Request validation failed"
  },
  "request_id": "9f6c4e8a-1d3b-4c8b-9f1e-7a3b1c2d3e4f"
}
Missing or invalid credentials application/json
Type: ApiError
  • error object required
    Show fields
    • code string required

      Stable machine-readable error code from the catalog.

    • message string required

      Human-readable description suitable for logging.

    • details object

      Optional, code-specific context (e.g. errors array for validation_error, retry_after for service_unavailable). Shape depends on error.code; treat as opaque otherwise.

      Show fields

      Empty object (no properties).

  • Server-generated correlation id for the request. Mirrors the X-Correlation-ID response header. Include this when contacting support.

    format: `uuid`

Example response
{
  "error": {
    "code": "unauthorized",
    "message": "Missing or invalid credentials"
  },
  "request_id": "9f6c4e8a-1d3b-4c8b-9f1e-7a3b1c2d3e4f"
}
You do not have permission to access this resource application/json
Type: ApiError
  • error object required
    Show fields
    • code string required

      Stable machine-readable error code from the catalog.

    • message string required

      Human-readable description suitable for logging.

    • details object

      Optional, code-specific context (e.g. errors array for validation_error, retry_after for service_unavailable). Shape depends on error.code; treat as opaque otherwise.

      Show fields

      Empty object (no properties).

  • Server-generated correlation id for the request. Mirrors the X-Correlation-ID response header. Include this when contacting support.

    format: `uuid`

Example response
{
  "error": {
    "code": "forbidden",
    "message": "You do not have permission to access this resource"
  },
  "request_id": "9f6c4e8a-1d3b-4c8b-9f1e-7a3b1c2d3e4f"
}
Resource not found application/json
Type: ApiError
  • error object required
    Show fields
    • code string required

      Stable machine-readable error code from the catalog.

    • message string required

      Human-readable description suitable for logging.

    • details object

      Optional, code-specific context (e.g. errors array for validation_error, retry_after for service_unavailable). Shape depends on error.code; treat as opaque otherwise.

      Show fields

      Empty object (no properties).

  • Server-generated correlation id for the request. Mirrors the X-Correlation-ID response header. Include this when contacting support.

    format: `uuid`

Example response
{
  "error": {
    "code": "not_found",
    "message": "Resource not found"
  },
  "request_id": "9f6c4e8a-1d3b-4c8b-9f1e-7a3b1c2d3e4f"
}
Resource conflict application/json
Type: ApiError
  • error object required
    Show fields
    • code string required

      Stable machine-readable error code from the catalog.

    • message string required

      Human-readable description suitable for logging.

    • details object

      Optional, code-specific context (e.g. errors array for validation_error, retry_after for service_unavailable). Shape depends on error.code; treat as opaque otherwise.

      Show fields

      Empty object (no properties).

  • Server-generated correlation id for the request. Mirrors the X-Correlation-ID response header. Include this when contacting support.

    format: `uuid`

Example response
{
  "error": {
    "code": "conflict",
    "message": "Resource conflict"
  },
  "request_id": "9f6c4e8a-1d3b-4c8b-9f1e-7a3b1c2d3e4f"
}
Request body did not match the expected schema application/json
Type: ApiError
  • error object required
    Show fields
    • code string required

      Stable machine-readable error code from the catalog.

    • message string required

      Human-readable description suitable for logging.

    • details object

      Optional, code-specific context (e.g. errors array for validation_error, retry_after for service_unavailable). Shape depends on error.code; treat as opaque otherwise.

      Show fields

      Empty object (no properties).

  • Server-generated correlation id for the request. Mirrors the X-Correlation-ID response header. Include this when contacting support.

    format: `uuid`

Example response
{
  "error": {
    "code": "body_validation_error",
    "message": "Request body did not match the expected schema"
  },
  "request_id": "9f6c4e8a-1d3b-4c8b-9f1e-7a3b1c2d3e4f"
}
Per-minute rate limit exceeded application/json
Type: ApiError
  • error object required
    Show fields
    • code string required

      Stable machine-readable error code from the catalog.

    • message string required

      Human-readable description suitable for logging.

    • details object

      Optional, code-specific context (e.g. errors array for validation_error, retry_after for service_unavailable). Shape depends on error.code; treat as opaque otherwise.

      Show fields

      Empty object (no properties).

  • Server-generated correlation id for the request. Mirrors the X-Correlation-ID response header. Include this when contacting support.

    format: `uuid`

Example response
{
  "error": {
    "code": "rate_limit_exceeded",
    "message": "Per-minute rate limit exceeded"
  },
  "request_id": "9f6c4e8a-1d3b-4c8b-9f1e-7a3b1c2d3e4f"
}
An unexpected error occurred application/json
Type: ApiError
  • error object required
    Show fields
    • code string required

      Stable machine-readable error code from the catalog.

    • message string required

      Human-readable description suitable for logging.

    • details object

      Optional, code-specific context (e.g. errors array for validation_error, retry_after for service_unavailable). Shape depends on error.code; treat as opaque otherwise.

      Show fields

      Empty object (no properties).

  • Server-generated correlation id for the request. Mirrors the X-Correlation-ID response header. Include this when contacting support.

    format: `uuid`

Example response
{
  "error": {
    "code": "internal_error",
    "message": "An unexpected error occurred"
  },
  "request_id": "9f6c4e8a-1d3b-4c8b-9f1e-7a3b1c2d3e4f"
}
Service temporarily unavailable, please retry application/json
Type: ApiError
  • error object required
    Show fields
    • code string required

      Stable machine-readable error code from the catalog.

    • message string required

      Human-readable description suitable for logging.

    • details object

      Optional, code-specific context (e.g. errors array for validation_error, retry_after for service_unavailable). Shape depends on error.code; treat as opaque otherwise.

      Show fields

      Empty object (no properties).

  • Server-generated correlation id for the request. Mirrors the X-Correlation-ID response header. Include this when contacting support.

    format: `uuid`

Example response
{
  "error": {
    "code": "service_unavailable",
    "message": "Service temporarily unavailable, please retry"
  },
  "request_id": "9f6c4e8a-1d3b-4c8b-9f1e-7a3b1c2d3e4f"
}