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

Users API

Δημιουργήστε, ενημερώστε και διαχειριστείτε προφίλ χρηστών προγραμματιστικά.

Όλα τα endpoints αυτής της σελίδας είναι σχετικά ως προς το βασικό URL: https://api-eu1.joryio.com/api - δείτε Επισκόπηση API.

Έλεγχος ταυτότητας​

Όλα τα αιτήματα απαιτούν έλεγχο ταυτότητας με κλειδί API:

Authorization: Bearer jry_live_your_api_key_here
Content-Type: application/json

Track​

Η μία πόρτα εισαγωγής δεδομένων: ποιος είναι κάποιος, τι έκανε και τι αγόρασε - σε μία κλήση.

Κάθε πεδίο δέχεται ένα αντικείμενο ή έναν πίνακα, οπότε ένα αίτημα μπορεί να καλύψει ένα άτομο ή χίλια.

Endpoint​

POST /users/track

Σώμα αιτήματος​

ΠεδίοΤύποςΥποχρεωτικόΠεριγραφή
attributesαντικείμενο ή πίνακαςΌχιΠεδία προφίλ. Παραμένουν στο άτομο
eventsαντικείμενο ή πίνακαςΌχιΌσα συνέβησαν. Προστίθενται στο χρονολόγιο
purchasesαντικείμενο ή πίνακαςΌχιΠαραγγελίες, στην ίδια μορφή με το POST /orders

Απαιτείται τουλάχιστον ένα από τα τρία. Όρια ανά αίτημα: 1000 attributes, 500 events, 500 purchases. Ένα αίτημα πάνω από το όριο απορρίπτεται αντί να περικοπεί: η σιωπηλή επεξεργασία των πρώτων 500 από 5000 θα έχανε τα υπόλοιπα χωρίς καμία ένδειξη.

Τα attributes εφαρμόζονται πρώτα

Μέσα σε ένα αίτημα, τα attributes γράφονται πριν από τα events και τα purchases, ώστε ένα συμβάν να μπορεί να αναφέρεται σε άτομο που δημιουργήθηκε στην ίδια κλήση.

Ταυτότητα​

ΠεδίοΠεριγραφή
externalIdΤο δικό σας αναγνωριστικό, και το μόνο κλειδί δημιουργίας-ή-ενημέρωσης
userIdΤο εσωτερικό αναγνωριστικό της Joryio (24 hex). Μόνο ενημέρωση - ποτέ δημιουργία
anonymousIdΜια συνεδρία πριν την ταυτοποίηση. Συνδέστε την αργότερα με POST /users/identify
Μην στέλνετε το Order Completed ως συμβάν

Αυτό το συμβάν εκπέμπεται αυτόματα όταν στέλνετε μια αγορά. Η χειροκίνητη αποστολή απορρίπτεται, επειδή και οι δύο τρόποι αποτυχίας είναι σιωπηλοί: μόνο του καταγράφει έσοδα χωρίς παραγγελία από πίσω, οπότε η σελίδα Παραγγελιών, το RFM και η αξία ζωής πελάτη δεν βλέπουν ποτέ την πώληση - ενώ μαζί με πραγματική αγορά μετρά την πώληση δύο φορές.

Αντιστοίχιση μέσω email​

Ένα στοιχείο του attributes με email αλλά χωρίς externalId και χωρίς userId αντιστοιχίζεται μέσω του email (σε πεζά, χωρίς κενά στα άκρα), μέσα στο workspace. Μια διεύθυνση email δεν είναι μοναδική - ένα ζευγάρι ή μια οικογένεια μπορεί να μοιράζεται μία, και ένα άτομο μπορεί να υπάρχει με δύο αναγνωριστικά - επομένως:

  • Καμία επαφή δεν έχει το email: δημιουργείται νέα επαφή.
  • Ακριβώς μία το έχει: ενημερώνεται αυτή η επαφή.
  • Πολλές το έχουν: ενημερώνεται ακριβώς μία - η πιο πρόσφατα ενεργή, η επαφή της οποίας το προφίλ άλλαξε πιο πρόσφατα (σε ισοπαλία, αυτή που δημιουργήθηκε πιο πρόσφατα). Το ίδιο αίτημα επιλέγει πάντα την ίδια επαφή. Οι υπόλοιπες μένουν ως έχουν: η Joryio δεν συγχωνεύει ποτέ επαφές και δεν τις ενημερώνει όλες.
  • Μια απεγγραφή από λίστα στο στοιχείο εξακολουθεί να ισχύει για κάθε επαφή με αυτό το email. Μια εγγραφή σε λίστα ισχύει μόνο για την επαφή που ενημερώθηκε.

Ένα στοιχείο που αντιστοιχίστηκε σε πολλές επαφές αναφέρεται στο attributes.matchedSeveral - ειδοποίηση, όχι σφάλμα: η εγγραφή πέτυχε.

{
"attributes": {
"processed": 1,
"failed": [],
"matchedSeveral": [
{ "index": 0, "userId": "6650f1c2a9e4b3d2c1f0e9a8", "count": 2 }
]
}
}

Το userId είναι η επαφή που ενημερώθηκε και το count πόσες επαφές μοιράζονται τη διεύθυνση. Το matchedSeveral εμφανίζεται μόνο όταν συνέβη. Για να ενημερώσετε μία συγκεκριμένη επαφή, στείλτε externalId (αντιστοιχίζεται μόνο μέσω externalId, ακόμη κι όταν το email είναι κοινό) ή το userId της επαφής. Οι εισαγωγές αρχείων και οι συγχρονισμοί από data warehouse αντιστοιχίζουν με τον ίδιο τρόπο.

Συνδρομές σε λίστες​

