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

Οδηγοί

Εργασίες

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

Τι είναι η εργασία

Μια εργασία (task_...) είναι μια εξερχόμενη καμπάνια: ένας πράκτορας στη μηχανή του volai, μια λίστα παραληπτών με τηλεφωνικό αριθμό και προαιρετικές μεταβλητές για το system prompt, και κανόνες (προϋπολογισμός, παράθυρο κλήσεων, μέγιστος αριθμός προσπαθειών και διάρκεια κλήσης). Τρεις τύποι ανάλογα με τον σκοπό - invoice (υπενθύμιση πληρωμής), appointment (επιβεβαίωση ραντεβού) και custom (οτιδήποτε άλλο) - στους δύο πρώτους, όταν το source είναι integration, κάθε παραλήπτης φέρει επιπλέον αναφορά σε παραστατικό ή συμβάν (externalRefs), την οποία ο πράκτορας αναφέρει στην κλήση.

Ο πράκτορας πρέπει να βρίσκεται στη δική μηχανή του volai (useForOutboundTasks: true κατά τη δημιουργία, βλ. POST /v1/agents), όχι στο ElevenLabs - η μηχανή υποστηρίζει μεταβλητές για το system prompt, όρια διάρκειας κλήσης και επαλήθευση ότι η διαμόρφωσή της δεν άλλαξε κατά τη διάρκεια της καμπάνιας. Το πρόχειρο του πράκτορα πρέπει να είναι ΔΗΜΟΣΙΕΥΜΕΝΟ (PATCH /v1/agents/{id} ή POST /v1/agents/{id}/draft/publish) ΚΑΙ η δημοσιευμένη έκδοση πρέπει να έχει ΔΟΚΙΜΑΣΤΕΙ (POST /v1/agents/{id}/simulate) - αν λείπει οποιοδήποτε βήμα, η εκκίνηση επιστρέφει agent_not_ready.

Καταστάσεις και μεταβάσεις

Στην πράξη μια εργασία πηγαίνει πάντα από το `draft` κατευθείαν στο `running` (`start`)· η διαγραφή (`DELETE`) επιτρέπεται μόνο στις σημειωμένες καταστάσεις.

