Μετάβαση στο περιεχόμενο
Τεκμηρίωση

Webhook παράδοσης: λήψη άρθρων στη δική σας τοποθεσία

Το υπογεγραμμένο webhook που στέλνει τα άρθρα του AutoPSEO στη δική σας τοποθεσία: κεφαλίδες, κάθε συμβάν και payload, οι απαντήσεις που πρέπει να δίνετε, επαναλήψεις, εντολές σε αναμονή και IndexNow.

Ιδιότητα → Περιεχόμενο → Πού δημοσιεύονται τα άρθρα20 λεπτά ανάγνωσης

Το AutoPSEO στέλνει κάθε άρθρο που δημοσιεύει, ενημερώνει ή αποσύρει στη δική σας τοποθεσία ως υπογεγραμμένο HTTPS POST. Η τοποθεσία σας αποθηκεύει το άρθρο και το αποδίδει με τα δικά της πρότυπα, ώστε το περιεχόμενο να ζει στο δικό σας σύστημα και να συνεχίσει να λειτουργεί ακόμη κι αν κάποτε φύγετε. Αυτή η σελίδα είναι ο οδηγός αναφοράς για τον προγραμματιστή που υλοποιεί τον δέκτη: υπογραφή, κάθε συμβάν με το payload του, οι απαντήσεις που διαβάζει το AutoPSEO, επαναλήψεις, εντολές σε αναμονή και IndexNow.

Ρύθμιση του webhook

  1. Ανοίξτε τη σελίδα Περιεχόμενο της ιδιότητας και μεταβείτε στο Πού δημοσιεύονται τα άρθρα.
  2. Συμπληρώστε το πεδίο Διεύθυνση webhook στην τοποθεσία σας. Πρέπει να είναι URL https:// με δημόσιο όνομα υπολογιστή: οι διευθύνσεις IP και το localhost απορρίπτονται. Το AutoPSEO δεν ακολουθεί ανακατευθύνσεις, επομένως δώστε την τελική διεύθυνση.
  3. Συμπληρώστε το πεδίο Διεύθυνση της τοποθεσίας σας, για παράδειγμα https://example.com. Η διαδρομή κάθε τύπου περιεχομένου εκτείνεται κάτω από αυτήν, οπότε ένα άρθρο τύπου με διαδρομή /answers βρίσκεται στο https://example.com/answers/<slug>.
  4. Επιλέξτε Αποθήκευση και αποστολή δοκιμής. Το AutoPSEO δημιουργεί ένα μυστικό υπογραφής (whsec_ ακολουθούμενο από 48 δεκαεξαδικούς χαρακτήρες) και στέλνει ping στη διεύθυνσή σας. Ένας δέκτης που ελέγχει τις υπογραφές θα αποτύχει σε αυτό το πρώτο ping, επειδή δεν έχει ακόμη το μυστικό.
  5. Εμφανίστε το Μυστικό υπογραφής με Εμφάνιση ή Αντιγραφή, αποθηκεύστε το ως μυστικό στην τοποθεσία σας και έπειτα επιλέξτε Αποστολή δοκιμής.
  6. Διαβάστε το Τι χειρίζεται η τοποθεσία σας: κάθε εντολή εμφανίζεται ως Συνδεδεμένη, Μη συνδεδεμένη, Δηλωμένη, χωρίς δοκιμή ή Χωρίς δοκιμή.

Οι νέες ιδιότητες ξεκινούν με το AutoPSEO να φιλοξενεί τα άρθρα στη δική του διεύθυνση (δείτε Φιλοξενία), και η φιλοξενία με το webhook μπορούν να λειτουργούν παράλληλα. Μόλις η τοποθεσία σας εμφανίζει τα άρθρα, επιλέξτε Διακοπή φιλοξενίας στο AutoPSEO: κάθε δημοσιευμένο άρθρο μεταφέρεται στη διεύθυνση της τοποθεσίας σας και αποστέλλεται στο webhook σας ως article.published. Αυτό το κουμπί απαιτεί webhook που απάντησε στην τελευταία δοκιμή του και τη διεύθυνση της τοποθεσίας σας. Όσο η φιλοξενία είναι απενεργοποιημένη, το webhook δεν μπορεί να αφαιρεθεί.

Το Νέο μυστικό αντικαθιστά το μυστικό υπογραφής αμέσως και το παλιό παύει να επαληθεύεται άμεσα. Βάλτε το νέο μυστικό στην τοποθεσία σας αμέσως μετά τη δημιουργία του.