Ένα στοιχείο του attributes μπορεί επίσης να ορίσει τις συνδρομές του ατόμου σε λίστες, οπότε ένα αίτημα δημιουργεί ή ενημερώνει το άτομο, καταγράφει τα συμβάντα του και το εγγράφει σε λίστα.

ΠεδίοΤύποςΥποχρεωτικόΠεριγραφή
subscriptions[].listIdstringΝαιΤο id της λίστας συνδρομών (Subscriptions API)
subscriptions[].channelstringΌχιemail (προεπιλογή), sms, whatsapp, push ή viber
subscriptions[].statusstringΌχιsubscribed (προεπιλογή) ή unsubscribed

Έως 100 ανά στοιχείο. Εφαρμόζονται αφού γραφτεί το άτομο, μέσω της ίδιας διαδρομής συγκατάθεσης με το POST /subscriptions/contacts/:userId/lists/:listId, και καταγράφονται με πηγή api στο ιστορικό συγκατάθεσης.

  • Ένα υπάρχον opt-out δεν αναιρείται ποτέ. Αν το άτομο έχει ήδη απεγγραφεί από αυτή τη λίστα σε αυτό το κανάλι, ένα αίτημα subscribed παραλείπεται και αναφέρεται. Η επανεγγραφή του είναι μια σκόπιμη κλήση στο endpoint εγγραφής. Το status: "unsubscribed" εφαρμόζεται πάντα.
  • Η λίστα πρέπει να ανήκει σε αυτό το workspace. Ένα άγνωστο ή αρχειοθετημένο id λίστας, ή λίστα άλλου workspace, παραλείπεται και αναφέρεται, δεν γράφεται ποτέ.
  • Χωρίς email επιβεβαίωσης. Το API καταγράφει τη συνδρομή απευθείας, ακόμη και σε λίστα που απαιτεί double opt-in - αυτό το βήμα επιβεβαίωσης αφορά τις φόρμες εγγραφής. Στέλνετε μέσω του API μόνο συγκατάθεση που έχετε ήδη συλλέξει.
  • Αναφορά με τον δείκτη του στοιχείου. Όταν κάποιο στοιχείο στέλνει subscriptions, το αποτέλεσμα του attributes προσθέτει subscriptions: { applied, skipped[] }, και κάθε παράλειψη αναφέρει το index του στοιχείου, το listId, το channel και το reason. Μια συνδρομή που παραλείφθηκε δεν αποτυγχάνει το στοιχείο - το άτομο δημιουργείται ή ενημερώνεται κανονικά.
{
"attributes": {
"processed": 1,
"failed": [],
"subscriptions": {
"applied": 0,
"skipped": [
{
"index": 0,
"listId": "3f9d2c1e-7a54-4b2e-9c1d-8e6f5a4b3c2d",
"channel": "email",
"reason": "Existing opt-out is not resurrected by user creation; use POST /subscriptions/contacts/:userId/lists/:listId for an explicit re-opt-in"
}
]
}
}
}

Παράδειγμα αιτήματος​

curl -X POST https://api-eu1.joryio.com/api/users/track \
-H "Authorization: Bearer jry_live_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"attributes": {
"externalId": "user_123",
"email": "[email protected]",
"attributes": { "firstName": "John", "plan": "premium" }
},
"events": {
"externalId": "user_123",
"name": "Product Viewed",
"properties": { "productId": "SKU-456", "price": 49.99 }
},
"purchases": {
"orderId": "ord_789",
"externalId": "user_123",
"total": 129.90,
"currency": "USD",
"items": [
{ "productId": "SKU-456", "name": "Blue T-Shirt", "quantity": 1, "price": 129.90, "total": 129.90 }
]
}
}'

Δεν είναι το ίδιο με την αποστολή anonymousId στο /users/track. Η παρακολούθηση δημιουργεί ή ενημερώνει ένα άτομο· το identify συνδέει την ανώνυμη εγγραφή με ένα γνωστό άτομο. Στην πρώτη σύνδεση - όταν κανένα προφίλ δεν έχει ακόμη αυτό το externalId - το ίδιο το ανώνυμο προφίλ γίνεται το γνωστό, κρατώντας το id και το ιστορικό του. Όταν το άτομο έχει ήδη προφίλ, το ανώνυμο συγχωνεύεται σε αυτό και το ιστορικό του μεταφέρεται. Η καταγραφή anonymousId σε μια κλήση tracking δεν συγχωνεύει τίποτα.

Απόκριση​

Κάθε πίνακας αναφέρεται ξεχωριστά. Ένα λανθασμένο στοιχείο δεν αποτυγχάνει ποτέ ολόκληρη την παρτίδα - οι αποτυχίες αναφέρονται ανά δείκτη και ό,τι είναι έγκυρο επεξεργάζεται κανονικά.

{
"attributes": { "processed": 1, "failed": [] },
"events": { "processed": 1, "failed": [] },
"purchases": { "processed": 1, "failed": [] }
}

Προειδοποιήσεις: έγινε δεκτό, αλλά δεν είναι προσβάσιμο​

Μια εσφαλμένη διεύθυνση email αποθηκεύεται, δεν απορρίπτεται - αυτό το endpoint χρησιμοποιείται από ενσωματώσεις τύπου fire-and-forget, όπου ένα 400 που δεν διαβάζει κανείς σημαίνει απώλεια ολόκληρης της εγγραφής. Η διεύθυνση επισημαίνεται εσωτερικά και εξαιρείται από κάθε αποστολή email, οπότε δεν μπορεί να προκαλέσει hard bounce.

Επειδή αυτό δεν φαίνεται στην αποθηκευμένη τιμή, η απάντηση το δηλώνει:

{
"attributes": {
"processed": 2,
"failed": [],
"warnings": [
{
"index": 1,
"field": "email",
"reason": "Stored, but flagged undeliverable and excluded from email sends. Correct the address to make this contact reachable by email."
}
]
}
}