draft
Τι σημαίνειΜόλις δημιουργήθηκε, δεν έχει εκτελεστεί ποτέ start. Επεξεργάσιμη (PATCH), διαγράψιμη.
ready
Τι σημαίνειΚατάσταση του μοντέλου ανάμεσα στο draft και το running, την οποία το start δέχεται ως αφετηρία - κανένα δημόσιο endpoint (REST ή MCP) δεν μεταφέρει σήμερα εργασία σε αυτήν, οπότε στην πράξη δεν θα τη συναντήσετε. Αν προέκυπτε, είναι επεξεργάσιμη και διαγράψιμη όπως το draft.
running
Τι σημαίνειΚαλεί παραλήπτες. ΜΗ ΕΠΕΞΕΡΓΑΣΙΜΗ - το PATCH επιστρέφει task_not_editable χωρίς εξαίρεση. Όποιος χρειάζεται να αλλάξει μεταβλητές, πρέπει πρώτα να σταματήσει την εργασία (POST .../pause) και να την επεξεργαστεί στο paused - και μόνο όσο δεν έχει κληθεί ακόμη κανένας παραλήπτης· μετά την πρώτη προσπάθεια τα recipients (και άρα οι μεταβλητές) δεν μπορούν να αντικατασταθούν (items_immutable) και μένει να δημιουργήσετε νέα εργασία. Δεν διαγράφεται. Όταν φτάσει σε όριο κλήσεων (rate_limited - όριο εξερχόμενων λεπτών της δικής μας μηχανής, ανώτατο όριο ταυτόχρονων εξερχόμενων κλήσεων της, από προεπιλογή 10 κλήσεις το λεπτό ή 1000 την ημέρα), παραμένει running: ορίζει lastError: "rate_limited", η προσπάθεια δεν μετρά και οι επαφές που περιμένουν παίρνουν items[].nextAttemptAt στο τέλος του ορίου (σύμφωνα με το Retry-After, αλλιώς σε 5 λεπτά· για το όριο ταυτόχρονων κλήσεων της μηχανής η μηχανή στέλνει Retry-After: 30). Μετά τη λήξη του συνεχίζει μόνη της. Περιμένει με τον ίδιο τρόπο όταν είναι γεμάτη η ποσόστωση ταυτόχρονων κλήσεων του πράκτορα ανά λογαριασμό (relay_lease_limit, από προεπιλογή 2 κλήσεις σε εξέλιξη): lastError: "relay_lease_limit", επόμενη προσπάθεια σε ένα λεπτό, η προσπάθεια δεν μετρά. Κατειλημμένος αριθμός (destination_busy - στον ίδιο αριθμό εκτελείται αυτή τη στιγμή άλλη κλήση, για παράδειγμα από άλλη εργασία ή χειροκίνητη κλήση, ή ο αριθμός είναι κλειδωμένος για 15 λεπτά μετά από αβέβαιη κλήση) κάνει να περιμένει μόνο η συγκεκριμένη επαφή, όχι ολόκληρη η εργασία: items[].lastError: "destination_busy", items[].nextAttemptAt σύμφωνα με τον υπολειπόμενο χρόνο κλειδώματος του αριθμού (τουλάχιστον 30 s, το πολύ 16 λεπτά, χωρίς κλείδωμα 90 s), η προσπάθεια δεν μετρά (countsAsAttempt: false) και οι υπόλοιπες επαφές συνεχίζουν να καλούνται. Μετά την 6η συνεχόμενη κατάληψη (δηλαδή μετά από 5 αναμονές) η επαφή πηγαίνει σε review με reviewReason: "dial:destination_busy". Μόνιμο εμπόδιο στον αριθμό (on_dnc, destination_auto_blocked, cannot_call_own_number, cannot_call_volai_number, invalid_number, unsupported_country, blocked_destination) δεν σταματά ούτε αυτό την εργασία: η επαφή πηγαίνει σε review με reviewReason: "dial:<code>" (η κλήση δεν δημιουργήθηκε, οπότε η προσπάθεια έχει countsAsAttempt: false και δεν καταναλώνει το maxAttempts), η εργασία παραμένει running, καλεί τις υπόλοιπες επαφές και περνά σε needs_attention μόνο όταν δεν έχει μείνει άλλη δουλειά. Όταν ο διαχειριστής του volai παγώσει χειροκίνητα τον πράκτορα της εργασίας, η εργασία παραμένει running και δεν καλεί τίποτα· μετά την επαναφορά συνεχίζει μόνη της. Έναν παγωμένο πράκτορα τον αναγνωρίζετε από το suspended: true στο GET /v1/agents/{id}.
paused
Τι σημαίνειΣταμάτησε πριν από την επόμενη κλήση (POST .../pause)· κλήση που έχει ήδη ξεκινήσει ολοκληρώνεται. Επεξεργάσιμη, διαγράψιμη, το start την επαναφέρει. Παύση στη μέση κλήσης αφήνει reviewReason: "dispatch_in_flight" μέχρι το reconcile (ο χρονοπρογραμματιστής το εκτελεί μέσα σε λίγα λεπτά) να εκκαθαρίσει την κλήση, και μέχρι τότε το start απορρίπτεται με task_needs_attention· στη συνέχεια εργασία με υπολειπόμενη δουλειά παραμένει paused, ακόμη κι αν άλλες επαφές περιμένουν σε review. Παύση που πέφτει λίγο πριν από την ίδια την κλήση (η κλήση δεν έχει ακόμη δημιουργηθεί) δεν αφήνει dispatch_in_flight: ο χρονοπρογραμματιστής επιστρέφει την επαφή στις εκκρεμείς και η εργασία είναι αμέσως paused χωρίς λόγο. Επαφή της οποίας η επεξεργασία διακόπηκε από κατάρρευση πριν δημιουργηθεί κλήση, ελευθερώνεται από το reconcile το νωρίτερο 15 λεπτά μετά την έναρξη της κλήσης (claim 10 λεπτών συν περιθώριο 5 λεπτών) και επιστρέφει στις εκκρεμείς· εργασία που είχε σταματήσει στο μεταξύ λόγω ληγμένου claim (dispatch_claim_expired) περνά τότε σε paused. Αν μια κλήση σε εξέλιξη τελειώσει χωρίς γνωστή τιμή, η εργασία περνά πρώτα σε needs_attention με reviewReason: "billing_unknown" και επιστρέφει σε paused όταν φτάσει η τιμή (την συμπληρώνει το reconcile). Αν στο μεταξύ μειώσετε το maxAttempts έτσι ώστε καμία επαφή που περιμένει επόμενη προσπάθεια να μην έχει ελεύθερη προσπάθεια, η εργασία παραμένει paused (μια τέτοια επαφή μετρά ως δουλειά), αλλά το start την απορρίπτει με task_not_startable μέχρι να αυξήσετε το maxAttempts.
completed
Τι σημαίνειΌλοι οι παραλήπτες έχουν τελικό αποτέλεσμα. Διαγράψιμη (δεν εκκρεμεί πια τίποτα).
needs_attention
Τι σημαίνειΚάτι απαιτεί παρέμβαση - συνήθως άλλαξε η διαμόρφωση του πράκτορα κατά την εκτέλεση (agent_version_changed), η μηχανή δεν ήταν προσωρινά διαθέσιμη (engine_contract_unavailable) ή δεν είναι ακόμη γνωστή η τιμή κλήσης που έχει ήδη γίνει (billing_unknown). Το POST .../reconcile συμφιλιώνει την κατάσταση· διαγράψιμη όσο κανένα στοιχείο δεν έχει μείνει in_progress. Επαφή σε κατάσταση review τη διευθετείτε μέσω POST .../items/{itemId}/resolve (retry/skip)· επαφή με μόνιμο εμπόδιο στον αριθμό (dial:on_dnc, dial:destination_auto_blocked, dial:cannot_call_own_number, dial:cannot_call_volai_number, dial:invalid_number, dial:unsupported_country, dial:blocked_destination, ή dial:destination_busy μετά την 6η συνεχόμενη κατάληψη) σταματά την εργασία μόνο όταν ολοκληρωθούν οι υπόλοιπες επαφές. Αβέβαιο αποτέλεσμα κλήσης (π.χ. dial:engine_unavailable) στέλνει την εργασία σε needs_attention αμέσως και οι υπόλοιπες επαφές δεν καλούνται. Όταν η κλήση πίσω από μια τέτοια διακοπή (ή άγνωστη τιμή) εκκαθαριστεί μέσω reconcile, η εργασία περνά σε paused όσο κάποια επαφή περιμένει επόμενη προσπάθεια, ακόμη κι αν άλλες είναι σε review· σε needs_attention μόνο όταν δεν μένει τίποτα προς κλήση εκτός από επαφή σε review, και σε completed όταν δεν μένει τίποτα. Κλήση της οποίας το αποτέλεσμα παραμένει αβέβαιο (η κλήση δεν βρίσκεται) κρατά την εργασία σε needs_attention μέχρι να αποφασίσετε για την επαφή. Για συνηθισμένο λόγο, μετά την τελευταία απόφαση η εργασία περνά σε paused αν μένει δουλειά, ή σε completed αν όλες οι επαφές έχουν ολοκληρωθεί ή παραλειφθεί. Λόγος σε επίπεδο ολόκληρης της εργασίας παραμένει σε needs_attention μέχρι να επιλυθεί· εξαίρεση αποτελεί το budget_exceeded, όπου η παράλειψη όλων των επαφών που περιμένουν επόμενη προσπάθεια ολοκληρώνει την εργασία, αν δεν εκκρεμεί κατάσταση παρόχου. Ιδιαίτερη διαδικασία για το billing_unknown υπάρχει παρακάτω.

