Sari la conținut

Documentația API

Aceleași operațiuni ca în interfață, prin cheie de API: catalog, articole, publicări, campanii, rapoarte, redactare. Fiecare rută cu permisiunea cerută, câmpurile și un exemplu de răspuns. Aceeași sursă ca fișierul OpenAPI.

Autentificare

Cheia se trimite în antetul `Authorization`. Se emite din pagina de integrări și se vede o singură dată — noi păstrăm doar amprenta ei, exact ca la parole.

curl --location 'https://app.comunicate.top/api/v1/partner/balance' \
  --header 'Authorization: Bearer bk_live_…'
Adresa de bază
https://app.comunicate.top/api/v1
Limita de cereri
Per cheie, pe minut — scrisă pe cheie când o emiți. O integrare scăpată de sub control nu blochează celelalte chei ale aceluiași cont. Depășirea întoarce 429 cu `Retry-After`, nu 403: singurul caz în care reîncercarea are sens.
Rutele cu AI
Scrierea, importul de documente și completarea metadatelor au o limită în plus: șaizeci pe oră, pe organizație, indiferent câte chei ai. Consumă din cotele modelelor, care sunt ale platformei, nu ale contului tău — iar un singur client care le-ar epuiza ar opri generarea pentru toți.
Organizația
Vine din cheie, nu din adresă. Nu există niciun `organizationId` de trimis, și nici de greșit.
Erorile
Cod HTTP real — 400, 401, 403, 404, 409 — și un corp cu `message`. La validare, `errors` spune care câmp și de ce.

Un răspuns de eroare

{
  "message": "Datele trimise nu sunt valide",
  "errors": [{ "path": "tags", "code": "invalid_type", "message": "Expected array, received string" }]
}

Permisiuni

Fiecare cheie primește doar permisiunile de care are nevoie. O integrare care citește catalogul n-are cum să publice, oricât ar încerca.

  • CATALOG_READCitirea catalogului de publicații și a tipurilor de campanie.
  • ARTICLES_READCitirea articolelor organizației.
  • ARTICLES_WRITECrearea și modificarea articolelor, importul de documente și din Drive, cererea de redactare.
  • MEDIA_WRITEÎncărcarea de imagini în galerie.
  • PUBLICATIONS_READCitirea publicărilor și a stării lor.
  • PUBLICATIONS_WRITECererea de publicare — singura permisiune care cheltuie credite sau bani.
  • CAMPAIGNS_READCitirea campaniilor.
  • CAMPAIGNS_WRITECrearea campaniilor.
  • BALANCE_READCitirea soldului și a pachetelor deținute.
  • REPORTS_READCitirea rapoartelor pe interval.
35 rute

Catalogul public

Patru rute care merg fără nicio cheie: nișele rețelei, o nișă cu publicații de probă, cifrele catalogului și statistica pieței. Sunt aceleași date pe care le arată site-ul public, servite ca JSON — bune pentru comparații, pentru un asistent care vrea să știe ce e în rețea, sau pentru cine vrea să vadă cum arată datele înainte să-și facă cont. Nu există rută publică pentru lista întreagă de publicații, deliberat: inventarul nu se descarcă dintr-o cerere.

GET/public/statsCifrele cataloguluifără cheie

Câte publicații active are rețeaua și pe câte nișe. Fără cheie.

Exemplu

curl 'https://app.comunicate.top/api/v1/public/stats'

Câmpuri din răspuns

publicationsintegerPublicații active.
nichesintegerNișe cu publicații.

Răspuns

{ "publications": 3822, "niches": 21 }
GET/public/nichesNișele rețeleifără cheie

Toate nișele, cu numărul de publicații și autoritatea medie a fiecăreia. Fără cheie.

Parametri

locale'ro' | 'en'Limba numelor și descrierilor. Implicit `ro`.

Exemplu

curl 'https://app.comunicate.top/api/v1/public/niches?locale=ro'

Câmpuri din răspuns

slugstringIdentificatorul nișei, folosit în ruta următoare.
namestringNumele nișei în limba cerută.
descriptionstringCe fel de materiale primesc publicațiile din nișă.
publicationCountintegerCâte publicații active are nișa.
averageDaintegerAutoritatea de domeniu medie (Moz DA).

Răspuns

[
  {
    "slug": "stiri",
    "name": "Știri",
    "description": "Publicațiile de actualitate generală din rețea…",
    "publicationCount": 1299,
    "averageDa": 38
  }
]
GET/public/niches/{slug}O nișă, cu publicații de probăfără cheie

Nișa cerută și câteva publicații din ea, cu autoritate, termen, preț și felul marcajului publicitar. E o mostră, nu inventarul: lista întreagă se vede din cont.

Parametri

locale'ro' | 'en'Limba numelor și descrierilor. Implicit `ro`.

Exemplu

curl 'https://app.comunicate.top/api/v1/public/niches/stiri?locale=ro'

Câmpuri din răspuns

slugstringIdentificatorul nișei.
namestringNumele nișei.
publicationCountintegerCâte publicații are nișa în total.
averageDaintegerAutoritatea medie a nișei.
publicationsobject[]Mostra: `domain`, `language`, `metricDa`, `metricPa`, `deliveryDays`, `priceCents`, `currency`, `marcaj`.

Răspuns

{
  "slug": "stiri",
  "name": "Știri",
  "publicationCount": 1299,
  "averageDa": 38,
  "publications": [
    {
      "domain": "corrierefiorentino.corriere.it",
      "language": "it",
      "metricDa": 92,
      "metricPa": 62,
      "deliveryDays": 2,
      "priceCents": 1296200,
      "currency": "RON",
      "marcaj": "PROPRIU"
    }
  ]
}
GET/public/statistici-piataStatistica piețeifără cheie

Cifrele agregate ale catalogului: câte publicații, câte din rețeaua proprie, distribuția autorității, termenele și prețul pe fiecare tip de campanie. Datele din spatele paginii „Cât costă un advertorial".

Exemplu

curl 'https://app.comunicate.top/api/v1/public/statistici-piata'

Câmpuri din răspuns

publicatiiintegerPublicații active cu preț public.
reteaintegerCâte dintre ele sunt ale noastre.
autoritateobjectMinim, maxim, mediană, medie și distribuția pe intervale.
termeneobject[]Câte publicații livrează în câte zile.
preturiobject[]Pe fiecare tip de campanie: preț, minim, maxim și câte publicații îl acceptă.

Răspuns

