efrisapi.com

Docs / Quickstart

Quickstart

From a fresh install to a business fiscalising invoices through your platform. Work against URA's sandbox until the output is right — documents submitted to production are real tax records.

What each client needs from URA

You collect these once per business you onboard:

Nobody needs to apply for an appId. It names the integration channel, not the integrator, and is the same value for everyone using the web-service API. It looks like a credential, which is why it trips people up.

1. Run the platform

pip install -r requirements.txt
cp .env.example .env          # set DATABASE_URL and JWT_SECRET_KEY
python init_auth.py           # creates the owner account, prints the password
uvicorn api_multitenant:app --host 0.0.0.0 --port 8001

Check /health. It should report healthy with database: connected. Tables are created on first start.

2. Log in as owner

POST /auth/login
Content-Type: application/x-www-form-urlencoded

[email protected]&password=<your password>

Returns an access_token. Send it as Authorization: Bearer <token> on every owner endpoint.

This endpoint takes form fields, not JSON, and the field is username rather than email. Sending JSON returns a validation error naming fields you did not send, which is confusing the first time.

3. Onboard a business

One request creates the client, stores their certificate and issues their credentials:

POST /api/owner/add-client
Authorization: Bearer <token>
Content-Type: multipart/form-data

company_name  = Acme Wholesalers Ltd
email         = [email protected]
password      = <their login password>
tin           = 1000000000
device_no     = 1000000000_02
cert_password = <their .pfx password>
test_mode     = true
pfx_file      = @acme.pfx

The response carries their api_key, api_secret and api_endpoint. That is everything their ERP needs — no certificate ever goes near their codebase.

4. The client calls your API

GET /api/external/efris/server-time
X-API-Key: efris_...

Always start with server-time. It is the lightest call and confirms the certificate and TIN are accepted. If it succeeds and everything else fails, the problem is the document rather than the credentials — which separates the two most common first-day failures.

Then fiscalise:

POST /api/external/efris/submit-invoice
X-API-Key: efris_...

{
  "invoice_number": "INV-2026-0042",
  "customer_name":  "Beta Trading Ltd",
  "customer_tin":   "2000000000",
  "buyer_type":     "0",
  "items": [
    { "item_name": "Office Chair", "item_code": "CHAIR-001",
      "quantity": 2, "unit_price": 150000, "tax_rate": 18 }
  ]
}

The response carries the fiscal document number and verification details URA assigned.

Two kinds of authentication

EndpointsAuthUsed by
/api/owner/*, /api/companies/*, /auth/* Authorization: BearerYou
/api/external/efris/* X-API-KeyThe businesses you onboard

When URA says no

Rejections carry a numeric code. Branch on the number, never on the message text — URA rewords messages between releases and some return in mixed language.

The summary block causes most first rejections: netAmount must equal grossAmount minus taxAmount (1343), taxAmount must include excise (1344) while grossAmount must exclude it (1345), and itemCount must exclude discount lines (1304).

Going to production

Next


EFRIS Gateway handles this case already — it is one of the rejections it was calibrated against. It is a complete multi-tenant EFRIS platform, sold as source. This page stays free either way.