Η ακριβής προϋπόθεση διαγραφής: η κατάσταση είναι μία από τις παραπάνω σημειωμένες ΚΑΙ κανένα στοιχείο δεν έχει status: "in_progress" (κλήση που έχει ξεκινήσει και δεν έχει τελειώσει) - αλλιώς task_not_deletable.

Εισαγωγή παραληπτών (CSV)

Το POST /v1/tasks/csv-preview αναλύει ένα CSV και το επιστρέφει με σφάλματα ανά γραμμή - ΤΙΠΟΤΑ δεν αποθηκεύεται, είναι μόνο προεπισκόπηση πριν από τη δημιουργία ή την ενημέρωση μιας εργασίας. Την ίδια λειτουργία καλεί και η φόρμα νέας εργασίας στην πύλη.

  • Ο διαχωριστής αναγνωρίζεται αυτόματα (κόμμα ή ερωτηματικό) από την πρώτη γραμμή.
  • Πρέπει να υπάρχει στήλη phone - δεν παίζουν ρόλο τα πεζά-κεφαλαία, τα κενά γύρω από το όνομα ούτε η άνω και κάτω τελεία μετά από αυτό, ενώ γίνονται δεκτά και τα telefon, tel ή mobile· στην προεπισκόπηση η στήλη επιστρέφεται πάντα ως phone. Δεκτή είναι και απλή λίστα αριθμών χωρίς κεφαλίδα (ένας ανά γραμμή, μία μόνο στήλη). Διαφορετικά ολόκληρο το CSV αποτυγχάνει με ένα μόνο σφάλμα phone στην κεφαλίδα.
  • Κάθε άλλη στήλη είναι μεταβλητή για το system prompt του πράκτορα ({{column_name}}) - το πολύ 20 στήλες, όνομα έως 64 χαρακτήρες, τιμή έως 512 χαρακτήρες.
  • Ο τηλεφωνικός αριθμός κανονικοποιείται όπως παντού στο API (normalizePhone) - ένας άκυρος ή κενός αριθμός είναι σφάλμα μόνο σε ΑΥΤΗ τη γραμμή, το υπόλοιπο CSV επεξεργάζεται κανονικά.
  • Κελί που μοιάζει με τύπο υπολογιστικού φύλλου (ξεκινά με =, +, - ή @) απορρίπτεται - προστασία από CSV injection κατά το άνοιγμα στο Excel.
  • Το πολύ 1000 γραμμές ανά CSV (το ίδιο όριο με τον αριθμό παραληπτών μιας εργασίας) και 1 MB ακατέργαστου κειμένου· ολόκληρη η εργασία μαζί με τα δεδομένα της πρέπει να χωράει σε 2 MB, αλλιώς η δημιουργία επιστρέφει validation.

Η απάντηση περιλαμβάνει headers, delimiter, rows (κάθε γραμμή με τα δικά της σφάλματα), validRows (μόνο οι άψογες, ακριβώς στη μορφή που περιμένει το recipients στο POST /v1/tasks) και συγκεντρωτικό πίνακα errors. Στείλτε τα validRows απευθείας ως recipients κατά τη δημιουργία ή την ενημέρωση της εργασίας.

Προϋπολογισμός και παράθυρο κλήσεων

Προϋπολογισμός