{
  "publicatii": 3822,
  "retea": 109,
  "autoritate": { "minim": 1, "maxim": 92, "mediana": 35, "medie": 34 },
  "termene": [{ "zile": 2, "cate": 3822 }],
  "preturi": [
    { "tip": "PRESS_RELEASE", "lei": 35, "minim": 35, "maxim": 14868, "publicatii": 1737 }
  ]
}

Cheia și permisiunile

Prima cerere a oricărei integrări: cine e cheia și ce are voie. Tot aici se vede dacă organizația a pornit „asistenții AI pot comanda și publica" — comutatorul care decide ce poate face un asistent MCP cu banii contului.

GET/partner/meCine suntorice cheie

Organizația din spatele cheii, permisiunile ei și comutatorul pentru asistenți AI. Nu cere nicio permisiune: orice cheie validă poate întreba.

Exemplu

curl --location 'https://app.comunicate.top/api/v1/partner/me' \
  --header 'Authorization: Bearer bk_live_…'

Câmpuri din răspuns

organizationobject`id` și `name`.
scopesstring[]Permisiunile cheii.
aiPublishingboolean`true` dacă asistenții AI pot comanda publicări și redactare (Integrări → Asistenți AI).

Răspuns

{
  "organization": { "id": "e0b5…", "name": "Agenția Exemplu SRL" },
  "keyPrefix": "bk_live_a1b2",
  "scopes": ["CATALOG_READ", "ARTICLES_WRITE"],
  "aiPublishing": false
}

Catalog

Ce publicații există, cât costă pe fiecare tip de campanie și dacă le poți plăti din pachetele pe care le ai.

GET/partner/catalogLista publicațiilorCATALOG_READ

Catalogul paginat, cu aceleași filtre ca în interfață. Fiecare intrare spune și cum se poate plăti: din pachet, din sold, sau deloc.

Parametri

pageintPagina cerută, de la 1.
pageSizeintCâte intrări pe pagină, cel mult 100.
searchstringCaută în nume și domeniu.
campaignstringDoar publicațiile care acceptă tipul dat (vezi `campaign-types`).
serviceTypestring`PUBLISH_ONLY`, `WRITE_AND_PUBLISH`, `HOMEPAGE_PLACEMENT` sau `FACEBOOK_SHARE`. Pentru celelalte trei, doar site-urile cu o ofertă activă de tipul cerut apar în listă — publicarea simplă e serviciul de bază, îl are orice site cu preț.

Exemplu

curl --location 'https://app.comunicate.top/api/v1/partner/catalog?page=1&campaign=SEO' \
  --header 'Authorization: Bearer bk_live_…'

Câmpuri din răspuns

entries[].iduuidId-ul publicației. Cu el se cere publicarea.
entries[].metricsobjectDR, DA, PA și numărul de backlinkuri. `null` unde nu avem citire.
entries[].auditobject | null`flagged` e singurul câmp care schimbă o decizie: un site marcat de Google ca periculos n-ar trebui cumpărat.
entries[].preturiCampaniiobjectPrețul publicării, pe fiecare tip de campanie acceptat, în bani.
entries[].accessobject`OWN` (site propriu), `CREDIT` (acoperit de un pachet), `MONEY` (se plătește din sold), `UNAVAILABLE`. Când `packages` are mai multe intrări, publicarea cere `packageTypeId`.
entries[].masuratobjectCe am măsurat noi din propriile comenzi: media orelor până la apariție, câte publicări verificate mai sunt în regulă. `null` unde n-am publicat destul.

Răspuns

{
  "entries": [
    {
      "id": "3f1c…",
      "name": "Exemplu.ro",
      "url": "https://exemplu.ro",
      "language": "ro",
      "niches": ["Auto"],
      "metrics": { "dr": 34, "da": 41, "pa": 38, "backlinks": 12045 },
      "audit": { "flagged": false, "threatTypes": [], "perfMobile": 62, "crux": "AVERAGE" },
      "acceptedCampaigns": ["SEO", "BRAND_AWARENESS"],
      "preturiCampanii": { "SEO": 18000, "BRAND_AWARENESS": 15000 },
      "deliveryDays": 2,
      "automat": true,
      "linkPolicy": "DOFOLLOW",
      "maxLinks": 2,
      "access": { "kind": "MONEY", "packages": [], "priceCents": 18000, "currency": "RON", "affordable": true }
    }
  ],
  "page": 1,
  "pageSize": 25,
  "total": 184
}
GET/partner/catalog/{siteId}O publicațieCATALOG_READ

Aceeași formă ca o intrare din listă, plus detaliile care nu încap în listare: condițiile pe fiecare tip de campanie, temele acceptate, ofertele active — redactare, plasare pe homepage, distribuire pe Facebook. Lipsa unei oferte dintr-un tip înseamnă că site-ul nu-l vinde.

Exemplu

curl --location 'https://app.comunicate.top/api/v1/partner/catalog/3f1c…' \
  --header 'Authorization: Bearer bk_live_…'

Răspuns

{
  "id": "3f1c…",
  "name": "Exemplu.ro",
  "acceptedTopics": "Fără politică, fără jocuri de noroc.",
  "offers": [
    { "serviceType": "WRITE_AND_PUBLISH", "words": 700, "priceCents": 25000, "currency": "RON" },
    { "serviceType": "HOMEPAGE_PLACEMENT", "words": null, "priceCents": 5000, "currency": "RON" }
  ]
}
GET/partner/campaign-typesTipurile de campanieCATALOG_READ

Tipul nu e o etichetă, ci un set de condiții pe care articolul le trece sau nu la trimitere. Verificarea lor înainte scutește un lanț de respingeri, una câte una.

Ce tipuri acceptă un site anume e altă întrebare, și stă în catalog, la `acceptedCampaigns`.

Exemplu

curl --location 'https://app.comunicate.top/api/v1/partner/campaign-types' \
  --header 'Authorization: Bearer bk_live_…'

Răspuns

[
  {
    "id": "SEO",
    "rezumat": "Advertorial optimizat: articolul susține un cuvânt-cheie și trimite către pagina promovată.",
    "obligatoriu": [
      "Cel puțin un link către site-ul promovat",
      "Cuvânt-cheie declarat, prezent în text",
      "Minimum 300 de cuvinte"
    ],
    "interzis": ["Ancore fără conținut („click aici")"]
  },
  {
    "id": "CASINO",
    "rezumat": "Jocuri de noroc: se publică doar cu marcajele cerute de lege, pe site-urile care acceptă.",
    "obligatoriu": ["Marcajul 18+", "Avertismentul de joc responsabil", "Licența ONJN a operatorului"],
    "interzis": ["Promisiuni de câștig"]
  }
]

