39α kodikos39a.app

Ο κωδικός 39α βγαίνει από εδώ.

Ο 6ψήφιος κωδικός μιας χρήσης για αγορές χωρίς ΦΠΑ, κατευθείαν από την ΑΑΔΕ. Χωρίς Java, χωρίς εγκατάσταση, από το κινητό ή τον υπολογιστή.

  • Οι κωδικοί σας μένουν στον browser σας
  • Ο διακομιστής μας δεν κρατά κανένα στοιχείο σας
  • Ο κωδικός εκδίδεται από την ίδια την ΑΑΔΕ

κωδικοί μιας χρήσης έχουν εκδοθεί από το kodikos39a.app

Κωδικός μιας χρήσης 39α

Με τους ειδικούς κωδικούς 39α, όχι τους κωδικούς TAXISnet. Πώς τους βγάζω;

Ο ΑΦΜ στον οποίο ανήκουν οι ειδικοί κωδικοί.

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

Τι κρατάμε από εσάς

Μας ζητάτε να βάλετε κωδικούς της ΑΑΔΕ σε σελίδα που δεν είναι της ΑΑΔΕ. Εύλογα θέλετε να ξέρετε τι γίνεται με αυτούς. Σύντομα: οι κωδικοί σας δεν αποθηκεύονται σε διακομιστή, δεν υπάρχουν logs, cookies ή διαφημίσεις, και ό,τι κρατιέται, κρατιέται στον browser σας μόνο αν το επιλέξετε. Για ανώνυμα στατιστικά επισκέψεων χρησιμοποιούμε το Cloudflare Web Analytics, χωρίς cookies. Η αναλυτική εξήγηση, μαζί με ολόκληρο τον κώδικα του διακομιστή, είναι παρακάτω.

Οδηγός

Με το άρθρο 39α, παρ. 5 του Κώδικα ΦΠΑ, ένας αγοραστής του κανονικού καθεστώτος ΦΠΑ αγοράζει κινητά, κονσόλες παιχνιδιών, laptop και tablet χωρίς να καταβάλει ΦΠΑ στον πωλητή (αντίστροφη επιβάρυνση). Ο πωλητής επιβεβαιώνει την ιδιότητά σας στην ΑΑΔΕ πριν εκδώσει το τιμολόγιο.

Ο κωδικός μιας χρήσης είναι 6ψήφιος και τον δημιουργεί ο αγοραστής. Με αυτόν ταυτοποιείται ο εκπρόσωπος που κάνει την αγορά, όταν ο αγοραστής έχει ορίσει ότι απαιτείται κωδικός για εκείνον.

Μια φορά
  1. Ειδικοί κωδικοί 39α

    Μπείτε στη Διαχείριση Ειδικών Κωδικών της ΑΑΔΕ με τους κωδικούς TAXISnet και δημιουργήστε ζεύγος για την «Υπηρεσία άρθρου 39α, παρ. 5 κώδικα ΦΠΑ». Αυτό το όνομα χρήστη και τον κωδικό βάζετε εδώ.

    Για νομικά πρόσωπα, τους δημιουργεί το φυσικό πρόσωπο που έχει οριστεί εκπρόσωπος του νομικού προσώπου.

  2. Εγγραφή και εκπρόσωπος

    Εγγραφείτε στην υπηρεσία ως αγοραστής και ορίστε τουλάχιστον έναν εκπρόσωπο: τον εαυτό σας ή κάποιον άλλον, με τη συγκατάθεσή του. Γίνεται από το επίσημο πρόγραμμα της ΑΑΔΕ.

Σε κάθε αγορά
  1. Βγάλτε κωδικό

    Συνδεθείτε στο μηχάνημα στην κορυφή της σελίδας, διαλέξτε πόσο θα ισχύει και πατήστε «Βγάλτε κωδικό» (ή «Νέος κωδικός», αν έχετε ήδη έναν). Αν την αγορά θα την κάνει άλλος, βάλτε τον ΑΦΜ του ως εκπροσώπου.

  2. Στο κατάστημα

    Δώστε στον πωλητή τον ΑΦΜ και τον κωδικό. Ο πωλητής επιβεβαιώνει στην ΑΑΔΕ και εκδίδει τιμολόγιο χωρίς ΦΠΑ.