Το budgetHal είναι το ΟΡΙΟ δαπάνης για ολόκληρη την εργασία, στη μικρότερη υποδιαίρεση του νομίσματος (hal). Κατά τη δημιουργία πρέπει να καλύπτει τουλάχιστον μία προσπάθεια μέγιστης διάρκειας (αλλιώς budget_too_low)· κατά την εκκίνηση, πριν από ΚΑΘΕ κλήση δεσμεύεται η υψηλότερη δυνατή τιμή της προσπάθειας (reservedBudgetHal) και μόνο μια κλήση που απαντήθηκε τη μεταφέρει στο spentHal. Η δέσμευση είναι η τιμή κλήσης ακριβώς διάρκειας maxDurationSecs (σκέλος κλήσης και σκέλος πράκτορα, το καθένα στρογγυλοποιημένο προς τα πάνω στο hal, όπως στη χρέωση) και μια κλήση που τερματίστηκε από το όριο διάρκειας χρεώνεται το πολύ για maxDurationSecs, ακόμη κι αν τελειώσει κλάσμα δευτερολέπτου αργότερα. Η εργασία δεν ξοδεύει ποτέ περισσότερα από όσα της δίνετε στο budgetHal.

Παράθυρο κλήσεων

Το callingWindow είναι {timezone: "Europe/Prague", start, end, days} - σήμερα η μόνη υποστηριζόμενη ζώνη ώρας είναι της Πράγας, τα start/end σε μορφή HH:MM (το τέλος συμπεριλαμβάνει ολόκληρο το λεπτό: παράθυρο 09:00-18:00 επιτρέπει την τελευταία κλήση στις 18:00:59, παράθυρο μέχρι 23:59 καλύπτει ολόκληρη την ημέρα) και τα days είναι αριθμοί 0-6 (0 = Κυριακή). Χωρίς ρύθμιση ισχύουν οι εργάσιμες 9:00-18:00. Εκτός παραθύρου το start επιστρέφει window_closed - είτε περιμένετε να ανοίξει, είτε αλλάξτε το παράθυρο με PATCH. Το προαιρετικό expiresAt είναι το τέλος της καμπάνιας ως θετικός ασφαλής ακέραιος σε χιλιοστά του δευτερολέπτου Unix. Ελέγχεται κατά την εκκίνηση και πριν από κάθε κλήση, συμπεριλαμβανομένης της πρώτης. Από αυτή τη στιγμή δεν ξεκινά νέα κλήση και καμία προσπάθεια δεν καταναλώνεται· κλήση σε εξέλιξη ολοκληρώνεται. Ο ορίζοντας επανάληψης της πολιτικής lorela_enterprise (retryMaxAgeDays, από προεπιλογή 5) αντίθετα υπολογίζεται ως N × 24 ώρες από την πρώτη προσμετρούμενη προσπάθεια, όχι από τη δημιουργία της εργασίας.

Προσπάθειες και διάρκεια κλήσης

