Endpointuri

Cereri și răspunsuri ale endpointurilor API-ului de administrare a spațiului de lucru

Aceasta este referința cererilor/răspunsurilor pentru fiecare endpoint /v2/admin. Autentificarea, idempotența, limitele de rată, crearea tokenurilor și semantica domeniilor de acces sunt documentate în API-ul de administrare a spațiului de lucru. Tipurile reutilizabile la nivel de câmp și exemplele se află în Scheme și exemple. Citește fiecare rând de endpoint împreună cu Contractul de răspunsuri și erori, care enumeră toate corpurile posibile de răspuns de nereușită comune și specifice endpointurilor.

Contract comun

Fiecare cale începe cu originea implementată app-api. Spațiul de lucru este derivat exclusiv din tokenul autentificat; clienții nu trebuie să trimită cpoId. Toate valorile documentate ale căilor de resurse :...Id sunt numere întregi zecimale pozitive. Fiecare cerere necesită exact unul:

Authorization: Bearer <workspace-access-token>

Cererile afișate cu un corp JSON necesită Content-Type: application/json. Toate modificările necesită Idempotency-Key (POST, PUT, PATCH și DELETE), inclusiv POST /v2/admin/reports/send; dacă un rând nu precizează altfel, tipul de conținut al succesului este application/json, datele JSON sunt șiruri RFC 3339, iar numerele sunt numere JSON.

Fiecare cerere poate include X-Request-Id și X-Error-Format: envelope; vezi Contractul de răspunsuri și erori. Aceste antete nu modifică schemele de succes.

Notația folosită mai jos:

  • none înseamnă fără corp de cerere. Un DELETE care documentează un corp JSON necesită în continuare acel corp.
  • ? marchează o proprietate sau un parametru de interogare opțional.
  • T | null înseamnă că proprietatea este prezentă și poate fi null.
  • 204 empty înseamnă fără corp de răspuns.
  • CursorPage<T> înseamnă { items: T[], nextCursor: number|string|null }, cu excepția cazului în care rândul numește explicit un obiect page sau pagination.
  • Toate cazurile de resurse imbricate negăsite, inclusiv ID-uri din alte spații de lucru, folosesc 404 { "error": "Workspace resource not found", "code": "RESOURCE_NOT_FOUND" }, cu excepția funcțiilor care documentează un conflict mai specific.

Scheme comune de cerere

Date de intrare pentru spații de lucru și locații

WorkspacePatch = {
  name?: string(1..100), email?: email|null, website?: string|null,
  addressLine1?: string|null, addressLine2?: string|null,
  postalCode?: string|null, city?: string|null, state?: string|null,
  countryId?: positive integer
} // at least one property

SiteInput = {
  name: string(1..255), description?: string|null = null,
  addressLine1?: string|null = null, addressLine2?: string|null = null,
  postalCode?: string|null = null, city?: string|null = null, state?: string|null = null,
  countryId: positive integer, timezoneId: positive integer,
  latitude?: number[-90,90]|null = null, longitude?: number[-180,180]|null = null
}

Date de intrare pentru gestionarea puterii

PowerConfigurationInput = { pools: PowerPoolInput[0..200] }
PowerPoolInput = {
  id?: positive integer|null, name?: string(0..255),
  limit: integer[0,100000000], meterSources?: ExternalMeterInput[0..16],
  children?: (PowerPoolInput | ChargerPoolChild)[0..1000]
}
ChargerPoolChild = { chargepointId: positive integer, priority?: integer[-1000000,1000000] }
ExternalMeterInput = {
  id?: positive integer|null, sourceId?: positive integer|null,
  provider?: "perific", name?: string(0..255), externalId: string(1..80),
  measurementMode?: "available_headroom"|"external_non_ev_load_only"|"total_site_load_including_ev",
  valueMode?: "perific_relative"|"perific_direct"|"perific_meter",
  reserveA?: integer[0,100000], offlineSafeA?: integer[0,100000],
  ttlSeconds?: integer[30,86400], enabled?: boolean
}

Date de intrare pentru stații

ChargerCreate = { name: string(1..40), identifier: string(1..40), password?: string(0..40) = "", siteId: positive integer }
ChargerPatch = {
  name?: string(1..40), siteId?: positive integer, invertedRfid?: boolean,
  smartMode?: integer[0,3], automationDisabled?: boolean
} // at least one
ConnectorPatch = {
  connectorFormatId: positive integer, connectorTypeId: positive integer,
  powerTypeId: positive integer, maxVoltage: integer[1,10000],
  maxAmperage: integer[1,10000], maxElectricPower: integer[1,100000000]
}

