Onboarding API: endpoints¶
| Base URL | Δοκιμαστικό https://provider-dev.timologisi.online · Παραγωγή https://provider.timologisi.online |
| Αυθεντικοποίηση | Header API-KEY, το ίδιο κλειδί με το Provider API. Το ποιο software house καλεί προκύπτει από το κλειδί. Δεν στέλνεται ποτέ στο body ή στο URL. |
| Όριο | 60 κλήσεις / λεπτό ανά κλειδί. Το header X-RateLimit-Remaining δείχνει πόσες απομένουν. Πάνω από το όριο: 429 RATE_LIMITED με Retry-After. |
| Ημερομηνίες | Ημερομηνία-ώρα σε ISO-8601 UTC. Σκέτη ημερομηνία σε YYYY-MM-DD. |
| Αρχεία | OpenAPI (YAML) · Postman |
| Endpoint | Τι κάνει | |
|---|---|---|
| POST | /api/v1/requests |
Δημιουργία αίτησης για έναν πελάτη |
| GET | /api/v1/requests |
Λίστα των αιτήσεών σας |
| GET | /api/v1/requests/{requestId} |
Κατάσταση αίτησης |
| GET | /api/v1/requests/{requestId}/history |
Ιστορικό μεταβολών |
| GET | /api/v1/requests/{requestId}/contract |
Λήψη της σύμβασης (PDF) |
| POST | /api/v1/requests/{requestId}/signed-contract |
Ανέβασμα της υπογεγραμμένης σύμβασης |
| DELETE | /api/v1/requests/{requestId} |
Ακύρωση αίτησης |
| POST GET DELETE | /api/v1/webhooks… |
Webhooks |
Η μορφή κάθε απάντησης¶
Όλα τα JSON endpoints απαντούν μέσα σε φάκελο:
Στο error μπορεί να υπάρχουν επίσης το context (π.χ. existingRequestId, currentStatus) και, μόνο σε 500, το traceId.
Δημιουργία αίτησης¶
POST /api/v1/requests
| Header | |
|---|---|
Idempotency-Key |
Προαιρετικό. Ένα GUID δικό σας, ένα ανά πελάτη, σταθερό σε όλα τα retries. Αν χαθεί η απάντηση και ξαναστείλετε με το ίδιο key, παίρνετε πίσω την αρχική αίτηση (200 αντί για 201). Μην το ξαναχρησιμοποιήσετε για άλλο ΑΦΜ, ή για αίτηση που ακυρώθηκε ή απορρίφθηκε: 409. |
{
"companyDetails": {
"legalName": "Παπαδόπουλος Α.Ε.",
"tradeName": "PapaCorp",
"vatNumber": "094019245",
"taxOffice": "Α΄ Αθηνών",
"transactionTypes": [
"B2B",
"B2C"
]
},
"address": {
"city": "Αθήνα",
"streetAddress": "Ερμού 15",
"postalCode": "10563"
},
"contactInfo": {
"email": "info@papacorp.gr",
"phone": "2101234567",
"backupPhone": "6971234567"
},
"administrator": {
"fullName": "Γιάννης Παπαδόπουλος",
"vatNumber": "090000045"
},
"ispDetails": {
"providerName": "Cosmote",
"contractNumber": "CSM-2026-1",
"contractDate": "2026-09-01"
}
}
| Πεδίο | Υποχρεωτικό | Κανόνες |
|---|---|---|
companyDetails.legalName |
ναι | |
companyDetails.tradeName |
||
companyDetails.vatNumber |
ναι | 9 ψηφία με σωστό check digit. Δοκιμαστικά όπως το 123456789 απορρίπτονται. |
companyDetails.taxOffice |
ναι | |
companyDetails.transactionTypes |
ναι | Τουλάχιστον ένα από B2B, B2C. Το B2G δεν γίνεται δεκτό. |
address.city, address.streetAddress |
ναι | |
address.postalCode |
||
contactInfo.email |
ναι | Εδώ στέλνεται η σύμβαση. |
contactInfo.phone |
ναι | E.164 (+30…) ή ελληνικό 10ψήφιο |
contactInfo.backupPhone |
Ίδια μορφή | |
administrator.fullName |
ναι | Ο νόμιμος εκπρόσωπος |
administrator.vatNumber |
ναι | Έγκυρος ΑΦΜ (check digit) |
ispDetails.providerName, contractNumber, contractDate |
αν B2C | Ο πάροχος internet του πελάτη, και τα τρία πεδία. Το contractDate δεν μπορεί να είναι μελλοντικό. Αν μόνο B2B, το ispDetails παραλείπεται. |
Όλα τα λάθη πεδίων επιστρέφονται μαζί στο error.details[].
Τον τύπο της αίτησης τον αποφασίζει το σύστημα, δεν τον στέλνετε εσείς:
NEW_CONTRACT: ο ΑΦΜ δεν έχει ενεργή σύμβαση με τη Novus. Παράγεται σύμβαση σε PDF και η αίτηση πάει σεPENDING_SIGNATURE.LINK_EXISTING: ο ΑΦΜ έχει ήδη ενεργή σύμβαση μέσω άλλου software house. Τοcontractείναιnull, δεν χρειάζεται υπογραφή, και η αίτηση πάει κατευθείαν σεUNDER_REVIEW.
Ο πελάτης λαμβάνει αυτόματα email με τη σύμβαση και σύνδεσμο για να την ανεβάσει μόνος του. Άρα η αίτηση μπορεί να περάσει σε UNDER_REVIEW χωρίς δική σας ενέργεια.
| HTTP | Πότε |
|---|---|
201 |
Η αίτηση δημιουργήθηκε. |
200 |
Επανάληψη με το ίδιο Idempotency-Key: επιστρέφεται η αρχική αίτηση. |
409 |
DUPLICATE_OPEN_REQUEST: υπάρχει ήδη ανοιχτή αίτηση για τον ΑΦΜ, το error.context.existingRequestId δείχνει ποια. CLIENT_ALREADY_LINKED: ο ΑΦΜ είναι ήδη ενεργός στο κλειδί σας. Ή επαναχρησιμοποίηση Idempotency-Key για άλλο ΑΦΜ / για ακυρωμένη ή απορριφθείσα αίτηση. |
422 |
VALIDATION_ERROR: δείτε το details[]. |
{
"success": true,
"data": {
"requestId": "req_8f7b2c9a",
"requestType": "NEW_CONTRACT",
"status": "PENDING_SIGNATURE",
"message": "Η αίτηση καταχωρήθηκε. Απαιτείται υπογραφή της σύμβασης από τον πελάτη.",
"contract": {
"contractNumber": "10000",
"contractDate": "2026-09-17",
"templateVersion": "v6",
"downloadUrl": "https://provider.timologisi.online/api/v1/requests/req_8f7b2c9a/contract"
},
"provisioning": null,
"aadeStatement": null,
"createdAt": "2026-09-17T08:42:00Z"
}
}
{
"success": true,
"data": {
"requestId": "req_3a1c7d02",
"requestType": "LINK_EXISTING",
"status": "UNDER_REVIEW",
"message": "Το ΑΦΜ έχει ήδη ενεργή σύμβαση. Η αίτηση σύνδεσης εστάλη για έλεγχο.",
"contract": null,
"provisioning": null,
"aadeStatement": null,
"createdAt": "2026-09-17T08:42:00Z"
}
}
Λίστα αιτήσεων¶
GET /api/v1/requests?status=UNDER_REVIEW,ACTION_REQUIRED&page=1&pageSize=50
Επιστρέφει μόνο τις δικές σας αιτήσεις.
| Query | Περιγραφή |
|---|---|
status |
Ένα ή περισσότερα status, χωρισμένα με κόμμα |
requestType |
NEW_CONTRACT ή LINK_EXISTING |
vatNumber |
ΑΦΜ πελάτη |
createdFrom, createdTo |
Διάστημα ημερομηνιών (YYYY-MM-DD) |
page |
Από 1 (default 1) |
pageSize |
1 έως 200 (default 50) |
sort |
createdAt:desc (default), createdAt:asc, updatedAt:desc, updatedAt:asc |
Το data είναι { "items": [ … ], "total": 137, "page": 1, "pageSize": 50 }.
Κατάσταση αίτησης¶
GET /api/v1/requests/{requestId}
Η πραγματική κατάσταση της αίτησης. Μετά το APPROVED συμπληρώνονται τα provisioning και aadeStatement.
| Πεδίο | Τι σημαίνει |
|---|---|
status |
Δείτε τις καταστάσεις. |
message |
Το τελευταίο μήνυμα, π.χ. γιατί η αίτηση είναι σε ACTION_REQUIRED. |
contract |
Αριθμός, ημερομηνία, templateVersion, downloadUrl. Μετά το ανέβασμα και signedVersion (αυξάνεται σε κάθε ανέβασμα) και sha256. Σε LINK_EXISTING είναι null, και αυτό δεν είναι σφάλμα. |
provisioning |
Μετά το APPROVED. status: PENDING → IN_PROGRESS → COMPLETED ή FAILED. Βήματα clientAdded, clientLinked, contractUploaded, statementSent, το καθένα PENDING, IN_PROGRESS, DONE ή FAILED. Και error. |
aadeStatement |
Η Δήλωση Παρόχου στην ΑΑΔΕ. status: SUBMITTED, ACCEPTED (την αποδέχτηκε ο πελάτης), PRESUMED_ACCEPTED (πέρασαν 10 ημέρες χωρίς ενέργεια), RECALLED. Και acceptDate. |
Πότε ο πελάτης μπορεί να εκδίδει
Όταν provisioning.status = COMPLETED.
Αν δείτε FAILED, η Novus έχει ήδη ειδοποιηθεί και το αναλαμβάνει. Μην ξαναστείλετε αίτηση.
Παράδειγμα: εγκεκριμένη και ενεργοποιημένη αίτηση
{
"success": true,
"data": {
"requestId": "req_8f7b2c9a",
"requestType": "NEW_CONTRACT",
"status": "APPROVED",
"message": "Η αίτηση εγκρίθηκε.",
"contract": {
"contractNumber": "10000",
"contractDate": "2026-09-17",
"templateVersion": "v6",
"signedVersion": 1,
"sha256": "9f2c1d6e8a0b4c7d5e3f1a2b8c9d0e4f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d",
"downloadUrl": "https://provider.timologisi.online/api/v1/requests/req_8f7b2c9a/contract"
},
"provisioning": {
"status": "COMPLETED",
"clientAdded": "DONE",
"clientLinked": "DONE",
"contractUploaded": "DONE",
"statementSent": "DONE",
"error": null
},
"aadeStatement": { "status": "SUBMITTED", "acceptDate": null },
"createdAt": "2026-09-17T08:42:00Z",
"updatedAt": "2026-09-17T11:03:00Z"
}
}
Ιστορικό μεταβολών¶
GET /api/v1/requests/{requestId}/history
Χρονολογική λίστα των αλλαγών. Είναι χρήσιμη π.χ. όταν ο πελάτης ανέβασε μόνος του τη σύμβαση. Κάθε εγγραφή έχει:
| Πεδίο | |
|---|---|
occurredAt |
Πότε |
status, previousStatus |
Από ποιο status σε ποιο |
message |
Μήνυμα |
actor |
Ποιος προκάλεσε την αλλαγή: SOFTWARE_HOUSE, CLIENT, NOVUS, SYSTEM |
Λήψη της σύμβασης¶
GET /api/v1/requests/{requestId}/contract?kind=unsigned
Επιστρέφει application/pdf.
| Query | |
|---|---|
kind |
unsigned (default) ή signed |
version |
Έκδοση του υπογεγραμμένου. Χωρίς αυτό επιστρέφεται η τελευταία. |
Δεν είναι δημόσιο link
Χρειάζεται το API key σας. Μη στείλετε το downloadUrl στον πελάτη ως έχει. Κατεβάστε το PDF και προωθήστε το εσείς.
Σε αίτηση LINK_EXISTING δεν υπάρχει σύμβαση: 409 NOT_APPLICABLE. Το ίδιο και όταν δεν υπάρχει η έκδοση που ζητήσατε.
Ανέβασμα της υπογεγραμμένης σύμβασης¶
POST /api/v1/requests/{requestId}/signed-contract
multipart/form-data, ένα αρχείο στο πεδίο contractFile.
curl -X POST "https://provider-dev.timologisi.online/api/v1/requests/req_8f7b2c9a/signed-contract" \
-H "API-KEY: $NOVUS_API_KEY" \
-F "contractFile=@signed-contract.pdf;type=application/pdf"
Κανόνες:
- ακριβώς ένα αρχείο,
- πραγματικό PDF (ελέγχονται τα magic bytes, όχι η κατάληξη), έως 15 MB, όχι κατεστραμμένο ή κλειδωμένο με κωδικό,
- η αίτηση σε
PENDING_SIGNATUREήACTION_REQUIRED, μεrequestType = NEW_CONTRACT.
Τα παλιά αρχεία δεν σβήνονται. Κάθε ανέβασμα είναι νέα έκδοση. Με επιτυχία (200) η αίτηση περνά σε UNDER_REVIEW.
| HTTP | error.code |
Πότε |
|---|---|---|
400 |
BAD_REQUEST |
Λάθος multipart, περισσότερα από ένα αρχεία, ή κατεστραμμένο / κλειδωμένο PDF |
409 |
INVALID_TRANSITION |
Λάθος status, π.χ. υπάρχει ήδη αρχείο υπό έλεγχο |
409 |
NOT_APPLICABLE |
Η αίτηση είναι LINK_EXISTING |
413 |
FILE_TOO_LARGE |
Πάνω από 15 MB |
415 |
UNSUPPORTED_FILE_TYPE |
Δεν είναι PDF |
Ο πελάτης μπορεί να ανεβάσει το αρχείο και μόνος του, από το link του email.
Ακύρωση αίτησης¶
DELETE /api/v1/requests/{requestId}
Προαιρετικό body { "reason": "…" } (έως 500 χαρακτήρες). Επιτρέπεται μόνο πριν την έγκριση. Σε αίτηση που είναι ήδη εγκεκριμένη ή σε τελική κατάσταση: 409 INVALID_TRANSITION. Η διακοπή συνεργασίας μετά την έγκριση γίνεται μόνο σε συνεννόηση με τη Novus, όχι από το API.
Κωδικοί σφαλμάτων¶
| HTTP | error.code |
Τι σημαίνει |
|---|---|---|
| 400 | BAD_REQUEST |
Κακοδιατυπωμένο JSON ή multipart |
| 401 | UNAUTHORIZED |
Λείπει ή είναι άκυρο το API key |
| 403 | FORBIDDEN |
Η ενέργεια δεν επιτρέπεται με αυτό το κλειδί |
| 404 | NOT_FOUND |
Δεν υπάρχει ή ανήκει σε άλλο software house. Επιστρέφεται 404 αντί για 403, ώστε να μη φαίνεται καν ότι υπάρχει. |
| 409 | DUPLICATE_OPEN_REQUEST |
Υπάρχει ήδη ανοιχτή αίτηση για τον ΑΦΜ (context.existingRequestId) |
| 409 | CLIENT_ALREADY_LINKED |
Ο ΑΦΜ είναι ήδη ενεργός στο κλειδί σας |
| 409 | CLIENT_ALREADY_ACTIVE |
Ο ΑΦΜ απέκτησε ενεργή σύμβαση πριν την έγκριση |
| 409 | INVALID_TRANSITION |
Δεν επιτρέπεται στο τρέχον status (context.currentStatus) |
| 409 | NOT_APPLICABLE |
Δεν ισχύει για αυτόν τον τύπο αίτησης |
| 413 | FILE_TOO_LARGE |
Αρχείο πάνω από 15 MB |
| 415 | UNSUPPORTED_FILE_TYPE |
Δεν είναι PDF |
| 422 | VALIDATION_ERROR |
Λάθος πεδία, δείτε το details[] |
| 429 | RATE_LIMITED |
Πάνω από 60 κλήσεις / λεπτό. Ξαναδοκιμάστε μετά από Retry-After δευτερόλεπτα. |
| 500 | INTERNAL_ERROR |
Απρόσμενο σφάλμα, με traceId. Δώστε μας τον traceId. |
| 502 | UPSTREAM_ERROR |
Προσωρινή αποτυχία εξωτερικής υπηρεσίας. Ξαναδοκιμάστε αργότερα. |