Let drivers charge with RFID cards

Choose who each charger accepts, enrol cards, give them to people, permit, suspend and erase people, and keep chargers working offline.

6 min readEdit this page
On this page

A driver taps a card and the charger starts, or politely refuses. You decide which: per charger, per location or for a whole project. Cards identify people, people are permitted where they may charge, and Flowion keeps every charger's offline list in step with your decisions.

Choose who a charger accepts

Every charger has an access type:

accessTypeWho may charge
openAnyone, with any card
privatePeople permitted at this charger, its location or its project
paidNo one with a card alone

Set it for the whole project, then override it for a location or a single charger where you need to. The nearest level wins.

PUT/v1/projects/$PROJECT/access-policybash
curl -X PUT "$API/projects/$PROJECT/access-policy" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"accessType": "private"}'

The same body works on /v1/locations/{id}/access-policy and /v1/charging-stations/{id}/access-policy, where null clears the value and the level above applies again. A project with nothing set is private, so new chargers start locked down.

A change that would let more people charge somewhere asks first: it answers 409 until you send it again with "confirmMorePermissive": true. Send "dryRun": true to see what a change would do, including how many chargers it affects, without applying it.

Setting a project or a location needs the authorization.access_policy.manage permission, opening a charger to everyone needs authorization.access_policy.open, and a single charger's own setting needs authorization.access_policy.manage_charger.

Enrol a card

POST/v1/projects/$PROJECT/id-tokensbash
curl -X POST "$API/projects/$PROJECT/id-tokens" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"value": "045C7A2B4F1D80",
       "label": "Fleet card 12",
       "tokenType": "ISO14443",
       "expiresAt": "2027-01-01T00:00:00Z"}'

Only value, the number the card reports, is required. label is for people reading lists, expiresAt retires the card on a date, and tokenType records what kind of credential it is: ISO14443 or ISO15693 for RFID cards, KeyCode, MacAddress, eMAID, Central, Local or NoAuthorization. A value already enrolled in the project is 409.

A card enrolled like this belongs to no one yet. On a private charger it charges once a permitted person holds it.

Enrol a stack of cards

Scanned twenty cards before handing them out? Send them in one call, up to 500:

POST/v1/projects/$PROJECT/id-tokens/batchbash
curl -X POST "$API/projects/$PROJECT/id-tokens/batch" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"cards": [
        {"value": "045C7A2B4F1D80", "label": "Box 1, card 1"},
        {"value": "045C7A2B4F1D81", "label": "Box 1, card 2"}]}'

The answer has one result per card, in the order you sent them, each the card or the reason it was refused. One duplicate does not stop the rest.

Give cards to people

A person is who may charge. A card only identifies them. One person can hold many cards, a card has at most one holder, and losing a card never costs anyone their access.

Enrol a card straight to a new person, the shortest path when you keep no list of people yourself:

POST/v1/projects/$PROJECT/id-tokensbash
curl -X POST "$API/projects/$PROJECT/id-tokens" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"value": "045C7A2B4F1D80",
       "holder": {"newPrincipal":
                  {"displayName": "Anna Andersson"}}}'

Or to someone who already exists, with "holder": {"principalId": "…"}. The API calls a person a principal. Each one has an optional display name, email and phone, and a status of active, suspended or erased.

Holding people in Flowion is optional. If your own system already knows who has which card, set externalUserId on the card (PATCH /v1/id-tokens/{id}) as your own label and find cards by it with GET /v1/projects/{projectId}/id-tokens/external-user/{externalUserId}.

Attach, move and detach a card

bash
# attach an unassigned card, or move one to someone else
curl -X PUT "$API/id-tokens/$CARD/holder" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"principalId": "'$PRINCIPAL'"}'

# detach it again
curl -X DELETE "$API/id-tokens/$CARD/holder" \
  -H "Authorization: Bearer $TOKEN"

Moving a card moves only the card: the person it left keeps their permissions. A blocked card cannot be attached until you unblock it.

Company cards and personal cards

A card is project-owned by default, like an office handing out badges. Send "ownership": "principal" when enrolling a card the person brought themselves.

RowProject-ownedPersonal
Move to another personYesNo
Detach from its holderGoes back in stockErased, after you confirm with ?confirmErase=true
When its holder is erasedGoes back in stockErased with them

POST /v1/id-tokens/{id}/hand-over turns a personal card into a project card, still held by the same person.

Match people to your own system

Record your own id for a person as a reference: a provider name you choose and an externalId.

PUT/v1/projects/$PROJECT/principals/by-reference/hr/83921bash
curl -X PUT \
  "$API/projects/$PROJECT/principals/by-reference/hr/83921" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"displayName": "Anna Andersson"}'