Το AutoPSEO βάζει παραδόσεις στην ουρά μόνο για webhook του οποίου το τελευταίο ping απαντήθηκε με 2xx. Ένα ping που αποτυγχάνει (κατά την αποθήκευση, στο Αποστολή δοκιμής ή στην αρχή μιας σάρωσης τοποθεσίας) σημειώνει το webhook ως εσφαλμένο, και τα άρθρα που δημοσιεύονται όσο βρίσκεται σε σφάλμα δεν μπαίνουν στην ουρά γι' αυτό. Φροντίστε το ping να απαντά και επιλέξτε Αποστολή δοκιμής αφού αποκαταστήσετε μια διακοπή.

Κεφαλίδες και υπογραφή

Κάθε αίτημα είναι POST με σώμα JSON και τις παρακάτω κεφαλίδες:

ΚεφαλίδαΤιμή
Content-Typeapplication/json
User-AgentAutoPSEO-Webhook/1
X-AutoPSEO-EventΤο όνομα του συμβάντος, που υπάρχει και στο σώμα ως event
X-AutoPSEO-DeliveryΤο αναγνωριστικό της παράδοσης, που υπάρχει και στο σώμα ως id. Είναι το ίδιο σε κάθε επανάληψη της ίδιας παράδοσης
X-AutoPSEO-TimestampΏρα Unix σε δευτερόλεπτα κατά την οποία υπογράφηκε αυτή η προσπάθεια
X-AutoPSEO-Signaturesha256= ακολουθούμενο από το δεκαεξαδικό HMAC-SHA256 του <timestamp>.<raw body>

Για να επαληθεύσετε ένα αίτημα:

  1. Πάρτε την κεφαλίδα χρονοσήμανσης, μια τελεία και το ακατέργαστο σώμα του αιτήματος ακριβώς όπως έφτασε, πριν από οποιαδήποτε ανάλυση JSON.
  2. Υπολογίστε HMAC-SHA256 σε αυτή τη συμβολοσειρά. Το κλειδί είναι ολόκληρο το μυστικό υπογραφής όπως το εμφανίζει η εφαρμογή, με το πρόθεμα whsec_, ως byte UTF-8.
  3. Κωδικοποιήστε το αποτέλεσμα σε δεκαεξαδική μορφή και συγκρίνετέ το με το τμήμα του X-AutoPSEO-Signature μετά το sha256=, σε σταθερό χρόνο. Απορρίψτε το αίτημα όταν διαφέρουν.

Κάθε προσπάθεια υπογράφεται εκ νέου με τη δική της χρονοσήμανση, οπότε μπορείτε να απορρίπτετε αιτήματα με χρονοσήμανση μακριά από το ρολόι σας (πέντε λεπτά είναι συνηθισμένο περιθώριο) χωρίς να επηρεάζονται οι επαναλήψεις. Το ίδιο το HMAC ορίζεται στο RFC 2104.

Κάθε σώμα περιέχει id, event, occurredAt (ISO 8601, UTC) και site: { propertyId, domain }.

Συμβάντα

ΣυμβάνΕίδοςΠότε το στέλνει το AutoPSEO
pingΈλεγχοςΌταν αποθηκεύετε το webhook, στο Αποστολή δοκιμής και στην αρχή κάθε σάρωσης τοποθεσίας
testΈλεγχοςΑμέσως μετά από ένα επιτυχές ping, ένα για κάθε εντολή
article.publishedΠαράδοσηΈνα άρθρο δημοσιεύεται για πρώτη φορά· κάθε δημοσιευμένο άρθρο όταν διακόπτετε τη φιλοξενία
article.updatedΠαράδοσηΔημοσιεύεται νέα αναθεώρηση (ανανέωση, βελτιστοποίηση, επαναφορά, νέα δημοσίευση μετά από απόσυρση, προσθήκη γλωσσών) ή προστέθηκε εξώφυλλο
article.unpublishedΠαράδοσηΈνα άρθρο αποσύρεται ή συγχωνεύεται σε άλλη σελίδα
path.addΠαράδοσηΕγκρίθηκε μια νέα τιμή ενός τύπου περιεχομένου με τύπους
path.removeΠαράδοσηΚάποιος ζήτησε την απόσυρση της διαδρομής μιας τιμής
path.checkΚλήσηΠριν το AutoPSEO προγραμματίσει μια σελίδα σε διεύθυνση όπου η τοποθεσία σας δεν έχει σελίδα, ή προτείνει νέα τιμή
site.exportΚλήσηΚατά τη διάρκεια μιας σάρωσης τοποθεσίας, στον ημερήσιο συγχρονισμό θεμάτων και πριν το AutoPSEO αλλάξει ένα δημοσιευμένο άρθρο
articles.adoptedΚλήσηΑφού μια σάρωση εισήγαγε άρθρα που εξήγαγε η τοποθεσία σας
site.handoverΚλήσηΌταν κάποιος αναθέτει τη συγγραφή τύπων περιεχομένου στο AutoPSEO ή την επιστρέφει