Articole

Un articol intră în platformă pe patru căi: scris de tine în HTML, importat dintr-un document, luat dintr-un folder Drive, sau scris de platformă de la un brief. Toate produc același lucru — o ciornă care se poate publica.

POST/partner/articlesCreează un articol din HTMLARTICLES_WRITE

Calea directă, când ai deja textul. Marcajul trece prin aceeași sanitizare ca importul: scripturile, stilurile inline și elementele care nu-și au locul într-un articol se elimină, iar ce s-a scos apare în răspuns.

Câmpurile de optimizare se normalizează, nu se resping: dacă trimiți cinci cuvinte-cheie despărțite prin virgulă, se păstrează primul; dacă trimiți zece etichete, se păstrează primele trei. Un articol susține un singur termen, iar douăzeci de etichete înseamnă pagini de arhivă cu un singur text.

Corpul cererii

title· obligatoriustring(3–300)Titlul articolului.
contentHtml· obligatoriustring(≤500 000)Corpul articolului, în HTML.
focusKeywordstringCuvântul-cheie pentru care se optimizează. **Unul singur** — dintr-o listă se păstrează primul.
tagsstring[]Cel mult trei, oricâte s-ar trimite. Se acceptă și lista despărțită prin virgulă într-un singur element.
metaDescriptionstring(≤320)Descrierea din rezultatele căutării.
slugstringAdresa propusă a articolului. WordPress o poate schimba la coliziune; ce a ieșit efectiv se citește înapoi și se păstrează pe publicare.
excerptstring(≤1000)Rezumatul folosit de teme în listări și pe pagina de categorie.
featuredImageAltstring(≤300)Textul alternativ al imaginii reprezentative. Lipsa lui e una dintre constatările pe care le raportează analiza SEO.
seoTitlestring(≤200)Titlul din rezultatele căutării, când diferă de cel al articolului.
featuredImageUrlstringImaginea reprezentativă. Poate fi adresa întoarsă de `POST /partner/media`.
campaignIduuidCampania în care intră articolul.
idempotencyKeystring(≤200)Aleasă de tine — un UUID generat local e suficient. Trimisă din nou, cu aceeași organizație, întoarce articolul deja creat în loc să facă unul nou. Fără efect la `PATCH`. Recomandat pentru orice cod care poate retrimite cererea după un timeout.

Exemplu

curl --location 'https://app.comunicate.top/api/v1/partner/articles' \
  --header 'Authorization: Bearer bk_live_…' \
  --header 'Content-Type: application/json' \
  --data '{
    "title": "Ce verifici la o firmă de amenajări înainte să semnezi",
    "contentHtml": "<p>Un contract de amenajare se semnează o dată…</p>",
    "focusKeyword": "amenajări interioare",
    "tags": ["amenajari", "interioare", "design"],
    "idempotencyKey": "9f2c7e40-9b1e-4c2a-8b0e-2e6a1f9c3d10"
  }'

Răspuns

{
  "id": "2668…",
  "title": "Ce verifici la o firmă de amenajări înainte să semnezi",
  "status": "DRAFT",
  "focusKeyword": "amenajări interioare",
  "tags": ["amenajari", "interioare", "design"],
  "idempotencyKey": "9f2c7e40-9b1e-4c2a-8b0e-2e6a1f9c3d10",
  "version": 1
}
POST/partner/articles/importImportă un documentARTICLES_WRITE

Se acceptă `.docx`, `.doc`, `.odt`, `.rtf`, `.fodt`, `.html` și `.htm`. Formatele vechi trec prin LibreOffice, deci durează câteva secunde în plus.

**Ordinea fișierelor contează**: primul e documentul, al doilea — opțional — imaginea reprezentativă. Nu se poate distinge după numele câmpului, fiindcă fiecare își numește fișierele cum vrea.

Imaginile din corpul documentului se aduc în galerie și se rescriu în text; cele care nu se pot aduce apar în `images.skipReasons`, cu motivul. Metadatele — descriere, etichete — se completează în fundal, după import.

Formular (multipart/form-data)

(primul fișier)· obligatoriufileDocumentul.
(al doilea fișier)fileImaginea reprezentativă, pentru documentele care n-au niciuna în corp.
campaignIduuidCampania în care intră articolul.
folderIduuidFolderul din galerie în care ajung imaginile documentului.

Exemplu

curl --location 'https://app.comunicate.top/api/v1/partner/articles/import' \
  --header 'Authorization: Bearer bk_live_…' \
  --form 'document=@articol.docx' \
  --form 'imagine=@coperta.jpg' \
  --form 'campaignId=8b2e…'

Câmpuri din răspuns

articles[]arrayArticolele create, cu titlu și număr de cuvinte.
imagesobjectCâte imagini au intrat, câte s-au refolosit, câte au fost convertite și de ce au fost ignorate celelalte.
sanitizedobjectCe a eliminat sanitizarea. Dacă articolul arată altfel decât documentul, aici scrie de ce.

Răspuns

{
  "articles": [{ "id": "2668…", "title": "Ce verifici la o firmă de amenajări", "wordCount": 712 }],
  "images": { "imported": 3, "reused": 1, "skipped": 1, "converted": 1, "skipReasons": ["WMF nu poate fi convertit"] },
  "sanitized": { "elements": ["script"], "attributes": ["style"], "links": 2, "relativeLinks": 1 },
  "warnings": []
}
GET/partner/articles/driveCe e într-un folder DriveARTICLES_WRITE

Folderul trebuie partajat „oricine cu linkul": platforma îl citește cu contul ei, clientul nu se loghează nicăieri.

Listarea e un pas separat de import dinadins. Un folder are adesea și ciorne, și versiuni vechi, și documentul bun — iar importul a tot ce se găsește produce zece articole din care se șterg nouă.

Parametri

link· obligatoriustringLinkul folderului, așa cum îl dă Google.

Exemplu

curl --location --get 'https://app.comunicate.top/api/v1/partner/articles/drive' \
  --data-urlencode 'link=https://drive.google.com/drive/folders/1AbC…' \
  --header 'Authorization: Bearer bk_live_…'

Răspuns

