Esquemas y ejemplos

Esquemas y ejemplos de Admin API

Este archivo define los tipos JSON reutilizables citados en la Referencia de endpoints. ? indica que la entrada es opcional; | null indica que la propiedad está presente y admite null en la salida, salvo indicación contraria del endpoint. DateTime es una cadena RFC 3339; las fechas y horas de las solicitudes deben incluir un desplazamiento horario.

Tipos primitivos y de referencia

PositiveInt = integer > 0
NonnegativeInt = integer >= 0
DateTime = RFC3339 string, for example "2026-08-24T12:30:00Z"
NamedLookup = { id: PositiveInt, name: string }
SiteRef = { id: PositiveInt, name: string|null }
Cost = { currency: string, net: number, tax: number, total: number }

Se deben ignorar los campos futuros desconocidos. Los ID son números JSON, excepto los cursores opacos y los ID de tokens de acceso gestionados por el portal. La API no devuelve UID RFID sin enmascarar, contraseñas de cargadores, tokens de espacios de trabajo, contractId, secretos de proveedores ni valores de configuración de tipo secreto sin ocultar.

Conversión de tipos en solicitudes y propiedades desconocidas

La API no aplica una única política global de conversión numérica:

  • Cada ID de recurso en la ruta y cada parámetro numérico de consulta acepta una cadena decimal como "12" si cumple la restricción de entero e intervalo documentada.
  • El countryId del espacio de trabajo, countryId/timezoneId del emplazamiento, los campos numéricos del emplazamiento/conector del cargador y de comandos, todos los campos numéricos de tarifas y todos los de perfiles de carga también se convierten a partir de cadenas JSON numéricas.
  • La latitud/longitud del emplazamiento, el smartMode del cargador, todos los números de gestión de potencia y de programación de informes y los ID y valores de cuerpos de usuarios/RFID/acceso/límites/usuarios locales requieren números JSON y no se convierten automáticamente.
  • Los objetos de cuerpo de tarifas, perfiles de carga, programaciones de informes y usuarios rechazan propiedades desconocidas con 422. Los objetos de espacio de trabajo, emplazamiento, gestión de potencia y otros objetos de cargadores/informes y de consulta ignoran las propiedades desconocidas.

Estos detalles describen el comportamiento de transporte, no una recomendación: los clientes deben enviar números JSON para los campos numéricos del cuerpo.

Tipos de espacios de trabajo y emplazamientos

Workspace = {
  id: PositiveInt,
  name: string,
  email: string|null,
  website: string|null,
  address: {
    line1: string|null, line2: string|null, postalCode: string|null,
    city: string|null, state: string|null, countryId: PositiveInt,
    countryCode: string, countryName: string
  },
  createdAt: DateTime,
  updatedAt: DateTime
}

Site = {
  id: PositiveInt,
  name: string,
  description: string|null,
  address: {
    line1: string|null, line2: string|null, postalCode: string|null,
    city: string|null, state: string|null, countryId: PositiveInt,
    countryCode: string, countryName: string
  },
  timezone: { id: PositiveInt, name: string },
  latitude: number|null,
  longitude: number|null,
  chargerCount: integer
}

SiteSession = {
  id: PositiveInt,
  charger: { id: PositiveInt, name: string },
  portId: PositiveInt,
  connectorId: integer,
  active: boolean,
  startedAt: DateTime,
  stoppedAt: DateTime|null,
  durationSeconds: integer|null,
  energyWh: number,
  costs: Cost[]
}

MetricsWindow = {
  from: DateTime, to: DateTime, sessionLimit: integer,
  sessionsIncluded: integer, totalsCapped: boolean
}

GET /sites/:siteId devuelve { site, recentSessions, totals, metricsWindow }. Su site añade el estado de los cargadores/conectores propios a la proyección base del emplazamiento; totals contiene sessions, energyWh, energyKwh, durationSeconds y costs: Cost[].

Los valores de referencia de emplazamientos son { countries: {countryId, countryCode, name}[], timezones: {timezoneId, name}[] }, con ID numéricos y nombres/códigos de tipo cadena.