Οι παραδόσεις περνούν από ένα outbox: καταγράφονται στην ίδια ομάδα εγγραφών της βάσης δεδομένων με την αλλαγή, αποστέλλονται αμέσως, επαναλαμβάνονται και μπορούν να περιμένουν την τοποθεσία σας. Οι κλήσεις είναι απλό αίτημα και απάντηση: το AutoPSEO διαβάζει την απάντηση επιτόπου. Το πότε αποστέλλονται οι εντολές διαδρομής εξηγείται στο Σελίδες με τύπους και νέες διαδρομές.

Το payload του άρθρου

Τα article.published και article.updated μεταφέρουν ολόκληρο το άρθρο, με όλες τις γλώσσες:

{
  "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
    }
  }
}

Η γερμανική εγγραφή εδώ είναι συντομευμένη· κάθε μετάφραση έχει την ίδια δομή με το copy.

ΠεδίοΣημασία
idΤο αναγνωριστικό του άρθρου στο AutoPSEO. Δεν αλλάζει ποτέ, οπότε είναι ασφαλές κλειδί
slugΤο τελευταίο τμήμα της διεύθυνσης. Στις σελίδες με τύπους περιέχει τμήματα ενωμένα με /, όπως google/software-engineer
pathΗ διεύθυνση σε σχέση με την τοποθεσία σας: η διαδρομή του τύπου συν το slug. Μένει σταθερή μόλις υπάρξει η σελίδα
type{ key, name, path }. Το key είναι σταθερό· το path είναι το σημείο όπου βρίσκονται τα άρθρα του τύπου (κενό για τη ρίζα της τοποθεσίας)
lang, langsΗ κύρια γλώσσα και όλες οι γλώσσες αυτής της αναθεώρησης
revΟ αριθμός αναθεώρησης
urlΗ πλήρης διεύθυνση όπως τη γνωρίζει το AutoPSEO: της τοποθεσίας σας όταν η φιλοξενία είναι απενεργοποιημένη, ή το url που απάντησε τελευταίο ο δέκτης σας
datePublished, dateModifiedYYYY-MM-DD. Η ημερομηνία δημοσίευσης μένει σταθερή στις επόμενες αναθεωρήσεις
contentHashΑποτύπωμα της αναθεώρησης
writerΠοιος έγραψε την αναθεώρηση: platform (AutoPSEO), mcp (η δική σας ΑΙ), user, import (το δικό σας κείμενο από την τοποθεσία) ή aggregate (σελίδα λίστας)
copyΤο άρθρο στην κύρια γλώσσα του
translationsΟι άλλες γλώσσες, με κλειδί τον κωδικό γλώσσας
categoryΗ κατηγορία της τοποθεσίας σας γι' αυτό, όταν η μορφή σας χρησιμοποιεί κατηγορίες
topic{ externalId, keyword } όταν το άρθρο γράφτηκε για θέμα που παρέδωσε η τοποθεσία σας, ώστε να μπορείτε να κλείσετε αυτό το θέμα
partsΣτις σελίδες με τύπους, η τιμή κάθε μέρους: { "company": "google", "role": "software-engineer" }
kind"list" σε σελίδα λίστας. Το copy της είναι { title, h1, items: [{ from, text }] }, όπου το from είναι η διαδρομή της σελίδας από την οποία προέρχεται κάθε στοιχείο, και το parts ονομάζει την τιμή που συγκεντρώνει
coverΕξώφυλλο που έφτιαξε το AutoPSEO για το άρθρο. Κατεβάστε το μία φορά και κρατήστε δικό σας αντίγραφο· η διεύθυνση δεν αλλάζει ποτέ επειδή το όνομα αρχείου είναι το SHA-256 της εικόνας
basedOnΣτο article.updated: η έκδοση της σελίδας σας από την οποία γράφτηκε αυτή η αναθεώρηση (δείτε τις συγκρούσεις παρακάτω)
redirectToΣτο article.unpublished μετά από συγχώνευση: προς πού οδηγεί πλέον η παλιά διεύθυνση. Απαντήστε με 301 και μην αποθηκεύσετε τίποτα νέο εκεί

