Punkty końcowe

Żądania i odpowiedzi punktów końcowych API administracyjnego obszaru roboczego

To dokumentacja żądań i odpowiedzi dla każdego punktu końcowego /v2/admin. Uwierzytelnianie, idempotencja, limity częstotliwości, tworzenie tokenów i znaczenie zakresów uprawnień opisano w API administracyjnym obszaru roboczego. Typy pól wielokrotnego użytku i przykłady są w sekcji Schematy i przykłady. Każdy wiersz punktu końcowego czytaj razem z Kontraktem odpowiedzi i błędów, który wymienia wszystkie możliwe wspólne i specyficzne treści odpowiedzi niepowodzenia.

Wspólny kontrakt

Każda ścieżka zaczyna się adresem źródłowym wdrożonej usługi app-api. Obszar roboczy jest wyznaczany wyłącznie na podstawie uwierzytelnionego tokena; klienci nie mogą wysyłać cpoId. Wszystkie udokumentowane wartości :...Id w ścieżkach zasobów są dodatnimi dziesiętnymi liczbami całkowitymi. Każde żądanie wymaga dokładnie jednego:

Authorization: Bearer <workspace-access-token>

Żądania pokazane z treścią JSON wymagają Content-Type: application/json. Wszystkie operacje zmieniające dane wymagają Idempotency-Key (POST, PUT, PATCH i DELETE), w tym POST /v2/admin/reports/send; o ile wiersz nie stanowi inaczej, typ zawartości pomyślnej odpowiedzi to application/json, daty JSON są ciągami RFC 3339, a liczby są liczbami JSON.

Każde żądanie może zawierać X-Request-Id i X-Error-Format: envelope; zobacz Kontrakt odpowiedzi i błędów. Te nagłówki nie zmieniają schematów pomyślnych odpowiedzi.

Oznaczenia używane poniżej:

  • none oznacza brak treści żądania. DELETE, dla którego udokumentowano treść JSON, nadal jej wymaga.
  • ? oznacza opcjonalną właściwość lub parametr zapytania.
  • T | null oznacza, że właściwość występuje i może mieć wartość null.
  • 204 empty oznacza brak treści odpowiedzi.
  • CursorPage<T> oznacza { items: T[], nextCursor: number|string|null }, chyba że wiersz jawnie wskazuje obiekt page lub pagination.
  • Wszystkie przypadki braku zagnieżdżonego zasobu, także identyfikatory z innego obszaru roboczego, używają 404 { "error": "Workspace resource not found", "code": "RESOURCE_NOT_FOUND" }, chyba że dokumentacja funkcji wskazuje bardziej konkretny konflikt.

Wspólne schematy żądań

Dane wejściowe obszaru roboczego i lokalizacji

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
}

Dane wejściowe zarządzania mocą

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
}

Dane wejściowe ładowarek

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]
}

Dane wejściowe raportów

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"
}

Zakresy raportów muszą spełniać from < to i nie mogą przekraczać 90 dni. Po pominięciu używane są ostatnie 90 dni. userId i anonymous=true wzajemnie się wykluczają. Zaplanowane eksporty nadrabiają pominiętą minutę UTC i używają ograniczonych ponowień (odstęp 5/10 minut, 30-minutowa rezerwacja przeterminowanego zadania, trzy próby).

Dane wejściowe taryf

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 }

Dane wejściowe profili ładowania

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 }

Dane wejściowe użytkowników

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 }

Podczas tworzenia limitu co najmniej jedno z pól energyValue lub timeValue musi być większe od zera. Z adresów e-mail usuwane są skrajne spacje, a litery zmieniane na małe. UID RFID są przyjmowane tylko przy zapisie i maskowane w odpowiedziach odczytu.

Podsumowanie DTO odpowiedzi

Tabele punktów końcowych pokazują każde opakowanie odpowiedzi najwyższego poziomu. To główne wielokrotnie używane DTO wewnątrz tych opakowań:

DTOPola
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; szczegóły dodają znormalizowane chargers i stan złącza
GeocodeCandidateplaceId, displayName, latitude, longitude; dane uwierzytelniające dostawcy i jego specyficzne metadane nigdy nie są zwracane
MetricsWindowfrom, to, limity/liczniki sesji i totalsCapped, jeśli dotyczy
Chargerid, name, identifier, cpoId, site, znormalizowane status, isPublic, flagi RFID/inteligentnego ładowania/automatyzacji, provisioned, connection, evses, connectors, createdAt, updatedAt; szczegóły dodają configuration z ukrytymi danymi wrażliwymi, firmware i liczniki
ConnectorportId, connectorId, identyfikatory słowników złącza, maxVoltage, maxAmperage, maxElectricPower
ReportSessionid, ładowarka/lokalizacja, identyfikatory portu i złącza, minimalne dane użytkownika, active, energyWh, początek/koniec/czas trwania i koszty netto/podatku/całości według waluty
ReportScheduleid, workspaceId, enabled, recipientEmail, format, UTC sendDay/sendTime, metadane utworzenia/aktualizacji i bezpieczne metadane ostatniego dostarczenia, w tym liczba prób
Tariffid, cpoId, name, obiekty typu/lokalizacji/waluty/strefy rynkowej, tax, fallbackPrice, efektywne price, components, assignmentCount
ChargingProfileid, cpoId, label, description, stackLevel, obiekty lokalizacji/przeznaczenia/rodzaju/powtarzania/jednostki limitu, ważność, harmonogram, assignmentCount, znaczniki czasu
Userid, membershipId, name, email, zamaskowane rfids, access ładowarki, limitCount; szczegóły dodają phone, createdAt i limits. Dane autoryzacji OCPP, takie jak contractId, nigdy nie są zwracane.
RFIDid, maskedUid, name, type, valid; surowy UID nigdy nie jest zwracany
AccessallChargers, posortowane chargerIds i items zawierające metadane dostępu/ładowarki/lokalizacji/wygaśnięcia
Limitid, limitTypeId, label, energyValue, timeValue
LocalUserDTO listy: id, customerId, name, email, expiresAt, systemManaged. Operacje zmieniające użytkowników lokalnych używają odrębnych struktur LocalUserMutation/LocalUserUpdate opisanych w sekcji Schematy i przykłady.

Obiekty słownikowe są zwracane przez ścieżki list i szczegółów, aby wywołujący mogli odkrywać prawidłowe identyfikatory. Nieznane dodane pola traktuj jako rozszerzenia zgodne z przyszłymi wersjami, a decyzje opieraj wyłącznie na udokumentowanych stabilnych polach i kodach błędów.

Punkty końcowe obszaru roboczego

Metoda i ścieżkaZakres uprawnieńŻądaniePomyślna odpowiedź
GET /v2/adminworkspaces:readTreść: brak200 { workspace: Workspace }
PATCH /v2/adminworkspaces:updateTreść: WorkspacePatch200 { workspace: Workspace }
GET /v2/admin/dashboardworkspaces:read + reports:readTreść/parametry zapytania: brak200 { window, stats { chargerCount, onlineChargerCount, siteCount, userCount }, sessions: DashboardSession[], analytics }; sesje są ograniczone do 1000 w ciągu 90 dni

Punkty końcowe lokalizacji i zarządzania mocą

Metoda i ścieżkaZakres uprawnieńŻądaniePomyślna odpowiedź
GET /v2/admin/sitessites:readTreść/parametry zapytania: brak200 { items: Site[], metricsWindow: MetricsWindow, lookups { countries, timezones } }
GET /v2/admin/sites/geocodesites:readZapytanie: opcjonalne street (maks. 160), city, state, country (każde maks. 100), countryCode (maks. 2); opcjonalny nagłówek Accept-Language; wymagane są łącznie co najmniej dwa znaki ulicy/miasta/regionu200 { results: GeocodeCandidate[] }; identyczne wyszukiwania w toku są łączone, a operacje dostawcy używają ograniczonej kolejki sekwencyjnej i ograniczonej pamięci podręcznej serwera; nieprawidłowe wyszukiwania zwracają 400 INVALID_GEOCODE_QUERY, zapełniona kolejka zwraca 429 GEOCODING_BUSY z Retry-After, a awarie dostawcy zwracają 502 GEOCODING_UNAVAILABLE
POST /v2/admin/sitessites:createTreść: SiteInput201 { site: Site }
GET /v2/admin/sites/:siteIdsites:read + reports:readTreść/parametry zapytania: brak200 { site: SiteDetail, recentSessions: SiteSession[], totals, metricsWindow }
PATCH /v2/admin/sites/:siteIdsites:updateTreść: pełny SiteInput200 { site: Site }
DELETE /v2/admin/sites/:siteIdsites:deleteTreść: brak204 empty; niepusta lokalizacja zwraca 409 SITE_NOT_EMPTY
GET /v2/admin/sites/:siteId/power-managementsites:power-managementTreść/parametry zapytania: brak200 { configuration: PowerConfiguration } zawierające należącą do obszaru lokalizację, ładowarki/złącza, grupy, źródła pomiarowe, przypisania i stan zgodności
PUT /v2/admin/sites/:siteId/power-managementsites:power-managementTreść: PowerConfigurationInput200 { configuration: PowerConfiguration }; odmowa OCPP, przekroczenie czasu lub współbieżna zmiana zwraca 409 POWER_MANAGEMENT_CONFLICT bez zastosowania zastąpienia