Το maxAttempts είναι 1-3 χωρίς πολιτική (προεπιλογή 1), με retryPolicy: "lorela_enterprise" 1-4 (προεπιλογή κατά τη δημιουργία 4). Καθορίζει τον μέγιστο αριθμό αυτόματων κλήσεων μιας επαφής, συμπεριλαμβανομένης της πρώτης (1 = χωρίς επανάληψη). Μετρά κάθε προσπάθεια κατά την οποία η κλήση θα μπορούσε να έχει γίνει, άρα και κλήση που δεν απαντήθηκε, κλήση που απέρριψε ο καλούμενος και προσπάθεια με αβέβαιο αποτέλεσμα. Δεν μετρά προσπάθεια που το volai απέρριψε πριν από την κλήση (για παράδειγμα αποκλεισμένος, δικός σας ή άκυρος αριθμός, λίστα μη κλήσης, αριθμός στον οποίο εκτελείται ήδη άλλη κλήση, όρια κλήσεων)· μια τέτοια προσπάθεια έχει items[].attempts[].countsAsAttempt: false. Δεν μετρά ούτε κλήση της οποίας ο προορισμός δεν έφτασε εγκαίρως στον πάροχο, οπότε το τηλέφωνο του καλούμενου δεν χτύπησε καθόλου (η προσπάθεια έχει errorCode: "relay_not_routed", η κλήση endReason: "rejected"): η επαφή παίρνει νέα προσπάθεια το νωρίτερο σε ένα λεπτό (με την πολιτική lorela_enterprise σύμφωνα με το πρόγραμμά της) και μετά την τρίτη τέτοια προσπάθεια στη σειρά πηγαίνει για έλεγχο με reviewReason: "call:relay_not_routed". Δεν μετρά ούτε κλήση για την οποία η φωνητική μηχανή μας δεν ενημέρωσε ποτέ και την οποία κλείσαμε μετά από δύο ώρες χωρίς αναφορά ως μη πραγματοποιημένη και χωρίς τιμή (η προσπάθεια έχει errorCode: "no_provider_report"): η επαφή επιστρέφει στις εκκρεμείς και παίρνει νέα προσπάθεια το νωρίτερο σε ένα λεπτό (με την πολιτική lorela_enterprise σύμφωνα με το πρόγραμμά της). Τρεις μη προσμετρούμενες προσπάθειες στη σειρά, ακόμη και αναμεμειγμένες με προσπάθειες relay_not_routed, στέλνουν την επαφή για έλεγχο με reviewReason σύμφωνα με την τελευταία, δηλαδή call:no_provider_report· επαφές που μια τέτοια κλήση είχε στείλει νωρίτερα για έλεγχο (call:failed, με την πολιτική call:unknown) δεν ανανεώνονται μόνες τους. Χωρίς πολιτική το όριο ισχύει μόνο για τις αυτόματες κλήσεις: επαφή στην οποία, αφού εξαντληθούν οι προσπάθειες, εκτελέσετε resolve με action: "retry", παίρνει μία ακόμη κλήση. Το maxDurationSecs (30-300) είναι το όριο διάρκειας ΜΙΑΣ κλήσης, μετά το οποίο τερματίζεται αυτόματα - η προεπιλεγμένη διάρκεια είναι 120 δευτερόλεπτα. Η προαιρετική πολιτική lorela_enterprise ενεργοποιείται μέσω API ή MCP πριν από την πρώτη προσπάθεια· οι υπάρχουσες εργασίες δεν αλλάζουν μόνες τους. Η δεύτερη προσπάθεια γίνεται το νωρίτερο 8 λεπτά από την έναρξη της πρώτης πραγματικής προσπάθειας, μέσα στις 08:00-22:00 Europe/Prague. Η τρίτη πηγαίνει στο επόμενο διαφορετικό παράθυρο 08:00-09:00 ή 17:00-19:00, η τέταρτη στο αντίθετο παράθυρο την επόμενη ημερολογιακή ημέρα. Ισχύει πάντα και το callingWindow με τις ημέρες του· μετά τον ορίζοντα επανάληψης η πολιτική δεν καλεί ξανά: το προαιρετικό retryMaxAgeDays είναι ακέραιος αριθμός ημερών 1-30 (5 αν δεν δοθεί) και ισχύει μόνο με την πολιτική. Ο ορίζοντας λήγει N × 24 ώρες από την πρώτη προσμετρούμενη προσπάθεια της επαφής (σταθερές ημέρες 24 ωρών, οπότε με αλλαγή ώρας η τοπική ώρα λήξης μετατοπίζεται κατά μία ώρα). Μπορεί να αλλάξει μέσω PATCH και μετά την έναρξη των προσπαθειών (όχι σε εργασία running ή completed, που δεν επεξεργάζεται): η αύξηση σε εργασία σε παύση επιστρέφει τις επαφές που απορρίφθηκαν μόνο λόγω ορίζοντα (reviewReason: "retry_age_expired") στην κατάσταση failed (περιμένουν επόμενη προσπάθεια) με νέο nextAttemptAt, αν έχουν ακόμη ελεύθερη προσπάθεια και η πλησιέστερη θέση του προγράμματος πέφτει μέσα στον νέο ορίζοντα και πριν από το expiresAt· η μείωση δεν ανοίγει τίποτα. Ξανανοίγει μόνο ένα PATCH που αυξάνει τον ορίζοντα, γι' αυτό στείλτε το retryMaxAgeDays και το παρατεταμένο expiresAt στο ίδιο αίτημα. Επαναλαμβάνονται μόνο τα no_answer, missed, busy, ολοκληρωμένο τηλεφωνητή και απαντημένη κλήση στην οποία ο καλούμενος δεν είπε τίποτα (όλα χωρίς επαφή με άνθρωπο). Επαφή με άνθρωπο, άρνηση και σφάλμα της μηχανής σταματούν τις αυτόματες επαναλήψεις· ασαφές αποτέλεσμα πηγαίνει για έλεγχο. Η τελευταία επιτρεπόμενη προσπάθεια (maxAttempts) που τελειώνει με τέτοιο επαναλήψιμο αποτέλεσμα (αναπάντητη, κατειλημμένο, τηλεφωνητής ή απαντημένη κλήση στην οποία ο καλούμενος δεν είπε τίποτα) κλείνει την επαφή ως skipped με reviewReason: "retry_policy_exhausted" (όπως το retry_age_expired μετά τη λήξη του ορίζοντα): δεν υπάρχει τίποτα να ελεγχθεί ή να επαναληφθεί. Ασαφές αποτέλεσμα της τελευταίας προσπάθειας μένει σε review με τον ίδιο λόγο. Χωρίς πολιτική δεν αλλάζει τίποτα: η τελευταία αναπάντητη προσπάθεια παραμένει review. Επαληθευμένη επιστροφή κλήσης από άνθρωπο μετά την εξάντληση των προσπαθειών μεταφέρει την επαφή σε completed. Το DNC, ο προϋπολογισμός και τα όρια παραμένουν σε ισχύ: ο αυτόματος αποκλεισμός μετά από 3 αποτυχίες σε 24 ώρες μπορεί να σταματήσει και την τέταρτη προσπάθεια. Σε PATCH χωρίς maxAttempts παραμένει το υπάρχον όριο. Με την πολιτική το χειροκίνητο resolve με action: "retry" επιστρέφει σφάλμα validation· επιτρέπονται μόνο οι αυτόματα προγραμματισμένες προσπάθειές της. Εξαίρεση αποτελεί η επαναφορά αποδεδειγμένα μη πραγματοποιημένου ληγμένου claim πριν από την πρώτη πραγματική προσπάθεια: χωρίς ενεργό worker, πρόθεση dispatch, provider call ID, δέσμευση, τιμή ή callback και μόνο με αποδεδειγμένες απορρίψεις πριν από την κλήση στο ιστορικό. Η επαναφορά διατηρεί το ιστορικό και τα όρια και επιστρέφει την επαφή στις εκκρεμείς σε εργασία σε παύση· δεν καλεί η ίδια. Οι υπενθυμίσεις δεν μπορούν να ξανανοιχτούν με αυτόν τον τρόπο. Η χειροκίνητη επανάληψη δεν παρακάμπτει λοιπόν τις τέσσερις προσπάθειες, τον ορίζοντα επανάληψης ούτε τον τερματισμό μετά από επαφή με άνθρωπο.