Το article.unpublished περιέχει τα ίδια πεδία article, εκτός από τα copy, translations, category και cover.

Μέσα στο copy

ΠεδίοΣημασία
title, metaDescription, h1Ο τίτλος της σελίδας, η meta περιγραφή και η επικεφαλίδα
directAnswerΗ σύντομη απάντηση που εμφανίζεται πρώτη
keyTakeawaysΜια λίστα συμβολοσειρών
sections[{ heading, bodyHtml }]
faq[{ q, a }]
sources[{ title, url, lastVerified? }]
questionΠροαιρετικό: η ερώτηση του χρήστη που αναζητά, με δικά του λόγια, όταν η μορφή σας τη ζητά
categoryΠροαιρετικό: μία από τις κατηγορίες της τοποθεσίας σας
listsΠροαιρετικό: λίστες απλού κειμένου ανά κλειδί, για τύπους περιεχομένου που τις ζητούν (οι ενδεικτικές ερωτήσεις ενός οδηγού συνέντευξης)

Στα άρθρα που γράφει το AutoPSEO, το bodyHtml χρησιμοποιεί μόνο p, ul, li, strong, em, a και code, και οι σύνδεσμοι κρατούν μόνο το href. Το κείμενο που προέρχεται από τη δική σας τοποθεσία διατηρεί το HTML σας. Περάστε το και από τον δικό σας εξυγιαντή (sanitiser), αν τα πρότυπά σας το απαιτούν.

Τι απαντά ο δέκτης σας

Οποιοδήποτε 2xx ολοκληρώνει μια παράδοση. Το AutoPSEO διαβάζει επίσης ένα προαιρετικό αντικείμενο JSON από το σώμα της απάντησης· κρατήστε το κάτω από 64 KB, επειδή μεγαλύτερη απάντηση θεωρείται αποτυχία.

ΠεδίοΑποτέλεσμα
urlΗ διεύθυνση https:// όπου βρίσκεται πλέον το άρθρο. Το AutoPSEO την καταγράφει ως URL του άρθρου
versionΗ έκδοση της σελίδας σας, μια αδιαφανής συμβολοσειρά έως 128 χαρακτήρων. Επιστρέφει ως basedOn με την επόμενη ενημέρωση
urlsΟι διευθύνσεις https:// που άλλαξαν με αυτή την παράδοση, για το IndexNow (κάθε γλώσσα, ή οι διευθύνσεις που σταματήσατε να σερβίρετε). Το [] σημαίνει ότι δεν άλλαξε τίποτα
cover"wanted" όταν δεν έχετε εξώφυλλο για το άρθρο και η παράδοση δεν περιείχε κανένα. Το AutoPSEO φτιάχνει ένα και το στέλνει σε article.updated

Οι απαντήσεις σφάλματος έχουν διαφορετική σημασία:

Η απάντησή σαςΠώς την διαβάζει το AutoPSEOΤι συμβαίνει
4xx με { "error": "unknown_event" }, ή 501Δεν χειρίζεστε ακόμη αυτή την εντολήΗ παράδοση περιμένει, χωρίς επαναλήψεις
409 με { "error": "conflict" }Η ενημέρωση γράφτηκε από έκδοση που η σελίδα σας δεν έχει πιαΗ παράδοση αποτυγχάνει χωρίς επαναλήψεις και το άρθρο διαβάζεται ξανά από την τοποθεσία σας πριν από την επόμενη αλλαγή του
4xx εκτός από 408 ή 429 με { "error": "<code>", "details": [] } σε path.add ή path.removeΆρνηση με τον δικό σας λόγοΚαταγράφεται· δείτε Σελίδες με τύπους και νέες διαδρομές
Οτιδήποτε άλλο: καμία απάντηση εντός 10 δευτερολέπτων, σφάλμα δικτύου, ανακατεύθυνση, 408, 429, 5xx ή άλλο 4xxΠροσωρινή αποτυχίαΕπανάληψη με backoff

Επαναλήψεις και παραδόσεις που αντικαταστάθηκαν