Punkty końcowe ładowarek

Metoda i ścieżkaZakres uprawnieńŻądaniePomyślna odpowiedź
GET /v2/admin/chargerschargers:readTreść/parametry zapytania: brak200 { items: Charger[], metricsWindow: MetricsWindow, connectorLookups { formats, types, powerTypes } }
POST /v2/admin/chargerschargers:createTreść: ChargerCreate; identyfikator jest zamieniany na wielkie litery201 { charger: Charger }; hasło nigdy nie jest zwracane
GET /v2/admin/chargers/:chargerIdchargers:readTreść/parametry zapytania: brak200 { charger: ChargerDetail }
PATCH /v2/admin/chargers/:chargerIdchargers:updateTreść: ChargerPatch200 { charger: ChargerDetail }
DELETE /v2/admin/chargers/:chargerIdchargers:deleteTreść: brak204 empty
PATCH /v2/admin/chargers/:chargerId/credentialschargers:credentialsTreść: { password: string(0..40) }200 { success: true }
PATCH /v2/admin/chargers/:chargerId/connectors/:portIdchargers:connector-settingsTreść: ConnectorPatch200 { connector: Connector }
PATCH /v2/admin/chargers/:chargerId/public-listingchargers:publicTreść: { isPublic: boolean }200 { isPublic: boolean }; niespełnione warunki gotowości zwracają 409 CHARGER_CONFLICT
GET /v2/admin/chargers/:chargerId/public-readinesschargers:readTreść/parametry zapytania: brak200 { readiness: { ready, missingRequirements, connectorIds, missingTariffConnectorIds, ...commercialState } }
GET /v2/admin/chargers/:chargerId/logschargers:readZapytanie: 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:readZapytanie: 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:readZapytanie: connector?: integer[0,255]200 image/png binarny, 300 px, Content-Disposition: inline, Cache-Control: no-store
GET /v2/admin/chargers/:chargerId/composite-scheduleschargers:readZapytanie: cursor?, limit?=20 (1..50), connectorId?200 { items: CompositeSchedule[], nextCursor: number or null }
GET /v2/admin/chargers/:chargerId/configurationchargers:readTreść/parametry zapytania: brak200 { items: ChargerConfiguration[] }; wartości przypominające sekrety to [REDACTED]
PATCH /v2/admin/chargers/:chargerId/configurationchargers:configurationTreść: { key: string(1..50), value: string(0..500) }200 { status: string }, gdzie status jest wynikiem ładowarki/OCPP
POST /v2/admin/chargers/:chargerId/configuration/reloadchargers:configurationTreść: brak200 { status: string }
GET /v2/admin/chargers/:chargerId/firmwarechargers:readTreść/parametry zapytania: brak200 { firmware: { status, notifiedAt, currentVersion, bootNotifiedAt } }
POST /v2/admin/chargers/:chargerId/firmwarechargers:firmwareTreść: { url: HTTP-or-HTTPS URL, max 2048 characters }202 { status: string }
POST /v2/admin/chargers/:chargerId/commands/resetchargers:commandsTreść: { resetType: "Soft" or "Hard" }200 { status: string }
POST /v2/admin/chargers/:chargerId/commands/availabilitychargers:commandsTreść: { availabilityType: "Operative" or "Inoperative" }200 { status: string }
POST /v2/admin/chargers/:chargerId/commands/triggerchargers:commandsTreść: { messageType: "BootNotification", "Heartbeat", "StatusNotification", or "MeterValues" }200 { status: string, connectorResults: { connectorId, status }[] }
POST /v2/admin/chargers/:chargerId/commands/unlockchargers:commandsTreść: { connectorId: positive integer }200 { status: string }
POST /v2/admin/chargers/:chargerId/commands/composite-schedulechargers:commandsTreść: { connectorId: nonnegative integer, durationSeconds?: integer[60,604800], chargingRateUnit?: "W" or "A" }200 { status: string, connectorId: number, compositeSchedule: CompositeSchedule or null }

