Skip to content
ChargeVeta

How ChargeVeta works, end to end.

A technical guide for your engineers, your charger installer and your finance team: what runs where, how to connect a real charger, and what happens at every step from a card tap to a GST receipt.

01

The system at a glance

ChargeVeta is a charging station management system (CSMS) that many operators share, each seeing only their own chargers, drivers and money. Three programs make it run. The OCPP engine is the only part that talks to chargers. It holds one long-lived WebSocket per charger. The business core holds every rule: who may charge, what it costs, who pays. The apps are the operator console, the driver app and the fleet portal.

Chargers never talk to the business core directly, and browsers never talk to it directly either. Each goes through its own front door, so a fault or an attack on one side cannot walk through to the other.

Driversinstallable driver appOperator staffconsole · four rolesFleet managersfleet portalChargersOCPP 1.6 · 2.0.1 · 2.1app.chargeveta.inconsole · driver appfleet portalHTTPSocpp.chargeveta.inwss:// · chargers onlyBusiness core (API)tenants · tariffs · billingOCPP engineholds every charger socketRazorpay · email · pushoutside servicesPostgreSQLrow-level securityper operatorEvent workersessions · receipts · alertsEvent stream (Kafka)in order, per chargerOCPP-Jcommandsmay it connect?may it charge?eventspayments · messages
  • Commands: core → charger

    Remote start and stop, reset, unlock, configuration, firmware. The core asks the engine, and the engine sends the OCPP message on the charger's open socket.
  • Questions: charger → core, answered at once

    May this charger connect? May this card charge, and who pays? These need an answer while the charger waits, so they are direct calls, not queued.
  • Events: charger → core, in order

    Boot, status, meter readings, session start and end flow through Kafka, keyed per charger so each charger's events are processed in the order they happened.
  • One record of every session

    The console, the driver app, the fleet portal, the receipt and the dashboards all read the same rows. A dashboard can never disagree with the invoice behind it.

02

Addresses on chargeveta.in

Everything lives under one domain. The marketing site is www.chargeveta.in. The product is on its own subdomain, so the apps, their cookies and their installable versions are kept apart from the website.

WhoAddressNotes
Anyone (this website)https://www.chargeveta.inMarketing and this guide. Holds no data.
Operator staffhttps://app.chargeveta.in/sign-inOperator code, email and password. Roles: owner, admin, operator, viewer.
Drivershttps://app.chargeveta.in/driverInstallable app (add to home screen). Sign in with a phone code.
Fleet managershttps://app.chargeveta.in/fleetRead-only view of the fleet's drivers, sessions and statement; manages vehicles.
Platform teamhttps://app.chargeveta.in/platformChargeVeta's own staff: creates operators (tenants) and switches modules on.
Chargerswss://ocpp.chargeveta.in/ocpp/<operator code>/<charger id>OCPP-J over WebSocket. Not behind any CDN proxy, so the socket goes straight to us.
Payment webhookshttps://app.chargeveta.in/api/v1/payments/razorpay/webhookThe one API route reachable from outside; everything else goes through the apps.
  • Why the apps share one subdomain

    The console, driver app and fleet portal are one web application served from the root of app.chargeveta.in, each with its own sign-in and its own session cookie. The driver app installs with its own scope (/driver), so a driver’s home-screen icon opens only the driver app.
  • Why chargers get their own host

    A charger holds its socket for days. ocpp.chargeveta.in goes straight to our servers with hour-long timeouts and a ping every 30 seconds, and serves only /ocpp/… and a health check. A web CDN in between would cut idle sockets and hide the charger’s address.
  • No tokens in the browser

    The apps keep sign-ins in httpOnly, secure cookies and call the core through their own same-origin proxy. Nothing a script on the page can read ever holds a token.
  • Live updates

    Charger status and running sessions update live over a WebSocket on the same host (/realtime), so they work behind any firewall that allows the app itself.

03

Connecting a real charger

Any charger that speaks OCPP 1.6J, 2.0.1 or 2.1 can join. You do not need a ChargeVeta-specific firmware or adapter. Commissioning takes two parts: create the charger in the console, then point the charger at us.

Step 1: in the console

  1. Sign in at app.chargeveta.in/sign-in as an admin. Create the site first (address, map location, GSTIN state, tariff), if it is not there yet.
  2. Chargers → Add charger. Enter the charger ID exactly as the charger will send it (1–48 letters, digits, . _ ~ -; e.g. DEL-CP-001), the OCPP version it runs, and the site.
  3. On the charger’s page, open Connection password and generate one (20–128 characters). Copy it now: it is stored only as a hash and can never be shown again, only replaced.

Step 2: on the charger