Μια παράδοση αποστέλλεται μόλις αποθηκευτεί η αλλαγή, και ένα πρόγραμμα ανά πέντε λεπτά στέλνει ό,τι εκκρεμεί, ξεκινώντας από το παλαιότερο. Μετά από προσωρινή αποτυχία, το AutoPSEO περιμένει 1 λεπτό, μετά 5 λεπτά, 15 λεπτά, 1 ώρα, 3 ώρες, 6 ώρες και 12 ώρες ανάμεσα στις προσπάθειες. Η όγδοη αποτυχημένη προσπάθεια σημειώνει την παράδοση ως αποτυχημένη, και η σελίδα Περιεχόμενο την προσμετρά σε ένα κόκκινο σήμα δίπλα στο webhook.

Όταν υπάρχει νεότερη παράδοση για το ίδιο άρθρο, μια παλαιότερη που εκκρεμεί σημειώνεται ως αντικατεστημένη και δεν αποστέλλεται ποτέ. Κάθε παράδοση περιέχει ολόκληρο το άρθρο, άρα η νεότερη είναι το μόνο που χρειάζεται η τοποθεσία σας. Το ίδιο ισχύει για τις εντολές διαδρομής που αφορούν την ίδια τιμή.

Ο δέκτης σας μπορεί να δει την ίδια παράδοση δύο φορές, για παράδειγμα όταν αποθήκευσε το άρθρο αλλά απάντησε μετά το χρονικό όριο των 10 δευτερολέπτων. Αφαιρέστε τα διπλότυπα με βάση το X-AutoPSEO-Delivery, ή κάντε κάθε εγγραφή ιδεμποτική αποθηκεύοντας με βάση το article.id. Ένα article.updated μπορεί επίσης να φτάσει σε άρθρο που διαγράψατε μετά από article.unpublished, επειδή η νέα δημοσίευση ενός αποσυρμένου άρθρου στέλνει ενημέρωση: αντιμετωπίστε τις ενημερώσεις ως «δημιουργία ή αντικατάσταση».

Εντολές που η τοποθεσία σας δεν χειρίζεται ακόμη

Μια τοποθεσία μπορεί να υλοποιεί το πρωτόκολλο μία εντολή τη φορά. Το AutoPSEO κρατά την κατάσταση κάθε εντολής και την ανακαλύπτει με τρεις τρόπους:

  • Δοκιμές. Μετά από κάθε επιτυχές ping, το AutoPSEO στέλνει ένα test για κάθε εντολή. Το σώμα είναι { id, event: "test", occurredAt, site, test: { event: "<command>", ... } }, όπου το test περιέχει ένα δείγμα με τη μορφή της πραγματικής εντολής και αφορά το <type path>/autopseo-connection-test, μια διεύθυνση που δεν έχει καμία τοποθεσία. Ελέγξτε το όπως θα ελέγχατε την πραγματική εντολή, μην αλλάξετε τίποτα και απαντήστε με 2xx: { "test": "<command>", "ok": true } για Συνδεδεμένη, { "test": "<command>", "ok": false, "error": "unknown_event" } για Μη συνδεδεμένη. Μια απάντηση με ok: false και άλλο κωδικό σφάλματος, όπως η απόσυρση μιας διεύθυνσης που δεν έχετε, θεωρείται και πάλι συνδεδεμένη. Το δείγμα βρίσκεται κάτω από το test, ποτέ στο ανώτατο επίπεδο, ώστε ένας δέκτης που δεν γνωρίζει τίποτα για δοκιμές να μη βρει άρθρο μέσα του.
  • Πραγματικές παραδόσεις και κλήσεις. Ένα 2xx σημειώνει την εντολή ως συνδεδεμένη· το unknown_event τη σημειώνει ως μη συνδεδεμένη.
  • Η απάντηση στο ping. Οι εντολές που αναφέρει η απάντησή σας στο autopseo.events εμφανίζονται ως Δηλωμένη, χωρίς δοκιμή μέχρι να πει περισσότερα μια δοκιμή ή μια παράδοση.

Μια παράδοση για εντολή που δεν είναι συνδεδεμένη περιμένει. Η σελίδα Περιεχόμενο εμφανίζει τι περιμένει, για παράδειγμα «Η τοποθεσία σας δεν αποσύρει ακόμη άρθρα», με ένα κουμπί Έγινε στην τοποθεσία για οτιδήποτε εκτελέσατε χειροκίνητα· το AutoPSEO τότε δεν στέλνει ποτέ εκείνη την παράδοση. Όταν μια μεταγενέστερη δοκιμή ή παράδοση βρει την εντολή συνδεδεμένη, στέλνεται όλο όσο περίμενε γι' αυτήν.