Καλό να ξέρετε

Πώς προστατεύονται οι κωδικοί σας

Εδώ εξηγούμε τα πάντα: από πού περνούν οι κωδικοί, γιατί, τι χρειάζεται να μας εμπιστευτείτε, και πώς το ελέγχετε μόνοι σας.

  1. Ο browser σας Φτιάχνει το αίτημα, κρατά τους κωδικούς αν το επιλέξετε, δείχνει τον κωδικό μιας χρήσης.
  2. Αναμεταδότης kodikos39a.app Προωθεί το αίτημα αυτούσιο. Δεν κρατά τίποτα.
  3. ΑΑΔΕ · www1.gsis.gr Ελέγχει τους κωδικούς και εκδίδει τον κωδικό μιας χρήσης.

Γιατί δεν μιλά ο browser απευθείας με την ΑΑΔΕ

Θα θέλαμε να το κάνει: τότε οι κωδικοί σας δεν θα περνούσαν ούτε στιγμή από κανέναν άλλον. Δεν γίνεται, για λόγο που δεν εξαρτάται από εμάς.

Για την προστασία σας, ο browser αφήνει μια σελίδα να μιλήσει με άλλον διακομιστή μόνο αν εκείνος το επιτρέπει ρητά. Ο μηχανισμός λέγεται CORS. Η υπηρεσία 39α είναι φτιαγμένη για προγράμματα υπολογιστή, όπως το πρόγραμμα Java της ΑΑΔΕ, και δεν το επιτρέπει. Το ελέγξαμε: στο ερώτημα του browser απαντά με σφάλμα 405.

Οι επιλογές ήταν τρεις: να κατεβάσετε πρόγραμμα, να εγκαταστήσετε επέκταση στον browser (δεν δουλεύει στο κινητό), ή να περάσει το αίτημα από έναν ενδιάμεσο που απλώς το προωθεί. Επιλέξαμε το τρίτο και τον κρατήσαμε όσο πιο μικρό και ελέγξιμο γίνεται.

Ο αναμεταδότης

  • Δέχεται αιτήματα μόνο από αυτή τη σελίδα.
  • Τα προωθεί σε μια μόνο σταθερή διεύθυνση: την υπηρεσία 39α της ΑΑΔΕ.
  • Επιτρέπει μόνο ενέργειες για κωδικούς μιας χρήσης. Δεν αλλάζει εγγραφές ή εκπροσώπους.
  • Δέχεται έως 20 αιτήματα το λεπτό ανά σύνδεση, ώστε να μη μπορεί κανείς να μαντεύει κωδικούς μέσω αυτού.
  • Δεν αποθηκεύει κανένα στοιχείο σας. Το μόνο που κρατά ο διακομιστής είναι ένας αριθμός: πόσοι κωδικοί έχουν εκδοθεί συνολικά από εδώ. Η σελίδα τον αυξάνει με ένα κενό αίτημα, χωρίς κανένα στοιχείο για εσάς ή τον κωδικό.
  • Δεν γράφει logs. Η καταγραφή του Cloudflare Workers είναι απενεργοποιημένη.
  • Δεν διαβάζει και δεν αλλάζει το περιεχόμενο του αιτήματος ή της απάντησης.

Να είμαστε ειλικρινείς: επειδή το αίτημα περνά από τον αναμεταδότη, βρίσκεται στη μνήμη του όσο διαρκεί η προώθηση, κλάσματα του δευτερολέπτου. Γι' αυτό δημοσιεύουμε ολόκληρο τον κώδικα που τρέχει εκεί. Όπως κάθε πάροχος δικτύου, η Cloudflare βλέπει βασικά τεχνικά στοιχεία της σύνδεσης, π.χ. τη διεύθυνση IP, για προστασία από επιθέσεις. Το περιεχόμενο των αιτημάτων δεν καταγράφεται.

Ο πλήρης κώδικας του διακομιστή worker/index.ts · 98 γραμμές

Αυτό είναι όλο το πρόγραμμα που τρέχει στον διακομιστή. Ενσωματώνεται αυτόματα από το ίδιο αρχείο που ανεβαίνει στο Cloudflare, οπότε είναι πάντα η τρέχουσα έκδοση.