SettingValue
Central system / CSMS URLwss://ocpp.chargeveta.in/ocpp/<operator code>
Charge point identityThe charger ID from step 1. Most chargers append it to the URL themselves; if yours wants the full URL, end it with /<charger ID>.
OCPP versionSame as the console: 1.6J, 2.0.1 or 2.1 (subprotocol ocpp1.6, ocpp2.0.1, ocpp2.1)
Security profile2: TLS with HTTP Basic authentication (the default for new chargers). 1 only for a charger that cannot do TLS: see below.
Basic auth usernameThe charger ID (if the charger sends one, it must match)
Basic auth passwordThe generated password (1.6: AuthorizationKey; 2.x: BasicAuthPassword)
TLSPublic certificate, so no custom CA needs to be installed on the charger. Port 443.
HeartbeatSet by us at boot. Leave the charger's own value; we answer with ours.

Step 3: check it

  • The charger shows Online on the Chargers page within seconds of connecting, and each connector appears with its status (connectors register themselves from what the charger reports).
  • Its page shows the boot details (vendor, model, serial, firmware) and the address it connected from.
  • Try Remote start with a test card, or tap a card that is linked to a driver, and watch the session appear live.
  • Refused at connect?

    A wrong password, an unknown charger ID, a wrong operator code or a non-TLS connection on profile 2 is refused before the WebSocket opens (HTTP 401), never accepted and then dropped. Too many failures from one address are blocked for a few minutes. Check the ID's exact spelling and case first.
  • Charger can't do TLS?

    Older chargers on security profile 1 (Basic auth without TLS) can use ws://ocpp.chargeveta.in/ocpp/… on port 80. An admin switches that one charger to profile 1 under its settings, Connection security; every other charger stays on profile 2 and is refused without TLS. Profile 0 (no password) is never accepted.
  • Client certificates (profile 3)

    Supported by the engine, with the charger's certificate pinned by its SHA-256 fingerprint. Not yet open on the shared network; talk to us if your chargers require it.
  • Firewalls and SIM routers

    The charger only makes outbound connections to ocpp.chargeveta.in on 443 (or 80 for profile 1). Nothing needs to reach the charger. A 4G router with a short NAT timeout is fine: we ping every 30 seconds.

04

A charger connects and boots

The engine keeps no database, so every connection is decided by the business core before the WebSocket opens. Which operator the charger belongs to comes from that answer, never from the URL the charger chose.

  1. 1

    Charger → Engine: WebSocket upgrade to /ocpp/<operator>/<charger ID> with Basic auth and the OCPP subprotocol.

  2. 2

    Engine: Abuse guards first: connections per address, connect rate, a bounded queue of checks in flight.

  3. 3

    Engine → Core: May this charger connect? The core checks the password hash, the security profile and that the transport was TLS.

  4. 4

    Core → Engine: Yes: the charger, its operator, its OCPP version. Or no, and the upgrade is refused.

  5. connected
  6. 5

    Charger → Engine: BootNotification. Validated against the official OCPP schema for that version.

  7. 6

    Engine → Kafka: Boot event recorded first, then the charger is told Accepted with our heartbeat interval. A charger is never accepted by a system with no record of it.

  8. 7

    Charger → Engine: StatusNotification for each connector: Available, Preparing, Charging, Faulted…

  9. 8

    Engine → Charger: After the boot: the meter-value interval (60 s), the device model report on 2.x, and on 2.1 our price as SetDefaultTariff.

  10. every minute while connected
  11. 9

    Engine → Core: Is every socket I hold still allowed? A charger that was deactivated, deleted or quarantined, or whose operator was suspended, is disconnected.

05

A card tap: may it charge, and who pays?

The same decision answers a card tap, a session start, a remote start from the app and a reservation, so they can never disagree. First the card itself is checked; then, in a fixed order, who would pay.

  1. 1

    Card usable?

    Not blocked, not expired, not already charging elsewhere. Otherwise refused.

  2. 2

    Does a fleet pay?

    The card's driver is in a fleet billed monthly: accepted, charged to the fleet's statement.

  3. 3

    Free charging?

    Staff granted the card free charging (optionally until a date): accepted, the driver pays nothing.

  4. 4

    Is it a driver's card?

    A card linked to no driver has nobody to pay: blocked.

  5. 5

    Enough credit?

    Wallet above the start minimum, or a card hold waiting at this charger: accepted with a budget.

  6. 6

    Otherwise

    NoCredit on 2.0.1 and 2.1 (shown as Blocked on 1.6, which has no such status).

If the core cannot be reached, the charger gets an error and falls back to its own local list of cards. We keep that list in sync, and it only holds cards someone else pays for (fleet cards and free charging), so an outage never lets an unpaid session through.

06

Starting from the app or the console