Η απάντηση στο ping

Απαντήστε στο ping με 2xx. Μια τοποθεσία που απλώς λαμβάνει άρθρα δεν χρειάζεται τίποτα περισσότερο. Για να πείτε στο AutoPSEO τι άλλο κάνει η τοποθεσία σας, συμπεριλάβετε ένα αντικείμενο autopseo:

{
  "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"
  }
}
ΠεδίοΣημασία
version1. Το αντικείμενο αγνοείται χωρίς έκδοση 1 ή μεγαλύτερη
eventsΟι εντολές που χειρίζεστε, εμφανίζονται ως δηλωμένες μέχρι να δοκιμαστούν
coverstrue όταν οι σελίδες σας εμφανίζουν εξώφυλλο με κάθε άρθρο. Ο συγγραφέας του AutoPSEO τότε φτιάχνει το εξώφυλλο καθώς γράφει, ώστε η πρώτη παράδοση να το περιέχει, και ζητείται από τη δική σας ΑΙ να παρέχει ένα. Δείτε Εξώφυλλα
indexNow{ key, keyLocation? }: το κλειδί IndexNow που σερβίρετε (8 έως 128 γράμματα, ψηφία και παύλες) και, όταν το αρχείο κλειδιού δεν βρίσκεται στο /<key>.txt, η τοποθεσία του https://
exportΤι παραδίδει το site.export: articles, topics, profile
adoptΔέχεστε το articles.adopted, ώστε μια πλήρης σάρωση να μπορεί να αναλάβει τα υπάρχοντα άρθρα σας
handoverΔέχεστε το site.handover
typesΤα κλειδιά τύπων περιεχομένου που δέχεστε (έως 50)
writerΠοιος γράφει σήμερα τα νέα άρθρα σας: site ή autopseo

IndexNow για τις διευθύνσεις που σερβίρετε

Όταν η απάντησή σας στο ping δηλώνει indexNow, το AutoPSEO κάνει ping στο IndexNow στο api.indexnow.org μετά τις παραδόσεις που δέχεστε, και η τοποθεσία σας δεν κάνει η ίδια κανένα ping.

  • Στέλνει τα urls που ανέφερε η απάντησή σας. Χωρίς urls στέλνει το url της απάντησής σας, αλλιώς το URL του άρθρου. Το urls: [] δεν στέλνει τίποτα.
  • Μπαίνουν μόνο διευθύνσεις στον δικό σας υπολογιστή-διακομιστή (host), όπως απαιτεί το πρωτόκολλο IndexNow: ο host του keyLocation, αλλιώς ο host της διεύθυνσης της τοποθεσίας σας.
  • Κάθε κύκλος παραδόσεων στέλνει ένα ping ανά τοποθεσία, με έως 10.000 διευθύνσεις.
  • Τα 200 και 202 γίνονται δεκτά. Ένα 429, ένα 5xx ή η έλλειψη απάντησης κρατά τις διευθύνσεις και ξαναδοκιμάζει μετά από μία ώρα, διπλασιάζοντας κάθε φορά έως ένα εικοσιτετράωρο (περισσότερο όταν το ζητά το Retry-After), μαζί με ό,τι πρόσθεσαν οι μεταγενέστερες παραδόσεις. Ένα 403 (μη έγκυρο κλειδί) ή 422 (διευθύνσεις που δεν ανήκουν στον host) καταγράφεται και απορρίπτεται.
  • Η σελίδα Περιεχόμενο δείχνει το τελευταίο ping: πότε, πόσες διευθύνσεις, την κατάσταση HTTP και την επόμενη προσπάθεια.
  • Όσο το AutoPSEO φιλοξενεί και τα άρθρα, οι φιλοξενούμενες σελίδες υποβάλλονται με το δικό του κλειδί του AutoPSEO και το δικό σας δεν χρησιμοποιείται.

Το εργαλείο IndexNow στην ενότητα Ευρετηρίαση είναι ξεχωριστός, χειροκίνητος υποβολέας· δείτε IndexNow.

Συγκρούσεις: το κείμενο της τοποθεσίας σας είναι το πρωτότυπο

Το version της απάντησής σας (ή το version ενός άρθρου στην εξαγωγή σας) είναι αυτό που πιστεύει το AutoPSEO ότι είναι η σελίδα σας. Κάθε article.updated το μεταφέρει ως basedOn. Αν η σελίδα άλλαξε στην τοποθεσία σας από τότε, για παράδειγμα μετά από διόρθωση ενός συντάκτη, απαντήστε 409 με { "error": "conflict" } και μην αποθηκεύσετε τίποτα. Η παράδοση αποτυγχάνει χωρίς επαναλήψεις.