DashboardSession = {
  id: PositiveInt, chargerId: PositiveInt, connectorId: PositiveInt,
  userId: PositiveInt|null, userName: string|null, chargerName: string|null,
  site: SiteRef|null, status: string|null, energyWh: number,
  startedAt: DateTime|null, stoppedAt: DateTime|null,
  costs: Array<{ currency: string|null, price: number, tax: number }>
}

Dashboard = {
  window: { from: DateTime, to: DateTime, maxSessions: 1000 },
  stats: { chargerCount: integer, onlineChargerCount: integer, siteCount: integer, userCount: integer },
  sessions: DashboardSession[],
  analytics: {
    totals: { sessions: integer, energyWh: number, durationSeconds: integer, costs: Array<{currency:string, amount:number}> },
    daily: Array<{ date:string, sessions:integer, energyWh:number, costs:Array<{currency:string, amount:number}> }>,
    sites: Array<{ id:PositiveInt, name:string|null, sessions:integer, energyWh:number, costs:Array<{currency:string, amount:number}> }>,
    chargers: Array<{ id:PositiveInt, name:string|null, siteId:PositiveInt|null, siteName:string|null, sessions:integer, energyWh:number, costs:Array<{currency:string, amount:number}> }>
  }
}

SiteDetailCharger = {
  id: PositiveInt, name: string|null, identifier: string|null, status: string,
  connection: { lastSeenAt: DateTime|null, leaseExpiresAt: DateTime|null }|null,
  connectors: Array<{ evseId:PositiveInt, evseNumber:integer, portId:PositiveInt, connectorId:integer, status:string|null }>,
  sessionCount: integer,
  totals: { sessions:integer, energyWh:number, energyKwh:number, durationSeconds:integer, costs:Cost[] }
}

Ejemplo de actualización de un espacio de trabajo y su respuesta:

PATCH /v2/admin
Authorization: Bearer evc_ws_<selector>.<secret>
Idempotency-Key: workspace-contact-20260824
Content-Type: application/json

{"email":"ops@example.com","city":"Riga"}
{
  "workspace": {
    "id": 7,
    "name": "Example CPO",
    "email": "ops@example.com",
    "website": null,
    "address": {
      "line1": "1 Example Street",
      "line2": null,
      "postalCode": "LV-1001",
      "city": "Riga",
      "state": null,
      "countryId": 1,
      "countryCode": "LV",
      "countryName": "Latvia"
    },
    "createdAt": "2026-01-01T00:00:00.000Z",
    "updatedAt": "2026-08-24T12:30:00.000Z"
  }
}

Ejemplo de creación/actualización de emplazamiento; se pueden omitir los campos con valores predeterminados:

{
  "name": "Main depot",
  "addressLine1": "1 Example Street",
  "city": "Riga",
  "countryId": 1,
  "timezoneId": 1,
  "latitude": 56.9496,
  "longitude": 24.1052
}

Respuesta de gestión de potencia

PowerConfiguration = {
  site: { id: PositiveInt, updatedAt: DateTime },
  chargepoints: Array<{
    id: PositiveInt, name: string|null,
    compatible: boolean, compatibility: string, // values come from shared capability projection
    ...additional smart-charging capability flags
  }>,
  pools: Array<{
    id: PositiveInt, parentId: PositiveInt|null, name: string|null,
    limit: integer, defaultLimit: integer|null, mode: integer|string|null
  }>,
  assignments: Array<{
    poolId: PositiveInt, chargepointId: PositiveInt, priority: integer,
    chargingProfileId: PositiveInt|null,
    chargingProfileSynced: integer|null,
    limit: number|null
  }>,
  meterSources: Array<{
    id: PositiveInt, poolId: PositiveInt, sourceId: PositiveInt,
    provider: string, name: string|null, externalId: string,
    measurementMode: string, valueMode: string,
    reserveA: integer, offlineSafeA: integer, ttlSeconds: integer,
    enabled: boolean, lastComputedLimitA: number|null,
    lastComputedAt: DateTime|null, lastStatus: string|null,
    lastSeenAt: DateTime|null, effectiveLimitA: number|null
  }>,
  connectors: Array<{
    id: PositiveInt, connectorId: integer, chargepointId: PositiveInt,
    status: string|null
  }>
}