Συνολική διεκπεραιωτική ικανότητα

Η κλήση όλων των εργασιών σε ΟΛΟΚΛΗΡΗ την πλατφόρμα (όχι μόνο στον λογαριασμό σας) περνά από ένα cron που τρέχει κάθε 2 λεπτά και επεξεργάζεται το πολύ 20 στοιχεία ανά εκτέλεση - ΑΛΛΑ αυτό το όριο μοιράζεται ανάμεσα στις ταυτόχρονα εκτελούμενες εργασίες, δεν μπορεί να το εξαντλήσει μία μόνο εργασία: από ΚΑΘΕ ενεργή εργασία καλείται σε κάθε εκτέλεση ακριβώς ΕΝΑΣ παραλήπτης. Ακόμη και σε εντελώς άδεια πλατφόρμα, μία εργασία δεν καλεί ποτέ περισσότερους από έναν παραλήπτη ανά 2 λεπτά - εκατό παραλήπτες δεν ολοκληρώνονται λοιπόν σε ~20 λεπτά αλλά σε περίπου 200 λεπτά (100 x 2 λεπτά). Προγραμματίστε ανάλογα το παράθυρο κλήσεων σε χρονικά ευαίσθητες καμπάνιες (π.χ. υπενθύμιση appointment την προηγούμενη ημέρα).

Διαδικασία για πράκτορα

