fatura issues and signs e-Arsiv invoices from Node.js against the Turkish tax portal
eArşiv / eFatura Fatura Oluşturucu
At a glance
- What is it?
- fatura is a TypeScript library that creates, signs, retrieves and cancels invoices on Turkey's e-Arsiv portal for individual companies and companies, with a test environment and a step-by-step draft, find and sign flow. The README carries a blunt warning that the package creates tax liable financial data and that the risk belongs to the user.
- Who is it for?
- Adopt fatura if you are a developer in Turkey who needs to issue real e-Arsiv invoices from a Node.js service for a sole proprietorship or a company account, and if you are willing to work against a government portal that can change under you.
- Can I use it commercially?
- Check first. The repository uses a licence we do not classify automatically, so read its LICENSE file before any commercial use.
- Is it still maintained?
- Yes. The repository last received commits 60 days ago.
- What is it written in?
- Mainly TypeScript, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.
Editorial analysis
What problem fatura solves inside the e-Arsiv portal
fatura is a Node.js library for issuing invoices through the Turkish e-Arsiv system, which is the portal where businesses that are not registered for the full e-invoice system can still cut and sign official invoices. The README states that the system works with accounts belonging to the tax authority for sole proprietorship companies or for companies, and that invoices created this way can be viewed on the portal or downloaded through the library.
The credentials are not the library's own. The README says you can use the package with the user code and password used on the password screen of the portal's login page, and that you obtain those details from your accountant or from the tax authority's interactive tax office. So this is a client for a government system, using credentials that a human holds, rather than an API with its own keys.
The scope of the surface area is what makes the library interesting. It covers the whole invoice lifecycle: creating a draft, finding it again, signing it, downloading it, cancelling a draft, looking up recipient data by tax or identity number, reading and updating portal user data, running the SMS confirmation flow required for signing, and closing the session. The README also lists an alternatives table pointing at PHP and C# implementations of the same idea by other developers, so this is a known problem that has been solved several times over in different stacks.
The one thing every user needs to read twice is the warning at the end of the README. The package creates tax liable financial data, the package cannot be held responsible for problems arising from it, the risk belongs to the user, and if you think it is risky, do not use it.
The draft, find and sign sequence behind every invoice
The most instructive part of the API is how a single invoice is actually produced, because it is not one call to the portal. It is three steps that the higher level methods wrap for you.
First a draft is created. The createDraftInvoice method takes a token and the invoice details, and the returned value contains a uuid, a date and the response from the tax authority. If you do not supply a uuid, a new one is assigned. The details object carries the tax or trade registry number, the tax office, the title, name and surname, the full address, a list of items with quantity, unit price, price, VAT rate and VAT amount, and then the totals:
{
uuid: "4c72cb57-b72d-4812-ac48-0a0bce83e771",
date: "08/02/2020",
time: "09:07:48",
taxIDOrTRID: "11111111111",
taxOffice: "Beylikduzu",
title: "FATIH AKIN",
name: "",
surname: "",
fullAddress: "X Sok. Y Cad. No: 3 Z Istanbul",
items: [
{
name: "Stickker",
quantity: 1,
unitPrice: 100,
price: 100,
VATRate: 20,
VATAmount: 20,
},
],
totalVAT: 20,
grandTotal: 100.0,
grandTotalInclVAT: 120.0,
paymentTotal: 120.0,
}Second the draft is found again. The findInvoice method takes the draft object returned by createDraftInvoice, the one containing the date and the uuid, and returns the matching record from among that day's drafts. The README explains why this matters: the information needed for signing, such as the document number, lives on that object.
Third the draft is signed. signDraftInvoice takes the list item produced by findInvoice, and the README marks it with a hazard symbol because signing creates a financial transaction that counts as issued, and advises care.
The convenience method createInvoice does all three: it takes a token, creates the draft, finds it, and signs it when the sign option is true, which is the default. If the find step returns nothing, the signing is skipped. That fallback is a meaningful behaviour to know about, because a missing signature on an invoice is exactly the kind of thing you want to detect rather than discover later.
Signing, cancelling and the two convenience methods
Two methods cover the common case. createInvoiceAndGetDownloadURL creates the invoice, signs it and returns the download address, and createInvoiceAndGetHTML does the same but returns the invoice HTML instead, which the README says you can display in an iframe and print.
Both take the credentials, the invoice details and an options object whose sign flag defaults to true. The README's example passes sign: false explicitly, and the comment on that line notes that by default sign: true is sent. The consequence of that default is the thing to keep in mind when you call these methods: the call signs the invoice unless you opt out.
The other side of signing is cancellation, and the README is careful to distinguish it. cancelDraftInvoice cancels a draft. That is the only reversal the library offers, and it applies to drafts only, not to signed invoices.
The SMS confirmation flow is described as subject to the tax authority's rules, with sendSignSMSCode and verifySignSMSCode as the two entry points. This is a detail that affects how you can automate signing. Some invoices require a one-time code delivered by SMS to the portal account, and a server-side integration has no obvious way to satisfy that without a human in the loop.
Reading back is covered by two listing methods, one for invoices issued by the account and one for documents addressed to it, both taking a date range. On top of that, getRecipientDataByTaxIDOrTRID queries recipient information by tax or identity number, which is what you need before you can fill in a buyer on an invoice, and getUserData and updateUserData read and change the portal user information.
Installing the package and picking production or test
Installation is a single npm command, and the package requires Node.js 18 or newer, which the package.json also records in its engines field:
npm install faturaEverything runs through a client object created by a factory function, and the first thing to decide is which environment you are talking to. The production client is the default, and the factory takes no argument in that case:
const { createFaturaClient } = require("fatura");
const client = createFaturaClient();The test environment is a different portal host, earsivportaltest.efatura.gov.tr, and is selected by passing the environment name:
const client = createFaturaClient("TEST");The package is also usable as an ES module, with the same factory and the same client shape:
import { createFaturaClient } from "fatura";
const client = createFaturaClient();The credentials are not part of the client construction. They are passed to the methods that need them, user and pass as the first two arguments of the higher level calls, or you call getToken to obtain a session token and pass that to the lower level methods.
The repository is a TypeScript project with the sources in src, tests in tests, and separate Vitest configurations for unit tests and integration tests, the latter named vitest.config.integration.ts. There is also a website directory, an eslint config, a prettier config and a tsconfig, and the build script is a plain tsc, with prepare running the build so the dist output exists when the package is installed from a git URL.
Where fatura is the wrong tool
There are several ways to be wrong here, and they are worth separating.
The first is not having the credentials. The library drives a login form for a government portal and needs a user code and password issued to a business entity. If your use case is issuing invoices to customers without being a registered taxpayer entity in Turkey, this is not the path, because the portal will not accept the account.
The second is the signing automation. If your process needs every invoice signed without human involvement and the portal requires SMS confirmation, the library gives you the two SMS methods but it does not remove the human. Any pipeline that assumes unattended signing of every invoice is assuming something the tax authority controls.
The third is expecting a stable API. The README describes a client that talks to a government web portal, and portals of that kind change their request and response shapes without notice. The library version in package.json reads 0.2.1 while the most recent tagged release is v0.2.0, and the release before that, v0.1.4, dates from 2022, which is a release history with a long gap in it. The last push was on 2026-08-24, so work is happening, but a dependency that automates financial filings is a dependency you should pin and monitor rather than float.
The fourth is scope. This library creates invoices in one portal for one country's tax system. It is not a general e-invoicing abstraction, and there is no multi-country or multi-format support in the documented surface.
How fatura compares to the PHP and C# implementations
The README's alternatives table lists three other projects doing the same job: two in PHP, from Adem Ali Durmus and Furkan Kadioglu, and one in C#, BFY Digital's e-arsiv-fatura-dotnet. That is a useful comparison because the choice for a Turkish developer is often decided by the stack already in the shop rather than by features.
The difference in approach here is not a philosophical one but an architectural one. fatura splits the API into a client object, a factory that chooses production or test, and a set of methods that each map to a single portal operation, plus two convenience wrappers that chain several operations into one call. The getToken method separates authentication from the business operations, which is what lets a service hold a session token instead of re-authenticating for every invoice.
The signed and unsigned distinction runs through the whole surface. The download and HTML methods take a signed flag, and the create methods take a sign option that defaults to true. This library puts the portal's own state machine, draft then issued, in front of the caller, rather than hiding it. A caller who only wants a read-only listing of invoices can stay entirely in the token-based methods and never touch the signing path, and a caller who wants to issue can use the convenience wrappers and never touch the draft objects.
The licence needs a note. The README's licence section says MIT, and the package.json records the same MIT identifier, but the repository metadata classifies the licence file as a custom licence that GitHub cannot classify. A project whose whole purpose is generating tax data should have its licence terms read before you build on it, and the LICENSE file at the repository root is where to do that.
Editorial conclusion
Adopt fatura if you are a developer in Turkey who needs to issue real e-Arsiv invoices from a Node.js service for a sole proprietorship or a company account, and if you are willing to work against a government portal that can change under you. Do not adopt it if you need a general e-invoicing system, if you have no GIB user code, or if you cannot operate the SMS signing confirmation step, because the README states that signing creates a financial transaction that cannot be undone by the library. Verify first that the user code and password you have work on the login screen, that your invoices are built against the test environment at earsivportaltest.efatura.gov.tr before you point the client at production, and that the licence file in the repository matches the MIT statement in the README, since the repository metadata classifies it as a custom licence.
Frequently asked questions
What is fatura and what does it do for the e-Arsiv portal?
fatura is a TypeScript library for Node.js 18 or newer that creates, signs, lists, downloads and cancels invoices on the Turkish e-Arsiv portal for accounts belonging to a sole proprietorship company or a company. It works with the user code and password used on the portal login page.
How do I create and sign an invoice with fatura?
The createInvoice method takes a token, creates a draft, finds it and signs it when the sign option is true, which is the default. If finding the draft returns nothing, the signing is skipped, and createInvoiceAndGetDownloadURL or createInvoiceAndGetHTML wrap the same flow and return the address or the HTML instead.
How do I test fatura without issuing real invoices?
You create the client with the TEST environment argument, which points at the test portal host earsivportaltest.efatura.gov.tr, instead of the default production environment. The README documents the test host alongside the production one.
Can a fatura invoice be cancelled?
Only a draft can be cancelled, through cancelDraftInvoice. The README warns that signing creates a financial transaction that counts as issued, so a signed invoice has no reversal path in the library.
What licence is fatura released under?
The README licence section says MIT and the package.json records the MIT identifier, though the repository metadata classifies the LICENSE file as a custom licence that GitHub cannot classify. The repository also carries an explicit warning that the package creates tax liable financial data and that the risk of using it belongs to the user.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/f-fatura)Was this useful?