API Documentation
Everything the Smart-Copy dashboard does is available via API: order researched AI texts with images, publish them to WordPress (immediately, as drafts or scheduled), run autoblogging series and receive webhooks. Billed from your account balance.
OpenAPI 3.1 specification
The whole API contract in a single file — generate a client in any language, import it into Postman or hand it to AI tooling. Available without a token.
/api/v1/openapi.jsonQuick start
- Create a key in the dashboard: smart-copy.ai/developers (tick "Test key" to build your integration at zero cost — full validation, simulated responses).
- Base URL:
https://www.smart-copy.ai/api/v1 - Authorise with the header:
Authorization: Bearer sc_live_...
# Order an 8000-character text with an image
curl -X POST "https://www.smart-copy.ai/api/v1/texts" \
-H "Authorization: Bearer sc_live_..." \
-H "Content-Type: application/json" \
-d '{"topic": "How heat pumps work", "length": 8000, "language": "en"}'
# Track status (queued → researching → outlining → writing → generating_image → completed)
curl "https://www.smart-copy.ai/api/v1/texts/TEXT_ID" \
-H "Authorization: Bearer sc_live_..."The dashboard (API tab) also offers an interactive console with a request builder, code generator (cURL / Node.js / Python / PHP) and a call history.
Authentication
| Kind | Prefix | Description |
|---|---|---|
| Personal key | sc_live_ | Full account access (server-to-server). Created in the dashboard, shown once. |
| Test key | sc_test_ | Same validations and response shapes; orders are simulated (X-SmartCopy-Test: true header), zero cost. |
| OAuth 2.0 | sc_at_ | Access tokens issued to third-party apps with the user's consent — see the OAuth section below. |
- Rate limit: 120 requests/min per token (HTTP 429 with a Retry-After header).
-
Idempotency: send an
Idempotency-Keyheader withPOST /texts— a retried request with the same key returns the stored response without charging again. - Billing currency: PLN (the USD rate in /balance is indicative).
Texts
POST/v1/texts
Orders a text. Price is billed degressively per 1000 characters: 1.99 PLN up to 5,000 characters, 1.19 PLN for characters 5,001–15,000, 0.69 PLN above — capped at 29 PLN per text; charged from the balance on placement (POST /v1/estimate returns the exact amount). Batch: send a texts array (max 500) instead of a single object — one order, one charge. Product descriptions (text_type PRODUCT_DESCRIPTION) ordered together in one request get a volume discount: 25+ −25%, 100+ −45%, 500+ −60% (the response includes bulk_discount).
| Parameter | Type | Description |
|---|---|---|
topic | string, required | Topic, 3–300 chars. |
length | number, required | Length in characters, 500–300000 (2000 chars ≈ 1 page). |
language | string | pl | en
(default pl)
|
text_type | string | ARTICLE, BLOG_POST, COMPANY_TEXT, PRODUCT_DESCRIPTION, CATEGORY_DESCRIPTION, REPORT, ANALYSIS, SOCIAL_MEDIA, EMAIL_MARKETING, OTHER |
guidelines | string | Guidelines: tone, audience, what to cover. |
keywords | string[] | SEO keywords, max 10. |
links | object[] | SEO links to weave in: [{url, anchor?}], max 5. |
source_urls | string[] | Your own research sources, max 10. |
source_mode | string | auto | web | academic | hybrid (academic = scholarly sources) |
generate_image | boolean | AI featured image (default true, included). |
outline_approval | boolean | true = writing starts after outline approval in the dashboard (awaiting_outline_approval status). |
wp_site_id | string | WP site for auto-publication (GET /wp-sites). |
wp_status | string | draft | publish | future (future requires wp_scheduled_at) |
wp_scheduled_at | string (ISO 8601) | Publication date, at least 5 minutes ahead. |
Response 201:
{
"id": "d92dfaf2-...",
"object": "text",
"order_id": "f4a286ea-...",
"status": "queued",
"topic": "...",
"length": 8000,
"price": 31.92,
"currency": "PLN",
"revisions_used": 0,
"revisions_limit": 3,
"created_at": "2026-08-10T12:00:00.000Z"
}GET/v1/texts/:id
Status and result. Statuses: queued, researching, outlining, awaiting_outline_approval, writing (with a section {current, total} field), generating_image, completed, failed (funds refunded automatically). Once completed, the response includes html, featured_image {url, alt} and wp_publications.
GET/v1/texts
List texts. Parameters: limit
(1–100, default 20), created_before
(time cursor from next_created_before), wp_site_id (per-site filter).
Response: { "object": "list", "data": [...], "has_more": bool, "next_created_before": "..." }
— next_created_before is present
only when has_more is true.
POST/v1/texts/:id/revision
Free revision of a completed text. Body: {"feedback": "what to change (10–5000 chars)"}
. Limit: 3 revisions/text (403 revision_limit_reached once
exhausted). When done we send a text.completed webhook with
revised: true.
POST/v1/estimate
Price estimate without creating an order. Body: {"length": 8000} → price,
pages, balance and sufficient_balance. For a batch of
product descriptions add "text_type": "PRODUCT_DESCRIPTION", "quantity": 100
→ discounted unit price, total_price
and bulk_discount.
Autoblog
Content series: Smart-Copy plans a ~20-topic cluster (competitor research + site profile when available), writes texts at the chosen pace and publishes to WordPress. Each text is billed from the balance before generation; insufficient funds pause the series.
POST/v1/plans
| Parameter | Type | Description |
|---|---|---|
niche | string | Topic description (min. 20 chars). Optional when site_profile or a wp_site_id with a stored profile is provided — otherwise 422 insufficient_site_info. |
site_profile | object | {title, tagline, categories[], recent_posts[], excerpts[]} — automatic topic detection from the site. |
texts_per_week | number | 1–7 (default 2) |
target_length | number | 3000–30000 (default 8000) |
text_type | string | BLOG_POST | ARTICLE | COMPANY_TEXT |
with_images | boolean | default true |
wp_site_id, wp_status | string | Where to publish; wp_status: publish | draft. |
Also: GET /v1/plans (optionally
?wp_site_id=), GET /v1/plans/:id
(with items and statuses), POST /v1/plans/:id/pause and POST /v1/plans/:id/resume. Series
statuses: planning, active, paused, completed.
Balance & sites
GET/v1/balance
{
"object": "balance",
"balance": 776.56,
"currency": "PLN",
"usd_rate": 3.7324,
"balance_usd": 208.06,
"auto_topup_enabled": false
}GET/v1/wp-sites
WordPress sites connected to the account: id, name, base_url, auth_type (connector | app-password), verified, last_poll_at (live plugin heartbeat).
Webhooki
Configure a webhook URL on an API key (dashboard → API) or on an OAuth application. Events: text.completed (also after revisions, with revised: true), text.failed (with refunded: true — funds returned to the balance), outline.ready. Delivery: JSON POST, exponential retry up to 5 attempts.
POST your-endpoint
X-SmartCopy-Event: text.completed
X-SmartCopy-Signature: sha256=3f5c9a...
{
"event": "text.completed",
"created": "2026-08-10T12:34:56.000Z",
"data": {
"text": {
"id": "d92dfaf2-...",
"topic": "...",
"progress": "completed",
"price": 31.92,
"html": "<h1>...</h1>...",
"featured_image": { "url": "https://...", "alt": "..." }
}
}
}Signature verification (HMAC-SHA256 of the raw body with your whsec_ secret):
const crypto = require("crypto");
const expected = "sha256=" +
crypto.createHmac("sha256", process.env.WEBHOOK_SECRET)
.update(rawBody).digest("hex");
const valid = crypto.timingSafeEqual(
Buffer.from(expected),
Buffer.from(req.headers["x-smartcopy-signature"] || ""));OAuth 2.0
Build applications operating on Smart-Copy user accounts (SaaS integrations, Make.com, Zapier, agency dashboards). Flow: authorization code + PKCE (S256). Register your app in the dashboard → API → "Your OAuth applications" (public with PKCE or confidential with a secret).
| Endpoint | Description |
|---|---|
GET https://www.smart-copy.ai/oauth/authorize | Consent screen. Params: client_id, redirect_uri, response_type=code, scope (space/plus separated), state, code_challenge, code_challenge_method=S256. |
POST https://www.smart-copy.ai/api/oauth/token | Code exchange (grant_type=authorization_code + code_verifier) and refresh (grant_type=refresh_token). JSON or form-urlencoded. Access valid 2 h; refresh 60 days with rotation — reusing a rotated refresh token revokes all of the app's tokens (theft protection). |
POST https://www.smart-copy.ai/api/oauth/revoke | Token revocation (RFC 7009). |
Scopes: texts:read, texts:write (orders billed from
the user's balance), balance:read, wp:read, plans:read, plans:write. Users can view and
revoke access in the dashboard ("Connected applications").
Errors
{ "error": "insufficient_balance", "error_description": "..." }| HTTP | error | Description |
|---|---|---|
| 400 | invalid_request | Invalid parameters (details in error_description, prefixed texts[i] for batches). |
| 401 | invalid_token | Missing/invalid/revoked token. |
| 402 | insufficient_balance | Not enough funds (price and balance fields included). |
| 403 | insufficient_scope / revision_limit_reached / plan_limit_reached | Missing scope or an exhausted limit. |
| 404 | not_found | Resource not found. |
| 409 | conflict | Operation impossible in the current state (e.g. revising a text still generating). |
| 422 | insufficient_site_info | Autoblog: topic could not be detected — provide niche. |
| 429 | rate_limit_exceeded | 120/min limit exceeded (Retry-After header). |
Questions? support@smart-copy.ai