Το warnings υπάρχει μόνο όταν υπάρχει κάτι να αναφερθεί. Μια επαφή με προειδοποίηση δημιουργείται και ενημερώνεται κανονικά και είναι προσβάσιμη σε κάθε άλλο κανάλι - είναι η διεύθυνση email που δεν θα λάβει ποτέ τίποτα.

Αριθμοί τηλεφώνου​

Στείλτε τους αριθμούς τηλεφώνου με + και κωδικό χώρας

Στέλνετε πάντα τους αριθμούς τηλεφώνου σε πλήρη διεθνή μορφή (E.164): +, ο κωδικός χώρας και μετά ο αριθμός - για παράδειγμα +972501234567. Ένας αριθμός χωρίς + διαβάζεται με την προεπιλεγμένη χώρα για αριθμούς τηλεφώνου του χώρου εργασίας· αν δεν έχει οριστεί, ή αν τα ψηφία διαβάζονται με δύο τρόπους, αποθηκεύεται ως μη επαληθευμένος και δεν χρησιμοποιείται για μηνύματα. Πώς χειρίζονται οι αριθμοί τηλεφώνου

Στείλτε το phone σε διεθνή μορφή (+972501234567). Ένας αριθμός χωρίς κωδικό χώρας (0501234567) διαβάζεται με την προεπιλεγμένη χώρα για αριθμούς τηλεφώνου του workspace - με το Ισραήλ αποθηκεύεται ως +972501234567. Το Joryio δεν μαντεύει ποτέ χώρα: χωρίς προεπιλεγμένη χώρα, ένας τέτοιος αριθμός δεν μετατρέπεται.

Ένα τηλέφωνο που δεν είναι έγκυρος αριθμός διατηρείται, δεν απορρίπτεται: αποθηκεύεται σε ξεχωριστό πεδίο της επαφής, phoneUnverified, και το υπάρχον phone της επαφής δεν αλλάζει. Ένας μη επαληθευμένος αριθμός δεν χρησιμοποιείται ποτέ για μηνύματα, αποκλεισμούς, αντιστοίχιση επαφών ή φίλτρα τηλεφώνου σε segments. Ένα έγκυρο τηλέφωνο που στέλνεται αργότερα τον αντικαθιστά. Ψηφία που περιέχουν τον κωδικό χώρας χωρίς + (972501234567) γίνονται δεκτά όταν είναι έγκυρα - εκτός από συμβολοσειρά 10 ψηφίων, που μπορεί να είναι τοπικός ή αμερικανικός αριθμός και διατηρείται ως μη επαληθευμένη.

Όταν έχει οριστεί προεπιλεγμένη χώρα, ψηφία που είναι έγκυρος αριθμός και με τους δύο τρόπους - ως εθνικός αριθμός αυτής της χώρας και ως αριθμός άλλης χώρας με τον κωδικό της (το 13123456789 με Κίνα είναι κινεζικό κινητό αλλά και +1 312...) - είναι αμφίσημα: το Joryio δεν επιλέγει ποτέ έναν από τους δύο και τα κρατά ως μη επαληθευμένα. Στείλτε τέτοιους αριθμούς με +.

Η απόκριση το αναφέρει στον ίδιο πίνακα warnings:

{
"attributes": {
"processed": 1,
"failed": [],
"warnings": [
{
"index": 0,
"field": "phone",
"reason": "Phone saved as unverified and not used for messages - the number is not valid as written. Add the country code (for example +972501234567), or set a default country for phone numbers in workspace settings."
}
]
}
}

Οι επαφές που επιστρέφει το API περιέχουν το phoneUnverified όταν υπάρχει. Οι εισαγωγές αρχείων και οι συγχρονισμοί από αποθήκη δεδομένων ακολουθούν τους ίδιους κανόνες.

Στη σελίδα της επαφής, ένας μη επαληθευμένος αριθμός μπορεί να διορθωθεί (αποθηκεύεται ως τηλέφωνο - αν η επαφή έχει ήδη τηλέφωνο, αντικαθίσταται, και η σελίδα το λέει πρώτα) ή να απορριφθεί. Μέσω του API, PUT /users/{userId} με {"clearPhoneUnverified": true} αφαιρεί τον μη επαληθευμένο αριθμό και αφήνει το phone όπως είναι.

Identify​

Συνδέστε συμπεριφορά που καταγράφηκε σε ανώνυμη συνεδρία με ένα γνωστό άτομο.

ΠεδίοΤύποςΥποχρεωτικόΠεριγραφή
anonymousIdstringΝαιΗ συνεδρία στην οποία καταγράφηκε η συμπεριφορά
externalIdstringΝαιΤο αναγνωριστικό σας για τη σύνδεση
attributesαντικείμενοΌχιΠεδία προφίλ που ορίζονται κατά την ταυτοποίηση
curl -X POST https://api-eu1.joryio.com/api/users/identify \
-H "Authorization: Bearer jry_live_your_api_key" \
-H "Content-Type: application/json" \
-d '{ "anonymousId": "anon_abc123", "externalId": "user_123" }'

Συσκευές push​

Μαζική σύνδεση push tokens - η διαδρομή για μετάβαση από άλλον πάροχο.

POST /api/users/track
Content-Type: application/json

