Dokumentáció
Kézbesítési webhook: cikkek fogadása a saját webhelyén
Az aláírt webhook, amely az AutoPSEO cikkeit a webhelyére küldi: fejlécek, az egyes események és hasznos adataik, a küldendő válaszok, az újrapróbálkozások, a várakozó parancsok és az IndexNow.
Az AutoPSEO minden cikket, amelyet közzétesz, frissít vagy levesz, aláírt HTTPS POST-kérésként elküld a saját webhelyére. A webhelye eltárolja a cikket, és a saját sablonjaival jeleníti meg, így a tartalom az Ön rendszerében marad, és akkor is működik tovább, ha egyszer elhagyja az AutoPSEO-t. Ez az oldal a fogadót építő fejlesztőnek szóló referencia: az aláírás, az összes esemény a hasznos adatával, a válaszok, amelyeket az AutoPSEO olvas, az újrapróbálkozások, a várakozó parancsok és az IndexNow.
A webhook beállítása
- Nyissa meg a tulajdon Tartalom oldalát, és lépjen a Hol jelennek meg a cikkek részhez.
- Töltse ki a Webhook címe a webhelyén mezőt. Nyilvános gazdanévre mutató
https://URL-nek kell lennie: az IP-címeket és alocalhostcímet elutasítja a rendszer. Az AutoPSEO nem követ átirányításokat, ezért a végleges címet adja meg. - Töltse ki a Webhelye címe mezőt, például
https://example.com. Az egyes tartalomtípusok útvonala ez alá tartozik, így egy/answerstípusú cikk ahttps://example.com/answers/<slug>címen érhető el. - Válassza a Mentés és teszt küldése lehetőséget. Az AutoPSEO létrehoz egy aláíró titkot (
whsec_, utána 48 hexadecimális karakter), és pingeli a megadott címet. Az aláírást ellenőrző fogadó ezen az első pingen elbukik, mert még nincs meg a titok. - Jelenítse meg az Aláíró titkot a Megjelenítés vagy a Másolás gombbal, tárolja titokként a webhelyén, majd válassza a Teszt küldése lehetőséget.
- Olvassa el a Mit kezel a webhelye részt: minden parancs mellett a Csatlakoztatva, Nincs csatlakoztatva, Bejelentve, nem tesztelt vagy Nem tesztelt állapot látható.
Az új tulajdonokon a cikkeket kezdetben az AutoPSEO üzemelteti a saját címén (lásd: Üzemeltetés), és az üzemeltetés és a webhook egymás mellett is működhet. Amint a webhelye megjeleníti a cikkeket, válassza az Üzemeltetés leállítása az AutoPSEO-n lehetőséget: minden élő cikk átkerül a webhelye címére, és article.published eseményként elmegy a webhookjára. A gombhoz olyan webhook kell, amely válaszolt az utolsó tesztre, valamint meg kell adni a webhelye címét. Amíg az üzemeltetés ki van kapcsolva, a webhook nem távolítható el.
Az Új titok azonnal lecseréli az aláíró titkot, és a régi azonnal megszűnik érvényesíteni. A titok létrehozása után rögtön tegye be az újat a webhelyére.
Az AutoPSEO csak olyan webhookhoz sorol be kézbesítéseket, amelynek utolsó pingjére 2xx válasz érkezett. A sikertelen ping (mentéskor, a Teszt küldése gombnál vagy egy webhelybejárás elején) hibásnak jelöli a webhookot, és a hibás állapot alatt közzétett cikkek nem kerülnek sorba hozzá. Hagyja, hogy a ping mindig válaszoljon, és egy kiesés elhárítása után válassza a Teszt küldése lehetőséget.
Fejlécek és aláírás
Minden kérés POST, JSON törzzsel és a következő fejlécekkel:
| Fejléc | Érték |
|---|---|
Content-Type | application/json |
User-Agent | AutoPSEO-Webhook/1 |
X-AutoPSEO-Event | Az esemény neve, a törzsben is szerepel event néven |
X-AutoPSEO-Delivery | A kézbesítés azonosítója, a törzsben is szerepel id néven. Ugyanaz egy kézbesítés minden újrapróbálkozásánál |
X-AutoPSEO-Timestamp | Unix-idő másodpercben, amikor ezt a kísérletet aláírták |
X-AutoPSEO-Signature | sha256=, majd a <timestamp>.<nyers törzs> hexadecimális HMAC-SHA256 értéke |
A kérés ellenőrzése:
- Vegye az időbélyeg-fejlécet, egy pontot, majd a kérés nyers törzsét pontosan úgy, ahogy megérkezett, a JSON-elemzés előtt.
- Számítson HMAC-SHA256 értéket erre a karakterláncra. A kulcs a teljes aláíró titok, úgy, ahogy az alkalmazás mutatja, a
whsec_előtaggal együtt, UTF-8 bájtokként. - Kódolja hexadecimálisan az eredményt, és hasonlítsa össze az
X-AutoPSEO-Signaturesha256=utáni részével, állandó idejű összehasonlítással. Ha eltérnek, utasítsa el a kérést.
Minden kísérletet új, saját időbélyeggel írnak alá, ezért elutasíthatja azokat a kéréseket, amelyek időbélyege messze esik az Ön óráján látott időtől (az öt perc gyakori ablak), anélkül, hogy az újrapróbálkozások megsérülnének. Magát a HMAC-ot az RFC 2104 határozza meg.
Minden törzs tartalmazza az id, event, occurredAt (ISO 8601, UTC) és site: { propertyId, domain } mezőket.
Események
| Esemény | Fajta | Mikor küldi az AutoPSEO |
|---|---|---|
ping | Ellenőrzés | A webhook mentésekor, a Teszt küldése gombnál és minden webhelybejárás elején |
test | Ellenőrzés | Sikeres ping után azonnal, parancsonként egy |
article.published | Kézbesítés | Egy cikk először válik élővé; minden élő cikk, amikor leállítja az üzemeltetést |
article.updated | Kézbesítés | Új változat válik élővé (frissítés, optimalizálás, visszaállítás, újbóli közzététel levétel után, nyelvek hozzáadása), vagy borítókép került hozzá |
article.unpublished | Kézbesítés | Egy cikket levettek, vagy egy másik oldalba olvasztottak |
path.add | Kézbesítés | Egy típusos tartalomtípus új értékét jóváhagyták |
path.remove | Kézbesítés | Valaki kérte egy érték útvonalának levételét |
path.check | Hívás | Mielőtt az AutoPSEO olyan címre tervez oldalt, ahol a webhelyén nincs oldal, vagy új értéket javasol |
site.export | Hívás | Webhelybejáráskor, a napi témaszinkronizáláskor, és mielőtt az AutoPSEO módosít egy élő cikket |
articles.adopted | Hívás | Miután egy bejárás beimportálta a webhelye által exportált cikkeket |
site.handover | Hívás | Amikor valaki tartalomtípusok írását átadja az AutoPSEO-nak, vagy visszaveszi |
A kézbesítések egy kimenő postaládán (outbox) keresztül mennek: ugyanabban az adatbázis-kötegben rögzítik őket, mint a változást, azonnal elküldik, újrapróbálják, és várhatnak a webhelyére. A hívások egyszerű kérés-válasz párok: az AutoPSEO a választ azonnal elolvassa. Hogy a path-parancsokat mikor küldi, azt a Típusos oldalak és új útvonalak írja le.
A cikk hasznos adata
Az article.published és az article.updated a teljes cikket tartalmazza, minden nyelvvel együtt:
{
"id": "0f6d2c1e-7a51-4c1b-9d0e-5b8f3a2e9c41",
"event": "article.published",
"occurredAt": "2026-10-12T08:30:00.000Z",
"site": { "propertyId": "prop_123", "domain": "example.com" },
"article": {
"id": "a4c09e2b-6f1d-4e57-8b3a-1d2e3f4a5b6c",
"slug": "plan-a-content-calendar",
"path": "/answers/plan-a-content-calendar",
"type": { "key": "answers", "name": "Answers", "path": "/answers" },
"lang": "en",
"langs": ["en", "de"],
"rev": 1,
"url": "https://example.com/answers/plan-a-content-calendar",
"datePublished": "2026-10-12",
"dateModified": "2026-10-12",
"contentHash": "9f2c4e1a7b3d5f6081a2c3d4",
"writer": "platform",
"category": "Planning",
"copy": {
"title": "How to plan a content calendar",
"metaDescription": "A content calendar in five steps, with a template.",
"h1": "How to plan a content calendar",
"directAnswer": "List your topics, give each a date and an owner, then review the plan weekly.",
"keyTakeaways": ["Plan a quarter at a time.", "Give every piece one owner."],
"sections": [{ "heading": "Start from your topics", "bodyHtml": "<p>Begin with the searches you want to win.</p>" }],
"faq": [{ "q": "How far ahead should I plan?", "a": "One quarter is enough for most teams." }],
"sources": [{ "title": "Creating helpful content", "url": "https://developers.google.com/search/docs/fundamentals/creating-helpful-content" }]
},
"translations": { "de": { "title": "Einen Redaktionsplan erstellen", "h1": "Einen Redaktionsplan erstellen" } },
"cover": {
"url": "https://app.autopseo.com/media/covers/prop_123/<sha256>.jpg",
"sha256": "<sha256>",
"contentType": "image/jpeg",
"width": 1536,
"height": 1024
}
}
}
A német bejegyzés itt le van rövidítve; minden fordítás ugyanolyan szerkezetű, mint a copy.
| Mező | Jelentése |
|---|---|
id | A cikk AutoPSEO-azonosítója. Sosem változik, ezért biztonságos kulcs |
slug | A cím utolsó része. Típusos oldalakon / jellel összefűzött szegmensekből áll, például google/software-engineer |
path | A webhelyéhez viszonyított cím: a típus útvonala plusz a slug. Az oldal létrejötte után rögzített |
type | { key, name, path }. A key stabil; a path az, ahol a típus cikkei élnek (a webhely gyökerénél üres) |
lang, langs | Az elsődleges nyelv és a változat összes nyelve |
rev | A változat sorszáma |
url | A teljes cím, ahogy az AutoPSEO ismeri: az üzemeltetés kikapcsolása után a webhelyéé, vagy az url, amelyet a fogadója legutóbb válaszként adott |
datePublished, dateModified | YYYY-MM-DD. A közzétételi dátum a későbbi változatokon át változatlan marad |
contentHash | A változat ujjlenyomata |
writer | Ki írta a változatot: platform (AutoPSEO), mcp (az Ön saját MI-je), user, import (a webhelye saját szövege) vagy aggregate (listaoldal) |
copy | A cikk az elsődleges nyelvén |
translations | A többi nyelv, nyelvkóddal kulcsolva |
category | A webhelye kategóriája a cikkhez, ha a formátuma kategóriákat tart nyilván |
topic | { externalId, keyword }, ha a cikk egy, a webhelye által átadott témára készült, így lezárhatja a témát |
parts | Típusos oldalakon az egyes részek értéke: { "company": "google", "role": "software-engineer" } |
kind | "list" listaoldalon. A szövege { title, h1, items: [{ from, text }] }, ahol a from annak az oldalnak az útvonala, amelyből az elem származik, a parts pedig megnevezi az általa összegyűjtött értéket |
cover | Az AutoPSEO által a cikkhez készített borítókép. Egyszer töltse le, és tartsa meg a saját másolatát; a cím sosem változik, mert a fájlnév a kép SHA-256 értéke |
basedOn | Az article.updated eseményen: az oldala azon változata, amelyből ez a változat készült (lásd az ütközésekről szóló részt) |
redirectTo | Az article.unpublished eseményen összeolvasztás után: hová vezet most a régi cím. Válaszoljon rá 301-gyel, és ne tegyen oda újat |
Az article.unpublished ugyanazokat az article mezőket hordozza, kivéve a copy, translations, category és cover mezőket.
A copy belseje
| Mező | Jelentése |
|---|---|
title, metaDescription, h1 | Az oldal címe, a meta description és a főcím |
directAnswer | A rövid válasz, amely elsőként jelenik meg |
keyTakeaways | Karakterláncok listája |
sections | [{ heading, bodyHtml }] |
faq | [{ q, a }] |
sources | [{ title, url, lastVerified? }] |
question | Opcionális: a keresők kérdése a saját szavaikkal, ha a formátuma kéri |
category | Opcionális: a webhelye egyik kategóriája |
lists | Opcionális: kulcs szerinti egyszerű szöveges listák azokhoz a tartalomtípusokhoz, amelyek kérik őket (egy interjúútmutató mintakérdései) |
Az AutoPSEO által írt cikkekben a bodyHtml csak a p, ul, li, strong, em, a és code elemeket használja, a hivatkozásokon pedig csak a href marad meg. A webhelye saját szövegéből átvett szöveg megtartja az Ön HTML-jét. Ha a sablonjai megkívánják, futtassa át a saját szanitizálóján is.
Mit válaszoljon a fogadó
Bármely 2xx befejez egy kézbesítést. Az AutoPSEO a válasz törzséből egy opcionális JSON-objektumot is beolvas; tartsa 64 KB alatt, mert a nagyobb válasz hibának számít.
| Mező | Hatása |
|---|---|
url | Az https:// cím, ahol a cikk most él. Az AutoPSEO ezt rögzíti a cikk URL-jeként |
version | Az oldala verziója, legfeljebb 128 karakteres átlátszatlan karakterlánc. A következő frissítéskor basedOn néven tér vissza |
urls | Az https:// címek, amelyeket ez a kézbesítés módosított, az IndexNow számára (minden nyelv, vagy azok a címek, amelyeket már nem szolgál ki). Az [] azt jelenti, hogy semmi sem változott |
cover | "wanted", ha nincs borítóképe a cikkhez, és a kézbesítés sem hozott. Az AutoPSEO készít egyet, és article.updated eseményben elküldi |
A hibaválaszok különböző dolgokat jelentenek:
| Az Ön válasza | Hogyan érti az AutoPSEO | Mi történik |
|---|---|---|
4xx { "error": "unknown_event" } tartalommal, vagy 501 | Ezt a parancsot még nem kezeli | A kézbesítés újrapróbálkozás nélkül várakozik |
409 { "error": "conflict" } tartalommal | A frissítés olyan verzióból készült, amellyel az oldala már nem rendelkezik | A kézbesítés újrapróbálkozás nélkül sikertelen lesz, és a cikket a következő módosítása előtt újra beolvassa a webhelyéről |
A 408-tól és 429-től eltérő 4xx { "error": "<code>", "details": [] } tartalommal path.add vagy path.remove esetén | Elutasítás az Ön indoklásával | Rögzítve; lásd: Típusos oldalak és új útvonalak |
| Minden más: nincs válasz 10 másodpercen belül, hálózati hiba, átirányítás, 408, 429, 5xx vagy más 4xx | Átmeneti hiba | Növekvő várakozással újrapróbálja |
Újrapróbálkozások és felülírt kézbesítések
A kézbesítést a változás mentése után azonnal elküldi a rendszer, egy ötpercenkénti ütemezés pedig a esedékes kézbesítéseket küldi, a legrégebbitől kezdve. Átmeneti hiba után az AutoPSEO a kísérletek között 1 percet, majd 5 percet, 15 percet, 1 órát, 3 órát, 6 órát és 12 órát vár. A nyolcadik sikertelen kísérlet sikertelennek jelöli a kézbesítést, és a Tartalom oldal piros jelvénnyel számolja a webhook mellett.
Ha ugyanahhoz a cikkhez létezik újabb kézbesítés, a még függő régebbit felülírtnak jelöli a rendszer, és sosem küldi el. Minden kézbesítés a teljes cikket hordozza, így a legújabb elég a webhelyének. Az ugyanarra az értékre vonatkozó path-parancsok ugyanígy működnek.
A fogadója ugyanazt a kézbesítést kétszer is láthatja, például ha eltárolta a cikket, de a 10 másodperces időkorlát után válaszolt. Szűrje a duplikátumokat az X-AutoPSEO-Delivery alapján, vagy tegye minden írását idempotenssé úgy, hogy az article.id alapján tárol. Az article.updated olyan cikkhez is érkezhet, amelyet egy article.unpublished után törölt, mert a levett cikk újbóli közzététele frissítést küld: kezelje a frissítéseket "létrehozás vagy csere" műveletként.
Parancsok, amelyeket a webhelye még nem kezel
Egy webhely a protokollt parancsonként is megvalósíthatja. Az AutoPSEO minden parancs állapotát nyilvántartja, és háromféleképpen értesül róla:
- Tesztek. Minden sikeres ping után az AutoPSEO parancsonként egy
testeseményt küld. A törzs{ id, event: "test", occurredAt, site, test: { event: "<command>", ... } }, ahol atestegy, a valódi parancshoz hasonló mintát tartalmaz egy<type path>/autopseo-connection-testcímről, amely egyetlen webhelyen sem létezik. Ellenőrizze úgy, mintha valódi lenne, ne módosítson semmit, és válaszoljon 2xx-szel:{ "test": "<command>", "ok": true }a Csatlakoztatva állapothoz,{ "test": "<command>", "ok": false, "error": "unknown_event" }a Nincs csatlakoztatva állapothoz. Azok: falseés más hibakód, például egy olyan cím levétele, amellyel nem rendelkezik, szintén csatlakoztatottnak számít. A minta atestalatt van, sosem a legfelső szinten, így az a fogadó, amely nem tud a tesztekről, nem talál benne cikket. - Valódi kézbesítések és hívások. A 2xx csatlakoztatottnak jelöli a parancsot; az
unknown_eventnem csatlakoztatottnak. - A ping válasza. Az
autopseo.eventsmezőben felsorolt parancsok Bejelentve, nem tesztelt állapotban látszanak, amíg egy teszt vagy kézbesítés többet nem mond.
A nem csatlakoztatott parancshoz tartozó kézbesítés várakozik. A Tartalom oldal felsorolja, mi vár, például "A webhelye még nem vesz le cikkeket", és minden kézzel elvégzett teendőhöz van egy Megtörtént a webhelyen gomb; az AutoPSEO ezután sosem küldi el azt. Amikor egy későbbi teszt vagy kézbesítés csatlakoztatottnak találja a parancsot, minden, ami rá várt, elmegy.
A ping válasza
A ping eseményre válaszoljon 2xx-szel. Az a webhely, amely csak fogadja a cikkeket, nem igényel többet. Ha közölni szeretné az AutoPSEO-val, mit tud még a webhelye, vegyen fel egy autopseo objektumot:
{
"ok": true,
"autopseo": {
"version": 1,
"events": ["article.published", "article.updated", "article.unpublished"],
"covers": true,
"indexNow": { "key": "3f1c9a7e5b2d4f60", "keyLocation": "https://example.com/3f1c9a7e5b2d4f60.txt" },
"export": ["articles", "topics", "profile"],
"adopt": true,
"handover": true,
"types": ["answers"],
"writer": "site"
}
}
| Mező | Jelentése |
|---|---|
version | 1. Az objektumot figyelmen kívül hagyja, ha a verzió nem legalább 1 |
events | A kezelt parancsok, bejelentettként jelennek meg a tesztelésig |
covers | true, ha az oldalai minden cikkhez borítóképet mutatnak. Az AutoPSEO írója ekkor írás közben elkészíti a borítót, így az első kézbesítés már tartalmazza, és a saját MI-jétől is kér egyet. Lásd: Borítóképek |
indexNow | { key, keyLocation? }: az Ön által kiszolgált IndexNow-kulcs (8–128 betű, számjegy és kötőjel), és ha a kulcsfájl nem a /<key>.txt címen van, annak https:// helye |
export | Mit ad át a site.export: articles, topics, profile |
adopt | Elfogadja az articles.adopted eseményt, így egy teljes bejárás átveheti a meglévő cikkeit |
handover | Elfogadja a site.handover eseményt |
types | Az elfogadott tartalomtípus-kulcsok (legfeljebb 50) |
writer | Ki írja ma az új cikkeit: site vagy autopseo |
IndexNow a kiszolgált címekhez
Ha a ping válasza indexNow mezőt jelent be, az AutoPSEO az Ön által elfogadott kézbesítések után pingeli az IndexNow-t az api.indexnow.org címen, a webhelye pedig maga semmit sem pingel.
- A válasza által felsorolt
urlscímeket küldi.urlsnélkül a válaszurlmezőjét küldi, ennek hiányában a cikk URL-jét. Azurls: []semmit sem küld. - Csak a saját gazdagépén lévő címek kerülnek be, ahogy az IndexNow protokoll megköveteli: a
keyLocationgazdagépe, ennek hiányában a webhelye címének gazdagépe. - Minden kézbesítési kör webhelyenként egy pinget küld, legfeljebb 10 000 címmel.
- A 200 és a 202 elfogadott. A 429, az 5xx vagy a válasz hiánya megtartja a címeket, és egy óra múlva újrapróbálja, minden alkalommal megduplázva a várakozást legfeljebb egy napig (hosszabban, ha a
Retry-Afterazt kéri), a későbbi kézbesítések által hozzáadott címekkel együtt. A 403 (érvénytelen kulcs) vagy a 422 (a címek nem a gazdagépen vannak) rögzítésre kerül, és a címek elvetésre kerülnek. - A Tartalom oldal az utolsó pinget mutatja: mikor volt, hány cím, a HTTP-állapot és a következő próbálkozás.
- Amíg az AutoPSEO is üzemelteti a cikkeket, az üzemeltetett oldalakat az AutoPSEO saját kulcsával pingeli, és az Öné nem kerül használatra.
Az Indexelés alatti IndexNow eszköz különálló, kézi beküldő; lásd: IndexNow.
Ütközések: a webhelye szövege az eredeti
A válasza version értéke (vagy az exportjában szereplő cikk version értéke) az, amit az AutoPSEO az oldala állapotának hisz. Minden article.updated ezt basedOn néven hordozza. Ha az oldal azóta megváltozott a webhelyén, például egy szerkesztő javítása után, válaszoljon 409 kóddal és { "error": "conflict" } tartalommal, és ne tároljon semmit. A kézbesítés újrapróbálkozás nélkül sikertelen lesz.
Mielőtt egy élő cikk sorban álló módosítását megírná, az AutoPSEO újra beolvassa a cikket a webhelyéről a site.export és a paths segítségével, ha a webhelye kezeli a site.export parancsot. Ha az Ön verziója közben továbblépett, az Ön szövege lesz a cikk következő változata (a író: import), és az ezt követő frissítés az Ön aktuális verzióját hordozza basedOn néven.
path.add és path.remove
Ez a két kézbesítés egy típusos tartalomtípus egy értékére vonatkozik, például egy cégre az /interviews/{company}/{role} útvonalban. article helyett egy path objektumot hordoznak:
{
"id": "7c1e9d2a-3b4f-4e8a-9c0d-1e2f3a4b5c6d",
"event": "path.add",
"occurredAt": "2026-10-12T08:30:00.000Z",
"site": { "propertyId": "prop_123", "domain": "example.com" },
"path": {
"path": "/interviews/jane-street",
"type": { "key": "interviews", "name": "Interviews", "path": "/interviews" },
"part": "company",
"value": {
"value": "jane-street",
"name": "Jane Street",
"aliases": [],
"url": "https://<its own site>/",
"sameAs": ["https://<its careers page>/"],
"description": "<what it is, in a few words>",
"facts": [
{ "text": "<one sentence, as the source states it>", "source": "https://<the page that says it>", "lastVerified": "2026-10-01", "tier": "official" }
]
},
"takes": { "role": ["software-engineer"] }
}
}
| Mező | Jelentése |
|---|---|
path | Az érték saját címe a webhelyén |
type | A tartalomtípus { key, name, path } alakban |
part | A cím azon része, amelyet az érték kitölt |
value | { value, name }, path.add esetén emellett az AutoPSEO írója által összegyűjtött aliases, url, sameAs, description és facts. Minden tény tartalmaz text, source, lastVerified mezőt és official vagy reported értékű tier mezőt |
takes | path.add esetén: a többi rész értékei, amelyekkel együtt keresnek rá |
redirectTo | path.remove esetén: hová vezessenek innentől az érték címei, 301-gyel |
Ha elfogadta a parancsot, válaszoljon 2xx-szel; path.add esetén megadhatja az url mezőt, ahol az érték most él, path.remove esetén pedig az urls mezőt azokkal a címekkel, amelyeket már nem szolgál ki, és amelyek az IndexNow-hoz kerülnek. Az elutasításhoz válaszoljon 4xx-szel és { "error": "<code>", "details": ["<why>"] } tartalommal. path.add esetén az invalid_value az indoklásával együtt visszaküldi az értéket az írónak (a harmadik elutasítás végleges), bármely más kód pedig véglegesen elutasítja. path.remove esetén a not_found késznek számít, bármely más kód, például a 409 in_use, mindent úgy hagy, ahogy volt. Egy várakozó path-parancs Megtörtént a webhelyen jelölése a webhelye igenlő válaszának számít.
Hívások: kérések, amelyeknek az AutoPSEO a válaszát olvassa
A hívásokat ugyanúgy írják alá, mint a kézbesítéseket. A hívás alapértelmezés szerint legfeljebb 60 másodpercet vár, az újraolvasásoknál és a path-ellenőrzéseknél 30 másodpercet, és legfeljebb 24 MB-os válaszokat olvas. Minden, a 2xx-től eltérő válasz sikertelenné teszi a hívást.
site.export
A kérés tartalmazza az export: { what, cursor, limit } mezőt, továbbá a témákhoz since (ISO-idő) vagy újraolvasáshoz paths mezőt. Válaszoljon { "items": [], "next": "<cursor>" } alakban; az AutoPSEO addig kér újra, a cursor értékét a next értékére állítva, amíg az üres vagy null nem lesz.
- A
what: "articles"teljes webhelybejáráskor fut, oldalanként 10 elemmel, ha azexportmezőben bejelentette azarticlesértéket ésadopt: trueértéket is. A 400-as válasz azt jelenti: "nem támogatott". Apaths: ["/answers/x"]éslimit: 1megadásával egyetlen cikket olvas újra; csak azt a cikket adja vissza. - A
what: "topics"minden bejáráskor és a napi szinkronizáláskor fut, oldalanként 50 elemmel; a napi szinkronizálássincemezőt küld, az utolsó lekérés idejével. - A
what: "profile"minden bejáráskor fut. Válaszoljon{ "profile": { types, languages, rules, categories, format } }alakban, mindegyik elem opcionális: atypes[{ key, name, path }]alakban, arulespedigbrandTerms,synonyms,noise,onTopicésoffTopicmezőkkel.
Egy exportált cikkhez kell externalId, slug (bármely írásrendszer betűi és számjegyei, valamint kötőjelek, legfeljebb 200 karakter, a szegmenseket / fűzi össze), a slug-gal végződő path, és legalább title, h1 és egy szakasz a copy mezőben. Opcionális mezők: lang (alapértelmezés en), type (tartalomtípus-kulcs), url, keyword, category, datePublished, dateModified, version, translations, owner (az AutoPSEO cikkazonosítója, átvétel után) és maintenance: { kind: "refresh" or "optimize", reason }, amely sorba állítja az adott feladatot. Minden exportált cikkből kezelt cikk lesz, az Ön szövegével első változatként, és semmi sem megy vissza. Az ismételt exportálás biztonságos, és az AutoPSEO által levett cikk sosem tér vissza exporton keresztül.
A téma eleme { keyword, status?, volume?, source?, externalId?, type?, reason? }, ahol a status értéke queued, planned vagy rejected.
articles.adopted
Az importálás után az AutoPSEO arra kéri, hogy engedje kezelnie az új cikkeket: { "articles": [{ "externalId", "articleId", "slug", "path" }] }. Válaszoljon { "adopted": ["<externalId>"], "refused": [{ "externalId": "<id>", "reason": "<why>" }] } alakban. Az a cikk, amelyet nem erősít meg, ismét eltávolításra kerül az AutoPSEO-ból, kivéve ha az AutoPSEO már írt hozzá változatot.
site.handover
{ "handover": { "types": ["answers"], "writer": "autopseo" } }, akkor küldi, amikor valaki a tulajdon Webhelye oldalán a Az AutoPSEO írja őket vagy az Írás visszaadása a webhelynek lehetőséget választja. Válaszoljon { "ok": true, "writer": "autopseo" } alakban. Az AutoPSEO-nak történő átadás után a webhelye az általa jóváhagyott témákat átadja az AutoPSEO-nak ahelyett, hogy maga írná meg őket.
path.check
{ "paths": [{ "path": "/interviews/google/data-engineer" }, { "path": "/interviews/jane-street", "new": { "part": "company", "value": "jane-street", "name": "Jane Street" } }] }. Útvonalanként egy eredménnyel válaszoljon: { "results": [{ "path": "/interviews/google/data-engineer", "ok": true }, { "path": "/interviews/jane-street", "ok": false, "error": "not_allowed", "details": ["We only list companies with a careers page."] }] }. Az elutasítást az indoklásával együtt megőrzi, és nem kérdezi újra; a kihagyott útvonalat később ismét megkérdezi.
Egy minimális fogadó
Egy Cloudflare Worker, amely a Web Crypto API segítségével ellenőrzi az aláírást, kezeli a három cikkparancsot, a többit pedig unknown_event válasszal elutasítja. A cikkeket egy ARTICLES néven kötött KV-névtérben tárolja, az aláíró titkot pedig egy AUTOPSEO_SECRET nevű Worker-titokban.
const HANDLED = ["article.published", "article.updated", "article.unpublished"];
const MAX_SKEW_SECONDS = 300;
const SITE = "https://example.com";
const json = (data, status = 200) =>
new Response(JSON.stringify(data), { status, headers: { "content-type": "application/json" } });
function hexToBytes(hex) {
if (!/^[0-9a-f]{64}$/.test(hex)) return null;
const out = new Uint8Array(32);
for (let i = 0; i < 32; i++) out[i] = parseInt(hex.slice(i * 2, i * 2 + 2), 16);
return out;
}
async function verified(request, body, secret) {
const timestamp = request.headers.get("X-AutoPSEO-Timestamp") || "";
const signature = (request.headers.get("X-AutoPSEO-Signature") || "").replace(/^sha256=/, "");
if (!/^\d+$/.test(timestamp)) return false;
if (Math.abs(Date.now() / 1000 - Number(timestamp)) > MAX_SKEW_SECONDS) return false;
const bytes = hexToBytes(signature);
if (!bytes) return false;
const enc = new TextEncoder();
const key = await crypto.subtle.importKey("raw", enc.encode(secret), { name: "HMAC", hash: "SHA-256" }, false, ["verify"]);
// verify() compares in constant time.
return crypto.subtle.verify("HMAC", key, bytes, enc.encode(`${timestamp}.${body}`));
}
export default {
async fetch(request, env) {
if (request.method !== "POST") return new Response("Method not allowed", { status: 405 });
const body = await request.text();
if (!(await verified(request, body, env.AUTOPSEO_SECRET))) return json({ error: "bad_signature" }, 401);
let msg;
try {
msg = JSON.parse(body);
} catch {
return json({ error: "bad_json" }, 400);
}
if (msg.event === "ping") return json({ ok: true, autopseo: { version: 1, events: HANDLED } });
if (msg.event === "test") {
const command = msg.test && msg.test.event;
// Check the sample as you would the real command, and store nothing.
return HANDLED.includes(command)
? json({ test: command, ok: true })
: json({ test: command, ok: false, error: "unknown_event" });
}
if (msg.event === "article.published" || msg.event === "article.updated") {
const a = msg.article;
const stored = JSON.parse((await env.ARTICLES.get(a.id)) || "null");
if (a.basedOn && stored && stored.version && stored.version !== a.basedOn) {
return json({ error: "conflict", details: ["The page changed on the site."] }, 409);
}
// Any change to the page, here or in your own editor, gets a new version.
const version = crypto.randomUUID();
await env.ARTICLES.put(a.id, JSON.stringify({ ...a, version }));
return json({ url: SITE + a.path, version });
}
if (msg.event === "article.unpublished") {
const a = msg.article;
if (a.redirectTo) await env.ARTICLES.put(a.id, JSON.stringify({ path: a.path, redirectTo: a.redirectTo }));
else await env.ARTICLES.delete(a.id);
return json({ ok: true });
}
return json({ error: "unknown_event" }, 400);
},
};
Node.js-en ugyanígy ellenőrizhet a createHmac és a timingSafeEqual segítségével, a keretrendszere által kapott nyers törzsön:
import { createHmac, timingSafeEqual } from "node:crypto";
export function verifyAutopseo(rawBody, headers, secret) {
const timestamp = String(headers["x-autopseo-timestamp"] || "");
const given = String(headers["x-autopseo-signature"] || "");
if (!/^\d+$/.test(timestamp) || Math.abs(Date.now() / 1000 - Number(timestamp)) > 300) return false;
const expected = "sha256=" + createHmac("sha256", secret).update(timestamp + ".").update(rawBody).digest("hex");
return given.length === expected.length && timingSafeEqual(Buffer.from(given), Buffer.from(expected));
}
Következő lépés: hogy mi jut el a webhookhoz, azt az írás és jóváhagyás és a karbantartás dönti el; a teljes folyamatot a tartalommotor áttekintése mutatja be.