Skip to main content

Python SDK for the Visibly Content Autopilot API - Pull API client, HMAC webhook verification, and Flask Blueprint.

Project description

ai-content-autopilot

Python SDK for the Visibly Content Autopilot API.

Visibly Content Autopilot is an AI-powered content generation platform that creates SEO-optimized articles for your projects. It handles keyword research, content planning, and article generation — then delivers finished articles to your CMS via webhooks or a Pull API.

This SDK gives you everything you need to integrate Content Autopilot into any Python/Flask application:

  • Pull API Client — fetch, list, and confirm articles programmatically
  • Webhook Receiver — a ready-made Flask Blueprint that verifies HMAC signatures, fetches full article content, and calls your handler
  • HMAC-SHA256 Verification — standalone signature verification for custom webhook implementations

How It Works

1. Content Autopilot generates & approves an article
                    |
2. Webhook fires to your endpoint (POST /webhooks/visibly)
   with HMAC-SHA256 signature for security
                    |
3. Your app verifies the signature, then calls the Pull API
   to fetch the full article (HTML, Markdown, keywords, SEO score)
                    |
4. Your app saves/publishes the article in your CMS
                    |
5. Your app confirms publication back to Visibly
   (article status changes to "published")

Installation

pip install ai-content-autopilot

Requirements: Python 3.8+, Flask 2.3+, Requests 2.25+

Getting Started

1. Get your credentials

  • API Key: Go to Account > API Keys and create a new key (starts with sk_live_)
  • Webhook Secret: Go to your Project > CMS Settings and configure a webhook endpoint. The secret is generated automatically.

Full API documentation: Developer Docs

2. Choose your integration style

Option A: Full Flask Blueprint (recommended)

The easiest way to integrate. Register the blueprint and provide a handler function — the SDK handles signature verification, article fetching, and error responses automatically.

from flask import Flask
from ai_content_autopilot import configure_visibly, contentpilot_webhook_bp

app = Flask(__name__)

def my_handler(article):
    """Called when a webhook delivers an article.

    article dict contains:
      id, title, slug, content_html, content_markdown,
      keywords, meta_description, seo_score, word_count,
      _webhook_event, _webhook_timestamp, _scheduled_date
    """
    # Save to your database, CMS, filesystem, etc.
    db.session.add(Post(
        title=article['title'],
        body=article['content_html'],
        slug=article['slug'],
        publish_at=article.get('_scheduled_date'),
    ))
    db.session.commit()
    return True  # Return False to reject (422 response)

configure_visibly(
    webhook_secret='your-webhook-secret',
    api_key='sk_live_your_api_key',
    on_article_received=my_handler,
)

app.register_blueprint(contentpilot_webhook_bp)
# POST /webhooks/visibly is now active and handles:
#   1. HMAC-SHA256 signature verification
#   2. Full article fetch via Pull API
#   3. Calls my_handler(article)
#   4. Returns {"success": true} or appropriate error

Option B: Standalone Pull API Client

Use the client directly to poll for articles or integrate into non-Flask applications.

from ai_content_autopilot import VisiblyClient

client = VisiblyClient(api_key='sk_live_your_api_key')

# List approved articles ready for publishing
articles = client.list_articles(status='approved', project_id=5, limit=20)
for a in articles:
    print(a['id'], a['title'], a.get('scheduled_date'))

# Fetch a single article with full content
article = client.fetch_article(42, include_markdown=True)
print(article['content_html'])
print(article['keywords'])       # e.g. ["seo", "keyword research"]
print(article['seo_score'])      # 0-100

# Confirm publication (updates status to "published" in Visibly)
client.confirm_published(42, 'https://myblog.com/seo-guide-2026')

Option C: HMAC verification only

For custom webhook implementations in any framework.

from ai_content_autopilot import verify_webhook_signature

# In your webhook endpoint:
payload_bytes = request.get_data()       # raw bytes, NOT request.json
signature = request.headers.get('X-Webhook-Signature', '')

if not verify_webhook_signature(payload_bytes, 'your-secret', signature):
    return {'error': 'Invalid signature'}, 401

Article Lifecycle

Status Description Webhook Event
queued Waiting to be generated -
generating AI is writing the article -
draft Draft ready for review -
approved Ready for publishing article.approved
published Confirmed published via API article.published
rejected Rejected by user -
failed Generation failed article.failed

API Reference

Function / Class Description
configure_visibly(webhook_secret, api_key, base_url, on_article_received) Configure the Blueprint with credentials and callback
verify_webhook_signature(payload_bytes, secret, signature_header) Verify HMAC-SHA256 signature. Returns True/False
VisiblyClient(api_key, base_url, timeout) Pull API client for fetching, listing, and confirming articles
client.fetch_article(article_id, include_markdown) Returns article dict or None on error
client.list_articles(status, project_id, limit, offset) Returns list of article dicts
client.confirm_published(article_id, published_url) Confirms publication. Returns True/False
contentpilot_webhook_bp Flask Blueprint. Register with app.register_blueprint(). Endpoint: POST /webhooks/visibly
default_flask_blog_handler(article) Default handler: saves article as JSON to ./content_output/