Date de intrare pentru rapoarte

ReportFilters = {
  from?: RFC3339, to?: RFC3339, siteId?: positive integer,
  chargerId?: positive integer, userId?: positive integer,
  anonymous?: true|false|1|0, active?: true|false|1|0
}
ReportScheduleInput = {
  enabled: boolean, recipientEmail: email(max 255; may be empty only when disabled), format: "csv"|"pdf",
  sendDay: integer[1,28], sendTime: UTC "HH:mm"
}

Intervalele rapoartelor trebuie să respecte from < to și nu pot depăși 90 de zile. Când sunt omise, este folosit ultimul interval de 90 de zile. userId și anonymous=true se exclud reciproc. Exporturile programate recuperează o minută UTC ratată și folosesc reîncercări limitate (întârziere de 5/10 minute, rezervare de 30 de minute pentru o revendicare expirată, trei încercări).

Date de intrare pentru tarife

TariffInput = {
  name: string(1..64),
  exactly one of currencyId: positive integer, currencyCode: 3 letters, currency: 3 letters,
  biddingZoneId?: positive integer|null, tax?: finite number
}
TariffComponentInput = {
  typeId: positive integer, seasonId: positive integer, priority?: finite number,
  price: finite number, validFromMonth?: finite number, validToMonth?: finite number,
  validFromWeekDay?: finite number, validToWeekDay?: finite number,
  validFromHour?: finite number, validToHour?: finite number
}
TariffAssignmentCreateInput = { tariffId: positive integer, connectorId?: nonnegative integer }
TariffAssignmentUpdateInput = { tariffId: positive integer, connectorId: positive integer }

Date de intrare pentru profiluri de încărcare

ChargingProfileInput = {
  label: string(1..40), locationId: positive integer, stackLevel: nonnegative number,
  purposeId: positive integer, kindId: positive integer,
  recurrencyKindId?: positive integer|null, validFrom?: RFC3339|null,
  validTo?: RFC3339|null, startSchedule?: RFC3339|null,
  rateUnitId: positive integer, minChargingRate?: nonnegative number|null
}
ChargingProfileCreate = ChargingProfileInput & { schedule?: SchedulePeriod[0..256] }
SchedulePeriod = { startPeriod: nonnegative number, limit: nonnegative number, numberOfPhases?: positive integer|null }
ChargingScheduleInput = { rateUnitId: positive integer, periods: SchedulePeriod[1..256] }
ProfileAssignmentInput = { profileId: positive integer, connectorId?: nonnegative integer }

Date de intrare pentru utilizatori

UserCreate = { email: email(max 255), name: string(1..255) }
InvitationInput = {
  email: email, name?: string|null, rfid?: string|null,
  allChargers?: boolean, chargerIds?: unique positive integer[0..500]
} // chargerIds must be non-empty unless allChargers=true
AccessInput = { allChargers?: boolean, chargerIds?: unique positive integer[0..500] }
LimitCreate = { limitTypeId: positive integer, energyValue?: nonnegative integer = 0, timeValue?: nonnegative integer = 0 }
LimitPatch = { limitTypeId?: positive integer, energyValue?: nonnegative integer, timeValue?: nonnegative integer }

Cel puțin unul dintre energyValue sau timeValue trebuie să fie mai mare decât zero la crearea unei limite. Spațiile de la capetele adreselor de email sunt eliminate, iar adresele sunt convertite în litere mici. UID-urile RFID sunt acceptate doar la scriere și sunt mascate în răspunsurile de citire.

Rezumatul DTO-urilor de răspuns

Tabelele endpointurilor afișează fiecare anvelopă de răspuns de nivel superior. Acestea sunt principalele DTO-uri reutilizabile din acele anvelope:

DTOCâmpuri
Workspaceid, name, email, website, address { line1, line2, postalCode, city, state, countryId, countryCode, countryName }, createdAt, updatedAt
Siteid, name, description, address, timezone { id, name }, latitude, longitude, chargerCount; detaliul adaugă chargers normalizat și starea conectorului
GeocodeCandidateplaceId, displayName, latitude, longitude; datele de autentificare și metadatele specifice furnizorului nu sunt returnate niciodată
MetricsWindowfrom, to, limite/număr de sesiuni și totalsCapped, unde este cazul
Chargerid, name, identifier, cpoId, site, status normalizat, isPublic, indicatori RFID/inteligent/automatizare, provisioned, connection, evses, connectors, createdAt, updatedAt; detaliul adaugă configuration redactat, firmware și numărători
ConnectorportId, connectorId, ID-uri de referință ale conectorului, maxVoltage, maxAmperage, maxElectricPower
ReportSessionid, stație/locație, ID-uri de port și conector, utilizator minimizat, active, energyWh, început/sfârșit/durată și costuri nete/taxe/totale per monedă
ReportScheduleid, workspaceId, enabled, recipientEmail, format, sendDay/sendTime UTC, metadate de creare/actualizare și metadate sigure despre ultima livrare, inclusiv numărul încercărilor
Tariffid, cpoId, name, obiecte de tip/locație/monedă/zonă de ofertare, tax, fallbackPrice, price efectiv, components, assignmentCount
ChargingProfileid, cpoId, label, description, stackLevel, obiecte de locație/scop/tip/recurență/unitate de rată, valabilitate, program, assignmentCount, marcaje temporale
Userid, membershipId, name, email, rfids mascat, access al stației, limitCount; detaliul adaugă phone, createdAt și limits. Datele de autorizare OCPP, precum contractId, nu sunt returnate niciodată.
RFIDid, maskedUid, name, type, valid; UID-ul brut nu este returnat niciodată
AccessallChargers, chargerIds sortat și items care conține metadate de permisiune/stație/locație/expirare
Limitid, limitTypeId, label, energyValue, timeValue
LocalUserDTO de listă: id, customerId, name, email, expiresAt, systemManaged. Modificările utilizatorilor locali folosesc structurile distincte LocalUserMutation/LocalUserUpdate din Scheme și exemple.

Obiectele de referință sunt returnate de rutele de listă/detaliu, astfel încât apelanții să poată descoperi ID-uri valide. Tratează câmpurile noi necunoscute ca fiind compatibile cu versiunile viitoare și diferențiază cazurile doar pe baza câmpurilor stabile și codurilor de eroare documentate.

Endpointuri pentru spații de lucru

Metodă și caleDomeniu de accesCerereRăspuns de succes
GET /v2/adminworkspaces:readCorp: fără200 { workspace: Workspace }
PATCH /v2/adminworkspaces:updateCorp: WorkspacePatch200 { workspace: Workspace }
GET /v2/admin/dashboardworkspaces:read + reports:readCorp/interogare: fără200 { window, stats { chargerCount, onlineChargerCount, siteCount, userCount }, sessions: DashboardSession[], analytics }; sesiunile sunt limitate la 1.000 pe 90 de zile

Endpointuri pentru locații și gestionarea puterii

Metodă și caleDomeniu de accesCerereRăspuns de succes
GET /v2/admin/sitessites:readCorp/interogare: fără200 { items: Site[], metricsWindow: MetricsWindow, lookups { countries, timezones } }
GET /v2/admin/sites/geocodesites:readInterogare: opțional street (max. 160), city, state, country (max. 100 fiecare), countryCode (max. 2); antet opțional Accept-Language; sunt necesare cel puțin două caractere de stradă/oraș/stat cumulate200 { results: GeocodeCandidate[] }; căutările identice aflate în curs sunt reunite, iar activitatea furnizorului folosește o coadă serializată limitată și un cache limitat pe server; căutările nevalide returnează 400 INVALID_GEOCODE_QUERY, saturarea cozii returnează 429 GEOCODING_BUSY cu Retry-After, iar erorile furnizorului returnează 502 GEOCODING_UNAVAILABLE
POST /v2/admin/sitessites:createCorp: SiteInput201 { site: Site }
GET /v2/admin/sites/:siteIdsites:read + reports:readCorp/interogare: fără200 { site: SiteDetail, recentSessions: SiteSession[], totals, metricsWindow }
PATCH /v2/admin/sites/:siteIdsites:updateCorp: SiteInput complet200 { site: Site }
DELETE /v2/admin/sites/:siteIdsites:deleteCorp: fără204 empty; o locație care nu este goală returnează 409 SITE_NOT_EMPTY
GET /v2/admin/sites/:siteId/power-managementsites:power-managementCorp/interogare: fără200 { configuration: PowerConfiguration } care conține locația deținută, stații/conectori, grupuri, surse de contor, atribuiri și starea compatibilității
PUT /v2/admin/sites/:siteId/power-managementsites:power-managementCorp: PowerConfigurationInput200 { configuration: PowerConfiguration }; refuzul OCPP, expirarea sau o modificare concurentă returnează 409 POWER_MANAGEMENT_CONFLICT fără a aplica înlocuirea