Punkty końcowe raportów

Metoda i ścieżkaZakres uprawnieńŻądaniePomyślna odpowiedź
GET /v2/admin/reports/datareports:readZapytanie: ReportFilters, nieprzezroczysty cursor?, limit?=50 (1..100)200 { items: ReportSession[], pageTotals, page { limit, nextCursor }, range { from, to, toExclusive: true } }
GET /v2/admin/reports/schedulereports:readTreść/parametry zapytania: brak200 { schedule: ReportSchedule or null }
PUT /v2/admin/reports/schedulereports:schedulesTreść: ścisły schemat ReportScheduleInput200 { schedule: ReportSchedule }
POST /v2/admin/reports/sendreports:sendTreść: brak; nagłówek Idempotency-Key jest wymagany200 { sent: true, format: "csv" or "pdf", rowCount: number, range { from, to } }; brak zapisanego harmonogramu zwraca 409 REPORT_SCHEDULE_REQUIRED
GET /v2/admin/reports/measurementsreports:readZapytanie: wymagane transactionLogId, nieprzezroczysty cursor?, limit?=500 (1..1000)200 { transactionLogId, measurements: { name, unit, lines[] }[], page { limit, nextCursor, sampleValuesTruncated, sampleLimitPerMeterValue: 64 } }
GET /v2/admin/reports/exportreports:exportZapytanie: ReportFilters, format?="csv" or "pdf"200 binarny CSV/PDF z nazwą pliku załącznika, Cache-Control: private, no-store, X-Content-Type-Options: nosniff; więcej niż 2000 wierszy zwraca 422 REPORT_EXPORT_ROW_LIMIT

Punkty końcowe taryf

Metoda i ścieżkaZakres uprawnieńŻądaniePomyślna odpowiedź
GET /v2/admin/tariffstariffs:readTreść/parametry zapytania: brak200 { items: Tariff[], lookups { currencies, biddingZones, currencyRates, componentTypes, seasons, tariffTypes } }
POST /v2/admin/tariffstariffs:createTreść: TariffInput201 { tariff: Tariff }
GET /v2/admin/tariffs/:tariffIdtariffs:readTreść/parametry zapytania: brak200 { tariff: Tariff, lookups }
PATCH /v2/admin/tariffs/:tariffIdtariffs:updateTreść: pełny TariffInput200 { tariff: Tariff }
PUT /v2/admin/tariffs/:tariffId/componentstariffs:componentsTreść: { components: TariffComponentInput[0..256] }200 { tariff: Tariff, components: TariffComponent[] }
DELETE /v2/admin/tariffs/:tariffIdtariffs:deleteTreść: brak204 empty; odwołania z rekordów ładowania zwracają 409 TARIFF_CONFLICT
GET /v2/admin/tariffs/:tariffId/market-pricestariffs:readZapytanie: wymagane startsAt, nieujemny znacznik czasu Unix200 { items: { id, value, currencyId, startsAt, endsAt, startsAtIso, endsAtIso, intervalMinutes }[], truncated: boolean }; maksymalnie 10 000 wierszy
GET /v2/admin/chargers/:chargerId/tariff-assignmentschargers:tariff-assignments + tariffs:readTreść/parametry zapytania: brak200 { items: TariffAssignment[], tariffs: Tariff[] }
POST /v2/admin/chargers/:chargerId/tariff-assignmentschargers:tariff-assignments + tariffs:assignTreść: TariffAssignmentCreateInput; pominięcie connectorId lub connectorId=0 oznacza wszystkie złącza201 { assignments: TariffAssignment[] }
PATCH /v2/admin/chargers/:chargerId/tariff-assignments/:assignmentIdchargers:tariff-assignments + tariffs:assignTreść: TariffAssignmentUpdateInput; złącze jest wymagane i nie może mieć wartości 0200 { assignment: TariffAssignment }
DELETE /v2/admin/chargers/:chargerId/tariff-assignments/:assignmentIdchargers:tariff-assignments + tariffs:assignTreść: brak204 empty

TariffAssignment zawiera id, chargerId, connectorId, bezpieczne podsumowanie taryfy/waluty, createdAt i updatedAt.

Punkty końcowe profili ładowania