{
  "folderId": "1AbC…",
  "fisiere": [
    { "id": "1x…", "nume": "Advertorial final.docx", "mimeType": "application/vnd.openxmlformats-officedocument.wordprocessingml.document", "fel": "document", "marimeOcteti": 84213 },
    { "id": "1y…", "nume": "coperta.jpg", "mimeType": "image/jpeg", "fel": "imagine", "miniatura": "https://…" }
  ]
}
POST/partner/articles/driveImportă din folderul DriveARTICLES_WRITE

Cel mult cincizeci de documente odată. Un document stricat nu oprește restul: rezultatul are o intrare per fișier, cu numărul de articole sau cu eroarea lui.

Imaginea aleasă se descarcă o singură dată și se folosește pentru toate documentele care n-au niciuna în corp.

Corpul cererii

link· obligatoriustringAcelași link de folder ca la listare. Fiecare fișier cerut se verifică împotriva lui: descărcarea se face cu contul platformei, care vede și folderele altor clienți, deci ruta nu acceptă identificatori Drive oarecare.
fisiere· obligatoriuarrayDocumentele alese, cu `id`, `nume` și `mimeType` din listare.
imagineIdstringId-ul unei imagini din același folder, folosită ca reprezentativă.
campaignIduuidCampania în care intră articolele.

Exemplu

curl --location 'https://app.comunicate.top/api/v1/partner/articles/drive' \
  --header 'Authorization: Bearer bk_live_…' \
  --header 'Content-Type: application/json' \
  --data '{
    "link": "https://drive.google.com/drive/folders/1AbC…",
    "fisiere": [{ "id": "1x…", "nume": "Advertorial final.docx", "mimeType": "application/vnd.openxmlformats-officedocument.wordprocessingml.document" }],
    "imagineId": "1y…"
  }'

Răspuns

{
  "rezultate": [
    { "nume": "Advertorial final.docx", "articole": 1 },
    { "nume": "Ciorna veche.doc", "eroare": "Fișierul nu e un document valid sau e protejat cu parolă" }
  ]
}
PATCH/partner/articles/{articleId}Modifică un articolARTICLES_WRITE

Toate câmpurile de la creare, toate opționale. Se trimit doar cele care se schimbă. Aceleași normalizări: un cuvânt-cheie, cel mult trei etichete.

`version` crește **doar când se schimbă titlul sau conținutul**, nu la orice modificare. Ea intră în cheia de idempotență a publicării: un articol corectat și retrimis e o publicare nouă, pe când o etichetă schimbată nu produce alt articol pe site.

Un articol aflat în curs de publicare nu se poate modifica: se întoarce `409`. Worker-ul lucrează pe conținutul citit la începutul procesului, iar o modificare acum ar pune pe site altceva decât ce e în platformă.

Exemplu

curl --location --request PATCH 'https://app.comunicate.top/api/v1/partner/articles/2668…' \
  --header 'Authorization: Bearer bk_live_…' \
  --header 'Content-Type: application/json' \
  --data '{ "metaDescription": "Ce verifici înainte să semnezi contractul." }'

Răspuns

{
  "id": "2668…",
  "metaDescription": "Ce verifici înainte să semnezi contractul.",
  "version": 2
}
GET/partner/articlesLista articolelorARTICLES_READ

Articolele organizației, cel mai recent modificat primul. Paginată pe cursor: `nextCursor` din răspuns se retrimite ca `cursor` pentru pagina următoare, `null` la ultima.

Parametri

cursoruuidId-ul ultimului articol văzut. Lipsă la prima pagină.
limitint (implicit 50, cel mult 200)Câte articole pe pagină.

Exemplu

curl --location 'https://app.comunicate.top/api/v1/partner/articles?limit=50' \
  --header 'Authorization: Bearer bk_live_…'

Răspuns

{
  "items": [
    { "id": "2668…", "title": "Ce verifici la o firmă de amenajări", "status": "DRAFT", "version": 2 }
  ],
  "nextCursor": "9a11…"
}
GET/partner/articles/{articleId}Un articolARTICLES_READ

Articolul întreg, cu textul lui. Aici se vede și dacă o ciornă cerută prin `redactare` s-a terminat: `redactedAt` completat înseamnă gata, iar `redactionFindings` spune ce a rămas nerezolvat.

Exemplu

curl --location 'https://app.comunicate.top/api/v1/partner/articles/e056…' \
  --header 'Authorization: Bearer bk_live_…'

Câmpuri din răspuns

redactedAtdatetime | nullCând s-a terminat de scris. `null` cât timp e la coadă.
redactionFindingsarrayCe n-a ieșit bine, cu `cod` și `mesaj`. Un articol cu constatări blocante se poate trimite, dar are șanse mari să fie respins de publisher.
suggestedCampaignTypestring | nullCe fel de articol pare a fi, după ce l-am citit. Separat dinadins de tipul comandat: un articol clasificat „SEO" dar cumpărat ca mențiune de brand e o întrebare de pus înainte de plată, nu o corectură făcută pe la spate.
classificationConfidenceint | nullDin 100. Regulile singure dau siguranță mare; când a fost nevoie de model ca să despartă doi candidați, e mai mică — și se vede.
classificationReasonstring | nullMotivul, scris pentru un om. Se poate contrazice.
versionintCrește doar la schimbarea titlului sau a conținutului. Intră în cheia de idempotență a publicării.
statusstring`DRAFT`, `IN_REVIEW`, `APPROVED`, `SCHEDULED`, `PUBLISHING`, `PUBLISHED`, `FAILED`, `REJECTED`, `ARCHIVED`.
createdViaApibooleanA intrat printr-o cheie, nu din interfață. Tot ce creezi prin API apare în cont ca orice altceva — la Articole, la Campanii, la Publicări — cu semnul ăsta lângă, ca să se vadă ce a făcut integrarea.

Răspuns

{
  "id": "e056…",
  "title": "Cum alegi un service auto autorizat pentru garanția mașinii",
  "contentHtml": "<h2>…</h2>",
  "redactedAt": "2026-09-03T14:22:10.000Z",
  "redactionFindings": [
    { "cod": "cifre-nesustinute", "mesaj": "Textul dă cifre care nu se află printre datele primite: 250, 400.", "blocant": true }
  ]
}

Comenzi de redactare

Prin API nu se pornește nicio generare. Trimiți o comandă, o vedem, o scriem sau o refuzăm cu motiv, iar tu afli rezultatul pe aceeași cale. Motivul e simplu: o cheie rulează într-un script și poate cere o mie de articole peste noapte, din cote care sunt ale platformei, comune tuturor clienților. Iar un text scris de model, livrat automat și nevăzut de nimeni de la noi, pleacă spre publisheri sub numele nostru.