Los nombres exactos de los campos adicionales de compatibilidad los genera smartChargingCompatibility(); el tipo de retorno de esa función auxiliar no tiene un nombre explícito en el código. Es el único fragmento de respuesta cuya lista cerrada de campos no se puede determinar a partir de un tipo exportado, por lo que los campos adicionales se indican deliberadamente como inciertos en lugar de inventarlos.

Ejemplo de sustitución:

{
  "pools": [
    {
      "name": "Depot supply",
      "limit": 125,
      "meterSources": [
        {
          "externalId": "meter-42",
          "measurementMode": "available_headroom",
          "enabled": true
        }
      ],
      "children": [
        {"chargepointId": 11, "priority": 10},
        {"name": "Secondary", "limit": 32, "children": []}
      ]
    }
  ]
}

Tipos de cargador

Charger = {
  id: PositiveInt, name: string, identifier: string, cpoId: PositiveInt,
  site: { id: PositiveInt, name: string }, status: string,
  isPublic: boolean, invertedRfid: boolean, smartMode: integer,
  automationDisabled: boolean, provisioned: boolean,
  connection: {
    protocol: string|null, lastSeenAt: DateTime|null, leaseExpiresAt: DateTime|null
  } | null,
  evses: Array<{ id: PositiveInt, number: integer, status: string|null }>,
  connectors: Array<{
    evseId: PositiveInt, evseNumber: integer, status: string|null,
    id: PositiveInt, connectorId: integer, portNumber: integer,
    format: { id: PositiveInt, name: string, description: string|null },
    type: { id: PositiveInt, name: string, description: string|null },
    powerType: { id: PositiveInt, name: string, description: string|null },
    maxVoltage: number, maxAmperage: number, maxElectricPower: number,
    maxPowerKw: number
  }>,
  createdAt: DateTime, updatedAt: DateTime
}

ChargerDetail = Charger & {
  configuration: Array<{
    chargepointConfigId: PositiveInt, key: string,
    value: string|null, readonly: boolean|number, setByServer: boolean|number,
    modified: DateTime
  }>,
  firmware: { status: string|null, statusAt: DateTime|null, version: string|null, bootAt: DateTime|null },
  counts: { localUsers: integer, sessions: integer, tariffAssignments: integer, profileAssignments: integer }
}

La proyección de lista añade campos de métricas acotadas y devuelve metricsWindow; la de detalle utiliza la estructura anterior. Los valores de configuración de claves sensibles son exactamente "[REDACTED]".

PublicReadiness = {
  ready: boolean,
  missingRequirements: Array<"site_coordinates"|"connector_tariffs"|"billing_plan"|"stripe_connect"|"legacy_payment_data">,
  commercialGateEnabled: boolean, siteCoordinatesDefined: boolean,
  allConnectorsHaveTariffs: boolean, connectorsMissingTariffs: integer[],
  connectorCount: integer, paymentDataDefined: boolean,
  billingAccountId: PositiveInt|null, planCode: string|null,
  billingPlanEligible: boolean, stripeConnectReady: boolean,
  stripeConnectState: "active"|"action_required"|"pending"|"not_configured",
  connectorIds: integer[], missingTariffConnectorIds: integer[]
}

RedactedOcppLog = {
  ocppServerLogId: PositiveInt, timestamp: DateTime, logLevelId: PositiveInt,
  logAction: string|null, logDirection: string|null, logMessage: string|null,
  messageId: string|null, transactionLogId: PositiveInt|null,
  logLevel: { name:string }|null
}