{
"devices": [
{ "externalId": "user-123", "platform": "ios", "pushToken": "a1b2c3…", "appId": "<ios-app-id>",
"deviceInfo": { "model": "iPhone15,2" } },
{ "externalId": "user-456", "platform": "android", "pushToken": "d4e5f6…", "appId": "<android-app-id>" }
]
}
ΠεδίοΤύποςΥποχρεωτικόΠεριγραφή
externalIdstringΝαιΤο δικό σας αναγνωριστικό. Στείλτε userId αν έχετε το εσωτερικό id του Joryio
platformios | android | webΝαι
pushTokenstringΝαιΤο token ακριβώς όπως το κατέγραψε ο προηγούμενος πάροχος
appIdstringΌχι*Σε ποια από τις εφαρμογές σας ανήκει το token. Οι αποστολές καμπανιών φιλτράρουν βάσει αυτού, οπότε ένα token που εισάγεται χωρίς αυτό διατηρείται αλλά δεν χρησιμοποιείται ποτέ. Προαιρετικό όταν ο χώρος εργασίας έχει ακριβώς μία εφαρμογή σε αυτή την πλατφόρμα - τότε προσδιορίζεται αυτόματα. Απαιτείται όταν έχετε περισσότερες. Δείτε τα ids με GET /apps
deviceInfoobjectΌχιΜοντέλο, έκδοση OS, έκδοση εφαρμογής - ελεύθερη μορφή

Έως 1000 συσκευές ανά αίτημα. Οι συσκευές εφαρμόζονται μετά τα attributes, οπότε μία κλήση μπορεί να δημιουργήσει τα άτομα και να συνδέσει τα tokens τους.

Μια επαφή που δεν υπάρχει αποτυγχάνει σε εκείνο το στοιχείο αντί να δημιουργηθεί - μια συσκευή χωρίς προφίλ μπορεί να λάβει push και δεν ανήκει σε κανέναν. Στείλτε την στα attributes στο ίδιο αίτημα.

Τι επιβιώνει πραγματικά μιας μετάβασης​

Όχι όλα, και αυτό καθορίζει το σχέδιο περισσότερο από το API:

  • iOS / APNs - τα tokens εκδίδονται ανά (bundle id, περιβάλλον), όχι ανά πάροχο. Ίδιο bundle id και το δικό σας .p8, και μεταφέρονται.
  • Android / FCM - τα tokens συνδέονται με έναν sender του Firebase. Ίδιο project και λειτουργούν· διαφορετικό project και ήταν ήδη νεκρά.
  • Web push - μια συνδρομή δεσμεύεται στο κλειδί VAPID που τη δημιούργησε. Δεν μεταφέρεται. Αυτοί οι χρήστες πρέπει να ερωτηθούν ξανά, ό,τι κι αν υπόσχεται ένα API.

Ένα token που ανήκει ήδη σε κάποιον άλλον​

Μετακινείται. Ένα push token ταυτοποιεί μια ΣΥΣΚΕΥΗ, όχι ένα άτομο, και οι επανεγκαταστάσεις, οι μεταπωλημένες συσκευές και τα κοινόχρηστα tablet είναι φυσιολογικά - οπότε το push το λαμβάνει όποιος κρατά τη συσκευή.

Η μετακίνηση καταγράφεται και στις δύο πλευρές. Η συσκευή της προηγούμενης επαφής σημειώνεται με deactivatedReason: "reassigned", reassignedToUserId και deactivatedAt, ώστε το «γιατί σταμάτησε να λαμβάνει push;» να έχει απάντηση αντί για μια ανενεργή εγγραφή που θα μπορούσε εξίσου να σημαίνει απεγκατάσταση.

Συναίνεση και επαλήθευση​

Η καταχώριση ενός token ποτέ δεν παραχωρεί συναίνεση για push. Η κατοχή token από προηγούμενο πάροχο δεν αποτελεί απόδειξη άδειας, οπότε οι κανόνες συνδρομής παραμένουν - οι αποκλεισμοί ισχύουν και η παραχώριση παραμένει ενέργεια συμμόρφωσης. Ίδιος κανόνας με την εισαγωγή αρχείου.

Τα tokens λαμβάνονται ως έχουν και δεν ελέγχονται. Θεωρούνται έγκυρα μέχρι μια αποστολή να αποτύχει, οπότε η διαδρομή παράδοσης τα απενεργοποιεί.

Λήψη χρήστη βάσει ID​

Ανακτήστε το προφίλ και τα γνωρίσματα ενός χρήστη. Υπάρχουν δύο διαδρομές αναζήτησης:

  • GET /users/by-user-id/:userId - αναζήτηση με το δικό σας αναγνωριστικό (το externalId με το οποίο δημιουργήσατε τον χρήστη). Είναι η προτεινόμενη διαδρομή για ενσωματώσεις.
  • GET /users/:userId - αναζήτηση με το εσωτερικό ID του Joryio (το 24-hex id που επιστρέφεται στις αποκρίσεις).

Endpoint​

GET /users/by-user-id/:userId

Παράμετροι διαδρομής​

ΠαράμετροςΤύποςΠεριγραφή
userIdstringΤο εξωτερικό σας αναγνωριστικό (externalId)

Παράδειγμα αιτήματος​

curl -X GET https://api-eu1.joryio.com/api/users/by-user-id/user_123 \
-H "Authorization: Bearer jry_live_your_api_key"

Απόκριση​

{
"id": "665f1e2a9b3c4d5e6f7a8b9c",
"userId": "665f1e2a9b3c4d5e6f7a8b9c",
"externalId": "user_123",
"email": "[email protected]",
"phone": "+1234567890",
"attributes": {
"firstName": "John",
"lastName": "Doe",
"plan": "premium",
"lifetimeValue": 1250.50
},
"segments": [],
"rndBucket": 4821,
"createdVia": "woocommerce",
"createdAt": "2024-01-15T10:30:00.000Z",
"updatedAt": "2024-01-20T14:20:00.000Z"
}

Λίστα χρηστών​