Webhook Payload

When a webhook fires, the POST /webhooks/visibly endpoint receives a JSON body with these fields:

{
  "event": "article.approved",
  "article_id": 42,
  "title": "SEO Guide 2026",
  "slug": "seo-guide-2026",
  "project_id": 5,
  "scheduled_date": "2026-03-01T09:00:00",
  "pull_url": "https://www.antonioblago.com/content-autopilot/api/v1/articles/42",
  "timestamp": "2026-02-20T10:00:00Z"
}
Field Type Description
event string article.approved, article.published, or article.failed
article_id int Database ID of the article
title string Article title
slug string URL-safe slug
project_id int Owning project ID
scheduled_date string/null ISO 8601 scheduled publish date, or null
pull_url string Full URL to fetch article content via Pull API
timestamp string ISO 8601 UTC timestamp of the event

The Blueprint automatically fetches the full article via pull_url and injects webhook metadata (_webhook_event, _webhook_timestamp, _scheduled_date) into the article dict before calling your handler.

Article Response Fields

When fetching an article via VisiblyClient.fetch_article(), the returned dict contains:

Field Type Description
id int Unique article ID
title string Article title
slug string URL-friendly slug
status string Current status (see Article Lifecycle)
content_html string Full article as HTML
content_markdown string Article as Markdown (only if include_markdown=True)
keywords list Target keywords, e.g. ["seo", "keyword research"]
meta_description string SEO meta description (max 160 chars)
seo_score int SEO optimization score (0-100)
word_count int Article word count
project_id int Owning project ID
published_url string Public URL after publication (empty if unpublished)
scheduled_date string/null Planned publish date (ISO 8601)
created_at string Creation timestamp
updated_at string Last update timestamp

Webhook Security

Every webhook request includes an X-Webhook-Signature header with an HMAC-SHA256 signature:

X-Webhook-Signature: sha256=<hex_digest>

The SDK verifies this automatically when using the Blueprint. The verification uses hmac.compare_digest for timing-safe comparison to prevent timing attacks.

Error Handling

The VisiblyClient methods handle errors gracefully:

  • fetch_article() returns None on any error (404, network failure, timeout)
  • list_articles() returns [] on any error
  • confirm_published() returns False on any error

All errors are logged via Python's logging module at WARNING or ERROR level.

When using the Blueprint, HTTP responses are:

Code Meaning
200 Success — article processed
400 Invalid JSON in webhook payload
401 HMAC signature verification failed
422 Handler returned False (article rejected)
500 Webhook not configured, or handler raised an exception
502 Failed to fetch article from Pull API

Rate Limits

The Visibly API enforces the following rate limits:

Endpoint Limit
GET /api/v1/articles 120 requests/min
GET /api/v1/articles/{id} 60 requests/min
POST /api/v1/articles/{id}/confirm 30 requests/min

When rate-limited, the API returns HTTP 429 with a Retry-After header.

Links

Development

git clone https://github.com/AntonioBlago/ai-content-autopilot.git
cd ai-content-autopilot
pip install -e ".[dev]"
pytest tests/ -v

License

MIT - see LICENSE for details.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

ai_content_autopilot-1.0.2.tar.gz (16.4 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

ai_content_autopilot-1.0.2-py3-none-any.whl (10.8 kB view details)

Uploaded Python 3

File details

Details for the file ai_content_autopilot-1.0.2.tar.gz.

File metadata

  • Download URL: ai_content_autopilot-1.0.2.tar.gz
  • Upload date:
  • Size: 16.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.8

File hashes

Hashes for ai_content_autopilot-1.0.2.tar.gz
Algorithm Hash digest
SHA256 63e0121be4264276758020bf350c0aa8bd505bfdc466d24f976b5f7a84383f9c
MD5 193ff6ff90850b6ad40a48751eb9abe3
BLAKE2b-256 332dfe9e5c3dc7cf3dd45784587478edda97bc240bf6a3d1998d8661a853d526

See more details on using hashes here.

File details

Details for the file ai_content_autopilot-1.0.2-py3-none-any.whl.

File metadata

File hashes

Hashes for ai_content_autopilot-1.0.2-py3-none-any.whl
Algorithm Hash digest
SHA256 fa7a7346cd3e0979006d17142f3e45ff574ae6e964cf4ddf4cf9821b8f1c4829
MD5 3d6d65e32a5488863062a4a7de46d57d
BLAKE2b-256 4a25fa60c4c1088e936e882086bc5a10d42630ffe8be96df5ebef602e7961aea

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page