CompositeSchedule = {
  id: PositiveInt, chargepointId: PositiveInt, connectorId: integer,
  evseId: PositiveInt|null, scheduleStart: DateTime, duration: integer,
  minChargingRate: number|null, chargingRateUnitId: PositiveInt,
  chargingRateUnit: string|null, chargingRateUnitDescription: string|null,
  periods: Array<{ id:PositiveInt, startPeriod:number, limit:number, numberPhases:integer|null, phaseToUse:integer|null }>
}

Una actualización correcta del conector devuelve exactamente { portId, connectorId, ocpiConnectorFormatEnumId, ocpiConnectorTypeEnumId, ocpiPowerTypeEnumId, maxVoltage, maxAmperage, maxElectricPower }.

connectorLookups contiene estas estructuras de referencia: los formatos utilizan { ocpiConnectorFormatEnumId, name, description }; los tipos, { ocpiConnectorTypeEnumId, name, description, icon }; los tipos de alimentación, { ocpiPowerTypeEnumId, name, shortDescr, description, numPhases }.

Ejemplos de creación y actualización de conectores:

{"name":"Warehouse 1","identifier":"cp-warehouse-1","password":"initial-secret","siteId":3}
{
  "connectorFormatId": 1,
  "connectorTypeId": 2,
  "powerTypeId": 1,
  "maxVoltage": 400,
  "maxAmperage": 32,
  "maxElectricPower": 22000
}

Los objetos de respuesta de comandos contienen status: string. Trigger también contiene connectorResults: { connectorId: number, status: string }[]; la programación compuesta también incluye connectorId y compositeSchedule (o null). Los estados son resultados OCPP o de operaciones posteriores guardados y la ruta no los restringe a una enumeración cerrada.

Tipos de informes

ReportSession = {
  id: PositiveInt,
  charger: { id: PositiveInt, name: string, site: { id: PositiveInt, name: string }|null },
  portId: PositiveInt, connectorId: integer,
  user: { id: PositiveInt, name: string }|null,
  active: boolean, energyWh: number,
  startedAt: DateTime, stoppedAt: DateTime|null,
  durationSeconds: integer|null, costs: Cost[]
}

ReportSchedule = {
  id: PositiveInt, workspaceId: PositiveInt, enabled: boolean,
  recipientEmail: string, format: "csv"|"pdf", sendDay: integer,
  sendTime: string, createdAt: DateTime, updatedAt: DateTime,
  lastDeliveryPeriod: string|null, lastDeliveryStatus: string|null,
  lastDeliveryAttemptAt: DateTime|null, lastDeliveryAttemptCount: integer,
  lastDeliveredPeriod: string|null, lastDeliveredAt: DateTime|null
}

ReportDataResponse = {
  items: ReportSession[],
  pageTotals: { sessions:integer, energyWh:number, durationSeconds:integer, costs:Cost[] },
  page: { limit:integer, nextCursor:string|null },
  range: { from:DateTime, to:DateTime, toExclusive:true }
}

MeasurementPoint = { meterValueId:PositiveInt, timestamp:DateTime, elapsedSeconds:integer, value:number }
Measurement = {
  name:string,
  unit:{ symbol:string|null, description:string|null },
  lines:Array<{ phase:string, points:MeasurementPoint[] }>
}
MeasurementsResponse = {
  transactionLogId:PositiveInt, measurements:Measurement[],
  page:{ limit:integer, nextCursor:string|null, sampleValuesTruncated:boolean, sampleLimitPerMeterValue:64 }
}

Ejemplo de solicitud y respuesta de programación:

{"enabled":true,"recipientEmail":"reports@example.com","format":"csv","sendDay":5,"sendTime":"08:30"}
{
  "schedule": {
    "id": 4,
    "workspaceId": 7,
    "enabled": true,
    "recipientEmail": "reports@example.com",
    "format": "csv",
    "sendDay": 5,
    "sendTime": "08:30",
    "createdAt": "2026-08-01T10:00:00.000Z",
    "updatedAt": "2026-08-24T12:30:00.000Z",
    "lastDeliveryPeriod": null,
    "lastDeliveryStatus": null,
    "lastDeliveryAttemptAt": null,
    "lastDeliveryAttemptCount": 0,
    "lastDeliveredPeriod": null,
    "lastDeliveredAt": null
  }
}