// The whole server side of kodikos39a.app.
//
// AADE's 39a service does not allow browsers to call it directly (no CORS), so the page sends
// its SOAP request to /api/aade and this Worker forwards it, unchanged, to one fixed AADE address.
// It does not read, store or log the request or the response.
//
// The only thing stored is one number: how many one-time codes were issued through the site.
// The page reports each success to /api/issued with an empty request, and /api/stats returns
// the total. Everything else on the site is static files.

interface Env {
  ASSETS: { fetch(request: Request): Promise<Response> };
  LIMITER: { limit(options: { key: string }): Promise<{ success: boolean }> };
  DB: D1Database;
}

// The only address the relay ever talks to.
const AADE = "https://www1.gsis.gr/wsaade/VtWs39aFPA/VtWs39aFPA";
const SERVICE = "http://vtws39afpa/VtWs39aFPAService";
// Only these operations are forwarded: version check and the buyer's one-time codes.
const OPERATIONS = new Set(["vt39afpaVersionInfo", "vt39afpaBu9GetOtp"]);
const MAX_BODY = 8 * 1024;

const reply = (status: number, message = "") =>
  new Response(message, { status, headers: { "Cache-Control": "no-store", "Content-Type": "text/plain; charset=utf-8" } });

// Rate limit per connection, so the relay can't be used to guess passwords and the counter
// can't be pumped. The IP is used only as a counter key in memory and is not stored.
async function limited(request: Request, env: Env, scope: string) {
  const ip = request.headers.get("CF-Connecting-IP") ?? "unknown";
  return !(await env.LIMITER.limit({ key: `${scope}:${ip}` })).success;
}

async function relay(request: Request, env: Env, url: URL): Promise<Response> {
  if (request.method !== "POST") return reply(405);
  // Only this site's own page may use the relay.
  if (request.headers.get("Origin") !== url.origin) return reply(403);

  const operation = request.headers.get("X-AADE-Operation") ?? "";
  if (!OPERATIONS.has(operation)) return reply(400);
  if (await limited(request, env, "aade")) return reply(429);

  const body = await request.arrayBuffer();
  if (body.byteLength === 0 || body.byteLength > MAX_BODY) return reply(413);

  let upstream: Response;
  try {
    upstream = await fetch(AADE, {
      method: "POST",
      headers: { "Content-Type": `application/soap+xml; charset=utf-8; action="${SERVICE}:${operation}"` },
      body,
      signal: AbortSignal.timeout(30_000),
    });
  } catch {
    return reply(504);
  }

  // AADE's answer goes back to the browser as it is.
  return new Response(upstream.body, {
    status: upstream.status,
    headers: { "Content-Type": "application/soap+xml; charset=utf-8", "Cache-Control": "no-store" },
  });
}

const total = (issued: number | undefined) =>
  Response.json({ issued: issued ?? 0 }, { headers: { "Cache-Control": "no-store" } });

// +1 to the public counter. The request carries no data at all; the reply is the new total.
async function issued(request: Request, env: Env, url: URL): Promise<Response> {
  if (request.method !== "POST") return reply(405);
  if (request.headers.get("Origin") !== url.origin) return reply(403);
  if (await limited(request, env, "issued")) return reply(429);
  const row = await env.DB.prepare("UPDATE stats SET issued = issued + 1 WHERE id = 1 RETURNING issued").first<{ issued: number }>();
  return total(row?.issued);
}

// The current total for everyone, read fresh on every visit.
async function stats(request: Request, env: Env): Promise<Response> {
  if (request.method !== "GET") return reply(405);
  const row = await env.DB.prepare("SELECT issued FROM stats WHERE id = 1").first<{ issued: number }>();
  return total(row?.issued);
}

export default {
  async fetch(request: Request, env: Env): Promise<Response> {
    const url = new URL(request.url);
    switch (url.pathname) {
      case "/api/aade":
        return relay(request, env, url);
      case "/api/issued":
        return issued(request, env, url);
      case "/api/stats":
        return stats(request, env);
      default:
        return env.ASSETS.fetch(request);
    }
  },
};