Μια τυπική εκτέλεση, με αυτή τη σειρά:

  1. Ο πράκτορας της εργασίας πρέπει να είναι ΔΗΜΟΣΙΕΥΜΕΝΟΣ και η δημοσιευμένη έκδοση ΔΟΚΙΜΑΣΜΕΝΗ (POST /v1/agents/{id}/draft/publish, έπειτα POST /v1/agents/{id}/simulate) - αλλιώς ένα μεταγενέστερο start επιστρέφει agent_not_ready.
  2. Προαιρετικά POST /v1/tasks/csv-preview - ελέγχει το CSV των παραληπτών πριν δημιουργηθεί η εργασία.
  3. POST /v1/tasks - δημιουργεί την εργασία σε κατάσταση draft. Τίποτα δεν καλείται.
  4. GET /v1/tasks/{id} - διαβάστε τα issues (επικύρωση dry-run) και βεβαιωθείτε ότι η εργασία είναι έτοιμη για εκκίνηση.
  5. Κατά περίπτωση PATCH /v1/tasks/{id} - προσαρμόστε τους κανόνες, ΠΑΝΤΑ με το revision από την τελευταία ανάγνωση.
  6. POST /v1/tasks/{id}/start - ξεκινά τις κλήσεις. Κάθε απαντημένη κλήση χρεώνεται αμέσως.
  7. POST /v1/tasks/{id}/pause οποιαδήποτε στιγμή κατά την εκτέλεση, το POST /v1/tasks/{id}/start την επαναφέρει.
  8. Μετά από διακοπή (παύση στη μέση κλήσης, ληγμένο claim, κλήση με άγνωστη ακόμη τιμή ή αβέβαιη κλήση της οποίας η κλήση βρέθηκε) το POST /v1/tasks/{id}/reconcile συμφιλιώνει την κατάσταση με τις πραγματικές κλήσεις· μια τέτοια εργασία με υπολειπόμενη δουλειά καταλήγει σε paused, ακόμη κι αν κάποιες επαφές περιμένουν σε review, και μπορεί να ξαναξεκινήσει με start. Εργασία σε εκτέλεση ή άλλος λόγος (variables_limit, αποτυχία ελέγχου τιμολογίου ή ημερολογίου, αβέβαιη κλήση της οποίας η κλήση δεν βρέθηκε) δεν αλλάζει από το reconcile· τις επαφές προς έλεγχο τις διευθετείτε με resolve.
  9. Επαφή που κατέληξε για έλεγχο (items[].status: "review") τη διευθετείτε με POST /v1/tasks/{id}/items/{itemId}/resolve με action: "retry" ή "skip". Για συνηθισμένο λόγο το retry επιστρέφει την επαφή στις εκκρεμείς και την εργασία σε paused· το skip την κλείνει και η εργασία περνά σε paused αν μένει δουλειά, ή σε completed αν όλες οι επαφές έχουν ολοκληρωθεί ή παραλειφθεί. Την εργασία σε paused ξαναενεργοποιείτε με POST /v1/tasks/{id}/start.
  10. Όταν μια επαφή έχει reviewReason: "dial:destination_auto_blocked", ο αριθμός είναι αυτόματα αποκλεισμένος για 30 ημέρες μετά από επανειλημμένες αναπάντητες κλήσεις και το retry από μόνο του δεν τον ξεμπλοκάρει - η επαφή θα επέστρεφε αμέσως σε review. Πρώτα άρετε τον αποκλεισμό (POST /v1/dnc/{e164}/unblock, στο MCP unblock_destination, πάρτε τον αριθμό από το items[].phone) και μετά κάντε resolve με action: "retry". Για dial:on_dnc αφαιρέστε πρώτα τον αριθμό από τη λίστα μη κλήσης (DELETE /v1/dnc/{e164}), αλλιώς παραλείψτε την επαφή. Για τον δικό σας αριθμό λογαριασμού, αριθμό άλλου λογαριασμού volai, άκυρο αριθμό, αριθμό εκτός Τσεχίας και Σλοβακίας και γραμμή επαυξημένης χρέωσης (dial:cannot_call_own_number, dial:cannot_call_volai_number, dial:invalid_number, dial:unsupported_country, dial:blocked_destination) μια νέα προσπάθεια δεν βοηθά: χρησιμοποιήστε μόνο skip.
  11. Όταν μια επαφή έχει reviewReason: "billing_unknown", η αρχική κλήση μπορεί να έχει ήδη γίνει, απλώς δεν είναι ακόμη γνωστή η τιμή της. Καλέστε πρώτα reconcile και ελέγξτε τη συνδεδεμένη κλήση. Το retry καταγράφει ότι η επαφή πρέπει να ξαναδοκιμαστεί, αλλά δεν επιτρέπει νέα κλήση μέχρι να οριστικοποιηθεί η αρχική τιμή· στη συνέχεια η εργασία περνά σε paused και απαιτεί νέο start. Το skip αποτρέπει την επόμενη κλήση· η αρχική κλήση παραμένει συνδεδεμένη και η δέσμευσή της συνεχίζει να μετρά στον προϋπολογισμό μέχρι να οριστικοποιηθεί η τιμή. Αν μένει δουλειά, η εργασία μετά το skip περνά κατευθείαν σε paused και μπορεί να ξεκινήσει· χωρίς άλλη δουλειά περιμένει σε needs_attention και μετά την οριστικοποίηση της τιμής καταλήγει σε completed. Κλήση που δεν πραγματοποιήθηκε ποτέ (η μηχανή την απέρριψε) δεν χρεώνεται ποτέ και οριστικοποιείται αμέσως στο 0.
  12. Επαφή που στο μεταξύ αγόρασε ή απεγγράφηκε, παραλείψτε την χωρίς κλήση μέσω resolve με action: "skip", reason: "customer_purchased" ή "unsubscribed", revision, σταθερό operationId και evidenceRef που παραπέμπει στο αποδεικτικό αγοράς ή απεγγραφής (ποτέ σε τηλέφωνο ή email). Γίνεται σε επαφή pending σε εργασία draft και σε pending/failed σε εργασία paused χωρίς ανεκκαθάριστη κλήση· οι προσπάθειες, οι τιμές και η λίστα μη κλήσης παραμένουν. Το GET /v1/tasks/{id} δείχνει τότε το αποδεικτικό στο items[].resolution (reason, operationId, evidenceRef, resolvedAt)· το ίδιο σώμα μπορεί να επαναληφθεί με ασφάλεια, ενώ διαφορετικό reason ή evidenceRef για την ίδια επαφή δίνει 409 revision_conflict. Η παράλειψη δεν γράφει τον αριθμό στη λίστα μη κλήσης: αν η επαφή δεν πρέπει να κληθεί ποτέ ξανά, προσθέστε την μέσω POST /v1/dnc.
  13. DELETE /v1/tasks/{id} στο τέλος, αν η εργασία δεν εκτελέστηκε ποτέ ή έχει ήδη ολοκληρωθεί και θέλετε να διαγράψετε την εγγραφή.

Σχεδόν κάθε κλήση εγγραφής (PATCH, start, pause, DELETE) παίρνει το revision από την τελευταία ανάγνωση της εργασίας - ο ίδιος αισιόδοξος συγχρονισμός όπως στα πρόχειρα του πράκτορα. Η ασυμφωνία επιστρέφει revision_conflict: διαβάστε ξανά την εργασία (GET) και επαναλάβετε με το τρέχον revision. Το reconcile αποτελεί εξαίρεση - εκεί το revision είναι προαιρετικό.

MCP

Τα ίδια εργαλεία με το REST (list_tasks, get_task, create_task, update_task, pause_task, resolve_task_item, reconcile_task, start_task) - εκτός από μία διαφορά στην εκκίνηση.

Το start_task επιβεβαιώνει τους αριθμούς