A driver taps Start in the app, or an operator starts a session from the console. The card is checked before the charger is ever asked, so a refused card fails fast with a clear reason.

  1. 1

    Driver app → Core: Start charging at this connector. A fleet driver with several vehicles picks the car first.

  2. 2

    Core: Who is asking and for which operator comes from the signed-in session. The card is adjudicated with the rule above.

  3. 3

    Core → Engine: Remote start command, over the internal network only.

  4. 4

    Engine → Charger: RequestStartTransaction (2.x) or RemoteStartTransaction (1.6) on the charger's open socket.

  5. 5

    Charger → Engine: Accepted or Rejected.

  6. 6

    Core → Driver app: The real outcome: accepted, rejected, timed out, or charger offline. Every command is recorded with who sent it.

  7. then
  8. 7

    Charger → Engine: The session starts (TransactionEvent Started / StartTransaction): next section.

07

A session, from start to GST receipt

The tariff is fixed when the session starts. A wallet or card-hold session gets a budget, and we stop the charger before the money runs out, not after.

  1. 1

    Charger → Engine: Session started, with the card.

  2. 2

    Engine → Core: Allocate the session: tariff fixed, budget set (card hold plus wallet), fleet vehicle recorded if known.

  3. 3

    Core → Charger: Accepted. On 2.1, the budget also travels as the charger's own transaction limit, a backstop if it loses its connection.

  4. every meter reading
  5. 4

    Charger → Worker: Energy, power, state of charge, through Kafka.

  6. 5

    Worker: Prices the session so far with the same code the receipt uses, tax included. Cost plus a safety reserve reaches the budget: ask for a stop.

  7. 6

    Driver app: Shows energy, time and cost so far, live.

  8. the session ends
  9. 7

    Charger → Worker: Session ended, with the final meter reading.

  10. 8

    Worker: Prices the whole session: energy, charging time, idle time past the grace period, session fee.

  11. 9

    Worker: Issues a numbered receipt (R-000042) with CGST + SGST, or IGST across states, and settles the wallet, the card hold, the fleet and any sponsor in the same database transaction.

  12. 10

    Worker → Driver app: Push notification: session complete, receipt ready.

  • Receipts never change

    Numbered per operator without gaps. A correction is a credit note (CN-…), never an edit, so your books always reconcile.
  • Idle time, as the charger reports it

    On 2.x, charging time is the time the charger reported Charging. Idle fees start only after the car stopped drawing power and the grace period passed; a charger holding power back is never idle.
  • Energy you can audit

    Billed from the charger's cumulative meter, or from its interval readings if it sends only those. The receipt records which.
  • A charger that lost its link

    It keeps charging on its own. When it reconnects, its queued readings arrive and the session is priced in full. Any shortfall becomes a debt the driver settles before the next session.

08

Payments through Razorpay

Drivers pay with a prepaid wallet (UPI, cards, netbanking) or a card hold: an amount authorised before charging and captured for the real price afterwards, with the rest refunded. ChargeVeta never holds the money; Razorpay does.

The rule throughout: Razorpay is asked, never told. A webhook, a browser confirmation or a retry is only a reason to fetch the payment from Razorpay and act on what it says now. A repeated or out-of-order webhook changes nothing, and nothing is credited twice.

  1. wallet top-up
  2. 1

    Driver app → Core: Add ₹500.

  3. 2

    Core → Razorpay: Create an order; Razorpay Checkout opens in the app.

  4. 3

    Driver → Razorpay: Pays by UPI, card or netbanking.

  5. 4

    Razorpay → Core: Signed webhook to /api/v1/payments/razorpay/webhook, and the app's own confirmation.

  6. 5

    Worker → Razorpay: Fetch the payment: captured? Then credit the wallet exactly once.

  7. card hold
  8. 6

    Driver app → Razorpay: Authorise ₹X on a card (held, not taken); the charger starts.

  9. 7

    Worker → Razorpay: After the receipt: capture the hold, refund the difference, follow the refund until it is processed.

  10. withdrawals
  11. 8

    Driver app → Core: Withdraw unused wallet money: paid back as refunds of the driver's own recent top-ups, newest first.

09

Operators, staff and drivers

There is no public sign-up for operators. The ChargeVeta platform team creates each operator (a tenant) and its owner; the owner builds their own team. Staff, drivers, fleet managers and the platform team are four separate kinds of account, with separate sign-ins, sessions and permissions.

  1. a new operator
  2. 1

    Platform team: Creates the operator: name, operator code (e.g. acme), owner's email. Switches on optional modules such as fleets.

  3. 2

    Owner: Receives a one-time setup link (valid 72 hours), chooses a password, signs in with the operator code.

  4. 3

    Owner: Adds sites, tariffs and chargers, and invites staff by email. Each invitee sets their own password.

  5. a driver
  6. 4

    Driver: Opens the driver app, enters the operator code and a mobile number, types the six-digit code. The first code creates the account; the phone number is the account.

  7. 5

    Driver: Gets an app card automatically, so they can start a charger at once. Can add and confirm an email later, then set a password.

  8. 6

    Staff: Link physical RFID cards to a driver. Drivers can't claim a card themselves: a number printed on a card doesn't prove you hold it.