Τι μένει στη συσκευή σας

  • Με το «Να θυμάται τα στοιχεία», το όνομα χρήστη, ο κωδικός 39α και οι ΑΦΜ αποθηκεύονται στο localStorage του browser σας, σε αυτή τη συσκευή μόνο.
  • Χωρίς αυτό, κρατιούνται μόνο όσο είναι ανοιχτή η σελίδα.
  • Το «Διαγραφή από τη συσκευή» τα σβήνει αμέσως.
  • Όποιος έχει πρόσβαση στον browser σας μπορεί να τα δει. Μην τα αποθηκεύετε σε κοινόχρηστο υπολογιστή.

Γιατί ο κίνδυνος είναι περιορισμένος

Η ΑΑΔΕ εκδίδει ξεχωριστό ζεύγος ειδικών κωδικών για κάθε υπηρεσία. Οι κωδικοί 39α δεν ανοίγουν το TAXISnet, το myAADE ή τις δηλώσεις σας: λειτουργούν μόνο στην υπηρεσία 39α.

Μπορείτε οποιαδήποτε στιγμή να τους αλλάξετε ή να τους ανακαλέσετε από τη Διαχείριση Ειδικών Κωδικών. Εμείς δεν ζητάμε ποτέ τους κωδικούς TAXISnet.

Στατιστικά επισκέψεων

Για να ξέρουμε πόσοι χρησιμοποιούν την υπηρεσία, μετράμε επισκέψεις με το Cloudflare Web Analytics. Δεν χρησιμοποιεί cookies και δεν σας παρακολουθεί από σελίδα σε σελίδα. Στέλνει στην Cloudflare τη διεύθυνση της σελίδας, από πού ήρθατε, τον τύπο browser και συσκευής και πόσο γρήγορα φόρτωσε η σελίδα. Δεν στέλνει ό,τι πληκτρολογείτε, τους κωδικούς σας ή τις απαντήσεις της ΑΑΔΕ. Το σενάριο το σερβίρουμε εμείς, από το kodikos39a.app, σε κλειδωμένη έκδοση που μπορείτε να διαβάσετε στο /cf-beacon.js.

Ελέγξτε το μόνοι σας

Δεν θέλετε να εμπιστευτείτε κανέναν; Απόλυτα κατανοητό. Η ίδια λειτουργία υπάρχει στο επίσημο πρόγραμμα της ΑΑΔΕ, που μιλά απευθείας με την υπηρεσία.

Ερωτήσεις

Τι είναι ο κωδικός μιας χρήσης 39α;

Ένας 6ψήφιος κωδικός που δημιουργεί ο αγοραστής στην υπηρεσία του άρθρου 39α, παρ. 5 του Κώδικα ΦΠΑ. Με αυτόν ο εκπρόσωπός του ταυτοποιείται στον πωλητή, ώστε να αγοράσει κινητά, κονσόλες παιχνιδιών, laptop ή tablet χωρίς να καταβάλει ΦΠΑ στον πωλητή.

Ποιοι κωδικοί χρειάζονται;

Οι ειδικοί κωδικοί πρόσβασης για την υπηρεσία 39α, που βγάζετε μια φορά από τη Διαχείριση Ειδικών Κωδικών της ΑΑΔΕ. Οι κωδικοί TAXISnet δεν λειτουργούν εδώ, και δεν τους ζητάμε ποτέ.

Πόσο ισχύει ο κωδικός;

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

Χρειάζεται να κατεβάσω κάτι;

Για την έκδοση κωδικών όχι: ούτε Java ούτε πρόγραμμα. Η αρχική εγγραφή ως αγοραστής και ο ορισμός εκπροσώπου γίνονται μια φορά από το επίσημο πρόγραμμα της ΑΑΔΕ.

Είναι της ΑΑΔΕ αυτή η σελίδα;

Όχι. Είναι ανεξάρτητη εφαρμογή που χρησιμοποιεί την επίσημη δημόσια διαδικτυακή υπηρεσία της ΑΑΔΕ για το άρθρο 39α. Οι κωδικοί εκδίδονται από την ίδια την ΑΑΔΕ, όπως και στο επίσημο πρόγραμμα.