The first call creates the person (201). Every later call with the same pair returns that same person (200) and leaves their details as they are, so an import can run as often as you like.

Permit people to charge

Whether a person may charge is a permission policy bound to them at a project, a location or a single charger. Bind the managed Charging policy to let them start a charge there (its id is 00000133-0000-4000-8000-000000000006, and the permission policies list shows it beside the others):

POST/v1/locations/$LOCATION/bindingsbash
curl -X POST \
  "$API/locations/$LOCATION/bindings" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"principalId": "'$PRINCIPAL'", "policyId": "00000133-0000-4000-8000-000000000006"}'

Every card the person holds then charges there, including cards they get later. A card that is itself blocked or expired is still refused, and their other cards are unaffected.

Binding at a project or a location needs authorization.access_policy.manage, at a single charger authorization.access_policy.manage_charger. To see who may charge at a place, and whether each person's card is on a charger's local list, read GET $API/projects/$PROJECT/who-can-charge, or the same under /locations/$LOCATION or /charging-stations/$CHARGER. It shows names and ids, never an email or phone, and needs authorization.access_policy.read.

Suspend a person

When a resident moves out or an employee leaves, suspend the person rather than each card:

POST/v1/principals/$PRINCIPAL/suspendbash
curl -X POST "$API/principals/$PRINCIPAL/suspend" \
  -H "Authorization: Bearer $TOKEN"

From the next tap, every card they hold is refused at your private chargers that can reach Flowion. Their permissions stay as they were, so POST /v1/principals/{id}/reinstate restores exactly what they had. A charger that is offline keeps the list it last received until it reconnects; see Keep chargers working offline.

Block or remove a card

POST/v1/id-tokens/$CARD/revokebash
curl -X POST "$API/id-tokens/$CARD/revoke" \
  -H "Authorization: Bearer $TOKEN"

A revoked card is refused from its next tap, at every charger that can reach Flowion, and keeps its history. POST /v1/id-tokens/{id}/unrevoke lets it charge again. A charger that is offline keeps the list it last received until it reconnects, so a revoked card can still charge there until then.

Erase a person

POST /v1/principals/{id}/erase (needs authorization.principal.erase) permanently removes a person's name, email, phone, references and permissions. Their personal cards are erased, and the project's cards they held go back in stock. The person's id stays, marked erased, so earlier records of their cards being accepted or refused still make sense. If an erase is interrupted, run it again: it finishes what it started.

Keep chargers working offline

A charger that loses its connection still has to answer the next driver. offlineCharging decides how:

offlineChargingWhile offline, the charger accepts
allowAny card
permittedOnlyCards on its offline list
denyNo one

It defaults to allow for open chargers, permittedOnly for private and deny for paid, and you set it in the same access policy call as accessType.

You never maintain the offline list by hand. Flowion builds each charger's list from the people who may charge there at every moment, and every card they hold, and updates it whenever a permission, a card or a person changes. A person allowed only in a time window, or whose access a deny could reach, is not on it: online they charge as always, and offline the charger's offlineCharging decides, as it does for any card it doesn't know. Who can charge says, for each person, whether their card is on a charger's list and, if not, why. A suspended person's cards stay on the list marked blocked, so an offline charger refuses them rather than treating them as unknown. Reading a charger's list needs ocpp.diagnostics.read:

GET/v1/charging-stations/$CHARGER/local-auth-listbash
curl "$API/charging-stations/$CHARGER/local-auth-list" \
  -H "Authorization: Bearer $TOKEN"

A charger that is offline hears about a change when it reconnects. When you make a charger stricter, Flowion also clears the cards it remembers on its own, so a card accepted while it was open does not keep working. Offline lists are not supported on every charger. See which.

Card numbers stay secret

Flowion stores a card's value only as a keyed hash, to recognise it, and an encrypted copy, to put it on a charger's offline list. No list or read endpoint returns it.

When you genuinely need a value back, someone holding authorization.id_token.reveal (the Owner policy) can reveal it:

POST/v1/id-tokens/$CARD/revealbash
curl -X POST "$API/id-tokens/$CARD/reveal" \
  -H "Authorization: Bearer $TOKEN"

Every reveal is recorded, and GET /v1/id-tokens/{id}/reveals lists who looked and when.

See why a card was refused

GET/v1/id-tokens/$CARD/authorization-decisionsbash
curl "$API/id-tokens/$CARD/authorization-decisions" \
  -H "Authorization: Bearer $TOKEN"

Every time a charger asked about the card, newest first: the charger, the answer in decidedStatus, and in decidedBy the rule that decided it, such as a suspended holder or a blocked card.

Endpoints

Authorization · Principals · Access policy · Local authorization list

In the API reference