Λίστα όλων των χρηστών με σελιδοποίηση. Τα αποτελέσματα ταξινομούνται με πρώτους τους πιο πρόσφατα ενημερωμένους - δεν υπάρχει σύνταξη query για φίλτρα γνωρισμάτων ή ταξινόμηση σε αυτό το endpoint (χρησιμοποιήστε τα Τμήματα για τμηματοποίηση βάσει γνωρισμάτων, ή το GET /users/search?query=... για αναζήτηση βάσει ονόματος/email/τηλεφώνου/ID).

Endpoint​

GET /users

Παράμετροι query​

ΠαράμετροςΤύποςΠροεπιλογήΠεριγραφή
limitnumber50Αποτελέσματα ανά σελίδα (μέγιστο 1000)
offsetnumber0Πλήθος χρηστών που παραλείπονται
emailstring-Ακριβής αντιστοίχιση, χωρίς διάκριση πεζών/κεφαλαίων
externalIdstring-Ακριβής αντιστοίχιση στο δικό σας αναγνωριστικό. Το GET /users/by-user-id/:userId επιστρέφει απευθείας τη μία εγγραφή
userIdstring-Ακριβής αντιστοίχιση στο εσωτερικό 24-ψήφιο id του Joryio
qstring-Μερική αντιστοίχιση: πρόθεμα σε email, externalId και όνομα· ψηφία οπουδήποτε στο τηλέφωνο· πλήρης τιμή για 24-ψήφιο id ή anonymousId. Αγνοείται όταν υπάρχει ακριβής παράμετρος. Δείτε Εύρεση ατόμου

Παράδειγμα αιτήματος​

curl -X GET "https://api-eu1.joryio.com/api/users?limit=50&offset=0" \
-H "Authorization: Bearer jry_live_your_api_key"

Απόκριση​

{
"data": [
{
"id": "665f1e2a9b3c4d5e6f7a8b9c",
"userId": "665f1e2a9b3c4d5e6f7a8b9c",
"externalId": "user_123",
"email": "[email protected]",
"attributes": {
"plan": "premium"
}
},
{
"id": "665f1e2a9b3c4d5e6f7a8b9d",
"userId": "665f1e2a9b3c4d5e6f7a8b9d",
"externalId": "user_456",
"email": "[email protected]",
"attributes": {
"plan": "premium"
}
}
],
"pagination": {
"total": 156,
"limit": 50,
"offset": 0,
"hasMore": true
}
}

Ενημέρωση χρήστη​

Ενημερώστε το email, το τηλέφωνο ή τα γνωρίσματα ενός χρήστη χωρίς να αντικαταστήσετε ολόκληρο το προφίλ. Τα γνωρίσματα συγχωνεύονται ανά κλειδί. Χρησιμοποιεί PUT (δεν υπάρχει διαδρομή PATCH):

  • PUT /users/by-user-id/:userId - ενημέρωση με το δικό σας αναγνωριστικό.
  • PUT /users/:userId - ενημέρωση με το εσωτερικό ID του Joryio.

Endpoint​

PUT /users/by-user-id/:userId

Σώμα αιτήματος​

ΠεδίοΤύποςΑπαιτείταιΠεριγραφή
emailstringΌχιΝέα διεύθυνση email
phonestringΌχιΝέος αριθμός τηλεφώνου
attributesobjectΌχιΓνωρίσματα προς συγχώνευση (ενημέρωση ανά κλειδί)

Παράδειγμα αιτήματος​

curl -X PUT https://api-eu1.joryio.com/api/users/by-user-id/user_123 \
-H "Authorization: Bearer jry_live_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"attributes": {
"plan": "enterprise",
"mrr": 499
}
}'

Απόκριση​

Το ενημερωμένο αντικείμενο χρήστη επιστρέφεται απευθείας:

{
"id": "665f1e2a9b3c4d5e6f7a8b9c",
"userId": "665f1e2a9b3c4d5e6f7a8b9c",
"externalId": "user_123",
"attributes": {
"firstName": "John",
"plan": "enterprise",
"mrr": 499,
"signupDate": "2024-01-15T10:30:00Z"
},
"updatedAt": "2024-01-20T15:30:00.000Z"
}

Διαγραφή χρήστη​

Διαγράψτε έναν χρήστη. Ο χρήστης μεταφέρεται σε έναν κάδο ανακύκλωσης (αρχειοθετείται με έλεγχο-ιστορικό) και μπορεί να επαναφερθεί - δεν διαγράφεται οριστικά.

Endpoint​

DELETE /users/:userId

Η παράμετρος διαδρομής είναι το εσωτερικό ID χρήστη του Joryio. Απαιτεί το scope users:delete. Περάστε ένα προαιρετικό ?reason= για να καταγράψετε τον λόγο, στο έλεγχο-ιστορικό της διαγραφής.

Παράδειγμα αιτήματος​

curl -X DELETE "https://api-eu1.joryio.com/api/users/665f1e2a9b3c4d5e6f7a8b9c?reason=duplicate" \
-H "Authorization: Bearer jry_live_your_api_key"

Απόκριση​

204 No Content - το σώμα της απόκρισης είναι κενό.

Σημειώσεις​

  • Ο χρήστης μεταφέρεται σε έναν κάδο ανακύκλωσης και μπορεί να επαναφερθεί - δείτε Λίστα διαγραμμένων χρηστών. Κάθε διαγραφή καταγράφεται με έλεγχο-ιστορικό ποιος / πότε / πώς / γιατί. (Η επαναφορά εκτελείται προς το παρόν μέσω εσωτερικού endpoint - επικοινωνήστε με την υποστήριξη για να επαναφέρετε μια διαγραμμένη επαφή.)
  • Ο χρήστης αφαιρείται από τα τμήματα και οι ενεργές καμπάνιες παύουν αμέσως να τον στοχεύουν.
  • Το ιστορικό συμβάντων διατηρείται, οπότε ένας χρήστης που επαναφέρεται διατηρεί όλο το ιστορικό του.
  • Για να διαγράψετε οριστικά έναν χρήστη και όλα τα δεδομένα του (δικαίωμα διαγραφής κατά GDPR), χρησιμοποιήστε αντ' αυτού τη ροή διαγραφής δεδομένων (DSR) - αυτή είναι μη αναστρέψιμη και αποτελεί διαφορετική λειτουργία.