Tipos de tarifas

TariffComponent = {
  id: PositiveInt,
  type: NamedLookup, season: NamedLookup,
  validFromMonth: number|null, validToMonth: number|null,
  validFromWeekDay: number|null, validToWeekDay: number|null,
  validFromHour: number|null, validToHour: number|null,
  priority: number, price: number
}

Tariff = {
  id: PositiveInt, cpoId: PositiveInt, name: string,
  type: NamedLookup,
  site: { id: PositiveInt, name: string, timezone: string|null }|null,
  currency: { id: PositiveInt, code: string, sign: string },
  biddingZone: { id: PositiveInt, code: string, name: string }|null,
  tax: number, fallbackPrice: number|null, price: number|null,
  components: TariffComponent[], assignmentCount: integer
}

TariffAssignment = {
  id: PositiveInt, chargerId: PositiveInt, connectorId: integer,
  tariff: { id: PositiveInt, name: string, currency: { code: string, sign: string } },
  createdAt: DateTime, updatedAt: DateTime
}

MarketPrice = {
  id: PositiveInt, value: number, currencyId: PositiveInt,
  startsAt: integer, endsAt: integer,
  startsAtIso: DateTime, endsAtIso: DateTime, intervalMinutes: number
}

TariffLookups = {
  currencies:Array<{id:PositiveInt,code:string,sign:string,fractionalUnit:string,enabled:boolean,minimalValue:integer}>,
  biddingZones:Array<{id:PositiveInt,code:string,name:string,currencyId:PositiveInt,enabled:boolean}>,
  currencyRates:Array<{currencyId:PositiveInt,rate:number,updatedAt:DateTime}>,
  componentTypes:NamedLookup[], seasons:NamedLookup[], tariffTypes:NamedLookup[]
}

Ejemplos de tarifas y componentes:

{"name":"Public AC","currencyCode":"EUR","biddingZoneId":1,"tax":21}
{
  "components": [
    {"typeId":1,"seasonId":1,"priority":0,"price":0.25,"validFromHour":0,"validToHour":24}
  ]
}

Tipos de perfiles de carga

SchedulePeriod = { id: PositiveInt, startPeriod: number, limit: number, numberOfPhases: integer|null }

ChargingProfile = {
  id: PositiveInt, cpoId: PositiveInt, label: string, description: string|null,
  stackLevel: number, location: NamedLookup, purpose: NamedLookup,
  kind: NamedLookup, recurrency: NamedLookup|null,
  validFrom: DateTime|null, validTo: DateTime|null,
  startSchedule: DateTime|null, durationSeconds: number|null,
  rateUnit: NamedLookup, minChargingRate: number|null,
  schedule: SchedulePeriod[], assignmentCount: integer,
  createdAt: DateTime, updatedAt: DateTime
}

ProfileAssignment = {
  id: PositiveInt, chargerId: PositiveInt, connectorId: integer,
  synced: boolean, syncCode: integer,
  syncStatus: "accepted"|"rejected"|"unknown",
  profile: { id: PositiveInt, label: string, stackLevel: number, purpose: string, kind: string|null },
  createdAt: DateTime, updatedAt: DateTime
}

ChargingProfileLookups = {
  locations:NamedLookup[], purposes:NamedLookup[], kinds:NamedLookup[],
  recurrencyKinds:NamedLookup[],
  rateUnits:Array<{id:PositiveInt,name:string,supported:boolean}>,
  allowedRateUnits:string[]
}

Ejemplos de creación y programación:

{
  "label":"Depot cap","locationId":3,"stackLevel":1,"purposeId":1,"kindId":1,
  "recurrencyKindId":null,"validFrom":null,"validTo":null,"startSchedule":null,
  "rateUnitId":1,"minChargingRate":6,
  "schedule":[{"startPeriod":0,"limit":32,"numberOfPhases":3}]
}
{"rateUnitId":1,"periods":[{"startPeriod":0,"limit":16,"numberOfPhases":3}]}

Tipos de usuarios