RoleCan
ViewerSee everything for the operator: chargers, sessions, drivers, receipts, dashboards.
OperatorAlso run chargers: remote start and stop, reset, unlock.
AdminAlso change setup: sites, tariffs, cards, fleets, users, charger settings.
OwnerEverything, including making other owners.

10

Fleets

A fleet is a company whose drivers charge on an operator’s chargers: a bus depot, a delivery firm, a carmaker’s fleet. The module is switched on per operator. Each fleet chooses how it is billed, and that choice is snapshotted on every session, so changing it never rebills an old one.

  • Driver pays

    Members pay each session from their own wallet or card; the fleet sees the sessions.
  • Fleet pays, monthly

    Members charge without paying; the fleet gets a monthly statement (price and GST shown apart), emailed from the 3rd of each month.
  • Vehicles on sessions

    A driver with several vehicles picks the car in the app before starting, so cost per vehicle and per kWh are exact.
  • Fleet managers

    Sign in at app.chargeveta.in/fleet: dashboard, members, sessions, depots, statement and CSV export. Membership and billing stay with the operator.

11

When something fails

Internet links drop and servers restart. Each part is built so that a driver mid-session doesn’t notice, and nothing is billed wrongly afterwards.

  • The core is down

    Connected chargers stay connected. A charger reconnecting with exactly the credentials it used successfully in the last day is let back in. Card taps fall back to the charger's local list.
  • The event stream is down

    The engine keeps answering chargers and buffers their events on disk, then sends them in order when the stream returns. Nothing is lost.
  • A charger goes offline mid-session

    It keeps charging. Its final readings arrive when it reconnects and the session is priced in full. On 2.1 its own transaction limit stops it at the budget.
  • A stop that never lands

    If a session reaches its budget and the charger doesn't stop, staff get a critical alert that retries the stop and escalates by email and text until someone acts.
  • A deploy

    The engine drains on shutdown: new connections wait, answers in flight are sent, and chargers reconnect within seconds. Database changes are backed up first and rolled back if a health check fails.
  • A payment webhook arrives twice

    Nothing happens twice. Every credit, capture and refund is keyed to the Razorpay payment and checked against Razorpay itself.

12

Security and data separation

Many operators share one database. Each operator’s rows are kept apart by PostgreSQL row-level security, enforced by the database itself rather than by remembering to filter in code.

  • The operator comes only from the signed-in session, never from a header, a URL or a form field. Asking for another operator’s record by its ID answers “not found”, so it doesn’t even confirm the ID exists.
  • The application connects as a role that cannot bypass row-level security, and refuses to start if it could.
  • Charger passwords and user passwords are stored only as argon2 hashes. Charger passwords sent as configuration are hidden in the audit log and command history.
  • The engine’s command interface is internal only and never reachable from the internet. The engine and the core each hold separate secrets; the event worker holds none of them.
  • Every change by staff is in the operator’s audit log: who, what, when, from which address. Failed sign-ins are recorded too.
  • Production refuses simulated text messages outright, and runs with test payment keys or a fixed sign-in code only when each one is switched on deliberately, by its own named setting.

13

OCPP support

OCPP 1.6J, 2.0.1 and 2.1 run side by side, chosen per charger. Every message in both directions is validated against the Open Charge Alliance’s own JSON schemas, and every request gets an answer, because a charger left without one retries forever.

AreaWhat ChargeVeta does
CoreBoot, heartbeat, status, authorize, sessions, meter values, data transfer
Remote controlStart, stop, reset, unlock connector, change availability, trigger message
ConfigurationGet and change configuration (1.6), get and set variables, base reports (2.x)
CardsLocal authorization list, kept in sync with differential updates; reservations
Smart chargingCharging profiles and composite schedules
Firmware and logsFirmware update (plain and signed), diagnostics and log upload
SecuritySecurity profiles 1–3, certificate install and listing, security events; the 1.6 security extension
Monitoring (2.x)Set, read and clear variable monitors; device events linked to the monitor that raised them
Pricing (2.1)Our tariff on the charger's screen (with GST), and a per-session cost limit the charger enforces itself

Tested against the open-source EVerest charger firmware on 1.6, 2.0.1 and 2.1, and against scripted simulators. Have a charger model you want checked before you buy? Write to support@chargeveta.in.

Bring a charger, we'll connect it with you.

Send us the charger's make, model and OCPP version. We'll set it up on a demo network and run a session with your team, start to receipt.