Metoda i ścieżkaZakres uprawnieńŻądaniePomyślna odpowiedź
GET /v2/admin/charging-profileschargingProfiles:readTreść/parametry zapytania: brak200 { items: ChargingProfile[], lookups { locations, purposes, kinds, recurrencyKinds, rateUnits, allowedRateUnits } }
POST /v2/admin/charging-profileschargingProfiles:createTreść: ChargingProfileCreate201 { profile: ChargingProfile }
GET /v2/admin/charging-profiles/:profileIdchargingProfiles:readTreść/parametry zapytania: brak200 { profile: ChargingProfile, lookups, isEditBlocked: boolean, usage { simpleChargingSchedule, smartSchedule, chargePoolChargepoint, isUsed } }
PATCH /v2/admin/charging-profiles/:profileIdchargingProfiles:updateTreść: pełny ChargingProfileInput200 { profile: ChargingProfile, ocppSync: OcppCommandResult[] }
PUT /v2/admin/charging-profiles/:profileId/schedulechargingProfiles:updateTreść: ChargingScheduleInput200 { profile: ChargingProfile, schedule: SchedulePeriod[], ocppSync: OcppCommandResult[] }
DELETE /v2/admin/charging-profiles/:profileIdchargingProfiles:deleteTreść: brak204 empty dopiero po zaakceptowaniu czyszczenia przez wszystkie przypisane ładowarki i ponownej walidacji stanu; w przeciwnym razie 409, a profil pozostaje
GET /v2/admin/chargers/:chargerId/profile-assignmentschargers:profile-assignments + chargingProfiles:readTreść/parametry zapytania: brak200 { items: ProfileAssignment[], profiles: ChargingProfile[] }
POST /v2/admin/chargers/:chargerId/profile-assignmentschargers:profile-assignments + chargingProfiles:assignTreść: ProfileAssignmentInput201 { assignment: ProfileAssignment, ocpp: OcppCommandResult }
PATCH /v2/admin/chargers/:chargerId/profile-assignments/:assignmentIdchargers:profile-assignments + chargingProfiles:assignTreść: ProfileAssignmentInput200 { assignment: ProfileAssignment, ocpp: OcppCommandResult }
DELETE /v2/admin/chargers/:chargerId/profile-assignments/:assignmentIdchargers:profile-assignments + chargingProfiles:assignTreść: brak204 empty po zsynchronizowanym wyczyszczeniu

ProfileAssignment zawiera identyfikator przypisania, identyfikatory ładowarki/złącza i bezpieczne podsumowanie profilu. Obiekty wyników OCPP ujawniają stabilne informacje żądania/statusu, nigdy dane uwierzytelniające.

Punkty końcowe użytkowników, RFID, dostępu, limitów i użytkowników lokalnych