Πριν γραφτεί μια αλλαγή στην ουρά για δημοσιευμένο άρθρο, το AutoPSEO διαβάζει ξανά αυτό το άρθρο από την τοποθεσία σας με site.export και paths, όταν η τοποθεσία σας χειρίζεται το site.export. Αν η έκδοσή σας έχει προχωρήσει, το κείμενό σας γίνεται η επόμενη αναθεώρηση του άρθρου (writer import), και η ενημέρωση που ακολουθεί μεταφέρει την τρέχουσα έκδοσή σας ως basedOn.

path.add και path.remove

Αυτές οι δύο παραδόσεις αφορούν μία τιμή ενός τύπου περιεχομένου με τύπους, για παράδειγμα μια εταιρεία στο /interviews/{company}/{role}. Μεταφέρουν ένα αντικείμενο path αντί για article:

{
  "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"] }
  }
}
ΠεδίοΣημασία
pathΗ δική της διεύθυνση της τιμής στην τοποθεσία σας
typeΟ τύπος περιεχομένου, ως { key, name, path }
partΤο μέρος της διεύθυνσης που συμπληρώνει η τιμή
value{ value, name }, και στο path.add επιπλέον τα aliases, url, sameAs, description και facts που συγκέντρωσε ο συγγραφέας του AutoPSEO. Κάθε στοιχείο (fact) έχει text, source, lastVerified και tier με τιμή official ή reported
takesΣτο path.add: οι τιμές των άλλων μερών που αναζητούν οι χρήστες μαζί με αυτό
redirectToΣτο path.remove: προς πού πρέπει να οδηγούν από εδώ και πέρα οι διευθύνσεις της τιμής, με 301

Απαντήστε με 2xx όταν αναλάβατε την εντολή· στο path.add μπορείτε να προσθέσετε το url όπου βρίσκεται πλέον η τιμή, και στο path.remove τα urls που σταματήσατε να σερβίρετε, τα οποία πηγαίνουν στο IndexNow. Για να αρνηθείτε, απαντήστε με 4xx και { "error": "<code>", "details": ["<why>"] }. Στο path.add, το invalid_value επιστρέφει την τιμή στον συγγραφέα με τον λόγο σας (η τρίτη άρνηση είναι οριστική) και οποιοσδήποτε άλλος κωδικός την απορρίπτει οριστικά. Στο path.remove, το not_found θεωρείται ολοκληρωμένο, και οποιοσδήποτε άλλος κωδικός, όπως το 409 in_use, αφήνει τα πάντα όπως ήταν. Η επισήμανση μιας εντολής διαδρομής σε αναμονή ως Έγινε στην τοποθεσία προσμετράται ως δικό σας «ναι».

Κλήσεις: αιτήματα των οποίων την απάντηση διαβάζει το AutoPSEO

Οι κλήσεις υπογράφονται όπως οι παραδόσεις. Μια κλήση περιμένει έως 60 δευτερόλεπτα από προεπιλογή και 30 δευτερόλεπτα για επαναναγνώσεις και ελέγχους διαδρομής, και διαβάζει απαντήσεις έως 24 MB. Οποιαδήποτε απάντηση εκτός από 2xx αποτυγχάνει την κλήση.

site.export

Το αίτημα περιέχει export: { what, cursor, limit }, συν since (ώρα ISO) για θέματα ή paths για επανάγνωση. Απαντήστε { "items": [], "next": "<cursor>" }· το AutoPSEO ρωτά ξανά με το cursor ίσο με το next σας μέχρι να είναι κενό ή null.

  • Το what: "articles" εκτελείται σε πλήρεις σαρώσεις τοποθεσίας, 10 ανά σελίδα, όταν έχετε δηλώσει export με articles και adopt: true. Μια απάντηση 400 σημαίνει «δεν υποστηρίζεται». Με paths: ["/answers/x"] και limit: 1 διαβάζει ξανά ένα άρθρο· απαντήστε μόνο με αυτό το άρθρο.
  • Το what: "topics" εκτελείται σε κάθε σάρωση και στον ημερήσιο συγχρονισμό, 50 ανά σελίδα· ο ημερήσιος συγχρονισμός στέλνει since, την ώρα της τελευταίας λήψης.
  • Το what: "profile" εκτελείται σε κάθε σάρωση. Απαντήστε { "profile": { types, languages, rules, categories, format } }, όλα προαιρετικά: types ως [{ key, name, path }], και rules με brandTerms, synonyms, noise, onTopic και offTopic.