Endpointuri pentru stații

Metodă și caleDomeniu de accesCerereRăspuns de succes
GET /v2/admin/chargerschargers:readCorp/interogare: fără200 { items: Charger[], metricsWindow: MetricsWindow, connectorLookups { formats, types, powerTypes } }
POST /v2/admin/chargerschargers:createCorp: ChargerCreate; identificatorul este convertit în majuscule201 { charger: Charger }; parola nu este returnată niciodată
GET /v2/admin/chargers/:chargerIdchargers:readCorp/interogare: fără200 { charger: ChargerDetail }
PATCH /v2/admin/chargers/:chargerIdchargers:updateCorp: ChargerPatch200 { charger: ChargerDetail }
DELETE /v2/admin/chargers/:chargerIdchargers:deleteCorp: fără204 empty
PATCH /v2/admin/chargers/:chargerId/credentialschargers:credentialsCorp: { password: string(0..40) }200 { success: true }
PATCH /v2/admin/chargers/:chargerId/connectors/:portIdchargers:connector-settingsCorp: ConnectorPatch200 { connector: Connector }
PATCH /v2/admin/chargers/:chargerId/public-listingchargers:publicCorp: { isPublic: boolean }200 { isPublic: boolean }; cerințele de pregătire neîndeplinite returnează 409 CHARGER_CONFLICT
GET /v2/admin/chargers/:chargerId/public-readinesschargers:readCorp/interogare: fără200 { readiness: { ready, missingRequirements, connectorIds, missingTariffConnectorIds, ...commercialState } }
GET /v2/admin/chargers/:chargerId/logschargers:readInterogare: cursor?, limit?=50 (1..200), from?, to?, action?, direction?, levelId?200 { items: RedactedOcppLog[], nextCursor: number or null }
GET /v2/admin/chargers/:chargerId/sessionschargers:read + reports:readInterogare: page?=1, limit?=25 (1..100), from?, to?, customerId?: positive integer or "unknown"200 { items: ChargerSession[], pagination { page, limit, total, totalPages }, filters { customers }, totals, totalsCapped }
GET /v2/admin/chargers/:chargerId/qrchargers:readInterogare: connector?: integer[0,255]200 image/png binar, 300 px, Content-Disposition: inline, Cache-Control: no-store
GET /v2/admin/chargers/:chargerId/composite-scheduleschargers:readInterogare: cursor?, limit?=20 (1..50), connectorId?200 { items: CompositeSchedule[], nextCursor: number or null }
GET /v2/admin/chargers/:chargerId/configurationchargers:readCorp/interogare: fără200 { items: ChargerConfiguration[] }; valorile asemănătoare secretelor sunt [REDACTED]
PATCH /v2/admin/chargers/:chargerId/configurationchargers:configurationCorp: { key: string(1..50), value: string(0..500) }200 { status: string } unde starea este rezultatul stației/OCPP
POST /v2/admin/chargers/:chargerId/configuration/reloadchargers:configurationCorp: fără200 { status: string }
GET /v2/admin/chargers/:chargerId/firmwarechargers:readCorp/interogare: fără200 { firmware: { status, notifiedAt, currentVersion, bootNotifiedAt } }
POST /v2/admin/chargers/:chargerId/firmwarechargers:firmwareCorp: { url: HTTP-or-HTTPS URL, max 2048 characters }202 { status: string }
POST /v2/admin/chargers/:chargerId/commands/resetchargers:commandsCorp: { resetType: "Soft" or "Hard" }200 { status: string }
POST /v2/admin/chargers/:chargerId/commands/availabilitychargers:commandsCorp: { availabilityType: "Operative" or "Inoperative" }200 { status: string }
POST /v2/admin/chargers/:chargerId/commands/triggerchargers:commandsCorp: { messageType: "BootNotification", "Heartbeat", "StatusNotification", or "MeterValues" }200 { status: string, connectorResults: { connectorId, status }[] }
POST /v2/admin/chargers/:chargerId/commands/unlockchargers:commandsCorp: { connectorId: positive integer }200 { status: string }
POST /v2/admin/chargers/:chargerId/commands/composite-schedulechargers:commandsCorp: { connectorId: nonnegative integer, durationSeconds?: integer[60,604800], chargingRateUnit?: "W" or "A" }200 { status: string, connectorId: number, compositeSchedule: CompositeSchedule or null }