Metoda i ścieżkaZakres uprawnieńŻądaniePomyślna odpowiedź
GET /v2/admin/usersusers:readZapytanie: cursor? zgodne ze statusem (members: dodatnie liczbowe; invitations: uwierzytelniony nieprzezroczysty i2.*; all: liczbowa kontynuacja starszego strumienia członków lub uwierzytelniony nieprzezroczysty kursor złożony a2.*), limit?=50 (1..100), status?="all", "members", or "invitations"; opcjonalny nagłówek X-Admin-User-Search (maks. 100)200 { items: User[], invitations: Invitation[], chargers: ChargerSummary[], page { nextCursor, memberNextCursor, invitationNextCursor, limit } }; zaproszenia są stronicowane i uzupełniane danymi przy użyciu tego samego wyrażenia znormalizowanego adresu e-mail, aby historyczne różnice wielkości liter lub spacji nie ukrywały wierszy; kursory są związane z obszarem roboczym i filtrem wyszukiwania, nie zawierają czytelnego adresu e-mail i muszą być odsyłane bez zmian; kursory all niezależnie przesuwają strumienie członków i zaproszeń
POST /v2/admin/usersusers:createTreść: UserCreate; klient musi być już zarejestrowany201 { user: User }; nieznany adres e-mail zwraca treść 404 RESOURCE_NOT_FOUND, która nie ujawnia istnienia zasobu; należy użyć zaproszeń
POST /v2/admin/users/invitationsusers:invitations + users:access; dodatkowo users:rfid, jeśli podano rfidTreść: InvitationInput200 or 201 { result }; wynik dołączenia to { kind:"attached", user, accessChanged, rfidChanged }; wynik oczekujący to { kind:"invited", email, name, maskedRfid, chargerIds, createdCount, emailSent, emailRetryReady, alreadyInvited }
POST /v2/admin/users/invitations/resendusers:invitationsTreść: { email: email }200 { result: { targetedChargers, emailSent, emailRetryReady } }; egzekwowany jest wspólny dla odbiorcy odstęp między wysyłkami niezależnie od źródła żądań
DELETE /v2/admin/users/invitationsusers:invitationsTreść: { email: email }204 empty
GET /v2/admin/users/:userIdusers:read + reports:readTreść/parametry zapytania: brak200 { user: UserDetail, sessions: UserSession[], totals { count, energyWh, durationSeconds }, window, limitTypes, chargers }; maksymalnie 200 sesji w ciągu 90 dni
PATCH /v2/admin/users/:userIdusers:updateTreść: { name: string(1..255) }200 { user: User }
DELETE /v2/admin/users/:userIdusers:deleteTreść: brak204 empty
GET /v2/admin/users/:userId/vehiclesusers:readZapytanie: liczbowe cursor?, limit?=50 (1..100)200 { items: Vehicle[], page { nextCursor, limit } }; DTO pojazdu zawiera bezpieczne pola dostawcy/statusu/modelu/telemetrii
GET /v2/admin/users/:userId/rfidsusers:readTreść/parametry zapytania: brak200 { items: RFID[] }; UID są maskowane
POST /v2/admin/users/:userId/rfidsusers:rfidTreść: { uid: string(1..36), name?: string or null }201 { rfid: RFID }; surowy UID nie jest odsyłany
PATCH /v2/admin/users/:userId/rfids/:rfidIdusers:rfidTreść: { name: string or null }200 { rfid: RFID }
DELETE /v2/admin/users/:userId/rfids/:rfidIdusers:rfidTreść: brak204 empty
GET /v2/admin/users/:userId/accessusers:readTreść/parametry zapytania: brak200 { access: Access }
PUT /v2/admin/users/:userId/accessusers:accessTreść: AccessInput200 { access: Access }
DELETE /v2/admin/users/:userId/access/:accessIdusers:accessTreść: brak204 empty
GET /v2/admin/users/:userId/limitsusers:readTreść/parametry zapytania: brak200 { items: Limit[] }
POST /v2/admin/users/:userId/limitsusers:limitsTreść: LimitCreate201 { limit: Limit }
PATCH /v2/admin/users/:userId/limits/:limitIdusers:limitsTreść: LimitPatch, co najmniej jedna właściwość200 { limit: Limit }
DELETE /v2/admin/users/:userId/limits/:limitIdusers:limitsTreść: brak204 empty
GET /v2/admin/chargers/:chargerId/local-userschargers:read + users:readTreść/parametry zapytania: brak200 { charger: ChargerSummary, items: LocalUser[], invitations: { email }[], availableMembers: [] }; API celowo pomija szeroki katalog dostępnych członków portalu
POST /v2/admin/chargers/:chargerId/local-userschargers:local-users + users:accessTreść: { customerId: positive integer, expiresAt?: RFC3339 or null }201 { localUser: LocalUserMutation }
POST /v2/admin/chargers/:chargerId/local-users/invitationschargers:local-users + users:invitations + users:accessTreść: { email: email }200 or 201 { result }; istniejący klient: { invited:false, localUser: LocalUserMutation }; zaproszenie: { invited:true, alreadyInvited, emailSent, emailRetryReady }
DELETE /v2/admin/chargers/:chargerId/local-users/invitationschargers:local-users + users:invitationsTreść: { email: email }204 empty
PATCH /v2/admin/chargers/:chargerId/local-users/:localUserIdchargers:local-users + users:accessTreść: { expiresAt: RFC3339 or null }200 { localUser: LocalUserUpdate }
DELETE /v2/admin/chargers/:chargerId/local-users/:localUserIdchargers:local-users + users:accessTreść: brak204 empty

Użytkownik systemowy Tagless jest chroniony przed tymi operacjami. Niepowodzenia wysyłki zaproszenia e-mailem zwracają bezpieczny stan dostarczenia bez ujawniania szczegółów SMTP; wywołujący mogą ponowić próbę, gdy emailRetryReady ma wartość true.

Odpowiedzi binarne

Dwie grupy punktów końcowych nie zwracają JSON przy powodzeniu:

Punkt końcowyTyp zawartościWażne nagłówki
QR ładowarkiimage/pngCache-Control: no-store, Content-Disposition: inline, X-Content-Type-Options: nosniff
Eksport raportutext/csv; charset=utf-8 lub application/pdfCache-Control: private, no-store, Content-Disposition: attachment, X-Content-Type-Options: nosniff

Błędy binarnych punktów końcowych nadal mają format JSON.