Ένα εξαγόμενο άρθρο χρειάζεται externalId, slug (γράμματα και ψηφία οποιασδήποτε γραφής και παύλες, έως 200 χαρακτήρες, τμήματα ενωμένα με /), path που τελειώνει σε αυτό το slug, και copy με τουλάχιστον title, h1 και μία ενότητα. Προαιρετικά πεδία: lang (προεπιλογή en), type (κλειδί τύπου περιεχομένου), url, keyword, category, datePublished, dateModified, version, translations, owner (το αναγνωριστικό άρθρου του AutoPSEO, μόλις υιοθετηθεί) και maintenance: { kind: "refresh" or "optimize", reason }, που βάζει στην ουρά αυτή την εργασία. Κάθε εξαγόμενο άρθρο γίνεται διαχειριζόμενο άρθρο με το κείμενό σας ως πρώτη αναθεώρηση, και δεν στέλνεται τίποτα πίσω. Η εκ νέου εξαγωγή είναι ασφαλής, και ένα άρθρο που απέσυρε το AutoPSEO δεν επιστρέφει ποτέ μέσω εξαγωγής.

Ένα στοιχείο θέματος είναι { keyword, status?, volume?, source?, externalId?, type?, reason? }, όπου το status είναι queued, planned ή rejected.

articles.adopted

Μετά την εισαγωγή, το AutoPSEO σας ζητά να του επιτρέψετε να διαχειριστεί τα νέα άρθρα: { "articles": [{ "externalId", "articleId", "slug", "path" }] }. Απαντήστε { "adopted": ["<externalId>"], "refused": [{ "externalId": "<id>", "reason": "<why>" }] }. Ένα άρθρο που δεν επιβεβαιώνετε αφαιρείται ξανά από το AutoPSEO, εκτός αν το AutoPSEO έχει ήδη γράψει αναθεώρησή του.

site.handover

{ "handover": { "types": ["answers"], "writer": "autopseo" } }, που αποστέλλεται όταν κάποιος επιλέγει Ας τα γράφει το AutoPSEO ή Επιστροφή της συγγραφής στην τοποθεσία στη σελίδα Η τοποθεσία σας της ιδιότητας. Απαντήστε { "ok": true, "writer": "autopseo" }. Μετά την ανάθεση στο AutoPSEO, η τοποθεσία σας περνά στο AutoPSEO τα θέματα που εγκρίνει, αντί να τα γράφει η ίδια.

path.check

{ "paths": [{ "path": "/interviews/google/data-engineer" }, { "path": "/interviews/jane-street", "new": { "part": "company", "value": "jane-street", "name": "Jane Street" } }] }. Απαντήστε με ένα αποτέλεσμα ανά διαδρομή: { "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."] }] }. Μια άρνηση διατηρείται με τον λόγο σας και δεν ξαναρωτιέται· μια διαδρομή που παραλείπετε ξαναρωτιέται αργότερα.

Ένας ελάχιστος δέκτης

Ένα Cloudflare Worker που επαληθεύει την υπογραφή με το Web Crypto API, χειρίζεται τις τρεις εντολές άρθρου και αρνείται τις υπόλοιπες ως unknown_event. Κρατά τα άρθρα σε έναν χώρο ονομάτων KV συνδεδεμένο ως ARTICLES, και το μυστικό υπογραφής σε ένα μυστικό του Worker με όνομα AUTOPSEO_SECRET.

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, επαληθεύστε με τον ίδιο τρόπο με createHmac και timingSafeEqual, πάνω στο ακατέργαστο σώμα που έλαβε το framework σας:

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));
}

Επόμενο βήμα: το τι φτάνει στο webhook αποφασίζεται από τη συγγραφή και αναθεώρηση και τη συντήρηση· ολόκληρη η ροή βρίσκεται στην επισκόπηση της μηχανής περιεχομένου.

Βάλτε το SEO περιεχόμενό σας σε αυτόματο πιλότο

Συνδέστε το Search Console και τον ιστότοπό σας. Το AutoPSEO τον σαρώνει και σχεδιάζει άμεσα τα πρώτα θέματα. Δεν απαιτείται πιστωτική κάρτα.