Λίστα διαγραμμένων χρηστών​

Λίστα του κάδου ανακύκλωσης - χρήστες που διαγράφηκαν, με το έλεγχο-ιστορικό της διαγραφής (ποιος, πότε, πώς, γιατί).

Endpoint​

GET /users/deleted

Απαιτεί το scope users:read.

Παράμετροι query​

ΠαράμετροςΤύποςΠροεπιλογήΠεριγραφή
querystring-Προαιρετικό. Αντιστοίχιση βάσει προθέματος email/externalId, τηλεφώνου ή αρχικού ID χρήστη.
limitnumber50Μέγιστα αποτελέσματα, προεπιλογή 50, μέγιστο 200
offsetnumber0Πλήθος που παραλείπεται, προεπιλογή 0

Παράδειγμα αιτήματος​

curl -X GET "https://api-eu1.joryio.com/api/users/deleted?limit=50" \
-H "Authorization: Bearer jry_live_your_api_key"

Απόκριση​

{
"total": 1,
"items": [
{
"originalId": "665f1e2a9b3c4d5e6f7a8b9c",
"email": "[email protected]",
"phone": "+15551234567",
"externalId": "usr_1001",
"deletedAt": "2026-08-09T03:00:30.000Z",
"deletedBy": "[email protected]",
"deletedVia": "api",
"deletedReason": "duplicate",
"restoredAt": null
}
]
}

Μαζικές λειτουργίες (σώμα-πίνακας)​

Δεν υπάρχει ξεχωριστό endpoint μαζικών λειτουργιών, ούτε διαδρομή που δέχεται σκέτο πίνακα χρηστών. Οι παρτίδες περνούν από το POST /users/track: κάθε πεδίο του - attributes, events, purchases, devices - δέχεται είτε ένα μεμονωμένο αντικείμενο είτε έναν πίνακα, οπότε ένα αίτημα μπορεί να μεταφέρει πολλά άτομα, τη δραστηριότητά τους και τις συνδρομές τους σε λίστες.

Endpoint​

POST /users/track
Content-Type: application/json

{ "attributes": [ { ... }, { ... } ], "events": [ { ... } ] }

Σώμα αιτήματος​

Το σώμα πρέπει να είναι αντικείμενο JSON με τουλάχιστον ένα από τα attributes, events, purchases, devices. Ένας σκέτος πίνακας ([ {...}, {...} ]) απορρίπτεται με 400 "Body must be an object with any of: attributes, events, purchases, devices.", όπως και ένα κενό αντικείμενο.

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

Παράδειγμα αιτήματος​

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

curl -X POST https://api-eu1.joryio.com/api/users/track \
-H "Authorization: Bearer jry_live_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"attributes": [
{
"externalId": "user_001",
"email": "[email protected]",
"attributes": { "firstName": "John", "plan": "free" },
"subscriptions": [
{ "listId": "3f9d2c1e-7a54-4b2e-9c1d-8e6f5a4b3c2d", "channel": "email" }
]
},
{
"externalId": "user_002",
"email": "[email protected]",
"attributes": { "firstName": "Jane", "plan": "premium" }
}
],
"events": [
{ "externalId": "user_001", "name": "Signed Up", "properties": { "source": "landing_page" } },
{ "externalId": "user_002", "name": "Signed Up", "properties": { "source": "referral" } }
]
}'

Απόκριση​

Μία σύνοψη ανά πίνακα. Το processed μετρά τα στοιχεία που εφαρμόστηκαν· το failed απαριθμεί τα υπόλοιπα με τον δείκτη τους σε εκείνον τον πίνακα. Το warnings εμφανίζεται μόνο όταν ένα στοιχείο αποθηκεύτηκε αλλά χρειάζεται προσοχή (δείτε Track).

{
"attributes": {
"processed": 2,
"failed": [],
"subscriptions": { "applied": 1, "skipped": [] }
},
"events": { "processed": 2, "failed": [] },
"purchases": { "processed": 0, "failed": [] },
"devices": { "processed": 0, "failed": [] }
}

Απόκριση με αποτυχίες​

Ένα κακοσχηματισμένο στοιχείο δεν αποτυγχάνει ποτέ ολόκληρη την παρτίδα - ό,τι είναι έγκυρο επεξεργάζεται κανονικά:

{
"attributes": {
"processed": 1,
"failed": [
{ "index": 1, "reason": "property emial should not exist" }
],
"subscriptions": {
"applied": 0,
"skipped": [
{
"index": 0,
"listId": "3f9d2c1e-7a54-4b2e-9c1d-8e6f5a4b3c2d",
"channel": "email",
"reason": "Existing opt-out is not resurrected by user creation; use POST /subscriptions/contacts/:userId/lists/:listId for an explicit re-opt-in"
}
]
}
},
"events": {
"processed": 1,
"failed": [
{ "index": 0, "reason": "name should not be empty" }
]
},
"purchases": { "processed": 0, "failed": [] },
"devices": { "processed": 0, "failed": [] }
}