POST/partner/redactareComandă un articolARTICLES_WRITE

Răspunsul e comanda, cu `status: "NOUA"`. Când e gata, aceeași comandă are `status: "LIVRATA"` și `articleId` completat.

**Se plătește din sold, nu din credite.** Un credit e „o publicare inclusă" dintr-un pachet, nu ore de scris. Prețul se rezervă în clipa în care intră comanda și se consumă la livrare; un refuz, o anulare sau o scriere eșuată la noi îl eliberează integral. Fără sold, comanda e respinsă cu `400` și nu se creează deloc — mai bine un refuz la intrare decât un articol scris pe datorie.

`fapte` e singurul câmp măsurat care schimbă calitatea textului. Cu datele clientului în față, articolul le folosește cu cifrele lor exacte; fără ele rămâne general — corect, dar mai puțin util. Regula e strictă: **doar ce apare acolo are voie să apară în articol ca cifră sau ca nume**.

Corpul cererii

tema· obligatoriustring(10–200)O frază, cum ai spune-o unui redactor. Din ea iese și titlul.
campaignType· obligatoriustringUnul dintre tipurile din `campaign-types`.
cuvinte· obligatoriu500 | 700 | 1000 | 1500Lungimea țintă.
cuvantCheiestringUnul singur, una–patru cuvinte.
brandstringBrandul promovat.
adresaPromovatastringAdresa către care duce articolul.
faptestring[] (≤20)Câte un lucru pe rând: prețuri, ani de activitate, certificări, cine poate fi citat.
campaignIduuidCampania în care intră articolul livrat.
notestring(≤2000)Orice altceva vrei să ne spui despre comandă.
idempotencyKeystring(≤200)Aleasă de tine — un UUID generat local e suficient. Trimisă din nou, cu exact aceleași date, întoarce comanda deja creată în loc să facă una nouă. Recomandat pentru orice cod care poate retrimite cererea după un timeout: fără cheie, o retrimitere creează o a doua comandă și o a doua rezervare de bani.

Exemplu

curl --location 'https://app.comunicate.top/api/v1/partner/redactare' \
  --header 'Authorization: Bearer bk_live_…' \
  --header 'Content-Type: application/json' \
  --data '{
    "tema": "Cum alegi un service auto autorizat pentru garanția mașinii",
    "campaignType": "SEO",
    "cuvinte": 700,
    "cuvantCheie": "service auto autorizat",
    "brand": "Service Exemplu",
    "fapte": ["Service-ul lucrează din 2009.", "Revizia de bază costă 350 de lei."],
    "idempotencyKey": "9f2c7e40-9b1e-4c2a-8b0e-2e6a1f9c3d10"
  }'

Răspuns

{
  "id": "7c1f…",
  "status": "NOUA",
  "tema": "Cum alegi un service auto autorizat pentru garanția mașinii",
  "campaignType": "SEO",
  "cuvinte": 700,
  "priceCents": 3900,
  "currency": "RON",
  "chargedCents": null,
  "articleId": null,
  "rejectionReason": null,
  "idempotencyKey": "9f2c7e40-9b1e-4c2a-8b0e-2e6a1f9c3d10",
  "createdAt": "2026-09-03T12:00:00.000Z",
  "deliveredAt": null
}
GET/partner/redactare/{orderId}Starea unei comenziARTICLES_READ

Stările: `NOUA` (a intrat), `IN_LUCRU` (cineva de la noi a luat-o), `LIVRATA` (`articleId` completat, `chargedCents` spune cât s-a încasat), `REFUZATA` (cu `rejectionReason`), `ANULATA`, `ESUATA` (scrierea n-a reușit la noi). În ultimele trei, suma rezervată se întoarce în sold.

`articleId` se întoarce **numai la livrare**. Cât timp se scrie, ciorna e a noastră: dacă modelul a scos ceva slab, se rescrie sau se refuză, fără ca cineva să fi apucat s-o trimită mai departe.

Un webhook pe `redaction.delivered` scutește interogarea în buclă — între cerere și articol trece o revizie făcută de un om, iar durata ei nu se poate prezice.

Exemplu

curl --location 'https://app.comunicate.top/api/v1/partner/redactare/7c1f…' \
  --header 'Authorization: Bearer bk_live_…'

Răspuns

{
  "id": "7c1f…",
  "status": "LIVRATA",
  "articleId": "e056…",
  "priceCents": 3900,
  "chargedCents": 3900,
  "deliveredAt": "2026-09-03T15:20:00.000Z"
}
GET/partner/redactareComenzile taleARTICLES_READ

`status` filtrează. Cele mai noi primele.

Parametri

statusstring`NOUA`, `IN_LUCRU`, `LIVRATA`, `REFUZATA`, `ANULATA`.

Exemplu

curl --location 'https://app.comunicate.top/api/v1/partner/redactare?status=LIVRATA' \
  --header 'Authorization: Bearer bk_live_…'

Răspuns

[{ "id": "7c1f…", "status": "LIVRATA", "articleId": "e056…" }]
POST/partner/redactare/{orderId}/anuleazaRenunță la o comandăARTICLES_WRITE

Numai cât timp e `NOUA`. Odată ce cineva de la noi a luat-o, munca e făcută sau în curs, iar anularea nu mai e a ta: se întoarce `409`, iar închiderea rămâne un refuz cu motiv, din partea noastră.

Exemplu

curl --location --request POST 'https://app.comunicate.top/api/v1/partner/redactare/7c1f…/anuleaza' \
  --header 'Authorization: Bearer bk_live_…'

Răspuns

{ "id": "7c1f…", "status": "ANULATA" }

Verificări

Ce se poate spune despre un articol fără să cheme niciun model: analiza SEO și potrivirea cu tipul de campanie. Amândouă sunt pe reguli, deci nu costă, nu sunt limitate și dau același răspuns de fiecare dată. Ele **raportează**; nu corectează nimic. Completarea rămâne a ta, printr-un `PATCH`.

GET/partner/articles/{articleId}/seoAnaliza SEOARTICLES_READ

Scor, constatări, statistici și structura de titluri. Scorul e procentul de verificări trecute, nu o promisiune de poziționare.

Ce contează în răspuns e `issues`: fiecare are un `code`, o severitate și un mesaj care spune ce lipsește. Ce se repară — titlu prea lung, descriere lipsă, imagini fără text alternativ — se scrie cu `PATCH /partner/articles/{id}`.