Endpointuri pentru rapoarte

Metodă și caleDomeniu de accesCerereRăspuns de succes
GET /v2/admin/reports/datareports:readInterogare: ReportFilters, cursor? opac, limit?=50 (1..100)200 { items: ReportSession[], pageTotals, page { limit, nextCursor }, range { from, to, toExclusive: true } }
GET /v2/admin/reports/schedulereports:readCorp/interogare: fără200 { schedule: ReportSchedule or null }
PUT /v2/admin/reports/schedulereports:schedulesCorp: ReportScheduleInput strict200 { schedule: ReportSchedule }
POST /v2/admin/reports/sendreports:sendCorp: fără; antetul Idempotency-Key este obligatoriu200 { sent: true, format: "csv" or "pdf", rowCount: number, range { from, to } }; lipsa unui program salvat returnează 409 REPORT_SCHEDULE_REQUIRED
GET /v2/admin/reports/measurementsreports:readInterogare: transactionLogId obligatoriu, cursor? opac, limit?=500 (1..1000)200 { transactionLogId, measurements: { name, unit, lines[] }[], page { limit, nextCursor, sampleValuesTruncated, sampleLimitPerMeterValue: 64 } }
GET /v2/admin/reports/exportreports:exportInterogare: ReportFilters, format?="csv" or "pdf"200 binar CSV/PDF cu numele fișierului atașat, Cache-Control: private, no-store, X-Content-Type-Options: nosniff; peste 2.000 de rânduri returnează 422 REPORT_EXPORT_ROW_LIMIT

Endpointuri pentru tarife

Metodă și caleDomeniu de accesCerereRăspuns de succes
GET /v2/admin/tariffstariffs:readCorp/interogare: fără200 { items: Tariff[], lookups { currencies, biddingZones, currencyRates, componentTypes, seasons, tariffTypes } }
POST /v2/admin/tariffstariffs:createCorp: TariffInput201 { tariff: Tariff }
GET /v2/admin/tariffs/:tariffIdtariffs:readCorp/interogare: fără200 { tariff: Tariff, lookups }
PATCH /v2/admin/tariffs/:tariffIdtariffs:updateCorp: TariffInput complet200 { tariff: Tariff }
PUT /v2/admin/tariffs/:tariffId/componentstariffs:componentsCorp: { components: TariffComponentInput[0..256] }200 { tariff: Tariff, components: TariffComponent[] }
DELETE /v2/admin/tariffs/:tariffIdtariffs:deleteCorp: fără204 empty; referințele înregistrărilor de încărcare returnează 409 TARIFF_CONFLICT
GET /v2/admin/tariffs/:tariffId/market-pricestariffs:readInterogare: startsAt obligatoriu, marcaj temporal Unix nenegativ200 { items: { id, value, currencyId, startsAt, endsAt, startsAtIso, endsAtIso, intervalMinutes }[], truncated: boolean }; cel mult 10.000 de rânduri
GET /v2/admin/chargers/:chargerId/tariff-assignmentschargers:tariff-assignments + tariffs:readCorp/interogare: fără200 { items: TariffAssignment[], tariffs: Tariff[] }
POST /v2/admin/chargers/:chargerId/tariff-assignmentschargers:tariff-assignments + tariffs:assignCorp: TariffAssignmentCreateInput; omiterea lui connectorId sau connectorId=0 înseamnă toți conectorii201 { assignments: TariffAssignment[] }
PATCH /v2/admin/chargers/:chargerId/tariff-assignments/:assignmentIdchargers:tariff-assignments + tariffs:assignCorp: TariffAssignmentUpdateInput; conectorul este obligatoriu și nu poate fi 0200 { assignment: TariffAssignment }
DELETE /v2/admin/chargers/:chargerId/tariff-assignments/:assignmentIdchargers:tariff-assignments + tariffs:assignCorp: fără204 empty