Όρια​

  • Ανά αίτημα: 1000 attributes, 500 events, 500 purchases, 1000 devices
  • Ένα αίτημα που υπερβαίνει ένα όριο απορρίπτεται με 400 (για παράδειγμα "events accepts at most 500 items per request (received 600). Split the batch.") αντί να περικοπεί - δεν επεξεργάζεται τίποτα από αυτό
  • Για μεγαλύτερες παρτίδες, χωρίστε σε διαδοχικά αιτήματα έως το όριο κάθε πεδίου. Η επανάληψη είναι ασφαλής: το /users/track είναι upsert βάσει externalId, οι αγορές κλειδώνονται με orderId, και τα συμβάντα μπορούν να φέρουν clientEventId για αποφυγή διπλοεγγραφών
Οι συνδρομές σε λίστες στέλνονται στην ίδια κλήση

Κάθε στοιχείο του attributes μπορεί να φέρει subscriptions (δείτε Συνδρομές σε λίστες). Στην παραπάνω απόκριση, το στοιχείο 0 του attributes εγγράφηκε στη λίστα· σε εκείνη με τις αποτυχίες, το υπάρχον opt-out του διατηρήθηκε και αναφέρθηκε, ενώ το άτομο ενημερώθηκε κανονικά. Για να αλλάξετε μια συνδρομή αργότερα, χρησιμοποιήστε το POST /subscriptions/contacts/:userId/lists/:listId.

Η μορφή πίνακα προορίζεται για προγραμματιστικές παρτίδες από το backend σας. Για αρχεία και πλήρεις μεταβάσεις, μη φτιάχνετε δικούς σας βρόχους ομαδοποίησης - χρησιμοποιήστε τη Μαζική εισαγωγή στο dashboard (CSV/JSON με αντιστοίχιση στηλών, απαλοιφή διπλοτύπων, κανόνες συγκατάθεσης και αναφορά σφαλμάτων) ή το Warehouse sync για επαναλαμβανόμενες φορτώσεις.


Συμβάντα χρήστη​

Λήψη των συμβάντων ενός χρήστη​

Ανακτήστε όλα τα συμβάντα ενός συγκεκριμένου χρήστη.

Endpoint​

GET /users/:userId/events

Η παράμετρος διαδρομής είναι το εσωτερικό ID χρήστη του Joryio.

Παράμετροι query​

ΠαράμετροςΤύποςΠροεπιλογήΠεριγραφή
limitnumber50Πλήθος συμβάντων που επιστρέφονται (μέγιστο 1000)
offsetnumber0Μετατόπιση σελιδοποίησης
startDatestring-Φιλτράρισμα συμβάντων μετά από αυτή την ημερομηνία (ISO 8601)
endDatestring-Φιλτράρισμα συμβάντων πριν από αυτή την ημερομηνία (ISO 8601)
eventNamestring-Φιλτράρισμα βάσει ονόματος συμβάντος
groupBySessionbooleanfalseΕπιστρέφει επιπλέον τα συμβάντα ομαδοποιημένα ανά συνεδρία
includeJourneyStepsbooleantrueΤο false αφήνει έξω τα συμβάντα βημάτων διαδρομής (canvas.step.entered / canvas.step.left) από τα συμβάντα και το σύνολο

Παράδειγμα αιτήματος​

curl -X GET "https://api-eu1.joryio.com/api/users/665f1e2a9b3c4d5e6f7a8b9c/events?limit=20" \
-H "Authorization: Bearer jry_live_your_api_key"

Απόκριση​

Τα πεδία των συμβάντων χρησιμοποιούν snake_case (προέρχονται από το analytics store):

{
"data": [
{
"event_id": "9b2f6c1e-4a8d-4f0b-9c3d-2e1f5a6b7c8d",
"event_name": "Order Completed",
"properties": {
"orderId": "order_456",
"total": 99.99
},
"timestamp": "2024-01-20 14:30:00"
},
{
"event_id": "1c3e5a7b-9d2f-4b6c-8e0a-3f5d7b9c1e2a",
"event_name": "Page Viewed",
"properties": {
"page": "/pricing"
},
"timestamp": "2024-01-20 14:25:00"
}
],
"total": 156,
"limit": 20,
"offset": 0
}

Συνήθη γνωρίσματα​

Ειδικά πεδία και γνωρίσματα​

Τα email και phone είναι πεδία προφίλ ανώτατου επιπέδου (όχι γνωρίσματα) - στείλτε τα στο ανώτατο επίπεδο του σώματος του αιτήματος.

Τα παρακάτω γνωρίσματα έχουν ειδική σημασία στο Joryio:

ΓνώρισμαΤύποςΠεριγραφή
firstNamestringΤο όνομα του χρήστη (χρησιμοποιείται στην αναζήτηση και στην εμφάνιση)
lastNamestringΤο επώνυμο του χρήστη (χρησιμοποιείται στην αναζήτηση και στην εμφάνιση)
languagestringΠροτιμώμενη γλώσσα (ορίζεται αυτόματα από τα SDK όταν είναι διαθέσιμη)
timezonestringΗ ζώνη ώρας του χρήστη, σε μορφή IANA (καθορίζει τις ώρες ησυχίας και την παράδοση journeys σε τοπική ώρα)
countrystringΚωδικός χώρας (σε ευρετήριο για τμηματοποίηση)

Προσαρμοσμένα γνωρίσματα​

Μπορείτε να προσθέσετε απεριόριστα προσαρμοσμένα γνωρίσματα:

{
"attributes": {
"plan": "premium",
"mrr": 99,
"signupSource": "google_ads",
"lifetimeValue": 1250.50,
"tags": ["vip", "early-adopter"],
"preferences": {
"emailNotifications": true,
"smsNotifications": false
}
}
}

Υποστηριζόμενοι τύποι δεδομένων​

  • String: "premium"
  • Number: 99.99
  • Boolean: true / false
  • Date: "2024-01-15T10:30:00Z" (ISO 8601)
  • Array: ["tag1", "tag2"]
  • Object: { "nested": "value" }

Αποκρίσεις σφαλμάτων​