Το start_task του MCP παίρνει επιπλέον confirmedRecipients και confirmedBudgetHal - πρέπει να ταιριάζουν ακριβώς με τον πραγματικό αριθμό παραληπτών και τον προϋπολογισμό της εργασίας, αλλιώς επιστρέφει validation με τις πραγματικές τιμές και δεν ξεκινά ΤΙΠΟΤΑ. Έτσι ένας ξένος πράκτορας AI, που ενεργεί με βάση μια ασαφώς κατανοημένη εντολή, δεν μπορεί να ξεκινήσει κατά λάθος επί πληρωμή καμπάνια με επινοημένους αριθμούς - το REST POST .../start δεν έχει αυτόν τον μηχανισμό, επειδή εκεί το καλεί απευθείας ο κάτοχος του λογαριασμού με το δικό του κλειδί.

Τα delete_task και η προεπισκόπηση CSV δεν υπάρχουν στο MCP - η διαγραφή μένει στο REST και στην πύλη (μη αναστρέψιμη ενέργεια με πληκτρολόγηση του ονόματος), η προεπισκόπηση CSV είναι μόνο βήμα της φόρμας.

Σφάλματα

  • task_not_found - Δεν υπάρχει στον λογαριασμό εργασία με αυτό το id.
  • task_not_editable - Η εργασία εκτελείται ή έχει ολοκληρωθεί (running/completed), ή είναι needs_attention χωρίς δυνατότητα ανάκαμψης - οι κανόνες της δεν μπορούν τώρα να αλλάξουν. Τον ίδιο κωδικό επιστρέφει και το POST .../items/{itemId}/resolve σε εργασία που εκτελείται: επαφή σε review εμφανίζεται ήδη όταν η εργασία καλεί τις υπόλοιπες επαφές και είναι ακόμη running - περιμένετε να περάσει σε needs_attention ή σταματήστε την (POST .../pause).
  • items_immutable - Η λίστα παραληπτών δεν μπορεί να αντικατασταθεί αφού έχει γίνει έστω και μία προσπάθεια κλήσης ή μια επαφή έχει παραλειφθεί με reason (αγορά ή απεγγραφή).
  • budget_too_low - Ο προϋπολογισμός δεν καλύπτει ούτε μία προσπάθεια μέγιστης διάρκειας κλήσης - αυξήστε το budgetHal ή μειώστε το maxDurationSecs.
  • task_not_startable - Η εργασία δεν είναι σε κατάσταση draft/ready/paused ή δεν έχει κανέναν εκκρεμή παραλήπτη.
  • task_needs_attention - Πριν από την επόμενη εκκίνηση χρειάζεται POST .../reconcile - κάτι (έκδοση πράκτορα, μηχανή) άλλαξε κατά την εκτέλεση.
  • agent_not_ready - Το πρόχειρο του πράκτορα είτε δεν είναι δημοσιευμένο είτε η δημοσιευμένη έκδοση δεν έχει δοκιμαστεί - δημοσιεύστε το (POST /v1/agents/{id}/draft/publish) και στη συνέχεια δοκιμάστε τη δημοσιευμένη έκδοση (POST /v1/agents/{id}/simulate) πριν από την εκκίνηση.
  • agent_version_changed - Η διαμόρφωση του πράκτορα άλλαξε ΚΑΤΑ ΤΗ ΔΙΑΡΚΕΙΑ της εκτέλεσης της εργασίας - δοκιμάστε και επανεκκινήστε μέσω reconcile.
  • engine_required - Ο πράκτορας της εργασίας δεν βρίσκεται στη μηχανή του volai (useForOutboundTasks: true) - οι εξερχόμενες καμπάνιες απαιτούν σήμερα τη μηχανή, όχι το ElevenLabs.
  • engine_contract_unavailable - Η μηχανή αυτή τη στιγμή δεν δηλώνει υποστήριξη για μεταβλητές και όρια εξερχόμενων εργασιών - δοκιμάστε ξανά την εκκίνηση αργότερα.
  • window_closed - Εκτός του ορισμένου παραθύρου κλήσεων - περιμένετε να ανοίξει ή αλλάξτε το callingWindow.
  • task_not_running - Η παύση γίνεται μόνο σε εργασία που εκτελείται.
  • item_not_resolvable - Η επαφή δεν είναι σε κατάσταση review - απόφαση (retry/skip) μπορεί να ληφθεί μόνο για επαφή που περιμένει έλεγχο και μόνο σε εργασία που δεν εκτελείται. Εξαίρεση αποτελεί η παράλειψη με reason (customer_purchased, unsubscribed): απαιτεί ανενεργή επαφή pending σε εργασία draft, ή pending/failed σε paused, χωρίς ανεκκαθάριστη κλήση.
  • task_not_deletable - Διαγράφεται μόνο εργασία χωρίς στοιχείο in_progress, σε κατάσταση draft/ready/paused/completed/needs_attention.
  • revision_conflict - Η εργασία άλλαξε στο μεταξύ - διαβάστε την ξανά (GET) και επαναλάβετε με το τρέχον revision.

Τον πλήρη πίνακα σφαλμάτων για κάθε endpoint θα βρείτε στην ενότητα Εργασίες στην αναφορά του REST API.