{
    "info": {
        "name": "Publicasta Publishing API",
        "description": "Create articles, upload images, add translations, check moderation status, and schedule publication through the Publicasta Publishing API.",
        "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
    },
    "variable": [
        {
            "key": "base_url",
            "value": "https://publicasta.com",
            "type": "string"
        },
        {
            "key": "channel_slug",
            "value": "demo_project",
            "type": "string"
        },
        {
            "key": "api_key",
            "value": "PASTE_API_KEY_HERE",
            "type": "secret"
        },
        {
            "key": "image_path",
            "value": "/absolute/path/to/illustration.png",
            "type": "string"
        },
        {
            "key": "image_url",
            "value": "PASTE_UPLOADED_IMAGE_URL_HERE",
            "type": "string"
        },
        {
            "key": "article_slug",
            "value": "agent_post",
            "type": "string"
        },
        {
            "key": "scheduled_at",
            "value": "2026-05-20T10:00:00+00:00",
            "type": "string"
        }
    ],
    "item": [
        {
            "name": "List channels",
            "request": {
                "method": "GET",
                "header": [
                    {
                        "key": "Accept",
                        "value": "application/json"
                    }
                ],
                "auth": {
                    "type": "bearer",
                    "bearer": [
                        {
                            "key": "token",
                            "value": "{{api_key}}",
                            "type": "string"
                        }
                    ]
                },
                "url": {
                    "raw": "{{base_url}}/api/v1/channels",
                    "host": [
                        "{{base_url}}"
                    ],
                    "path": [
                        "api",
                        "v1",
                        "channels"
                    ]
                },
                "description": "Returns channels owned by the API key owner. Call this before creating a channel to avoid duplicates."
            }
        },
        {
            "name": "Create channel",
            "request": {
                "method": "POST",
                "header": [
                    {
                        "key": "Accept",
                        "value": "application/json"
                    },
                    {
                        "key": "Content-Type",
                        "value": "application/json"
                    }
                ],
                "auth": {
                    "type": "bearer",
                    "bearer": [
                        {
                            "key": "token",
                            "value": "{{api_key}}",
                            "type": "string"
                        }
                    ]
                },
                "url": {
                    "raw": "{{base_url}}/api/v1/channels",
                    "host": [
                        "{{base_url}}"
                    ],
                    "path": [
                        "api",
                        "v1",
                        "channels"
                    ]
                },
                "body": {
                    "mode": "raw",
                    "raw": "{\n    \"slug\": \"{{channel_slug}}\",\n    \"default_language\": \"en\",\n    \"status\": \"published\",\n    \"translations\": [\n        {\n            \"language\": \"en\",\n            \"title\": \"Agent channel\",\n            \"description\": \"A publishing channel prepared through the Publicasta API.\"\n        }\n    ]\n}",
                    "options": {
                        "raw": {
                            "language": "json"
                        }
                    }
                },
                "description": "Creates a publishing channel. Channel limits are the same as in the dashboard."
            },
            "event": [
                {
                    "listen": "test",
                    "script": {
                        "type": "text/javascript",
                        "exec": [
                            "pm.test('Channel created or validation returned a clear response', function () {",
                            "  pm.expect(pm.response.code).to.be.oneOf([201, 422, 403]);",
                            "});"
                        ]
                    }
                }
            ]
        },
        {
            "name": "Upload channel cover",
            "request": {
                "method": "POST",
                "header": [
                    {
                        "key": "Accept",
                        "value": "application/json"
                    }
                ],
                "auth": {
                    "type": "bearer",
                    "bearer": [
                        {
                            "key": "token",
                            "value": "{{api_key}}",
                            "type": "string"
                        }
                    ]
                },
                "url": {
                    "raw": "{{base_url}}/api/v1/channels/{{channel_slug}}/media",
                    "host": [
                        "{{base_url}}"
                    ],
                    "path": [
                        "api",
                        "v1",
                        "channels",
                        "{{channel_slug}}",
                        "media"
                    ]
                },
                "body": {
                    "mode": "formdata",
                    "formdata": [
                        {
                            "key": "purpose",
                            "value": "channel_cover",
                            "type": "text"
                        },
                        {
                            "key": "image",
                            "type": "file",
                            "src": "{{image_path}}"
                        }
                    ]
                },
                "description": "Uploads and immediately sets the channel cover image."
            }
        },
        {
            "name": "Upload channel avatar",
            "request": {
                "method": "POST",
                "header": [
                    {
                        "key": "Accept",
                        "value": "application/json"
                    }
                ],
                "auth": {
                    "type": "bearer",
                    "bearer": [
                        {
                            "key": "token",
                            "value": "{{api_key}}",
                            "type": "string"
                        }
                    ]
                },
                "url": {
                    "raw": "{{base_url}}/api/v1/channels/{{channel_slug}}/media",
                    "host": [
                        "{{base_url}}"
                    ],
                    "path": [
                        "api",
                        "v1",
                        "channels",
                        "{{channel_slug}}",
                        "media"
                    ]
                },
                "body": {
                    "mode": "formdata",
                    "formdata": [
                        {
                            "key": "purpose",
                            "value": "channel_avatar",
                            "type": "text"
                        },
                        {
                            "key": "image",
                            "type": "file",
                            "src": "{{image_path}}"
                        }
                    ]
                },
                "description": "Uploads, crops and immediately sets the channel avatar image."
            }
        },
        {
            "name": "Upload image",
            "request": {
                "method": "POST",
                "header": [
                    {
                        "key": "Accept",
                        "value": "application/json"
                    }
                ],
                "auth": {
                    "type": "bearer",
                    "bearer": [
                        {
                            "key": "token",
                            "value": "{{api_key}}",
                            "type": "string"
                        }
                    ]
                },
                "url": {
                    "raw": "{{base_url}}/api/v1/channels/{{channel_slug}}/media",
                    "host": [
                        "{{base_url}}"
                    ],
                    "path": [
                        "api",
                        "v1",
                        "channels",
                        "{{channel_slug}}",
                        "media"
                    ]
                },
                "body": {
                    "mode": "formdata",
                    "formdata": [
                        {
                            "key": "image",
                            "type": "file",
                            "src": "{{image_path}}"
                        },
                        {
                            "key": "alt",
                            "value": "Generated illustration",
                            "type": "text"
                        }
                    ]
                },
                "description": "Set api_key, channel_slug, and image_path collection variables before sending. Copy markdown or html from the response into the article request. If page_slug is omitted, the image is stored as draft media; you may use that draft URL in every translation and Publicasta rewrites it to the final page media URL when the article is saved or published. If the article already exists and you need the final URL immediately, send page_slug."
            },
            "event": [
                {
                    "listen": "test",
                    "script": {
                        "type": "text/javascript",
                        "exec": [
                            "pm.test('Image uploaded', function () {",
                            "  pm.expect(pm.response.code).to.eql(201);",
                            "});",
                            "",
                            "pm.test('Response has markdown snippet', function () {",
                            "  const json = pm.response.json();",
                            "  pm.expect(json).to.have.property('markdown');",
                            "});"
                        ]
                    }
                }
            ]
        },
        {
            "name": "Create article",
            "request": {
                "method": "POST",
                "header": [
                    {
                        "key": "Accept",
                        "value": "application/json"
                    },
                    {
                        "key": "Content-Type",
                        "value": "application/json"
                    }
                ],
                "auth": {
                    "type": "bearer",
                    "bearer": [
                        {
                            "key": "token",
                            "value": "{{api_key}}",
                            "type": "string"
                        }
                    ]
                },
                "url": {
                    "raw": "{{base_url}}/api/v1/channels/{{channel_slug}}/pages",
                    "host": [
                        "{{base_url}}"
                    ],
                    "path": [
                        "api",
                        "v1",
                        "channels",
                        "{{channel_slug}}",
                        "pages"
                    ]
                },
                "body": {
                    "mode": "raw",
                    "raw": "{\n    \"slug\": \"{{article_slug}}\",\n    \"default_language\": \"en\",\n    \"status\": \"published\",\n    \"publish_translations\": true,\n    \"scheduled_at\": null,\n    \"translations\": [\n        {\n            \"language\": \"en\",\n            \"title\": \"Agent post\",\n            \"excerpt\": \"A separate teaser shown below the title and in previews.\",\n            \"content_markdown\": \"Body from **agent**.\\n\\n![Generated illustration]({{image_url}})\\n\\n## First section\\n\\nContinue the article here.\"\n        },\n        {\n            \"language\": \"ru\",\n            \"title\": \"Post agenta\",\n            \"excerpt\": \"Separate teaser for article cards and the article lead.\",\n            \"content_markdown\": \"Tekst ot **agenta**.\\n\\n## Pervyi razdel\\n\\nProdolzhaite statyu zdes.\"\n        }\n    ]\n}",
                    "options": {
                        "raw": {
                            "language": "json"
                        }
                    }
                },
                "description": "Creates or updates an article. Put the main title in translations[].title, not in content_markdown/content_html. translations[].excerpt is a separate standfirst/teaser shown below the title and in previews; do not copy or truncate the first body paragraph into excerpt if that paragraph remains in content_markdown/content_html. Use ## and ### for body sections. status can be draft or published. When scheduled_at is present, moderation starts immediately and publication happens later. On POST, published or scheduled multi-translation articles publish or schedule all sent translations by default; set publish_translations=false only when secondary translations must stay drafts. Inspect translation_status_summary and translations[].status in the response. If scheduled_paused=true appears later, the article lost scheduled publishing access and needs a new time or manual publication after upgrade."
            },
            "event": [
                {
                    "listen": "test",
                    "script": {
                        "type": "text/javascript",
                        "exec": [
                            "pm.test('Request succeeded', function () {",
                            "  pm.expect(pm.response.code).to.be.oneOf([200, 201]);",
                            "});",
                            "",
                            "pm.test('Response has public URL', function () {",
                            "  const json = pm.response.json();",
                            "  pm.expect(json).to.have.property('url');",
                            "});",
                            "",
                            "pm.test('Response exposes lifecycle status', function () {",
                            "  const json = pm.response.json();",
                            "  pm.expect(json).to.have.property('status');",
                            "  pm.expect(json).to.have.property('translations');",
                            "});"
                        ]
                    }
                }
            ]
        },
        {
            "name": "Get article",
            "request": {
                "method": "GET",
                "header": [
                    {
                        "key": "Accept",
                        "value": "application/json"
                    }
                ],
                "auth": {
                    "type": "bearer",
                    "bearer": [
                        {
                            "key": "token",
                            "value": "{{api_key}}",
                            "type": "string"
                        }
                    ]
                },
                "url": {
                    "raw": "{{base_url}}/api/v1/channels/{{channel_slug}}/pages/{{article_slug}}",
                    "host": [
                        "{{base_url}}"
                    ],
                    "path": [
                        "api",
                        "v1",
                        "channels",
                        "{{channel_slug}}",
                        "pages",
                        "{{article_slug}}"
                    ]
                },
                "description": "Returns current article status, scheduled_at, scheduled_paused, scheduled_pause_reason, published_at, translation_status_summary, translation statuses, and translation content_html."
            }
        },
        {
            "name": "Upsert one translation",
            "request": {
                "method": "PUT",
                "header": [
                    {
                        "key": "Accept",
                        "value": "application/json"
                    },
                    {
                        "key": "Content-Type",
                        "value": "application/json"
                    }
                ],
                "auth": {
                    "type": "bearer",
                    "bearer": [
                        {
                            "key": "token",
                            "value": "{{api_key}}",
                            "type": "string"
                        }
                    ]
                },
                "url": {
                    "raw": "{{base_url}}/api/v1/channels/{{channel_slug}}/pages/{{article_slug}}/translations/es",
                    "host": [
                        "{{base_url}}"
                    ],
                    "path": [
                        "api",
                        "v1",
                        "channels",
                        "{{channel_slug}}",
                        "pages",
                        "{{article_slug}}",
                        "translations",
                        "es"
                    ]
                },
                "body": {
                    "mode": "raw",
                    "raw": "{\n    \"title\": \"Post del agente\",\n    \"excerpt\": \"Resumen corto\",\n    \"content_markdown\": \"Texto del **agente**.\\n\\n## Primera secci\\u00f3n\\n\\nContin\\u00faa el art\\u00edculo aqu\\u00ed.\"\n}",
                    "options": {
                        "raw": {
                            "language": "json"
                        }
                    }
                },
                "description": "Creates or updates a single translation without resending the default language or other translations."
            }
        },
        {
            "name": "Schedule article",
            "request": {
                "method": "PATCH",
                "header": [
                    {
                        "key": "Accept",
                        "value": "application/json"
                    },
                    {
                        "key": "Content-Type",
                        "value": "application/json"
                    }
                ],
                "auth": {
                    "type": "bearer",
                    "bearer": [
                        {
                            "key": "token",
                            "value": "{{api_key}}",
                            "type": "string"
                        }
                    ]
                },
                "url": {
                    "raw": "{{base_url}}/api/v1/channels/{{channel_slug}}/pages/{{article_slug}}/status",
                    "host": [
                        "{{base_url}}"
                    ],
                    "path": [
                        "api",
                        "v1",
                        "channels",
                        "{{channel_slug}}",
                        "pages",
                        "{{article_slug}}",
                        "status"
                    ]
                },
                "body": {
                    "mode": "raw",
                    "raw": "{\n    \"status\": \"scheduled\",\n    \"publish_translations\": true,\n    \"scheduled_at\": \"{{scheduled_at}}\"\n}",
                    "options": {
                        "raw": {
                            "language": "json"
                        }
                    }
                },
                "description": "Changes article status or delayed publication time without resending article content. scheduled_at must be ISO 8601 with an explicit timezone. For existing multilingual articles, publish_translations is required: true submits translations together with the primary language, false keeps secondary translations as drafts. Setting a new scheduled_at clears an account-plan pause."
            }
        }
    ]
}