Exemplu

curl --location 'https://app.comunicate.top/api/v1/partner/articles/2668…/seo' \
  --header 'Authorization: Bearer bk_live_…'

Câmpuri din răspuns

scoreint0–100, procentul verificărilor trecute.
issues[]array`code`, `severity` și `message`.
statsobjectCuvinte, titluri, imagini fără text alternativ, linkuri interne și externe, densitatea cuvântului-cheie, lungimile titlului, descrierii și slugului.
outlinearrayStructura de titluri, cu nivelul fiecăruia.

Răspuns

{
  "score": 78,
  "issues": [
    { "code": "meta-description-missing", "severity": "warning", "message": "Articolul n-are descriere meta.", "autoFixable": false }
  ],
  "stats": { "wordCount": 712, "headingCount": 5, "imageCount": 2, "imagesWithoutAlt": 1, "internalLinks": 0, "externalLinks": 2, "keywordCount": 6, "keywordDensity": 0.84, "titleLength": 74, "metaLength": 0, "slugLength": 0 },
  "outline": [{ "level": 2, "text": "Devizul, pe articole" }]
}
GET/partner/articles/{articleId}/potrivireSe potrivește cu tipul de campanie?ARTICLES_READ

Altă întrebare decât analiza SEO: aceea spune cât de bine e scris textul, asta spune dacă e articolul **comandat**. Un text impecabil SEO e un refuz sigur într-o campanie de mențiune de brand, fiindcă poartă linkuri.

Verificarea oprește oricum comanda la trimitere. Fără ruta asta, singura cale de a afla era să încerci — articol cu articol, din erori. Răspunsul include și `cerinte`, ca mesajul către client să nu fie doar „nu se potrivește".

Când articolul e într-o campanie legată de un tip, verdictul vine oricum pe articol, în `potrivireCampanie`; asta e pentru un tip pe care încă nu l-ai ales.

Parametri

campaignTypestringTipul verificat. Implicit `SEO`.

Exemplu

curl --location 'https://app.comunicate.top/api/v1/partner/articles/2668…/potrivire?campaignType=BRAND_MENTION' \
  --header 'Authorization: Bearer bk_live_…'

Răspuns

{
  "potrivit": false,
  "constatari": [
    { "severitate": "BLOCANT", "mesaj": "Articolul are 2 linkuri externe; o mențiune de brand nu duce niciun link." }
  ],
  "cerinte": {
    "rezumat": "Mențiune: brandul apare în text, fără niciun link.",
    "obligatoriu": ["Numele brandului în text", "Minimum 200 de cuvinte"],
    "interzis": ["Orice link extern"]
  }
}
GET/partner/articles/{articleId}/revisionsVersiunile anterioareARTICLES_READ

Textul întreg al fiecărei versiuni înlocuite. Se scrie o revizie la fiecare schimbare de titlu sau conținut — adică exact când crește `version`.

Există pentru momentul în care publisherul spune că articolul de pe site nu mai seamănă cu ce a acceptat: răspunsul cere textul întreg, nu o mostră din jurnal.

Exemplu

curl --location 'https://app.comunicate.top/api/v1/partner/articles/2668…/revisions' \
  --header 'Authorization: Bearer bk_live_…'

Câmpuri din răspuns

curentaobjectVersiunea de acum, ca să existe cu ce compara prima revizie.
revizii[]arrayCel mult cincizeci, de la cea mai recentă. `changedBy` e gol când schimbarea a venit printr-o cheie de API.

Răspuns

{
  "curenta": { "version": 3, "title": "Titlul de acum", "contentHtml": "<p>…</p>" },
  "revizii": [
    { "id": "aa11…", "version": 2, "title": "Titlul dinainte", "contentHtml": "<p>…</p>", "changedBy": null, "createdAt": "2026-09-01T10:00:00.000Z" }
  ]
}
DELETE/partner/articles/{articleId}Șterge un articolARTICLES_WRITE

Răspunde `204` la reușită. Refuzat cu `409` dacă articolul are publicări: istoricul unei publicări trebuie să poată arăta ce s-a trimis, iar un articol publicat se scoate din listă, nu din bază.

Exemplu

curl --location --request DELETE 'https://app.comunicate.top/api/v1/partner/articles/2668…' \
  --header 'Authorization: Bearer bk_live_…'

Răspuns

(fără corp — 204 No Content)

Galerie

POST/partner/mediaÎncarcă o imagineMEDIA_WRITE

JPEG, PNG, GIF, WebP sau AVIF. Tipul se determină din conținut, nu din extensie sau din antet: un fișier deghizat e respins.

Aceeași imagine încărcată de două ori nu se dublează — se recunoaște după amprentă și se întoarce cea existentă. Adresa din răspuns se poate pune direct în `featuredImageUrl` la un articol.

Formular (multipart/form-data)

(fișier)· obligatoriufileImaginea.
folderIduuidFolderul din galerie.

Exemplu

curl --location 'https://app.comunicate.top/api/v1/partner/media' \
  --header 'Authorization: Bearer bk_live_…' \
  --form 'file=@coperta.jpg'

Răspuns

{
  "id": "4e4a…",
  "filename": "coperta.jpg",
  "url": "/api/v1/organizations/adb4…/media/4e4a…/content",
  "mimeType": "image/jpeg",
  "sizeBytes": 84213,
  "width": 1200,
  "height": 630
}

Publicări

O publicare leagă un articol de o publicație. E singurul loc din API care cheltuie credite sau bani.

POST/partner/publicationsCere publicareaPUBLICATIONS_WRITE

Un articol, una sau mai multe publicații.

**Ambiguitatea de plată nu se ghicește.** Când mai multe pachete deținute acoperă același site, cererea se respinge cu `409` și lista opțiunilor; integrarea alege și reia cu `packageTypeId`. A ghici ar însemna să consumăm din pachetul greșit, iar asta nu se poate întoarce.

Corpul cererii

articleId· obligatoriuuuidArticolul de publicat.
siteIds· obligatoriuuuid[]Publicațiile alese din catalog.
campaignType· obligatoriustringTipul campaniei. Trebuie să fie printre `acceptedCampaigns` ale site-ului.
packageTypeIduuidDin ce pachet se plătește, când mai multe acoperă site-ul.
licenseNumberstring(3–100)Licența ONJN a operatorului. Obligatorie la `campaignType: "CASINO"` — publicitatea la jocuri de noroc trebuie s-o afișeze, iar platforma o scrie singură pe articol înainte de trimitere.
extrasBySiteobjectExtrase cerute per site — `"HOMEPAGE_PLACEMENT"`, `"FACEBOOK_SHARE"`, cel mult amândouă. Cheia e `siteId`, valoarea o listă de tipuri; fiecare cerut trebuie să aibă o ofertă activă pe site (vezi `GET /partner/catalog`), altfel cererea se respinge.
scheduledFordatetimeCând să apară, dacă nu imediat.