Όλα τα σφάλματα χρησιμοποιούν το τυπικό σώμα σφάλματος - δείτε Επισκόπηση API: Απόκριση σφάλματος.

400 Bad Request​

{
"statusCode": 400,
"message": "Cannot create or update a user without a valid identifier (externalId or email to create; userId only updates an existing user)",
"timestamp": "2026-01-15T10:30:00.000Z",
"path": "/users"
}

401 Unauthorized​

{
"statusCode": 401,
"message": "Invalid or expired API key",
"timestamp": "2026-01-15T10:30:00.000Z",
"path": "/users"
}

404 Not Found​

{
"statusCode": 404,
"message": "User with userId 'user_123' not found",
"timestamp": "2026-01-15T10:30:00.000Z",
"path": "/users/by-user-id/user_123"
}

Καλές πρακτικές​

1. Οι επαναλήψεις είναι ασφαλείς - το POST /users/track είναι upsert​

Το POST /users/track έχει κλειδί το δικό σας userId - η επανάληψη του ίδιου αιτήματος ενημερώνει το ίδιο προφίλ αντί να δημιουργήσει διπλότυπο. Δεν υπάρχει κεφαλίδα Idempotency-Key· απλώς επαναλάβετε το αίτημα ως έχει σε αποτυχίες δικτύου:

curl -X POST https://api-eu1.joryio.com/api/users/track \
-H "Authorization: Bearer jry_live_your_api_key" \
-d '{...}'

2. Ονομασία γνωρισμάτων​

Χρησιμοποιείτε συνεπή, περιγραφικά ονόματα γνωρισμάτων:

Σωστό:

{
"signupDate": "2024-01-15",
"lifetimeValue": 1250.50,
"plan": "premium"
}

Λάθος:

{
"sd": "2024-01-15",
"ltv": 1250.50,
"p": "premium"
}

3. Μορφή αριθμού τηλεφώνου​

Στέλνετε τους αριθμούς τηλεφώνου σε μορφή E.164 - +, ο κωδικός χώρας και μετά ο αριθμός. Δείτε Αριθμοί τηλεφώνου για το πώς χειρίζεται ένας αριθμός χωρίς +.

Σωστό: "+972501234567", "+12125551234" Αποφύγετε: "050-123-4567", "(212) 555-1234" - χωρίς + εξαρτώνται από την προεπιλεγμένη χώρα του χώρου εργασίας


Όρια ρυθμού​

Το Users API δεν έχει σήμερα σταθερά όρια ρυθμού ανά endpoint - δείτε Επισκόπηση API: Όρια ρυθμού για τη συμπεριφορά σε επίπεδο πλατφόρμας και τον χειρισμό των αποκρίσεων 429.


Στατιστικά επαφών​

GET /users/stats
GET /users/stats/growth?days=30

Αριθμοί για αντιπαραβολή με τη δική σας πηγή αλήθειας - αν το κατάστημά σας έχει 40.000 πελάτες και εδώ γράφει 31.000, κάτι δεν φτάνει. Το GET /users/stats/growth?days=30 επιστρέφει πίνακα JSON από { "date", "activeUsers", "newUsers" } - μία εγγραφή ανά ημέρα (τοπική ημέρα του χώρου εργασίας, παλαιότερες πρώτα): activeUsers είναι τα άτομα που έκαναν κάτι εκείνη την ημέρα και newUsers όσα είχαν την πρώτη τους δραστηριότητα εκείνη την ημέρα. Το days έχει προεπιλογή 30 και περιορίζεται σε 1-365· δεν υπάρχει παράμετρος granularity - η σειρά είναι πάντα ημερήσια.

{
"total": 31204,
"thisWeek": 1840,
"lastWeek": 2110,
"growthPercent": -12.8,
"growthType": "down",
"lifetimeSessions": 96420,
"activeUsers30d": 7310,
"activeUsersPrev30d": 6980
}

Το total είναι το πλήθος επαφών, χωρίς τα προφίλ crawler. Κάθε άλλο μέγεθος μετρά ανθρώπους που ΕΚΑΝΑΝ κάτι - η λήψη μηνύματος δεν είναι δραστηριότητα - και είναι null αντί για 0 όταν το αναλυτικό store δεν είναι διαθέσιμο, ώστε ένα κενό να μην αναφέρεται ποτέ ως μηδέν. Οι εβδομάδες είναι στην ώρα του workspace και ξεκινούν Κυριακή· το thisWeek είναι εξ ορισμού μερική εβδομάδα, οπότε το growthPercent διαβάζεται χαμηλά νωρίς μέσα στην εβδομάδα. Το lifetimeSessions μετρά διακριτές συνεδρίες, όχι συμβάντα έναρξης.

Επόμενα βήματα​

Επανανίχνευση τύπων χαρακτηριστικών​

Τελικό σημείο​

POST /attributes/rescan-types

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

Σώμα αιτήματος​

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

Οι τύποι που έχει ορίσει η ομάδα σας δεν θίγονται ποτέ - η απόφαση ενός ανθρώπου δεν παλιώνει επειδή κινήθηκαν τα δεδομένα. Τα τυπικά πεδία (price, total, lastEventTime, ...) τυποποιούνται από την πλατφόρμα και επίσης δεν επηρεάζονται.

Απόκριση​

{ "success": true, "message": "Types will be detected again from current data" }
Πότε να το καλέσετε

Σπάνια. Η διατηρημένη απόφαση είναι το ζητούμενο - είναι αυτό που κάνει ένα τμήμα να σημαίνει σήμερα ό,τι σήμαινε χθες. Καλέστε το όταν η σημασία μιας ιδιότητας έχει πραγματικά αλλάξει στην πηγή, όχι βάσει χρονοδιαγράμματος.