Mydema Plugin API — Οδηγός ενσωμάτωσης
Ο οδηγός αυτός απευθύνεται σε developers που συνδέουν ένα e-shop ή ERP με το Mydema με τον ίδιο τρόπο που το κάνουν τα επίσημα plugins για OpenCart / WooCommerce: εμφάνιση τιμών αποστολής σε πραγματικό χρόνο στο ταμείο, μετατροπή των πληρωμένων παραγγελιών σε αποστολές Mydema (vouchers) και παρακολούθησή τους.
Σε αυτόν τον φάκελο υπάρχει μια έτοιμη προς χρήση συλλογή Postman:
| Αρχείο | Τι είναι |
|---|---|
mydema-plugin-api.postman_collection.json | Όλα τα αιτήματα αυτού του οδηγού, με τη σειρά κλήσης, με scripts που μεταφέρουν το token, το αναγνωριστικό καλαθιού (basket id) και την επιλεγμένη διαδρομή (route) από το ένα αίτημα στο επόμενο |
mydema-staging.postman_environment.json | Βασικό URL του staging και placeholders για το κλειδί σας |
mydema-production.postman_environment.json | Βασικό URL της παραγωγής και placeholders για το κλειδί σας |
#1. Περιβάλλοντα
| Περιβάλλον | Βασικό URL |
|---|---|
| Παραγωγή (production) | https://app.mydema.gr |
| Staging | https://stage.mydema.gr |
Κάθε path σε αυτόν τον οδηγό είναι σχετική ως προς το βασικό URL. Όταν παίρνετε κλειδί μέσω της ροής αυτοεξυπηρέτησης (ενότητα 2.1), η απάντηση του claim σας δίνει το βασικό URL που πρέπει να χρησιμοποιήσετε (apiEndpoint).
Το staging έχει δικά του δεδομένα και δικά του κλειδιά· ένα κλειδί παραγωγής δεν λειτουργεί στο staging.
#2. Απόκτηση κλειδιού API
Ένα κλειδί API (API key, mk_live_…, 48 χαρακτήρες) ανήκει σε έναν ιστότοπο (site — μια «integration» στο Mydema). Κάθε ιστότοπος έχει:
- έναν χρήστη υπηρεσίας (service user), ως τον οποίο ενεργεί το API,
- ένα πορτοφόλι προπληρωμένης πίστωσης (credit wallet) που πληρώνει τις αποστολές του (ενότητα 7.9),
- προαιρετικά ένα domain και μια λίστα επιτρεπόμενων IP (IP allowlist), με τα οποία ελέγχεται κάθε σύνδεση.
Υπάρχουν δύο τρόποι για να πάρετε κλειδί.
#2.1 Σύνδεση αυτοεξυπηρέτησης (προτείνεται για plugins)
Το κατάστημα ζητά σύνδεση, το προσωπικό του Mydema την εγκρίνει στο panel και το κατάστημα παραλαμβάνει το κλειδί του. Αυτά τα τρία endpoints είναι δημόσια (χωρίς token).
- Δημιουργήστε ένα τυχαίο μυστικό (για παράδειγμα 32 τυχαία bytes σε hex) και κρατήστε το στη μεριά σας.
POST/api/plugin/site-requestμε τα στοιχεία του καταστήματος καιclaimSecretHash= το SHA-256 σε hex αυτού του μυστικού. Παίρνετε έναrequestId.- Κάνετε polling στο
POST/api/plugin/site-request/statusμεrequestId+ το αυτούσιοclaimSecretμέχρι τοstatusνα γίνειapproved(ήrejected, μεrejectReason). Αρκεί polling κάθε λίγα λεπτά· η έγκριση γίνεται χειροκίνητα. POST/api/plugin/site-request/claimμε τις ίδιες δύο τιμές. ΠαίρνετεapiKey,apiEndpointκαιintegrationId. Κάθε claim εκδίδει νέο κλειδί και ακυρώνει το προηγούμενο, οπότε κάντε claim μία φορά και αποθηκεύστε το κλειδί.
#2.2 Κλειδί που εκδίδεται από το Mydema
Το προσωπικό του Mydema μπορεί να δημιουργήσει τον ιστότοπο στο panel και να σας στείλει απευθείας το κλειδί. Λειτουργεί ακριβώς όπως ένα κλειδί που αποκτήθηκε με claim.
Αποθηκεύστε το κλειδί όπως έναν κωδικό πρόσβασης. Το Mydema κρατά μόνο το hash του και δεν μπορεί να το εμφανίσει ξανά· αν χαθεί το κλειδί, χρειάζεται νέο claim ή νέο κλειδί από το Mydema.
#3. Αυθεντικοποίηση
#3.1 Σύνδεση
POST /api/auth/plugin-login
Content-Type: application/json
{"apiKey": "mk_live_…", "apiSecret": "", "domain": "myshop.gr"}| Πεδίο | Υποχρεωτικό | Σημειώσεις |
|---|---|---|
apiKey | ναι | Το κλειδί mk_live_… |
apiSecret | ναι, ως "" | Πρέπει να είναι κενή συμβολοσειρά για κλειδιά mk_live_. (Μια μη κενή τιμή ενεργοποιεί ένα παλαιότερο σχήμα κλειδιού + μυστικού.) |
domain | αν ο ιστότοπος έχει domain | Το host name του καταστήματός σας. Το scheme, το path, η θύρα και ένα αρχικό www. αγνοούνται και από τις δύο πλευρές. |
Αν ο ιστότοπος έχει λίστα επιτρεπόμενων IP, το αίτημα πρέπει να προέρχεται από μία από τις καταχωρισμένες διευθύνσεις (ακριβής αντιστοίχιση, χωρίς εύρη CIDR). Το μήνυμα απόρριψης αναφέρει τη διεύθυνση που είδε το Mydema.
Απάντηση (συντομευμένη):
{
"data": {
"accessToken": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9…",
"expiresAt": "2026-10-31T07:59:12+00:00",
"expiresIn": 43200,
"integration": {"id": 8, "name": "My Shop", "platform": null, "domain": "myshop.gr"},
"tokenData": {
"user": {"id": 260, "userRole": "PLUGIN", "customer": 273},
"company": {"id": 4, "name": "Customers Company", "type": "CUS"},
"plugin": true,
"integrationId": 8,
"pluginCustomerId": 273,
"pluginCustomerName": "Customers Company"
}
}
}Κρατήστε τα integrationId και pluginCustomerId (ο κάτοχος του πορτοφολιού)· ορισμένα endpoints τα χρειάζονται στο path.
#3.2 Χρήση του token
Στείλτε το σε κάθε άλλο αίτημα:
Authorization: Bearer <accessToken>Ακριβώς Bearer + ένα κενό· ο έλεγχος κάνει διάκριση πεζών-κεφαλαίων.
#3.3 Διάρκεια ισχύος και ανανέωση
- Το token ισχύει για 12 ώρες, κυλιόμενα: κάθε επιτυχημένο αίτημα μεταθέτει τη λήξη σε 12 ώρες από εκείνη τη στιγμή. Ένα κατάστημα με τακτική κίνηση κρατά το ίδιο token επ' αόριστον.
- Νέα σύνδεση ενώ το token είναι ακόμη έγκυρο επιστρέφει το ίδιο token, οπότε πολλοί workers του ίδιου καταστήματος μπορούν να το μοιράζονται με ασφάλεια.
Όταν το token δεν είναι πλέον έγκυρο, οποιοδήποτε endpoint επιστρέφει HTTP 401 με αυτό το σώμα (προσοχή: χωρίς περίβλημα
data/error):JSON{"message": "User timed out.", "code": "TOKEN_EXPIRED"}codeΣημασία MISSING_TOKENΛείπει ή είναι κακοσχηματισμένη η κεφαλίδα Authorization, ή άγνωστο tokenTOKEN_EXPIREDΠάνω από 12 ώρες χωρίς αίτημα TOKEN_CHANGEDΕκδόθηκε νεότερο token για αυτόν τον ιστότοπο Σε οποιαδήποτε από αυτές τις περιπτώσεις: συνδεθείτε ξανά και επαναλάβετε το αίτημα μία φορά.
Οι αποτυχίες σύνδεσης επιστρέφουν HTTP 403 με τον τυπικό φάκελο σφάλματος (ενότητα 4.3), για παράδειγμα Invalid credentials., Domain not allowed for this key., IP not allowed for this key. Detected IP: ….
#4. Συμβάσεις: αιτήματα, απαντήσεις, σφάλματα
#4.1 Αιτήματα
- Σώματα JSON, UTF-8,
Content-Type: application/json. ΣτείλτεAccept: application/json. - Τα endpoints λίστας και αναζήτησης είναι
POST, ακόμη κι όταν μόνο διαβάζουν. Αν τα καλέσετε μεGETείτε επιστρέφουν 405 είτε πέφτουν σε άλλο route του server και αποτυγχάνουν. - Τα χρηματικά ποσά είναι σε EUR. Τα βάρη σε kg. Οι διαστάσεις των δεμάτων είναι σε cm στα αιτήματα (το Mydema τις αποθηκεύει και τις επιστρέφει σε μέτρα).
#4.2 Επιτυχημένες απαντήσεις
HTTP 200 και ένα αντικείμενο data:
{"data": {"basketId": "695bca64-c645-4398-8b67-c16adcc89de4"}}#4.3 Απαντήσεις σφάλματος
Το Mydema χρησιμοποιεί περισσότερες από μία μορφές σφάλματος. Χειριστείτε όλες.
A. Τυπικός φάκελος (τα περισσότερα endpoints):
{"error": {"message": "{\"message\":\"District is not valid.\",\"code\":400}", "code": 500, "file": null, "line": null}}Το error.message είναι συνήθως το ίδιο μια συμβολοσειρά JSON. Αποκωδικοποιήστε το δεύτερη φορά για να πάρετε το αναγνώσιμο message και τον πραγματικό code (400 λανθασμένα δεδομένα, 403 δεν σας ανήκει, 404 δεν βρέθηκε, 409 σύγκρουση). Αν δεν είναι έγκυρο JSON, χρησιμοποιήστε το ως απλό κείμενο.
B. Σφάλμα framework (ορισμένα endpoints, σημειωμένα με «B» στην ενότητα 7):
{"type": "https://tools.ietf.org/html/rfc2616#section-10", "title": "An error occurred", "status": 500, "detail": "Internal Server Error"}Στην παραγωγή το detail είναι γενικό, οπότε δεν θα δείτε την αιτία. Επικυρώστε τα δεδομένα σας πριν τα στείλετε (ενότητα 6) και καταγράψτε το αίτημα που στείλατε.
C. Σφάλματα token: HTTP 401, {"message": …, "code": "TOKEN_EXPIRED"} (ενότητα 3.3).
D. Endpoints σύνδεσης (/api/plugin/site-request*) χρησιμοποιούν καθαρό φάκελο με την πραγματική κατάσταση HTTP: {"error": {"message": "Request is not approved.", "code": 409}}.
E. Προσωρινό κλείδωμα βάσης δεδομένων: HTTP 503 με κεφαλίδα Retry-After και {"error": {"message": "…temporary database lock…", "code": "DB_RETRY"}}. Περιμένετε και δοκιμάστε ξανά.
#4.4 Κωδικοί κατάστασης HTTP
| Κατάσταση | Σημασία | Επανάληψη; |
|---|---|---|
| 200 | Επιτυχία | — |
| 401 | Πρόβλημα token (ενότητα 3.3) | Νέα σύνδεση, μετά μία επανάληψη |
| 403 | Η σύνδεση απορρίφθηκε | Όχι· διορθώστε κλειδί / domain / IP |
| 404, 405 | Λάθος path ή λάθος μέθοδος HTTP | Όχι |
| 500 | Επιχειρησιακό σφάλμα ή σφάλμα επικύρωσης (λανθασμένα δεδομένα, δεν βρέθηκε, ανεπαρκής πίστωση…) — η πραγματική αιτία βρίσκεται στο σώμα | Όχι: το ίδιο αίτημα θα αποτύχει ξανά |
| 503 | Προσωρινό κλείδωμα βάσης δεδομένων | Ναι, μετά το Retry-After |
| Σφάλμα δικτύου / timeout | — | Αναγνώσεις και create: ναι. complete: ναι, είναι ασφαλές ανά καλάθι (κανόνας 8.2) |
Τα περισσότερα σφάλματα επικύρωσης και επιχειρησιακά σφάλματα επιστρέφονται ως HTTP 500, όχι 4xx. Μην αντιμετωπίζετε το 500 ως διακοπή λειτουργίας του server και μην το επαναλαμβάνετε στα τυφλά.
#4.5 Μορφή αιτήματος λίστας
Τα endpoints που περιγράφονται ως «ListRequest» δέχονται αυτό το προαιρετικό σώμα:
| Κλειδί | Τύπος | Σημειώσεις |
|---|---|---|
params | object | Φίλτρα ειδικά για το endpoint, π.χ. {"state": 65} |
limit | int | Μέγεθος σελίδας. Στις περισσότερες λίστες δεν υπάρχει προεπιλογή: αν το παραλείψετε, παίρνετε τα πάντα |
offset | int | Γραμμές προς παράλειψη |
orderBy | object | π.χ. {"name": "ASC"} |
Το {} είναι έγκυρο σώμα. Οι αριθμοί πρέπει να είναι αριθμοί, όχι συμβολοσειρές.
Τα αποτελέσματα έχουν τη μορφή {"data": {"<items>": [...], "meta": {"total": 17}}}.
#5. Η ροή ενσωμάτωσης με μια ματιά
εφάπαξ ρύθμιση ταμείο (ανά καλάθι αγορών) παραγγελία (ανά πληρωμένη παραγγελία)
────────────── ────────────────────────── ─────────────────────────────────────
plugin-login δημιουργία καλαθιού ──► search-routes update-basket (πραγματικά στοιχεία, σχόλιο)
shipment/templates (ένα καλάθι ανά αποθήκη αποστολής) search-routes (εκ νέου)
suppliers (αποθήκες) εμφάνιση Σ segment.price ανά διαδρομή set-routes (επιλεγμένη διαδρομή)
αναζητήσεις τοποθεσιών χωρίς διαδρομή; ──► scenarios έλεγχος υπολοίπου πίστωσης
payment-complete (creditAmount)
complete ──► id μεταφοράς
voucher-pdf, παρακολούθηση- Ρύθμιση. Συνδεθείτε. Φορτώστε τα πρότυπα δεμάτων. Καταχωρίστε κάθε αποθήκη από την οποία αποστέλλονται τα εμπορεύματα ως αποθήκη / σημείο παραλαβής (supplier) (ή χρησιμοποιήστε μία περιοχή αφετηρίας για όλα). Αντιστοιχίστε τις διευθύνσεις των πελατών σας σε αναγνωριστικά περιοχών (district ids) του Mydema (ενότητα 6.1).
- Προσφορά στο ταμείο. Για κάθε αποθήκη αφετηρίας στο καλάθι αγορών, δημιουργήστε ένα καλάθι (basket) με τα δέματα, τον αποστολέα (αποθήκη) και τον παραλήπτη, και μετά αναζητήστε διαδρομές. Κάθε διαδρομή είναι μία επιλογή αποστολής· η τιμή της είναι το άθροισμα του
priceτων τμημάτων της (segments) (ενότητα 7.6). Κρατήστε τοbasketIdκαι την ταυτότητα της διαδρομής (routeIdτων τμημάτων) μαζί με την επιλογή του πελάτη. - Παραγγελία → αποστολή. Όταν η παραγγελία πληρωθεί, ενημερώστε το καλάθι με τα πραγματικά στοιχεία επικοινωνίας και το σχόλιο του πελάτη, αναζητήστε ξανά διαδρομές (οι τιμές είναι επίκαιρες εκείνη τη στιγμή), στείλτε την επιλεγμένη διαδρομή με
set-routes, καταγράψτε την πληρωμή μεpayment-completeκαι μετά καλέστε τοcompleteμία φορά. Παίρνετε το αναγνωριστικό της εντολής μεταφοράς του Mydema. - Μετά. Κατεβάστε το PDF του voucher και κάνετε polling στο endpoint παρακολούθησης για την κατάσταση.
Ένα καλάθι αγορών με εμπορεύματα από πολλές αποθήκες αντιστοιχεί σε πολλά καλάθια: ένα ανά αποθήκη (αποστολέα), καθένα τιμολογείται και ολοκληρώνεται χωριστά. Τα επίσημα plugins εμφανίζουν το άθροισμά τους ως μία τιμή αποστολής.
#6. Δεδομένα αναφοράς: τοποθεσίες, δέματα, πρόσωπα
#6.1 Τοποθεσίες
Το δέντρο τοποθεσιών του Mydema είναι χώρα (country) → νομός (state) → δήμος (city) → περιοχή (district). Στην παραγωγή, ένα state είναι ελληνικός νομός (prefecture) και ένα city είναι δήμος (municipality).
Τα endpoints αποστολών χρειάζονται το αναγνωριστικό περιοχής του αποστολέα και του παραλήπτη. Οι διαδρομές συνδέουν περιοχές μεταξύ τους, και μόνο οι εξυπηρετούμενες περιοχές έχουν διαδρομές.
| Έχετε | Χρησιμοποιήστε |
|---|---|
| Ένα τοπωνύμιο που πληκτρολόγησε ο πελάτης | POST/api/location/district/avail-autocomplate → locations[].id (μόνο εξυπηρετούμενες περιοχές) |
| Έναν νομό, θέλετε τις εξυπηρετούμενες περιοχές του | POST/api/location/district/avail-list με params.state → locations[].districtId |
| Έναν ταχυδρομικό κώδικα | POST/api/autocomplate/location/postal-code → ονόματα τοποθεσιών (όχι αναγνωριστικά)· μετά αντιστοιχίστε το όνομα με τις δύο παραπάνω κλήσεις |
| Όνομα νομού → αναγνωριστικό state | POST/api/location/state/list |
Η πλήρης λίστα εξυπηρετούμενων περιοχών (avail-list χωρίς φίλτρα) είναι αρκετά μικρή ώστε να αποθηκεύεται στην cache για μερικές ώρες.
#6.2 Δέματα
Φορτώνετε τον κατάλογο δεμάτων μία φορά την ημέρα από το GET/api/shipment/templates. Τιμές κατά τη στιγμή της σύνταξης (Οκτώβριος 2026):
| Κωδικός | Τύπος | Εύρος όγκου (m³) | Χρέωση ως (m³) | Βάρος (kg) | Αποτύπωμα (cm) |
|---|---|---|---|---|---|
| S | M3 (κουτί) | 0 – 0.20 | 0.20 | 0 – 80 | — |
| M | M3 (κουτί) | 0.2001 – 0.50 | 0.50 | 0 – 80 | — |
| L | M3 (κουτί) | 0.5001 – 1.00 | 1.00 | 0 – 80 | — |
| XL | M3 (κουτί) | 1.0001 – 1.60 | 1.60 | 0 – 80 | — |
| PEUR1 | PL (παλέτα) | — | 1.92 | 80 – 1000 | 80 × 120, ύψος 200 |
| PEUR2 | PL (παλέτα) | — | 2.40 | 80 – 1000 | 100 × 120, ύψος 200 |
| PMNI6 | PL (παλέτα) | — | 0.48 | 80 – 300 | 60 × 80, ύψος 100 |
Το Mydema μπορεί να αλλάξει αυτές τις τιμές· διαβάζετέ τες από το API αντί να τις ενσωματώνετε στον κώδικα.
Αντικείμενο δέματος (χρησιμοποιείται από τα create, update-basket, quote-districts):
| Πεδίο | Τύπος | Υποχρεωτικό | Σημειώσεις |
|---|---|---|---|
weightType | string | ναι | M3 = κουτί / δέμα, PL = παλέτα, KG = ειδικά αντικείμενα |
weight | number | ναι | kg, ένα δέμα |
width, height, depth | number | ναι | cm |
isSensitive | bool | όχι | Εύθραυστα εμπορεύματα· προεπιλογή false |
shipmentType, shipmentSize | string | βλ. παρακάτω | Κωδικοί προτύπου / ειδικού αντικειμένου |
productWidth, productHeight, productDepth | number | όχι | Οι διαστάσεις του ίδιου του προϊόντος σε cm. Τυπώνονται μόνο στο voucher· δεν χρησιμοποιούνται για την τιμολόγηση |
Πώς προκύπτει η τιμή:
- M3 (κουτί): με βάση τον όγκο (
width × height × depth, m³) και το βάρος. Ένα δέμα μπορεί να ζυγίζει έως 220 kg. Στείλτε ένα δέμα ανά φυσικό δέμα. Παραλείψτε ταshipmentTypeκαιshipmentSize— ένας άγνωστος κωδικός κάνει όλο το αίτημα να αποτύχει μεSize is not valid/Type is not valid. - PL (παλέτα): με βάση το αποτύπωμα: τα
widthκαιdepthπρέπει να αντιστοιχούν σε ένα από τα παραπάνω αποτυπώματα παλέτας (σε οποιονδήποτε προσανατολισμό, π.χ. 80 και 120 για PEUR1). Τοheightείναι το ύψος του φορτίου· δεν επηρεάζει την τιμή. Παραλείψτε ταshipmentType/shipmentSize. - KG (ειδικά αντικείμενα): τα
shipmentTypeκαιshipmentSizeείναι και τα δύο υποχρεωτικά και πρέπει να είναι κωδικοί που σας έδωσε το Mydema για το συγκεκριμένο αντικείμενο.
Πολλά πανομοιότυπα δέματα = πολλά αντικείμενα δέματος. Ένα δέμα με weight 0 και χωρίς shipmentType αγνοείται σιωπηρά.
#6.3 Αποστολέας και παραλήπτης
{
"firstName": "Μαρία",
"lastName": "Παπαδοπούλου",
"email": "[email protected]",
"phone": "6900000000",
"customerType": "I",
"taxId": "",
"address": {
"address": "Οδός Παραλήπτη 5",
"postalCode": "53100",
"district": 158,
"city": null,
"officeName": "",
"taxOffice": "",
"location": ""
}
}| Πεδίο | Σημειώσεις |
|---|---|
customerType | I ιδιώτης, S επιχείρηση |
taxId | ΑΦΜ για επιχειρήσεις, έως 20 χαρακτήρες |
address.district | Υποχρεωτικό. Αναγνωριστικό περιοχής (ενότητα 6.1). Αν λείπει ή είναι άγνωστη η περιοχή, το αίτημα αποτυγχάνει |
address.city | Αναγνωριστικό δήμου, ή null ώστε να προκύψει από την περιοχή (προτείνεται) |
email, phone | Χρησιμοποιήστε πραγματικές τιμές όταν ολοκληρώνετε μια παραγγελία: το Mydema στέλνει e-mail στον παραλήπτη όταν δημιουργείται η αποστολή και ο courier βλέπει τον αριθμό τηλεφώνου. Κατά την προσφορά αρκούν placeholders |
Ο αποστολέας είναι η αποθήκη σας. Χρησιμοποιήστε customerType S και την περιοχή της αποθήκης.
#7. Αναφορά endpoints
Όλα τα endpoints εκτός από αυτά της 7.1 χρειάζονται Authorization: Bearer <token>. Το «Σφάλματα: A/B» παραπέμπει στις μορφές σφαλμάτων της ενότητας 4.3.
#7.1 Σύνδεση (δημόσια)
#POST/api/plugin/site-request
| Πεδίο | Υποχρεωτικό | Σημειώσεις |
|---|---|---|
domain | ναι | Host name του καταστήματος |
companyName | ναι | έως 191 |
contactName | ναι | έως 100 |
contactEmail | ναι | Εδώ αποστέλλεται το e-mail έγκρισης |
claimSecretHash | ναι | SHA-256 σε hex (64 χαρακτήρες) του μυστικού σας |
platform | όχι | opencart3, opencart4, woocommerce, magento2· άλλες τιμές αποθηκεύονται ως κενές |
siteName, pluginVersion, taxId, taxOffice, address, postalCode, city, contactPhone | όχι | Στοιχεία τιμολόγησης / επικοινωνίας |
{"data": {"requestId": "9b2f8f8e-3c1a-4f7e-9d1e-1a2b3c4d5e6f", "status": "pending"}}Αν στείλετε ξανά το ίδιο domain και μυστικό, επιστρέφεται το ίδιο αίτημα. Σφάλματα (μορφή D): 400 μη έγκυρο πεδίο, 409 υπάρχει άλλο ανοιχτό αίτημα για αυτό το domain, 429 περισσότερα από 5 αιτήματα ανά ώρα από μία IP.
#POST/api/plugin/site-request/status
Σώμα: {"requestId": "…", "claimSecret": "<raw secret>"}
{"data": {"status": "approved", "siteName": "My Shop", "domain": "myshop.gr", "rejectReason": null}}status: pending, approved, rejected, claimed. Άγνωστο αναγνωριστικό ή λάθος μυστικό → 404.
#POST/api/plugin/site-request/claim
Σώμα: {"requestId": "…", "claimSecret": "<raw secret>"}
{"data": {"apiKey": "mk_live_…", "apiEndpoint": "https://app.mydema.gr", "integrationId": 57}}Κάθε κλήση ανανεώνει (rotates) το κλειδί. Σφάλματα: 404, 409 δεν έχει εγκριθεί, 410 ο ιστότοπος δεν είναι πλέον ενεργός.
#7.2 Αυθεντικοποίηση
| Endpoint | Σημειώσεις |
|---|---|
POST/api/auth/plugin-login | Βλ. ενότητα 3.1 |
POST/api/auth/plugin-autologin | Ανοίγει μια σελίδα του panel του Mydema (πληρωμή αναπλήρωσης πίστωσης) στον browser του εμπόρου χωρίς κωδικό πρόσβασης. Βλ. ενότητα 7.9 |
#7.3 Τοποθεσίες
Όλα είναι POST. Σφάλματα: B.
#POST/api/location/district/avail-autocomplate
Εξυπηρετούμενες περιοχές που ταιριάζουν με ένα όνομα (ελληνικά ή λατινικά, οι τόνοι προαιρετικοί· αν δεν βρεθεί κάτι, γίνεται ασαφής αντιστοίχιση).
Σώμα: {"term": "Κομοτην", "limit": 10} (limit προεπιλογή 100)
{"data": {"locations": [{
"id": 1, "name": "Κομοτηνή", "nameLatin": "Komotini", "cityName": "Κομοτηνή", "CountryName": "Ελλάδα",
"city": {"id": 67, "name": "Κομοτηνή", "state": {"id": 65, "name": "Ροδόπης"}, "country": {"code": "GR"}},
"country": {"code": "GR", "name": "Ελλάδα"}
}]}}(Το CountryName όντως ξεκινά με κεφαλαίο C.)
#POST/api/location/district/avail-list — ListRequest
Όλες οι εξυπηρετούμενες περιοχές, σε επίπεδη λίστα. Φίλτρα: params.state (αναγνωριστικό νομού), params.city (αναγνωριστικό δήμου). Χωρίς limit τις παίρνετε όλες.
Σώμα: {"params": {"state": 65}}
{"data": {
"locations": [{"districtId": 1, "name": "Κομοτηνή", "cityId": 67, "cityName": "Κομοτηνή", "stateId": 65, "stateName": "Ροδόπης"}],
"locationDistricts": ["…same districts in the long format of avail-autocomplate…"],
"meta": {"total": 4, "limit": null, "offset": 0}
}}Χρησιμοποιήστε το locations· το locationDistricts διατηρείται για παλαιότερους clients.
#POST/api/autocomplate/location/postal-code
(Η ορθογραφία autocomplate είναι μέρος του path.) Σώμα: {"term": "69131", "limit": 50} (αντιστοίχιση προθέματος· limit προεπιλογή 10).
{"data": {"locationPostalCodes": [
{"id": 12752, "code": "69131", "district": "ΑΓΙΑ ΒΑΡΒΑΡΑ", "city": "ΡΟΔΟΠΗΣ"},
{"id": 12754, "code": "69131", "district": "ΚΟΜΟΤΗΝΗ", "city": "ΡΟΔΟΠΗΣ"}
]}}Το district είναι το όνομα του οικισμού και το city το όνομα του νομού — κείμενο, όχι αναγνωριστικά. Ένας ταχυδρομικός κώδικας μπορεί να καλύπτει πολλούς οικισμούς.
#POST/api/location/state/list — ListRequest
Σώμα: {"orderBy": {"name": "ASC"}}
{"data": {"locationStates": [{"id": 65, "name": "Ροδόπης", "nameLatin": null, "originalName": "Ροδόπης", "country": {"code": "GR"}}], "meta": {"total": 59}}}#POST/api/location/city/avail-list — ListRequest
Όλοι οι δήμοι ενός νομού. Το params.state είναι υποχρεωτικό (χωρίς αυτό η λίστα είναι κενή).
Σώμα: {"params": {"state": 65}} → {"data": {"locationCities": [{"id": 542, "name": "Αίγειρος", "state": {"id": 65, "name": "Ροδόπης"}}], "meta": {"total": 14}}}
#7.4 Πρότυπα δεμάτων
#GET/api/shipment/templates
{"data": {"templates": [
{"code": "S", "name": "Small", "shipmentType": "M3", "lengthCm": 0, "widthCm": 0, "heightCm": 0,
"minWeightKg": 0, "maxWeightKg": 80, "minVolumeM3": 0, "maxVolumeM3": 0.2, "volumeM3": 0.2,
"billingVolumeM3": 0.2, "isPallet": false, "displayOrder": 1},
{"code": "PEUR1", "name": "Standard EUR 1 80x120x200", "shipmentType": "PL", "lengthCm": 80, "widthCm": 120, "heightCm": 200,
"minWeightKg": 80, "maxWeightKg": 1000, "minVolumeM3": null, "maxVolumeM3": null, "volumeM3": 1.92,
"billingVolumeM3": 1.92, "isPallet": true, "displayOrder": 5}
]}}Δείτε την ενότητα 6.2 για τον τρόπο χρήσης τους. Σφάλματα: A.
#7.5 Αποθήκες / σημεία παραλαβής (suppliers)
Μια αποθήκη / σημείο παραλαβής (supplier) είναι ένα σημείο από το οποίο παραλαμβάνονται τα εμπορεύματά σας. Η περιοχή της είναι η περιοχή του αποστολέα στα καλάθια για αυτά τα εμπορεύματα. Κάθε ιστότοπος βλέπει και επεξεργάζεται μόνο τις δικές του αποθήκες. Σφάλματα: A (προβλήματα δικαιωμάτων: B).
Αντικείμενο αποθήκης (supplier)
{
"id": 3, "integrationId": 8, "companyId": 4, "companyUserId": 260,
"name": "Αποθήκη Κομοτηνής", "pickupAddress": "Οδός Δοκιμής 1",
"districtId": 1, "districtName": "Κομοτηνή", "cityId": 67, "cityName": "Κομοτηνή", "postalCode": "69100",
"latitude": null, "longitude": null, "googlePlaceId": null,
"contactName": "Γιώργος", "contactPhone": "2531000000", "contactEmail": null,
"pickupHoursStart": "09:00:00", "pickupHoursEnd": "17:00:00",
"notes": null, "externalCode": "WH-1", "isActive": true,
"createdAt": "2026-10-30T19:58:41+00:00", "updatedAt": "2026-10-30T19:58:41+00:00"
}Εγγράψιμα πεδία: name (υποχρεωτικό, έως 200), pickupAddress (υποχρεωτικό, έως 500), districtId (ο δήμος προκύπτει από αυτό), postalCode, latitude, longitude, googlePlaceId, contactName, contactPhone, contactEmail, pickupHoursStart, pickupHoursEnd ("09:00"), notes, externalCode (δικό σας αναγνωριστικό, μοναδικό ανά ιστότοπο).
| Endpoint | Σώμα | Απάντηση |
|---|---|---|
POST/api/supplier | πεδία αποθήκης | {"data": {"supplier": {…}}} |
GET/api/supplier/{id} | — | {"data": {"supplier": {…}}} |
PUT/api/supplier/{id} | μόνο τα πεδία προς αλλαγή | {"data": {"supplier": {…}}} |
DELETE/api/supplier/{id} | — | {"data": {"deleted": true}} |
POST/api/supplier/list | {} | {"data": {"suppliers": […], "total": 1}} |
GET/api/integration/{integrationId}/supplier | — | Ίδιο με τη λίστα |
POST/api/supplier/sync | {"integrationId": 8, "rows": [{…, "externalCode": "WH-1", "cityId": 67}]} | {"data": {"created": 1, "updated": 0, "errors": []}} |
Σημειώσεις:
- Στο
PUT, μη στέλνετεintegrationId(ή στείλτε0, που σημαίνει «διατήρηση»). Αν στείλετε"districtId": nullη περιοχή διαγράφεται. - Το
syncκάνει upsert με βάση τοexternalCode(έως 200 γραμμές ανά κλήση) και χρειάζεταιcityIdσε κάθε γραμμή. Τα σφάλματα γραμμών αναφέρονται στοerrorsμε τοindexτης γραμμής· οι υπόλοιπες αποθηκεύονται. - Το
externalCodeμιας διαγραμμένης αποθήκης δεν μπορεί να ξαναχρησιμοποιηθεί. - Συνήθη σφάλματα:
District is not valid.,Please select a district.,Supplier not found.,Supplier with this externalCode already exists for this integration.(409).
#7.6 Αποστολές: προσφορά
#POST/api/transportation/create — δημιουργία καλαθιού
{
"packages": [{"weightType": "M3", "weight": 25, "width": 58.48, "height": 58.48, "depth": 58.48, "isSensitive": false}],
"sender": {"firstName": "Αποθήκη", "lastName": "Κομοτηνής", "email": "[email protected]", "phone": "2531000000", "customerType": "S",
"address": {"address": "Οδός Δοκιμής 1", "postalCode": "69100", "district": 1, "city": null}},
"receiver": {"firstName": "Μαρία", "lastName": "Παπαδοπούλου", "email": "[email protected]", "phone": "6900000000", "customerType": "I",
"address": {"address": "Οδός Παραλήπτη 5", "postalCode": "", "district": 158, "city": null}}
}{"data": {"basketId": "695bca64-c645-4398-8b67-c16adcc89de4"}}Ένα καλάθι είναι ένα προσωρινό προσχέδιο προσφοράς/παραγγελίας. Τίποτα δεν έχει κρατηθεί ακόμη. Σφάλματα: B. Συνήθεις αιτίες: άγνωστο district, Size is not valid / Type is not valid (βλ. 6.2), λείπει το sender ή το receiver. Στείλτε το σχόλιο της παραγγελίας αργότερα με update-basket (το πεδίο comments εδώ περιορίζεται σε 10 χαρακτήρες).
#POST/api/transportation/search-routes
Σώμα: {"basketId": "…"}
{"data": {
"basketId": "695bca64-c645-4398-8b67-c16adcc89de4",
"serviceFee": 10,
"serviceFees": [{"total": 10.07, "serviceFee": 0, "tax": 0.22}],
"routes": [[
{"startPoint": 3, "endPoint": 698, "company": 15, "onlyB2B": false, "routeId": 78,
"price": 5.26, "tax": 1.01, "currency": "EUR", "hasAddressDelivery": true,
"deliveryDoor": false, "carrier": false, "deliveryDoorPrice": 0, "deliveryDoorTax": 0, "carrierPrice": 0, "carrierTax": 0,
"data": {"route": "Ροδόπης, Κομοτηνή-Θεσσαλονίκη, Κέντρο Διαλογής", "company": "ΚΟΚΟΒΙΔΗΣ ΦΡΙΓΚΟΤΡΑΝΣ",
"endPointName": "Θεσσαλονίκη, Κέντρο Διαλογής", "endPointAddress": "Π.Σ.Ο. Θεσ/νίκης-Ωραιοκάστρου\nΤηλέφωνα : 2310 785 050",
"companyPrices": [7095], "price": 4.78, "currency": "EUR"},
"packagePrices": [{"weightType": "M3", "weight": 25, "width": 0.5848, "height": 0.5848, "depth": 0.5848,
"shipmentSize": null, "shipmentType": null, "isSensitive": false, "productDimsCm": null,
"price": 4.78, "tax": 0.92, "basePrice": 3.86}],
"basePrice": 4.25, "serviceFee": 0},
{"startPoint": 698, "endPoint": 179, "company": 18, "onlyB2B": false, "routeId": 385,
"price": 5.84, "tax": 1.13, "currency": "EUR", "hasAddressDelivery": false,
"deliveryDoor": false, "carrier": false, "deliveryDoorPrice": 0, "deliveryDoorTax": 0, "carrierPrice": 0, "carrierTax": 0,
"data": {"route": "Θεσσαλονίκη, Κέντρο Διαλογής-Φλώρινας, Φλώρινα", "company": "ΣΑΛΒΑΡΙΝΑΣ ΑΛ. ΙΩΑΝΝΗΣ",
"endPointName": "Φλώρινας, Φλώρινα", "endPointAddress": "Λεωφόρος Αβέρωφ 47, Φλώρινα\nΤηλέφωνο: 2385023995",
"companyPrices": [953], "price": 5.31, "currency": "EUR"},
"packagePrices": ["…"], "basePrice": 4.71, "serviceFee": 0}
]]
}}Πώς να το διαβάσετε:
- Το
routesείναι μια λίστα διαδρομών· κάθε διαδρομή είναι μια λίστα τμημάτων (σκελών), ένα ανά μεταφορέα. Το παράδειγμα έχει μία διαδρομή με δύο σκέλη: Κομοτηνή → κέντρο διαλογής Θεσσαλονίκης → Φλώρινα. - Τιμή που εμφανίζεται στον πελάτη = Σ
priceτων τμημάτων της διαδρομής, με ΦΠΑ και την προμήθεια υπηρεσίας του Mydema να περιλαμβάνονται (εδώ 5.26 + 5.84 = 11.10 €). Ο ΦΠΑ που περιέχεται είναι Σtax(2.14 €). - Μη χρησιμοποιείτε τα
serviceFeesήdata.priceως τιμή πελάτη· είναι εσωτερικά μεγέθη. - Ο τρόπος παράδοσης προκύπτει από το τελευταίο τμήμα:
hasAddressDelivery: true= παράδοση στη διεύθυνση του παραλήπτη·false= ο παραλήπτης παραλαμβάνει από το κατάστημα του μεταφορέα στοdata.endPointName/data.endPointAddress. - Ονόματα μεταφορέων για εμφάνιση: το
data.companyκάθε τμήματος. - Οι διαδρομές δεν είναι ταξινομημένες. Αν υπάρχει έστω και μία απευθείας διαδρομή (ενός σκέλους), επιστρέφονται μόνο απευθείας διαδρομές.
routes: []με HTTP 200 σημαίνει ότι κανένας μεταφορέας δεν εξυπηρετεί αυτόν τον συνδυασμό (βλ.scenarios).
Το search-routes δεν αλλάζει το καλάθι· καλέστε το όσο συχνά χρειάζεστε.
#POST/api/transportation/scenarios
Εξηγεί ένα κενό αποτέλεσμα.
Σώμα: {"receiverDistrictId": 158, "isB2B": false, "hasAfm": false}
{"data": {"inService": true, "scenarios": [{"type": "IN_SERVICE"}, {"type": "B2C_SMS_NOTIFY"}]}}Όταν η περιοχή δεν εξυπηρετείται: {"inService": false, "scenarios": [{"type": "HUB_PICKUP", "hub": {"transferLocationId": 48, "name": "…", "address": "…", "cityId": 5, "districtId": 101}}]} (το hub μπορεί να είναι null). Σφάλματα: A.
#POST/api/transportation/quote-districts — τιμολόγηση πολλών προορισμών με μία κλήση
Για όταν γνωρίζετε την ευρύτερη περιοχή του πελάτη αλλά όχι την ακριβή περιοχή (district): τιμολογεί το ίδιο καλάθι αγορών για έως 15 περιοχές σε μία κλήση, χωρίς να δημιουργεί καλάθι.
Σώμα: το σώμα του create συν "districtIds": [158, 1]. Το address.district του παραλήπτη αντικαθίσταται διαδοχικά από κάθε αναγνωριστικό.
{"data": {"districts": [
{"districtId": 158, "found": true, "name": "Φλώρινα", "nameLatin": "Florina", "cityId": 192, "cityName": "Φλώρινα",
"serviceFee": 10, "serviceFees": ["…"], "routes": [["…segments as in search-routes…"]]},
{"districtId": 999999, "found": false, "routes": [], "serviceFees": []}
]}}Όταν ο πελάτης επιλέξει μία, κάντε create ένα καλάθι για αυτή την περιοχή και συνεχίστε κανονικά. Σφάλματα: B.
#7.7 Αποστολές: παραγγελία → voucher
#POST/api/transportation/update-basket
Αντικαθιστά τα δέματα, τον αποστολέα και τον παραλήπτη του καλαθιού και ορίζει το σχόλιο της παραγγελίας.
{"basketId": "…", "packages": ["…same as create…"], "sender": {"…": "…"}, "receiver": {"…": "…"},
"receiverComment": "Παρακαλώ τηλεφωνήστε πριν την παράδοση"}Απάντηση: {"data": {"basketId": "…"}}. Σφάλματα: B.
- Στέλνετε πάντα ξανά τα
packages: αν τα παραλείψετε, το καλάθι μένει άδειο. - Χρησιμοποιήστε το κατά την παραγγελία για να βάλετε στον παραλήπτη το πραγματικό όνομα, τηλέφωνο και e-mail του πελάτη.
- Το
receiverCommentεμφανίζεται ως οδηγίες του παραλήπτη στην αποστολή.
#POST/api/transportation/set-routes
Αποθηκεύει την επιλεγμένη διαδρομή. Το routes περιέχει τα τμήματα μίας διαδρομής (όχι λίστα διαδρομών), αντιγραμμένα από μια απάντηση του search-routes του ίδιου καλαθιού:
{"basketId": "…", "routes": [
{"company": 15, "startPoint": 3, "endPoint": 698, "routeId": 78, "price": 5.26, "tax": 1.01, "serviceFee": 0,
"packagePrices": ["…as returned…"], "deliveryDoor": false, "deliveryDoorPrice": 0, "carrier": false, "carrierPrice": 0,
"hasAddressDelivery": true},
{"company": 18, "startPoint": 698, "endPoint": 179, "routeId": 385, "price": 5.84, "tax": 1.13, "serviceFee": 0,
"packagePrices": ["…"], "deliveryDoor": false, "deliveryDoorPrice": 0, "carrier": false, "carrierPrice": 0,
"hasAddressDelivery": false}
]}Όλα τα παραπάνω πεδία είναι υποχρεωτικά εκτός από το hasAddressDelivery· το packagePrices δεν πρέπει να είναι κενό. Στείλτε τις τιμές ακριβώς όπως τις επέστρεψε το search-routes. Απάντηση: {"data": {"basketId": "…"}}. Σφάλματα: B.
#POST/api/transportation/payment-complete
Καταγράφει τον τρόπο πληρωμής της αποστολής. Για ιστότοπους με προπληρωμένο πορτοφόλι (όλοι οι ιστότοποι plugin), ορίστε το creditAmount στο σύνολο της διαδρομής ώστε να αφαιρεθεί από το πορτοφόλι κατά το complete.
{"basketId": "…", "totalPrice": 11.10, "creditAmount": 11.10, "status": "success",
"conversationId": "order-1001", "paymentType": "CREDIT", "currency": "EUR", "bank": "MyShop", "card": "MyShop"}| Πεδίο | Σημειώσεις |
|---|---|
totalPrice | Σ price των τμημάτων της επιλεγμένης διαδρομής |
creditAmount | Ποσό που αφαιρείται από το πορτοφόλι. Χρησιμοποιήστε την ίδια τιμή με το totalPrice |
status | Πρέπει να είναι success, διαφορετικά το complete απορρίπτει το καλάθι |
conversationId | Η αναφορά της παραγγελίας σας, έως 50 |
paymentType, currency, bank, card | Υποχρεωτικές μη κενές συμβολοσειρές· τα CREDIT, EUR και το όνομα του καταστήματός σας αρκούν |
Απάντηση: {"data": {"basketId": "…"}}. Δεν χρεώνεται ακόμη τίποτα. Σφάλματα: B.
#POST/api/transportation/complete
Δημιουργεί την εντολή μεταφοράς του Mydema (το voucher) από το καλάθι. Σώμα: {"basketId": "…"}.
{"data": {"transportations": {"id": 5123, "orderNumber": "MY-1042", "transferStatus": {"code": "CR", "name": "Created"},
"totalPrice": 11.1, "shipments": ["…"], "details": ["…"]}}}Το πλήρες αντικείμενο έχει την ίδια μορφή με το GET/api/transportation/{id} (7.8). Αποθηκεύστε το data.transportations.id. Σφάλματα: B.
Τι συμβαίνει:
- Το
creditAmountαφαιρείται από το πορτοφόλι του ιστότοπου. Αν η πίστωση δεν επαρκεί, το αίτημα αποτυγχάνει (Insufficient credit.) και δεν δημιουργείται τίποτα. Ελέγξτε πρώτα το υπόλοιπο (7.9). - Οι μεταφορείς της διαδρομής ειδοποιούνται, ο παραλήπτης λαμβάνει e-mail (αν το e-mail του παραλήπτη είναι πραγματικό) και η διεύθυνση του αποστολέα λαμβάνει e-mail επιβεβαίωσης.
- Μπορεί να επαναληφθεί με ασφάλεια για το ίδιο καλάθι. Από τη στιγμή που ένα καλάθι έχει γίνει αποστολή, το
completeεπιστρέφει ξανά την ίδια αποστολή και δεν χρεώνει τίποτα· ταset-routesκαιpayment-completeσε αυτό το καλάθι αγνοούνται (κανόνας 8.2).
Προϋποθέσεις, με τη σειρά: το καλάθι υπάρχει· η πληρωμή έχει καταγραφεί με status: success (διαφορετικά Payment is not valid)· επαρκής πίστωση.
#7.8 Αποστολές: voucher και παρακολούθηση
#GET/api/transportation/{id}/voucher-pdf?status=confirmed
Επιστρέφει το voucher ως application/pdf (Content-Disposition: attachment; filename="MY-1042.pdf"). Το status είναι confirmed ή temporary· ορίζει μόνο την κεφαλίδα απάντησης X-Mydema-Voucher-Status. Σφάλματα: A.
#GET/api/transportation/{id}
{"data": {"transportationOrder": {
"id": 5123, "orderNumber": "MY-1042", "totalPrice": 11.1, "taxTotal": "2.14", "serviceFee": 0,
"transferStatus": {"code": "CR", "name": "Created"},
"senderComment": "", "deliverComment": " Παρακαλώ τηλεφωνήστε πριν την παράδοση",
"sendAddress": {"…": "…"}, "deliverAddress": {"…": "…"},
"shipments": [{
"id": 9001, "orderNumber": "MY-1042",
"route": {"id": 78, "route": "Κομοτηνή - Θεσσαλονίκη", "company": {"id": 15, "name": "…", "phone": "…"}},
"shipmentStatus": {"code": "TR", "name": "In transit"},
"actions": [{"actionDate": "2026-10-31", "shipmentStatus": {"code": "TR", "name": "In transit"}}],
"packages": ["…"]
}],
"details": ["…one per package…"],
"createdAt": "2026-10-30 10:00:00", "updatedAt": "2026-10-31 09:12:00"
}}}Το shipments έχει μία εγγραφή ανά σκέλος· το actions είναι το ιστορικό αυτού του σκέλους. Σφάλματα: A (το Company not found. σημαίνει ότι το αναγνωριστικό παραγγελίας δεν υπάρχει).
transferStatus.code παραγγελίας | Σημασία |
|---|---|
| CR | Δημιουργήθηκε |
| PP | Εκκρεμεί πληρωμή |
| PA | Πληρώθηκε |
| TR | Σε μεταφορά |
| CM | Ολοκληρώθηκε |
| CL | Ακυρώθηκε |
shipmentStatus.code αποστολής | Σημασία |
|---|---|
| DO | Η εντολή δημιουργήθηκε |
| PE | Σε εκκρεμότητα |
| RE | Παραλήφθηκε από τον μεταφορέα |
| TR | Σε διαμετακόμιση |
| DT | Προς παράδοση |
| DE | Παραδόθηκε |
Δεν υπάρχει webhook· κάνετε polling σε αυτό το endpoint (για παράδειγμα ανά ώρα για τις ανοιχτές αποστολές).
#7.9 Πορτοφόλι πίστωσης
Οι αποστολές πληρώνονται από το προπληρωμένο πορτοφόλι του ιστότοπου. Και τα τρία endpoints λειτουργούν στο πορτοφόλι του συνδεδεμένου ιστότοπου. Σφάλματα: B.
#GET/api/customer/credit/balance
{"data": {"balance": 42.5, "currency": "EUR"}}#GET/api/customer/credit/transactions?page=1&limit=50
limit 1–200, προεπιλογή 50.
{"data": {"transactions": [
{"id": 9, "type": "shipment", "amount": -11.1, "balanceAfter": 31.4, "currency": "EUR",
"refType": "basket", "refId": "695bca64-…", "description": "Shipment payment", "createdAt": "2026-10-30 14:02:11"}
], "total": 1, "page": 1, "limit": 50}}type: topup, shipment, refund. Το createdAt είναι σε τοπική ώρα του server χωρίς ένδειξη ζώνης ώρας.
#POST/api/customer/credit/topup + σελίδα πληρωμής
Οι αναπληρώσεις πληρώνονται με κάρτα στη σελίδα πληρωμής του ίδιου του Mydema.
POST/api/customer/credit/topupμε{"amount": 50}(καθαρό ποσό, 1–1000 €). Απάντηση:{"data": {"basketId": "…", "customerId": 273, "amount": 50, "tax": 12, "chargeTotal": 62, "currency": "EUR"}}(προστίθεται ΦΠΑ 24%).POST/api/auth/plugin-autologinμε{"redirect": "/customer/<customerId>/credit/payment/<basketId>/init"}→{"data": {"token": "…"}}(ισχύει για 2 λεπτά).- Ανοίξτε το
<base URL>/plugin/auto-login?t=<token>στον browser του εμπόρου. Το Mydema συνδέει τον έμπορο και εμφανίζει τη σελίδα πληρωμής με κάρτα. Το υπόλοιπο αυξάνεται όταν η πληρωμή ολοκληρωθεί επιτυχώς.
#7.10 Προαιρετικά
#POST/api/afm — αναζήτηση ελληνικού ΑΦΜ
Σώμα: {"afmNumber": "099999999"} (9–12 χαρακτήρες). Σφάλματα: B.
{"data": {"taxData": {"taxId": "099999999", "taxOffice": "ΦΑΕ ΑΘΗΝΩΝ", "name": "ACME ΑΕ", "address": "ΟΔΟΣ 1", "zip": "10431", "location": "ΑΘΗΝΑ"}}}Ένας άγνωστος αριθμός επιστρέφει την ίδια μορφή με κενές συμβολοσειρές.
#Ρυθμίσεις ιστότοπου
Ελεύθερες ρυθμίσεις κλειδιού/τιμής που αποθηκεύονται στο Mydema για τον ιστότοπό σας.
| Endpoint | Σημειώσεις |
|---|---|
GET/api/integration/{integrationId}/settings | {"data": {"settings": {"currency": {"key": "currency", "value": "EUR", "valueType": "string"}}}} ([] όταν είναι κενό) |
GET/api/integration/{integrationId}/settings/{key} | {"data": {"setting": {…}}}· άγνωστο κλειδί → Setting not found. |
PUT/api/integration/{integrationId}/settings | {"settings": [{"key": "currency", "value": "EUR"}]} → {"data": {"written": 1, "errors": []}} |
DELETE/api/integration/{integrationId}/settings/{key} | {"data": {"deleted": true}} |
Επιτρεπόμενα κλειδιά: free_shipping_threshold, hide_shipping_cost, currency, language, default_pickup_supplier_id, default_pickup_branch_id, buffer_ratio, risk_premium_ratio, auto_voucher_email_to, voucher_email_subject, pickup_warning_html, emergency_mode_enabled, fallback_template_under_35kg, fallback_template_over_35kg. Άλλα κλειδιά αναφέρονται στο errors.
#Πληρωμές voucher (εβδομαδιαία τιμολόγια)
Τιμολόγια που εκδίδει το Mydema για τα vouchers του ιστότοπου σε εβδομαδιαίες δέσμες, πληρωτέα με τραπεζική μεταφορά. Αφορούν μόνο αν το Mydema τιμολογεί τον ιστότοπό σας με αυτόν τον τρόπο. Όλα είναι POST εκτός από τα δύο GET.
| Endpoint | Σώμα | Απάντηση |
|---|---|---|
POST/api/voucher-payment/summary | {} | {"data": {"count": 0, "totalAmount": 0, "oldestDueDate": null}} |
POST/api/voucher-payment/list | {"status": "unpaid", "page": 1, "perPage": 50} (επίσης weekBatchId, fromDate, toDate) | {"data": {"payments": [], "page": 1, "perPage": 50}} |
GET/api/voucher-payment/{id} | — | {"data": {"payment": {…}}} |
GET/api/voucher-payment/{id}/invoice-pdf | — | application/pdf |
#8. Κανόνες ενσωμάτωσης και παγίδες
8.1 Τα επιχειρησιακά σφάλματα είναι HTTP 500. Διαβάζετε το σώμα (ενότητα 4.3) αντί για τον κωδικό κατάστασης και μην επαναλαμβάνετε αυτόματα τις απαντήσεις 500. Αξίζει να επαναλαμβάνετε μόνο τα 503 και τις αποτυχίες δικτύου.
8.2 Το complete είναι idempotent ανά καλάθι. (Idempotent: η επανάληψη της κλήσης δίνει το ίδιο αποτέλεσμα.) Ένα καλάθι γίνεται το πολύ μία αποστολή: αν καλέσετε ξανά το complete για το ίδιο καλάθι, επιστρέφεται η υπάρχουσα αποστολή (ίδιο id) και το πορτοφόλι δεν χρεώνεται ξανά, οπότε μετά από timeout μπορείτε απλώς να το καλέσετε ξανά. Όσο μια πρώτη κλήση εκτελείται ακόμη, μια δεύτερη αποτυγχάνει με This basket is already being completed. Please try again in a moment. — δοκιμάστε ξανά λίγα δευτερόλεπτα αργότερα. Το complete μπορεί να διαρκέσει αρκετά δευτερόλεπτα (στέλνει τα e-mails πριν απαντήσει)· χρησιμοποιήστε timeout τουλάχιστον 30 s. Παρ' όλα αυτά αποθηκεύστε το αναγνωριστικό που επιστρέφεται μαζί με την παραγγελία σας: μια παραγγελία με εμπορεύματα από πολλές αποθήκες έχει ένα καλάθι, και μία αποστολή, ανά αποθήκη.
8.3 Τιμολογήστε ξανά, κατά την παραγγελία, τη διαδρομή που είδε ο πελάτης. Καλέστε το search-routes τη στιγμή της παραγγελίας, επιλέξτε τη διαδρομή με τα ίδια routeId και στείλτε ακριβώς αυτά τα τμήματα στο set-routes. Οι τιμές μπορεί να αλλάξουν μεταξύ προσφοράς και παραγγελίας.
8.4 Ελέγξτε το πορτοφόλι πριν από το complete. GET/api/customer/credit/balance ≥ σύνολο διαδρομής, διαφορετικά ζητήστε από τον έμπορο να κάνει αναπλήρωση (7.9) και δοκιμάστε ξανά αργότερα.
8.5 Ένα καλάθι ανά αποθήκη. Εμπορεύματα που αναχωρούν από διαφορετικές περιοχές είναι διαφορετικές αποστολές. Δημιουργήστε, τιμολογήστε και ολοκληρώστε ένα καλάθι ανά αποστολέα.
8.6 Περιοχές, όχι ονόματα. Κάθε προσφορά χρειάζεται αναγνωριστικό περιοχής και για τις δύο πλευρές. Αντιστοιχίστε τη διεύθυνση του πελάτη σε μια εξυπηρετούμενη περιοχή (6.1) πριν καλέσετε το create· όταν μπορείτε να την περιορίσετε μόνο σε επίπεδο νομού, χρησιμοποιήστε το quote-districts και αφήστε τον πελάτη να επιλέξει.
8.7 Δέματα τύπου κουτιού: παραλείψτε τα shipmentType / shipmentSize. Ένας άγνωστος κωδικός κάνει όλο το αίτημα να αποτύχει (6.2).
8.8 Στέλνετε ξανά τα δέματα στο update-basket. Αν τα παραλείψετε, το καλάθι αδειάζει.
8.9 Πραγματικά στοιχεία επικοινωνίας παραλήπτη κατά την παραγγελία. Το Mydema στέλνει e-mail στον παραλήπτη και ο courier του τηλεφωνεί· τα placeholders της προσφοράς πρέπει να αντικατασταθούν μέσω update-basket πριν από το complete.
8.10 Κρατήστε το token. Συνδεθείτε μία φορά, ξαναχρησιμοποιήστε το token και συνδεθείτε ξανά μόνο μετά από 401 (3.3). Η σύνδεση σε κάθε αίτημα είναι περιττή.