Exemplu

curl --location 'https://app.comunicate.top/api/v1/partner/publications' \
  --header 'Authorization: Bearer bk_live_…' \
  --header 'Content-Type: application/json' \
  --data '{
    "articleId": "2668…",
    "siteIds": ["3f1c…"],
    "campaignType": "SEO",
    "extrasBySite": { "3f1c…": ["HOMEPAGE_PLACEMENT"] }
  }'

Răspuns

{
  "publications": [
    {
      "id": "9a3b…",
      "siteId": "3f1c…",
      "status": "AWAITING_APPROVAL",
      "amountCents": 18000,
      "paymentSource": "MONEY",
      "extras": [
        { "type": "HOMEPAGE_PLACEMENT", "priceCents": 5000, "currency": "RON", "chargedCents": 5000 }
      ]
    }
  ]
}
GET/partner/publicationsLista publicărilorPUBLICATIONS_READ

Toate publicările organizației. `status` filtrează. Paginată pe cursor: `nextCursor` din răspuns se retrimite ca `cursor` pentru pagina următoare, `null` la ultima.

Pentru urmărirea stării, webhookurile sunt de preferat: `publication.published` vine cu adresa articolului în clipa în care apare, iar interogarea în buclă consumă din limita de cereri fără să afle nimic în plus.

Parametri

statusstring`DRAFT`, `AWAITING_APPROVAL`, `APPROVED`, `PUBLISHING`, `PUBLISHED`, `FAILED`, `REJECTED`, `CANCELLED`.
cursoruuidId-ul ultimei publicări văzute. Lipsă la prima pagină.
limitint (implicit 50, cel mult 200)Câte publicări pe pagină.

Exemplu

curl --location 'https://app.comunicate.top/api/v1/partner/publications?status=PUBLISHED&limit=50' \
  --header 'Authorization: Bearer bk_live_…'

Răspuns

{
  "items": [
    { "id": "9a3b…", "status": "PUBLISHED", "publishedUrl": "https://exemplu.ro/articol", "publishedAt": "2026-09-01T08:14:00.000Z" }
  ],
  "nextCursor": null
}
GET/partner/publications/{publicationId}O publicarePUBLICATIONS_READ

Publicarea întreagă, cu istoricul ei de evenimente și cu motivul, când a eșuat sau a fost respinsă.

Exemplu

curl --location 'https://app.comunicate.top/api/v1/partner/publications/9a3b…' \
  --header 'Authorization: Bearer bk_live_…'

Răspuns

{
  "id": "9a3b…",
  "status": "FAILED",
  "lastError": "Site-ul a răspuns 401 la autentificare",
  "attempts": 3,
  "publishedUrl": null
}

Campanii

Gruparea articolelor și a publicărilor pe client sau pe proiect. Echivalentul „proiectelor" din alte platforme.

GET/partner/campaignsLista campaniilorCAMPAIGNS_READ

`status` filtrează. Paginată pe cursor: `nextCursor` din răspuns se retrimite ca `cursor` pentru pagina următoare, `null` la ultima.

Parametri

statusstring`DRAFT`, `ACTIVE`, `PAUSED`, `COMPLETED`, `ARCHIVED`.
cursoruuidId-ul ultimei campanii văzute. Lipsă la prima pagină.
limitint (implicit 50, cel mult 200)Câte campanii pe pagină.

Exemplu

curl --location 'https://app.comunicate.top/api/v1/partner/campaigns?limit=50' \
  --header 'Authorization: Bearer bk_live_…'

Răspuns

{
  "items": [{ "id": "8b2e…", "name": "Client Exemplu — Q3", "status": "ACTIVE" }],
  "nextCursor": null
}
POST/partner/campaignsCreează o campanieCAMPAIGNS_WRITE

Corpul e strict: un câmp pe care nu-l cunoaște e respins cu `400`, nu ignorat în tăcere. Mai bine o eroare la prima încercare decât o setare care pare aplicată și nu e.

Corpul cererii

name· obligatoriustring(2–150)Numele campaniei.
campaignTypestringLeagă campania de un tip. Fiecare articol care intră în ea e verificat automat împotriva cerințelor tipului, iar verdictul apare pe articol în `potrivireCampanie`. Nu blochează scrierea — refuzul rămâne la comandă, unde e și plata.
clientNamestring(≤150)Eticheta clientului final. E text liber: clienții n-au cont în platformă.
objectivestring(≤500)Ce urmărește campania.
notesstring(≤2000)Însemnări interne.
startsAtdatetimeISO 8601. Trebuie să fie înaintea lui `endsAt`.
endsAtdatetimeISO 8601.
budgetCentsintBuget de urmărit, în bani. Nu e un portofel separat: banii stau în contul organizației.
budgetCreditsintLimită de credite consumate în campanie.
allowedSiteIdsuuid[] (≤500)Site-urile permise. Gol înseamnă „oricare din catalog".
idempotencyKeystring(≤200)Aleasă de tine — un UUID generat local e suficient. Trimisă din nou, cu aceeași organizație, întoarce campania deja creată în loc să facă una nouă. Recomandat pentru orice cod care poate retrimite cererea după un timeout.

Exemplu

curl --location 'https://app.comunicate.top/api/v1/partner/campaigns' \
  --header 'Authorization: Bearer bk_live_…' \
  --header 'Content-Type: application/json' \
  --data '{
    "name": "Client Exemplu — Q3",
    "clientName": "Exemplu SRL",
    "campaignType": "SEO",
    "idempotencyKey": "9f2c7e40-9b1e-4c2a-8b0e-2e6a1f9c3d10"
  }'

Răspuns

{
  "id": "8b2e…",
  "name": "Client Exemplu — Q3",
  "clientName": "Exemplu SRL",
  "campaignType": "SEO",
  "status": "ACTIVE",
  "idempotencyKey": "9f2c7e40-9b1e-4c2a-8b0e-2e6a1f9c3d10",
  "articleCount": 0
}
GET/partner/campaigns/{campaignId}O campanieCAMPAIGNS_READ