TariffAssignment conține id, chargerId, connectorId, un rezumat sigur al tarifului/monedei, createdAt și updatedAt.

Endpointuri pentru profiluri de încărcare

Metodă și caleDomeniu de accesCerereRăspuns de succes
GET /v2/admin/charging-profileschargingProfiles:readCorp/interogare: fără200 { items: ChargingProfile[], lookups { locations, purposes, kinds, recurrencyKinds, rateUnits, allowedRateUnits } }
POST /v2/admin/charging-profileschargingProfiles:createCorp: ChargingProfileCreate201 { profile: ChargingProfile }
GET /v2/admin/charging-profiles/:profileIdchargingProfiles:readCorp/interogare: fără200 { profile: ChargingProfile, lookups, isEditBlocked: boolean, usage { simpleChargingSchedule, smartSchedule, chargePoolChargepoint, isUsed } }
PATCH /v2/admin/charging-profiles/:profileIdchargingProfiles:updateCorp: ChargingProfileInput complet200 { profile: ChargingProfile, ocppSync: OcppCommandResult[] }
PUT /v2/admin/charging-profiles/:profileId/schedulechargingProfiles:updateCorp: ChargingScheduleInput200 { profile: ChargingProfile, schedule: SchedulePeriod[], ocppSync: OcppCommandResult[] }
DELETE /v2/admin/charging-profiles/:profileIdchargingProfiles:deleteCorp: fără204 empty doar după ce toate stațiile atribuite acceptă ștergerea și starea este revalidată; altfel 409, iar profilul rămâne
GET /v2/admin/chargers/:chargerId/profile-assignmentschargers:profile-assignments + chargingProfiles:readCorp/interogare: fără200 { items: ProfileAssignment[], profiles: ChargingProfile[] }
POST /v2/admin/chargers/:chargerId/profile-assignmentschargers:profile-assignments + chargingProfiles:assignCorp: ProfileAssignmentInput201 { assignment: ProfileAssignment, ocpp: OcppCommandResult }
PATCH /v2/admin/chargers/:chargerId/profile-assignments/:assignmentIdchargers:profile-assignments + chargingProfiles:assignCorp: ProfileAssignmentInput200 { assignment: ProfileAssignment, ocpp: OcppCommandResult }
DELETE /v2/admin/chargers/:chargerId/profile-assignments/:assignmentIdchargers:profile-assignments + chargingProfiles:assignCorp: fără204 empty după ștergerea sincronizată

ProfileAssignment conține ID-ul atribuirii, ID-urile stației/conectorului și un rezumat sigur al profilului. Obiectele de rezultat OCPP expun informații stabile despre cerere/stare și niciodată date de autentificare.

Endpointuri pentru utilizatori, RFID, acces, limite și utilizatori locali