RFID = { id: PositiveInt, maskedUid: string, name: string|null, type: string, valid: boolean }
AccessItem = { id: PositiveInt, chargerId: PositiveInt, chargerName: string, expiresAt: DateTime|null, site: SiteRef|null }
Access = { allChargers: boolean, chargerIds: PositiveInt[], items: AccessItem[] }
Limit = { id: PositiveInt, limitTypeId: PositiveInt, label: string, energyValue: integer, timeValue: integer }

User = {
  id: PositiveInt, membershipId: PositiveInt, name: string, email: string,
  rfids: RFID[], access: AccessItem[], limitCount: integer
}

UserDetail = User & {
  phone: string|null, createdAt: DateTime|null, limits: Limit[]
}

Vehicle = {
  id: PositiveInt, name: string|null, provider: string|null, status: string|null,
  vin: string|null, identifier: string|null, model: string|null,
  batteryCapacityWh: number|null, createdAt: DateTime,
  telemetry: { soc: number|null, chargeLimitSoc: number|null, recordedAt: DateTime|null }|null
}

LocalUser = {
  id: PositiveInt, customerId: PositiveInt, name: string, email: string,
  expiresAt: DateTime|null, systemManaged: boolean
}

LocalUserMutation = {
  chargepointLocalUserId: PositiveInt,
  customerId: PositiveInt,
  expiryDate: DateTime|null,
  customer: {} // `contractId` is removed by the workspace-admin response boundary
}
LocalUserUpdate = { id:PositiveInt, customerId:PositiveInt, expiresAt:DateTime|null }

Invitation = {
  email:string, name:string, chargerIds:PositiveInt[], rfids:string[]
}

UserListResponse = {
  items:User[], invitations:Invitation[], chargers:Array<{id:PositiveInt,name:string,identifier:string|null,site:SiteRef|null}>,
  page:{ nextCursor:number|string|null, memberNextCursor:number|null, invitationNextCursor:string|null, limit:integer }
}

UserSession = {
  id:PositiveInt, chargerId:PositiveInt, chargerName:string|null,
  connectorId:PositiveInt, site:SiteRef|null, energyWh:number,
  startedAt:DateTime|null, stoppedAt:DateTime|null
}

La respuesta de modificación de POST /chargers/:chargerId/local-users y el resultado para un cliente existente de POST /chargers/:chargerId/local-users/invitations devuelven LocalUserMutation; PATCH /chargers/:chargerId/local-users/:localUserId devuelve LocalUserUpdate. El endpoint de lista utiliza LocalUser. Los clientes deben tratarlos como tipos de respuesta intencionadamente distintos.

Ejemplos de usuarios, invitaciones, RFID y acceso:

{"email":"driver@example.com","name":"Example Driver"}
{
  "email":"new.driver@example.com",
  "name":"New Driver",
  "rfid":"04AABBCCDD",
  "allChargers":false,
  "chargerIds":[11,12]
}
{"uid":"04AABBCCDD","name":"Blue card"}
{"allChargers":false,"chargerIds":[11,12]}

Las escrituras correctas nunca devuelven el UID RFID sin enmascarar. Por ejemplo:

{"rfid":{"id":31,"maskedUid":"******CCDD","name":"Blue card","type":"RFID","valid":true}}

Cuerpos vacíos y binarios de respuestas correctas

  • 204 significa que no hay cuerpo de respuesta.
  • Una respuesta correcta de QR del cargador contiene bytes PNG, no JSON.
  • Una exportación correcta de informes contiene bytes CSV o PDF, no JSON.
  • Consulta el Contrato de respuestas y errores para ver los cuerpos JSON que se devuelven cuando falla cualquiera de los dos endpoints binarios.

Otros ejemplos de cuerpos de modificación

Las rutas de esta tabla de ejemplos son relativas a /v2/admin; las rutas completas están en la Referencia de endpoints. Los ejemplos extensos anteriores abarcan el espacio de trabajo, emplazamientos, gestión de potencia, creación de cargadores y ajustes de conectores, programación de informes, tarifas y componentes, perfiles y programaciones de carga, usuarios e invitaciones, RFID y sustitución de acceso. Cualquier otra operación de modificación con cuerpo utiliza una de estas estructuras exactas de ejemplo:

EndpointEjemplo de cuerpo JSON
PATCH /chargers/:chargerId{"name":"Warehouse east","siteId":4,"invertedRfid":false,"smartMode":1,"automationDisabled":false}; se acepta cualquier subconjunto no vacío
PATCH /chargers/:chargerId/credentials{"password":"replacement-secret"}
PATCH /chargers/:chargerId/public-listing{"isPublic":true}
PATCH /chargers/:chargerId/configuration{"key":"HeartbeatInterval","value":"60"}
POST /chargers/:chargerId/firmware{"url":"https://firmware.example.com/charger-v2.bin"}
POST /chargers/:chargerId/commands/reset{"resetType":"Soft"}
POST /chargers/:chargerId/commands/availability{"availabilityType":"Operative"}
POST /chargers/:chargerId/commands/trigger{"messageType":"StatusNotification"}
POST /chargers/:chargerId/commands/unlock{"connectorId":1}
POST /chargers/:chargerId/commands/composite-schedule{"connectorId":0,"durationSeconds":86400,"chargingRateUnit":"W"}
POST /chargers/:chargerId/tariff-assignments{"tariffId":17,"connectorId":0}
PATCH /chargers/:chargerId/tariff-assignments/:assignmentId{"tariffId":17,"connectorId":1}
POST o PATCH /chargers/:chargerId/profile-assignments[...]{"profileId":8,"connectorId":1}
PATCH /users/:userId{"name":"Updated Driver"}
POST /users/invitations/resend o DELETE /users/invitations{"email":"new.driver@example.com"}
PATCH /users/:userId/rfids/:rfidId{"name":"Replacement label"}; null borra la etiqueta
POST /users/:userId/limits{"limitTypeId":1,"energyValue":20000,"timeValue":0}
PATCH /users/:userId/limits/:limitId{"energyValue":25000}
POST /chargers/:chargerId/local-users{"customerId":42,"expiresAt":"2026-12-31T23:59:59Z"}
POST /chargers/:chargerId/local-users/invitations o su equivalente DELETE{"email":"driver@example.com"}
PATCH /chargers/:chargerId/local-users/:localUserId{"expiresAt":null}

Las demás operaciones de modificación no tienen cuerpo de solicitud. Aun así requieren exactamente una cabecera Idempotency-Key.

Ejemplos adicionales de respuestas correctas

Las listas vacías son válidas y hacen inequívocas las envolturas de nivel superior:

{"items":[],"metricsWindow":{"from":"2026-05-26T00:00:00.000Z","to":"2026-08-24T00:00:00.000Z","sessionLimit":10000,"sessionsIncluded":0,"totalsCapped":false},"connectorLookups":{"formats":[],"types":[],"powerTypes":[]}}
{"items":[],"pageTotals":{"sessions":0,"energyWh":0,"durationSeconds":0,"costs":[]},"page":{"limit":50,"nextCursor":null},"range":{"from":"2026-07-01T00:00:00.000Z","to":"2026-08-01T00:00:00.000Z","toExclusive":true}}
{"status":"Accepted"}
{"status":"Accepted","connectorResults":[{"connectorId":1,"status":"Accepted"}]}
{"sent":true,"format":"csv","rowCount":12,"range":{"from":"2026-07-01T00:00:00.000Z","to":"2026-08-01T00:00:00.000Z"}}
{"items":[],"invitations":[],"chargers":[],"page":{"nextCursor":null,"memberNextCursor":null,"invitationNextCursor":null,"limit":50}}

Para las respuestas que contienen objetos, sustituye en la envoltura indicada en la Referencia de endpoints el DTO con el nombre exacto de las secciones anteriores; por ejemplo, la creación de tarifas es { "tariff": Tariff }, la de perfiles es { "profile": ChargingProfile } y la de usuarios es { "user": User }.