Campania, cu articolele și publicările ei.

Exemplu

curl --location 'https://app.comunicate.top/api/v1/partner/campaigns/8b2e…' \
  --header 'Authorization: Bearer bk_live_…'

Răspuns

{ "id": "8b2e…", "name": "Client Exemplu — Q3", "articles": 12, "publications": 34 }
PATCH/partner/campaigns/{campaignId}Modifică o campanieCAMPAIGNS_WRITE

Toate câmpurile de la creare, toate opționale. Se trimit doar cele care se schimbă.

Cel mai des folosit pentru `campaignType`: leagă o campanie deja creată de un tip, sau o scoate cu `null`. Fiecare articol din campanie e reverificat automat împotriva noului tip — vezi `potrivireCampanie` pe articol.

Exemplu

curl --location --request PATCH 'https://app.comunicate.top/api/v1/partner/campaigns/8b2e…' \
  --header 'Authorization: Bearer bk_live_…' \
  --header 'Content-Type: application/json' \
  --data '{ "campaignType": "BRAND_AWARENESS" }'

Răspuns

{ "id": "8b2e…", "name": "Client Exemplu — Q3", "campaignType": "BRAND_AWARENESS", "articleCount": 12 }
DELETE/partner/campaigns/{campaignId}Șterge o campanieCAMPAIGNS_WRITE

Răspunde `204` la reușită. Refuzată cu `409` dacă e activă și are articole — aceeași regulă ca în interfață: o campanie cu istoric se arhivează (`PATCH` cu `status: "ARCHIVED"`), nu se șterge.

Exemplu

curl --location --request DELETE 'https://app.comunicate.top/api/v1/partner/campaigns/8b2e…' \
  --header 'Authorization: Bearer bk_live_…'

Răspuns

(fără corp — 204 No Content)

Sold și rapoarte

GET/partner/balanceSoldul disponibilBALANCE_READ

Pachetele deținute, cu creditul rămas pe fiecare, și soldul în bani. Se verifică înainte de a cere publicarea — altfel integrarea află din eroare, după ce a construit deja articolul.

`available` scade rezervările: o publicare în curs a blocat deja creditul, chiar dacă nu l-a consumat.

Exemplu

curl --location 'https://app.comunicate.top/api/v1/partner/balance' \
  --header 'Authorization: Bearer bk_live_…'

Răspuns

{
  "credits": [
    { "packageTypeId": "c1…", "packageName": "Pachet Regional 20", "available": 14, "total": 20 }
  ],
  "money": { "availableCents": 125000, "currency": "RON" }
}
GET/partner/reports/summaryRezumatul unei perioadeREPORTS_READ

Implicit ultimele 30 de zile. O integrare care nu trimite interval primește ceva util, nu tot istoricul.

Parametri

fromdateÎnceputul intervalului.
todateSfârșitul intervalului.

Exemplu

curl --location 'https://app.comunicate.top/api/v1/partner/reports/summary?from=2026-08-01&to=2026-08-31' \
  --header 'Authorization: Bearer bk_live_…'

Răspuns

{
  "from": "2026-08-01T00:00:00.000Z",
  "to": "2026-08-31T00:00:00.000Z",
  "publications": 42,
  "published": 39,
  "failed": 3,
  "distinctSites": 21,
  "creditsUsed": 18,
  "moneySpentCents": 372000,
  "successRate": 0.93
}
GET/partner/reports/publicationsPublicările din intervalREPORTS_READ

Rând cu rând, pentru raportarea către client.

Exemplu

curl --location 'https://app.comunicate.top/api/v1/partner/reports/publications?from=2026-08-01' \
  --header 'Authorization: Bearer bk_live_…'

Răspuns

[
  { "publishedAt": "2026-08-14T09:02:00.000Z", "article": "Ce verifici la o firmă de amenajări", "site": "exemplu.ro", "url": "https://exemplu.ro/articol", "campaign": "Client Exemplu — Q3" }
]

Webhookuri

Interogarea în buclă a stării unei publicări consumă din limita ta de cereri și află, de cele mai multe ori, că nu s-a schimbat nimic. Un webhook ajunge în clipa în care articolul apare, cu adresa lui. Capetele se configurează din pagina de integrări, nu prin API — cine își schimbă destinația evenimentelor trebuie să fie autentificat ca persoană.

Reîncercări

Un endpoint care nu răspunde cu 2xx (sau nu răspunde deloc) e reîncercat automat, cu pauze din ce în ce mai mari: 30 de secunde, apoi 1, 2, 4, 8, 16, 32 de minute — șapte încercări în total. Dacă tot eșuează, livrarea rămâne vizibilă în pagina de integrări, cu răspunsul primit și motivul, și se poate reîncerca manual de acolo — dacă și reîncercarea manuală eșuează, intră din nou în rotația automată.

Cum se verifică semnătura

Fiecare livrare are `X-Birou-Signature: t=<timp>,v1=<hmac>`. HMAC-SHA256 se calculează peste `<timp>.<corpul brut>`, cu secretul capătului — nu doar peste corp: fără marca de timp, o livrare interceptată ar putea fi retrimisă oricând cu aceeași semnătură validă. Verifică și că `t` e recent.

const [t, v1] = header.split(',').map((p) => p.split('=')[1]);
const expected = crypto
  .createHmac('sha256', secret)
  .update(`${t}.${rawBody}`)
  .digest('hex');
// comparație în timp constant, apoi: Math.abs(Date.now() / 1000 - Number(t)) < 300

Evenimente

  • article.createdUn articol a fost creat, prin orice cale.
  • article.generatedO ciornă cerută din interfață s-a terminat de scris. Comenzile trimise prin API folosesc `redaction.delivered`, fiindcă între cerere și articol trece și o revizie făcută de un om.
  • article.failedScrierea unei ciorne a eșuat.
  • publication.submittedPublicarea a fost trimisă către publisher.
  • publication.publishedArticolul a apărut pe site. Aici vine adresa lui.
  • publication.failedPublicarea a eșuat sau a fost respinsă.
  • indexing.updatedStarea de indexare a unui articol publicat s-a schimbat.
  • order.acceptedPublisherul a acceptat comanda.
  • redaction.deliveredO comandă de redactare a fost livrată. Vine cu `orderId` și `articleId` — de aici se citește articolul.
  • redaction.rejectedO comandă de redactare a fost refuzată. Vine cu motivul.
Documentația API Comunicate.top: rute, permisiuni, exemple