Metodă și caleDomeniu de accesCerereRăspuns de succes
GET /v2/admin/usersusers:readInterogare: cursor? corespunzător stării (members: numeric pozitiv; invitations: i2.* opac autentificat; all: continuare numerică de membru veche sau a2.* compozit opac autentificat), limit?=50 (1..100), status?="all", "members", or "invitations"; antet opțional X-Admin-User-Search (max. 100)200 { items: User[], invitations: Invitation[], chargers: ChargerSummary[], page { nextCursor, memberNextCursor, invitationNextCursor, limit } }; invitațiile sunt paginate și completate folosind aceeași expresie normalizată de email, astfel încât literele mari/mici sau spațiile vechi să nu poată ascunde rânduri; cursoarele sunt legate de spațiul de lucru și filtrul de căutare, nu conțin adrese de email lizibile și trebuie returnate nemodificate; cursoarele all avansează independent fluxurile de membri și invitații
POST /v2/admin/usersusers:createCorp: UserCreate; clientul trebuie să fie deja înregistrat201 { user: User }; o adresă de email necunoscută returnează corpul 404 RESOURCE_NOT_FOUND care nu permite enumerarea și ar trebui să folosească invitații
POST /v2/admin/users/invitationsusers:invitations + users:access; plus users:rfid dacă este furnizat rfidCorp: InvitationInput200 or 201 { result }; rezultatul asocierii este { kind:"attached", user, accessChanged, rfidChanged }; rezultatul în așteptare este { kind:"invited", email, name, maskedRfid, chargerIds, createdCount, emailSent, emailRetryReady, alreadyInvited }
POST /v2/admin/users/invitations/resendusers:invitationsCorp: { email: email }200 { result: { targetedChargers, emailSent, emailRetryReady } }; este aplicat intervalul de așteptare global al destinatarului
DELETE /v2/admin/users/invitationsusers:invitationsCorp: { email: email }204 empty
GET /v2/admin/users/:userIdusers:read + reports:readCorp/interogare: fără200 { user: UserDetail, sessions: UserSession[], totals { count, energyWh, durationSeconds }, window, limitTypes, chargers }; cel mult 200 de sesiuni pe 90 de zile
PATCH /v2/admin/users/:userIdusers:updateCorp: { name: string(1..255) }200 { user: User }
DELETE /v2/admin/users/:userIdusers:deleteCorp: fără204 empty
GET /v2/admin/users/:userId/vehiclesusers:readInterogare: cursor? numeric, limit?=50 (1..100)200 { items: Vehicle[], page { nextCursor, limit } }; DTO-ul vehiculului include câmpuri sigure de furnizor/stare/model/telemetrie
GET /v2/admin/users/:userId/rfidsusers:readCorp/interogare: fără200 { items: RFID[] }; UID-urile sunt mascate
POST /v2/admin/users/:userId/rfidsusers:rfidCorp: { uid: string(1..36), name?: string or null }201 { rfid: RFID }; UID-ul brut nu este repetat
PATCH /v2/admin/users/:userId/rfids/:rfidIdusers:rfidCorp: { name: string or null }200 { rfid: RFID }
DELETE /v2/admin/users/:userId/rfids/:rfidIdusers:rfidCorp: fără204 empty
GET /v2/admin/users/:userId/accessusers:readCorp/interogare: fără200 { access: Access }
PUT /v2/admin/users/:userId/accessusers:accessCorp: AccessInput200 { access: Access }
DELETE /v2/admin/users/:userId/access/:accessIdusers:accessCorp: fără204 empty
GET /v2/admin/users/:userId/limitsusers:readCorp/interogare: fără200 { items: Limit[] }
POST /v2/admin/users/:userId/limitsusers:limitsCorp: LimitCreate201 { limit: Limit }
PATCH /v2/admin/users/:userId/limits/:limitIdusers:limitsCorp: LimitPatch, cel puțin o proprietate200 { limit: Limit }
DELETE /v2/admin/users/:userId/limits/:limitIdusers:limitsCorp: fără204 empty
GET /v2/admin/chargers/:chargerId/local-userschargers:read + users:readCorp/interogare: fără200 { charger: ChargerSummary, items: LocalUser[], invitations: { email }[], availableMembers: [] }; API-ul omite intenționat directorul larg de membri disponibili al portalului
POST /v2/admin/chargers/:chargerId/local-userschargers:local-users + users:accessCorp: { customerId: positive integer, expiresAt?: RFC3339 or null }201 { localUser: LocalUserMutation }
POST /v2/admin/chargers/:chargerId/local-users/invitationschargers:local-users + users:invitations + users:accessCorp: { email: email }200 or 201 { result }; client existent: { invited:false, localUser: LocalUserMutation }; invitație: { invited:true, alreadyInvited, emailSent, emailRetryReady }
DELETE /v2/admin/chargers/:chargerId/local-users/invitationschargers:local-users + users:invitationsCorp: { email: email }204 empty
PATCH /v2/admin/chargers/:chargerId/local-users/:localUserIdchargers:local-users + users:accessCorp: { expiresAt: RFC3339 or null }200 { localUser: LocalUserUpdate }
DELETE /v2/admin/chargers/:chargerId/local-users/:localUserIdchargers:local-users + users:accessCorp: fără204 empty

Utilizatorul de sistem Tagless este protejat de aceste operațiuni. Eșecurile trimiterii emailurilor de invitație returnează o stare sigură a livrării fără a divulga detalii SMTP; apelanții pot reîncerca atunci când emailRetryReady este adevărat.

Răspunsuri binare

Două familii de endpointuri nu returnează JSON în caz de succes:

EndpointTip de conținutAntete importante
QR al stațieiimage/pngCache-Control: no-store, Content-Disposition: inline, X-Content-Type-Options: nosniff
Export de rapoartetext/csv; charset=utf-8 sau application/pdfCache-Control: private, no-store, Content-Disposition: attachment, X-Content-Type-Options: nosniff

Erorile endpointurilor binare sunt în continuare JSON.