Τεκμηρίωση
Webhook παράδοσης: λήψη άρθρων στη δική σας τοποθεσία
Το υπογεγραμμένο webhook που στέλνει τα άρθρα του AutoPSEO στη δική σας τοποθεσία: κεφαλίδες, κάθε συμβάν και payload, οι απαντήσεις που πρέπει να δίνετε, επαναλήψεις, εντολές σε αναμονή και IndexNow.
Το AutoPSEO στέλνει κάθε άρθρο που δημοσιεύει, ενημερώνει ή αποσύρει στη δική σας τοποθεσία ως υπογεγραμμένο HTTPS POST. Η τοποθεσία σας αποθηκεύει το άρθρο και το αποδίδει με τα δικά της πρότυπα, ώστε το περιεχόμενο να ζει στο δικό σας σύστημα και να συνεχίσει να λειτουργεί ακόμη κι αν κάποτε φύγετε. Αυτή η σελίδα είναι ο οδηγός αναφοράς για τον προγραμματιστή που υλοποιεί τον δέκτη: υπογραφή, κάθε συμβάν με το payload του, οι απαντήσεις που διαβάζει το AutoPSEO, επαναλήψεις, εντολές σε αναμονή και IndexNow.
Ρύθμιση του webhook
- Ανοίξτε τη σελίδα Περιεχόμενο της ιδιότητας και μεταβείτε στο Πού δημοσιεύονται τα άρθρα.
- Συμπληρώστε το πεδίο Διεύθυνση webhook στην τοποθεσία σας. Πρέπει να είναι URL
https://με δημόσιο όνομα υπολογιστή: οι διευθύνσεις IP και τοlocalhostαπορρίπτονται. Το AutoPSEO δεν ακολουθεί ανακατευθύνσεις, επομένως δώστε την τελική διεύθυνση. - Συμπληρώστε το πεδίο Διεύθυνση της τοποθεσίας σας, για παράδειγμα
https://example.com. Η διαδρομή κάθε τύπου περιεχομένου εκτείνεται κάτω από αυτήν, οπότε ένα άρθρο τύπου με διαδρομή/answersβρίσκεται στοhttps://example.com/answers/<slug>. - Επιλέξτε Αποθήκευση και αποστολή δοκιμής. Το AutoPSEO δημιουργεί ένα μυστικό υπογραφής (
whsec_ακολουθούμενο από 48 δεκαεξαδικούς χαρακτήρες) και στέλνει ping στη διεύθυνσή σας. Ένας δέκτης που ελέγχει τις υπογραφές θα αποτύχει σε αυτό το πρώτο ping, επειδή δεν έχει ακόμη το μυστικό. - Εμφανίστε το Μυστικό υπογραφής με Εμφάνιση ή Αντιγραφή, αποθηκεύστε το ως μυστικό στην τοποθεσία σας και έπειτα επιλέξτε Αποστολή δοκιμής.
- Διαβάστε το Τι χειρίζεται η τοποθεσία σας: κάθε εντολή εμφανίζεται ως Συνδεδεμένη, Μη συνδεδεμένη, Δηλωμένη, χωρίς δοκιμή ή Χωρίς δοκιμή.
Οι νέες ιδιότητες ξεκινούν με το AutoPSEO να φιλοξενεί τα άρθρα στη δική του διεύθυνση (δείτε Φιλοξενία), και η φιλοξενία με το webhook μπορούν να λειτουργούν παράλληλα. Μόλις η τοποθεσία σας εμφανίζει τα άρθρα, επιλέξτε Διακοπή φιλοξενίας στο AutoPSEO: κάθε δημοσιευμένο άρθρο μεταφέρεται στη διεύθυνση της τοποθεσίας σας και αποστέλλεται στο webhook σας ως article.published. Αυτό το κουμπί απαιτεί webhook που απάντησε στην τελευταία δοκιμή του και τη διεύθυνση της τοποθεσίας σας. Όσο η φιλοξενία είναι απενεργοποιημένη, το webhook δεν μπορεί να αφαιρεθεί.
Το Νέο μυστικό αντικαθιστά το μυστικό υπογραφής αμέσως και το παλιό παύει να επαληθεύεται άμεσα. Βάλτε το νέο μυστικό στην τοποθεσία σας αμέσως μετά τη δημιουργία του.
Το AutoPSEO βάζει παραδόσεις στην ουρά μόνο για webhook του οποίου το τελευταίο ping απαντήθηκε με 2xx. Ένα ping που αποτυγχάνει (κατά την αποθήκευση, στο Αποστολή δοκιμής ή στην αρχή μιας σάρωσης τοποθεσίας) σημειώνει το webhook ως εσφαλμένο, και τα άρθρα που δημοσιεύονται όσο βρίσκεται σε σφάλμα δεν μπαίνουν στην ουρά γι' αυτό. Φροντίστε το ping να απαντά και επιλέξτε Αποστολή δοκιμής αφού αποκαταστήσετε μια διακοπή.
Κεφαλίδες και υπογραφή
Κάθε αίτημα είναι POST με σώμα JSON και τις παρακάτω κεφαλίδες:
| Κεφαλίδα | Τιμή |
|---|---|
Content-Type | application/json |
User-Agent | AutoPSEO-Webhook/1 |
X-AutoPSEO-Event | Το όνομα του συμβάντος, που υπάρχει και στο σώμα ως event |
X-AutoPSEO-Delivery | Το αναγνωριστικό της παράδοσης, που υπάρχει και στο σώμα ως id. Είναι το ίδιο σε κάθε επανάληψη της ίδιας παράδοσης |
X-AutoPSEO-Timestamp | Ώρα Unix σε δευτερόλεπτα κατά την οποία υπογράφηκε αυτή η προσπάθεια |
X-AutoPSEO-Signature | sha256= ακολουθούμενο από το δεκαεξαδικό HMAC-SHA256 του <timestamp>.<raw body> |
Για να επαληθεύσετε ένα αίτημα:
- Πάρτε την κεφαλίδα χρονοσήμανσης, μια τελεία και το ακατέργαστο σώμα του αιτήματος ακριβώς όπως έφτασε, πριν από οποιαδήποτε ανάλυση JSON.
- Υπολογίστε HMAC-SHA256 σε αυτή τη συμβολοσειρά. Το κλειδί είναι ολόκληρο το μυστικό υπογραφής όπως το εμφανίζει η εφαρμογή, με το πρόθεμα
whsec_, ως byte UTF-8. - Κωδικοποιήστε το αποτέλεσμα σε δεκαεξαδική μορφή και συγκρίνετέ το με το τμήμα του
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, dateModified | YYYY-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"
}
}
| Πεδίο | Σημασία |
|---|---|
version | 1. Το αντικείμενο αγνοείται χωρίς έκδοση 1 ή μεγαλύτερη |
events | Οι εντολές που χειρίζεστε, εμφανίζονται ως δηλωμένες μέχρι να δοκιμαστούν |
covers | true όταν οι σελίδες σας εμφανίζουν εξώφυλλο με κάθε άρθρο. Ο συγγραφέας του 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 αποφασίζεται από τη συγγραφή και αναθεώρηση και τη συντήρηση· ολόκληρη η ροή βρίσκεται στην επισκόπηση της μηχανής περιεχομένου.