Endpointanrop och svar i arbetsytans Admin API
Detta är anrops- och svarsreferensen för varje /v2/admin-endpoint. Autentisering, idempotens, anropsgränser, tokenskapande och behörighetsområdenas betydelse dokumenteras i Workspace Admin API. Återanvändbara fälttyper och exempel finns i Scheman och exempel. Läs varje endpointrad tillsammans med Kontrakt för svar och fel, som listar alla möjliga gemensamma och endpointspecifika svarskroppar vid fel.
Gemensamt kontrakt
Varje sökväg börjar med den driftsatta app-api-serverns ursprung. Arbetsytan härleds uteslutande från den autentiserade token; klienter får inte skicka cpoId. Alla dokumenterade resursvärden :...Id i sökvägen är positiva decimala heltal. Varje anrop kräver exakt en:
Authorization: Bearer <workspace-access-token>
Anrop som visas med JSON-kropp kräver Content-Type: application/json. Alla ändringsåtgärder kräver Idempotency-Key (POST, PUT, PATCH och DELETE), inklusive POST /v2/admin/reports/send; om inget annat anges är innehållstypen vid framgång application/json, JSON-datum är RFC 3339-strängar och tal är JSON-tal.
Varje anrop får innehålla X-Request-Id och X-Error-Format: envelope; se Kontrakt för svar och fel. Dessa headrar ändrar inte scheman för lyckade svar.
Notation som används nedan:
nonebetyder ingen anropskropp. EnDELETEsom dokumenterar en JSON-kropp kräver fortfarande den kroppen.?markerar en valfri egenskap eller frågeparameter.T | nullbetyder att egenskapen finns och får vara null.204 emptybetyder ingen svarskropp.CursorPage<T>betyder{ items: T[], nextCursor: number|string|null }, utom där raden uttryckligen nämner ettpage- ellerpagination-objekt.- Alla saknade underordnade resurser, även ID:n från andra arbetsytor, använder
404 { "error": "Workspace resource not found", "code": "RESOURCE_NOT_FOUND" }om inte en funktion dokumenterar en mer specifik konflikt.
Gemensamma anropsscheman
Indata för arbetsytor och platser
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
}
Indata för effektstyrning
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
}
Laddarindata
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]
}
Rapportindata
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"
}
Rapportintervall måste uppfylla from < to och får inte överstiga 90 dagar. Vid utelämnande används de senaste 90 dagarna. userId och anonymous=true utesluter varandra. Schemalagda exporter körs i efterhand efter en missad UTC-minut och använder begränsade återförsök: 5/10 minuters väntetid, 30 minuters reservation för inaktuella behandlingsanspråk och tre försök.
Tariffindata
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 }
Indata för laddprofiler
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 }
Användarindata
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 }
Minst ett av energyValue eller timeValue måste vara större än noll när en gräns skapas. Inledande och avslutande blanksteg tas bort från e-postadresser och bokstäverna görs gemena. RFID-UID:n accepteras endast vid skrivning och maskeras i lässvar.
Sammanfattning av svars-DTO:er
Endpointtabellerna visar varje svarsomslutning på översta nivån. Detta är de viktigaste återanvändbara DTO:erna i omslutningarna:
| DTO | Fält |
|---|---|
Workspace | id, name, email, website, address { line1, line2, postalCode, city, state, countryId, countryCode, countryName }, createdAt, updatedAt |
Site | id, name, description, address, timezone { id, name }, latitude, longitude, chargerCount; detalj lägger till normaliserade chargers och kontakttillstånd |
GeocodeCandidate | placeId, displayName, latitude, longitude; leverantörsuppgifter och leverantörsspecifika metadata returneras aldrig |
MetricsWindow | from, to, sessionsgränser/-antal och totalsCapped där det är tillämpligt |
Charger | id, name, identifier, cpoId, site, normaliserad status, isPublic, RFID-/smart-/automatiseringsflaggor, provisioned, connection, evses, connectors, createdAt, updatedAt; detalj lägger till configuration med känsliga värden dolda, firmware och antal |
Connector | portId, connectorId, kontaktuppslags-ID:n, maxVoltage, maxAmperage, maxElectricPower |
ReportSession | id, laddare/plats, port- och kontakt-ID:n, minimerade användaruppgifter, active, energyWh, start/stopp/varaktighet samt netto-/skatte-/totalkostnad per valuta |
ReportSchedule | id, workspaceId, enabled, recipientEmail, format, UTC sendDay/sendTime, metadata för skapande/uppdatering och säkra metadata för senaste leverans inklusive antal försök |
Tariff | id, cpoId, name, objekt för typ/plats/valuta/elområde, tax, fallbackPrice, effektiv price, components, assignmentCount |
ChargingProfile | id, cpoId, label, description, stackLevel, objekt för placering/syfte/typ/återkomst/laddningsenhet, giltighet, schema, assignmentCount, tidsstämplar |
User | id, membershipId, name, email, maskerade rfids, laddarens access, limitCount; detalj lägger till phone, createdAt och limits. OCPP-auktoriseringsuppgifter som contractId returneras aldrig. |
RFID | id, maskedUid, name, type, valid; rått UID returneras aldrig |
Access | allChargers, sorterade chargerIds och items med metadata för åtkomst/laddare/plats/utgång |
Limit | id, limitTypeId, label, energyValue, timeValue |
LocalUser | List-DTO: id, customerId, name, email, expiresAt, systemManaged. Ändringar av lokala användare använder de separata strukturerna LocalUserMutation/LocalUserUpdate i Scheman och exempel. |
Uppslagsobjekt returneras av list- och detaljrutter så att klienter kan hitta giltiga ID:n. Behandla okända nytillkomna fält som framåtkompatibla och basera logiken enbart på dokumenterade stabila fält och felkoder.
Arbetsyteendpoints
| Metod och sökväg | Behörighetsområde | Anrop | Lyckat svar |
|---|---|---|---|
GET /v2/admin | workspaces:read | Kropp: ingen | 200 { workspace: Workspace } |
PATCH /v2/admin | workspaces:update | Kropp: WorkspacePatch | 200 { workspace: Workspace } |
GET /v2/admin/dashboard | workspaces:read + reports:read | Kropp/fråga: ingen | 200 { window, stats { chargerCount, onlineChargerCount, siteCount, userCount }, sessions: DashboardSession[], analytics }; sessioner begränsas till 1 000 under 90 dagar |
Endpoints för platser och effektstyrning
| Metod och sökväg | Behörighetsområde | Anrop | Lyckat svar |
|---|---|---|---|
GET /v2/admin/sites | sites:read | Kropp/fråga: ingen | 200 { items: Site[], metricsWindow: MetricsWindow, lookups { countries, timezones } } |
GET /v2/admin/sites/geocode | sites:read | Fråga: valfria street (högst 160), city, state, country (högst 100 vardera), countryCode (högst 2); valfri Accept-Language-header; minst två tecken sammanlagt i gata/stad/region krävs | 200 { results: GeocodeCandidate[] }; identiska pågående sökningar slås samman och leverantörsarbetet använder en begränsad seriell kö samt en begränsad servercache; ogiltiga sökningar returnerar 400 INVALID_GEOCODE_QUERY, full kö returnerar 429 GEOCODING_BUSY med Retry-After och leverantörsfel returnerar 502 GEOCODING_UNAVAILABLE |
POST /v2/admin/sites | sites:create | Kropp: SiteInput | 201 { site: Site } |
GET /v2/admin/sites/:siteId | sites:read + reports:read | Kropp/fråga: ingen | 200 { site: SiteDetail, recentSessions: SiteSession[], totals, metricsWindow } |
PATCH /v2/admin/sites/:siteId | sites:update | Kropp: fullständig SiteInput | 200 { site: Site } |
DELETE /v2/admin/sites/:siteId | sites:delete | Kropp: ingen | 204 empty; en plats som inte är tom returnerar 409 SITE_NOT_EMPTY |
GET /v2/admin/sites/:siteId/power-management | sites:power-management | Kropp/fråga: ingen | 200 { configuration: PowerConfiguration } med egen plats, laddare/kontakter, grupper, mätarkällor, tilldelningar och kompatibilitetstillstånd |
PUT /v2/admin/sites/:siteId/power-management | sites:power-management | Kropp: PowerConfigurationInput | 200 { configuration: PowerConfiguration }; OCPP-avslag, timeout eller samtidig ändring returnerar 409 POWER_MANAGEMENT_CONFLICT utan att ersättningen tillämpas |
Laddarendpoints
| Metod och sökväg | Behörighetsområde | Anrop | Lyckat svar |
|---|---|---|---|
GET /v2/admin/chargers | chargers:read | Kropp/fråga: ingen | 200 { items: Charger[], metricsWindow: MetricsWindow, connectorLookups { formats, types, powerTypes } } |
POST /v2/admin/chargers | chargers:create | Kropp: ChargerCreate; identifieraren görs till versaler | 201 { charger: Charger }; lösenordet returneras aldrig |
GET /v2/admin/chargers/:chargerId | chargers:read | Kropp/fråga: ingen | 200 { charger: ChargerDetail } |
PATCH /v2/admin/chargers/:chargerId | chargers:update | Kropp: ChargerPatch | 200 { charger: ChargerDetail } |
DELETE /v2/admin/chargers/:chargerId | chargers:delete | Kropp: ingen | 204 empty |
PATCH /v2/admin/chargers/:chargerId/credentials | chargers:credentials | Kropp: { password: string(0..40) } | 200 { success: true } |
PATCH /v2/admin/chargers/:chargerId/connectors/:portId | chargers:connector-settings | Kropp: ConnectorPatch | 200 { connector: Connector } |
PATCH /v2/admin/chargers/:chargerId/public-listing | chargers:public | Kropp: { isPublic: boolean } | 200 { isPublic: boolean }; bristande beredskap returnerar 409 CHARGER_CONFLICT |
GET /v2/admin/chargers/:chargerId/public-readiness | chargers:read | Kropp/fråga: ingen | 200 { readiness: { ready, missingRequirements, connectorIds, missingTariffConnectorIds, ...commercialState } } |
GET /v2/admin/chargers/:chargerId/logs | chargers:read | Fråga: cursor?, limit?=50 (1..200), from?, to?, action?, direction?, levelId? | 200 { items: RedactedOcppLog[], nextCursor: number or null } |
GET /v2/admin/chargers/:chargerId/sessions | chargers:read + reports:read | Fråga: 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/qr | chargers:read | Fråga: connector?: integer[0,255] | 200 image/png-binärdata, 300 px, Content-Disposition: inline, Cache-Control: no-store |
GET /v2/admin/chargers/:chargerId/composite-schedules | chargers:read | Fråga: cursor?, limit?=20 (1..50), connectorId? | 200 { items: CompositeSchedule[], nextCursor: number or null } |
GET /v2/admin/chargers/:chargerId/configuration | chargers:read | Kropp/fråga: ingen | 200 { items: ChargerConfiguration[] }; värden av hemlig karaktär är [REDACTED] |
PATCH /v2/admin/chargers/:chargerId/configuration | chargers:configuration | Kropp: { key: string(1..50), value: string(0..500) } | 200 { status: string }, där status är laddarens/OCPP-resultatet |
POST /v2/admin/chargers/:chargerId/configuration/reload | chargers:configuration | Kropp: ingen | 200 { status: string } |
GET /v2/admin/chargers/:chargerId/firmware | chargers:read | Kropp/fråga: ingen | 200 { firmware: { status, notifiedAt, currentVersion, bootNotifiedAt } } |
POST /v2/admin/chargers/:chargerId/firmware | chargers:firmware | Kropp: { url: HTTP-or-HTTPS URL, max 2048 characters } | 202 { status: string } |
POST /v2/admin/chargers/:chargerId/commands/reset | chargers:commands | Kropp: { resetType: "Soft" or "Hard" } | 200 { status: string } |
POST /v2/admin/chargers/:chargerId/commands/availability | chargers:commands | Kropp: { availabilityType: "Operative" or "Inoperative" } | 200 { status: string } |
POST /v2/admin/chargers/:chargerId/commands/trigger | chargers:commands | Kropp: { messageType: "BootNotification", "Heartbeat", "StatusNotification", or "MeterValues" } | 200 { status: string, connectorResults: { connectorId, status }[] } |
POST /v2/admin/chargers/:chargerId/commands/unlock | chargers:commands | Kropp: { connectorId: positive integer } | 200 { status: string } |
POST /v2/admin/chargers/:chargerId/commands/composite-schedule | chargers:commands | Kropp: { connectorId: nonnegative integer, durationSeconds?: integer[60,604800], chargingRateUnit?: "W" or "A" } | 200 { status: string, connectorId: number, compositeSchedule: CompositeSchedule or null } |
Rapportendpoints
| Metod och sökväg | Behörighetsområde | Anrop | Lyckat svar |
|---|---|---|---|
GET /v2/admin/reports/data | reports:read | Fråga: ReportFilters, ogenomskinlig cursor?, limit?=50 (1..100) | 200 { items: ReportSession[], pageTotals, page { limit, nextCursor }, range { from, to, toExclusive: true } } |
GET /v2/admin/reports/schedule | reports:read | Kropp/fråga: ingen | 200 { schedule: ReportSchedule or null } |
PUT /v2/admin/reports/schedule | reports:schedules | Kropp: strikt ReportScheduleInput | 200 { schedule: ReportSchedule } |
POST /v2/admin/reports/send | reports:send | Kropp: ingen; headern Idempotency-Key krävs | 200 { sent: true, format: "csv" or "pdf", rowCount: number, range { from, to } }; inget sparat schema returnerar 409 REPORT_SCHEDULE_REQUIRED |
GET /v2/admin/reports/measurements | reports:read | Fråga: obligatorisk transactionLogId, ogenomskinlig cursor?, limit?=500 (1..1000) | 200 { transactionLogId, measurements: { name, unit, lines[] }[], page { limit, nextCursor, sampleValuesTruncated, sampleLimitPerMeterValue: 64 } } |
GET /v2/admin/reports/export | reports:export | Fråga: ReportFilters, format?="csv" or "pdf" | 200 CSV/PDF-binärdata med bilagans filnamn, Cache-Control: private, no-store, X-Content-Type-Options: nosniff; fler än 2 000 rader returnerar 422 REPORT_EXPORT_ROW_LIMIT |
Tariffendpoints
| Metod och sökväg | Behörighetsområde | Anrop | Lyckat svar |
|---|---|---|---|
GET /v2/admin/tariffs | tariffs:read | Kropp/fråga: ingen | 200 { items: Tariff[], lookups { currencies, biddingZones, currencyRates, componentTypes, seasons, tariffTypes } } |
POST /v2/admin/tariffs | tariffs:create | Kropp: TariffInput | 201 { tariff: Tariff } |
GET /v2/admin/tariffs/:tariffId | tariffs:read | Kropp/fråga: ingen | 200 { tariff: Tariff, lookups } |
PATCH /v2/admin/tariffs/:tariffId | tariffs:update | Kropp: fullständig TariffInput | 200 { tariff: Tariff } |
PUT /v2/admin/tariffs/:tariffId/components | tariffs:components | Kropp: { components: TariffComponentInput[0..256] } | 200 { tariff: Tariff, components: TariffComponent[] } |
DELETE /v2/admin/tariffs/:tariffId | tariffs:delete | Kropp: ingen | 204 empty; referenser från laddposter returnerar 409 TARIFF_CONFLICT |
GET /v2/admin/tariffs/:tariffId/market-prices | tariffs:read | Fråga: obligatorisk startsAt, icke-negativ Unix-tidsstämpel | 200 { items: { id, value, currencyId, startsAt, endsAt, startsAtIso, endsAtIso, intervalMinutes }[], truncated: boolean }; högst 10 000 rader |
GET /v2/admin/chargers/:chargerId/tariff-assignments | chargers:tariff-assignments + tariffs:read | Kropp/fråga: ingen | 200 { items: TariffAssignment[], tariffs: Tariff[] } |
POST /v2/admin/chargers/:chargerId/tariff-assignments | chargers:tariff-assignments + tariffs:assign | Kropp: TariffAssignmentCreateInput; utelämnad connectorId eller connectorId=0 betyder alla kontakter | 201 { assignments: TariffAssignment[] } |
PATCH /v2/admin/chargers/:chargerId/tariff-assignments/:assignmentId | chargers:tariff-assignments + tariffs:assign | Kropp: TariffAssignmentUpdateInput; kontakt krävs och får inte vara 0 | 200 { assignment: TariffAssignment } |
DELETE /v2/admin/chargers/:chargerId/tariff-assignments/:assignmentId | chargers:tariff-assignments + tariffs:assign | Kropp: ingen | 204 empty |
TariffAssignment innehåller id, chargerId, connectorId, en säker tariff-/valutasammanfattning, createdAt och updatedAt.
Endpoints för laddprofiler
| Metod och sökväg | Behörighetsområde | Anrop | Lyckat svar |
|---|---|---|---|
GET /v2/admin/charging-profiles | chargingProfiles:read | Kropp/fråga: ingen | 200 { items: ChargingProfile[], lookups { locations, purposes, kinds, recurrencyKinds, rateUnits, allowedRateUnits } } |
POST /v2/admin/charging-profiles | chargingProfiles:create | Kropp: ChargingProfileCreate | 201 { profile: ChargingProfile } |
GET /v2/admin/charging-profiles/:profileId | chargingProfiles:read | Kropp/fråga: ingen | 200 { profile: ChargingProfile, lookups, isEditBlocked: boolean, usage { simpleChargingSchedule, smartSchedule, chargePoolChargepoint, isUsed } } |
PATCH /v2/admin/charging-profiles/:profileId | chargingProfiles:update | Kropp: fullständig ChargingProfileInput | 200 { profile: ChargingProfile, ocppSync: OcppCommandResult[] } |
PUT /v2/admin/charging-profiles/:profileId/schedule | chargingProfiles:update | Kropp: ChargingScheduleInput | 200 { profile: ChargingProfile, schedule: SchedulePeriod[], ocppSync: OcppCommandResult[] } |
DELETE /v2/admin/charging-profiles/:profileId | chargingProfiles:delete | Kropp: ingen | 204 empty först efter att alla tilldelade laddare accepterat rensning och tillståndet validerats igen; annars 409 och profilen behålls |
GET /v2/admin/chargers/:chargerId/profile-assignments | chargers:profile-assignments + chargingProfiles:read | Kropp/fråga: ingen | 200 { items: ProfileAssignment[], profiles: ChargingProfile[] } |
POST /v2/admin/chargers/:chargerId/profile-assignments | chargers:profile-assignments + chargingProfiles:assign | Kropp: ProfileAssignmentInput | 201 { assignment: ProfileAssignment, ocpp: OcppCommandResult } |
PATCH /v2/admin/chargers/:chargerId/profile-assignments/:assignmentId | chargers:profile-assignments + chargingProfiles:assign | Kropp: ProfileAssignmentInput | 200 { assignment: ProfileAssignment, ocpp: OcppCommandResult } |
DELETE /v2/admin/chargers/:chargerId/profile-assignments/:assignmentId | chargers:profile-assignments + chargingProfiles:assign | Kropp: ingen | 204 empty efter synkroniserad rensning |
ProfileAssignment innehåller tilldelnings-ID, laddar-/kontakt-ID:n och en säker profilsammanfattning. OCPP-resultatobjekt visar stabil anrops- och statusinformation men aldrig autentiseringsuppgifter.
Endpoints för användare, RFID, åtkomst, gränser och lokala användare
| Metod och sökväg | Behörighetsområde | Anrop | Lyckat svar |
|---|---|---|---|
GET /v2/admin/users | users:read | Fråga: statusanpassad cursor? (members: positiv numerisk; invitations: autentiserad ogenomskinlig i2.*; all: numerisk fortsättning av äldre medlemsström eller autentiserad ogenomskinlig sammansatt a2.*), limit?=50 (1..100), status?="all", "members", or "invitations"; valfri X-Admin-User-Search-header (högst 100) | 200 { items: User[], invitations: Invitation[], chargers: ChargerSummary[], page { nextCursor, memberNextCursor, invitationNextCursor, limit } }; inbjudningar sidindelas och fylls med samma normaliserade e-postuttryck så att äldre användning av versaler/gemener eller blanksteg inte kan dölja rader; markörer är bundna till arbetsyta och sökfilter, innehåller ingen läsbar e-postadress och måste returneras oförändrade; all-markörer för medlems- och inbjudningsströmmar framåt oberoende av varandra |
POST /v2/admin/users | users:create | Kropp: UserCreate; kunden måste redan vara registrerad | 201 { user: User }; en okänd e-postadress returnerar 404 RESOURCE_NOT_FOUND-kroppen utan att avslöja resursens existens och bör använda inbjudningar |
POST /v2/admin/users/invitations | users:invitations + users:access; samt users:rfid om rfid anges | Kropp: InvitationInput | 200 or 201 { result }; kopplat resultat är { kind:"attached", user, accessChanged, rfidChanged }; väntande resultat är { kind:"invited", email, name, maskedRfid, chargerIds, createdCount, emailSent, emailRetryReady, alreadyInvited } |
POST /v2/admin/users/invitations/resend | users:invitations | Kropp: { email: email } | 200 { result: { targetedChargers, emailSent, emailRetryReady } }; mottagarövergripande väntetid tillämpas |
DELETE /v2/admin/users/invitations | users:invitations | Kropp: { email: email } | 204 empty |
GET /v2/admin/users/:userId | users:read + reports:read | Kropp/fråga: ingen | 200 { user: UserDetail, sessions: UserSession[], totals { count, energyWh, durationSeconds }, window, limitTypes, chargers }; högst 200 sessioner under 90 dagar |
PATCH /v2/admin/users/:userId | users:update | Kropp: { name: string(1..255) } | 200 { user: User } |
DELETE /v2/admin/users/:userId | users:delete | Kropp: ingen | 204 empty |
GET /v2/admin/users/:userId/vehicles | users:read | Fråga: numerisk cursor?, limit?=50 (1..100) | 200 { items: Vehicle[], page { nextCursor, limit } }; fordons-DTO:n innehåller säkra fält för leverantör/status/modell/telemetri |
GET /v2/admin/users/:userId/rfids | users:read | Kropp/fråga: ingen | 200 { items: RFID[] }; UID:n maskeras |
POST /v2/admin/users/:userId/rfids | users:rfid | Kropp: { uid: string(1..36), name?: string or null } | 201 { rfid: RFID }; rått UID returneras inte |
PATCH /v2/admin/users/:userId/rfids/:rfidId | users:rfid | Kropp: { name: string or null } | 200 { rfid: RFID } |
DELETE /v2/admin/users/:userId/rfids/:rfidId | users:rfid | Kropp: ingen | 204 empty |
GET /v2/admin/users/:userId/access | users:read | Kropp/fråga: ingen | 200 { access: Access } |
PUT /v2/admin/users/:userId/access | users:access | Kropp: AccessInput | 200 { access: Access } |
DELETE /v2/admin/users/:userId/access/:accessId | users:access | Kropp: ingen | 204 empty |
GET /v2/admin/users/:userId/limits | users:read | Kropp/fråga: ingen | 200 { items: Limit[] } |
POST /v2/admin/users/:userId/limits | users:limits | Kropp: LimitCreate | 201 { limit: Limit } |
PATCH /v2/admin/users/:userId/limits/:limitId | users:limits | Kropp: LimitPatch, minst en egenskap | 200 { limit: Limit } |
DELETE /v2/admin/users/:userId/limits/:limitId | users:limits | Kropp: ingen | 204 empty |
GET /v2/admin/chargers/:chargerId/local-users | chargers:read + users:read | Kropp/fråga: ingen | 200 { charger: ChargerSummary, items: LocalUser[], invitations: { email }[], availableMembers: [] }; API:et utelämnar avsiktligt portalens breda katalog över tillgängliga medlemmar |
POST /v2/admin/chargers/:chargerId/local-users | chargers:local-users + users:access | Kropp: { customerId: positive integer, expiresAt?: RFC3339 or null } | 201 { localUser: LocalUserMutation } |
POST /v2/admin/chargers/:chargerId/local-users/invitations | chargers:local-users + users:invitations + users:access | Kropp: { email: email } | 200 or 201 { result }; befintlig kund: { invited:false, localUser: LocalUserMutation }; inbjudan: { invited:true, alreadyInvited, emailSent, emailRetryReady } |
DELETE /v2/admin/chargers/:chargerId/local-users/invitations | chargers:local-users + users:invitations | Kropp: { email: email } | 204 empty |
PATCH /v2/admin/chargers/:chargerId/local-users/:localUserId | chargers:local-users + users:access | Kropp: { expiresAt: RFC3339 or null } | 200 { localUser: LocalUserUpdate } |
DELETE /v2/admin/chargers/:chargerId/local-users/:localUserId | chargers:local-users + users:access | Kropp: ingen | 204 empty |
Tagless-systemanvändaren skyddas från dessa åtgärder. Fel vid inbjudningsmejl returnerar ett säkert leveranstillstånd utan att läcka SMTP-uppgifter; klienter kan försöka igen när emailRetryReady är sant.
Binära svar
Två endpointgrupper returnerar inte JSON vid framgång:
| Endpoint | Innehållstyp | Viktiga headrar |
|---|---|---|
| Laddarens QR-kod | image/png | Cache-Control: no-store, Content-Disposition: inline, X-Content-Type-Options: nosniff |
| Rapportexport | text/csv; charset=utf-8 eller application/pdf | Cache-Control: private, no-store, Content-Disposition: attachment, X-Content-Type-Options: nosniff |
Fel från binära endpoints är fortfarande JSON.