> ## Documentation Index
> Fetch the complete documentation index at: https://developer.plugchoice.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Import Transactions

Records charging sessions that happened outside the OCPP flow — for example sessions
captured by the Plugchoice app, a Peblar local API, or a backend you are migrating away
from. Every transaction created here is flagged with `imported: true` and stamped with the
`source` you supply, so imported sessions stay distinguishable from ones reported by the
charger itself.

The payload is always a list. Importing a single session means sending a list of one.

Rows are judged individually: valid ones are created, duplicates are skipped, and anything
else is reported against its position in the list. One bad row never discards the rest of
the batch.

Only finished sessions can be imported — `stopped_at` and `meter_stop` are required.

<ParamField path="charger" type="string" required>
  The UUID of the charger the sessions belong to.
</ParamField>

<ParamField body="source" type="string" required>
  Where these sessions came from, e.g. `Plugchoice app` or `peblar local`. Free text, up to
  100 characters. Stamped onto every transaction in the batch.
</ParamField>

<ParamField body="transactions" type="object[]" required>
  The sessions to import. Between 1 and 500 items.

  <Expandable title="transactions">
    <ParamField body="connector_id" type="integer" required>
      The OCPP connector id on this charger. The connector must already exist — importing
      does not create hardware.
    </ParamField>

    <ParamField body="id_tag" type="string" required>
      The RFID tag or token that authorized the session. Maximum 20 characters.
    </ParamField>

    <ParamField body="meter_start" type="integer" required>
      The meter reading at the start of the session, in Wh.
    </ParamField>

    <ParamField body="meter_stop" type="integer" required>
      The meter reading at the end of the session, in Wh. Must be greater than or equal to
      `meter_start`. Energy is always expressed as meter readings — `total_kwh` is derived
      from them and cannot be sent.
    </ParamField>

    <ParamField body="started_at" type="string" required>
      ISO 8601 timestamp of when the session started. Cannot be in the future.
    </ParamField>

    <ParamField body="stopped_at" type="string" required>
      ISO 8601 timestamp of when the session stopped. Must be at or after `started_at`, and
      cannot be in the future.
    </ParamField>

    <ParamField body="stop_reason" type="string">
      Why the session ended. One of `DeAuthorized`, `EmergencyStop`, `EVDisconnected`,
      `HardReset`, `Local`, `Other`, `PowerLoss`, `Reboot`, `Remote`, `SoftReset`, or
      `UnlockCommand`. May be omitted.
    </ParamField>

    <ParamField body="reservation_id" type="integer">
      The reservation id, if the session was tied to one.
    </ParamField>
  </Expandable>
</ParamField>

## Duplicates

A session is treated as a duplicate when the charger, connector and `started_at` all match
one that already exists — whether it was imported earlier or reported live by the charger.
Duplicates are counted in `skipped` rather than rejected, so re-sending a batch is safe and
will not double-count energy.

## Response

<ResponseField name="message" type="string">
  Always `Import completed`.
</ResponseField>

<ResponseField name="created" type="integer">
  How many transactions were created.
</ResponseField>

<ResponseField name="skipped" type="integer">
  How many rows were skipped as duplicates.
</ResponseField>

<ResponseField name="failed" type="integer">
  How many rows failed validation.
</ResponseField>

<ResponseField name="errors" type="object[]">
  One entry for every row that was not created — both failures and skipped duplicates.

  <Expandable title="errors">
    <ResponseField name="index" type="integer">
      The zero-based position of the row in the `transactions` list you sent.
    </ResponseField>

    <ResponseField name="errors" type="object">
      Messages keyed by field name, e.g. `{"meter_stop": ["The meter stop field must be
                  greater than or equal to meter start."]}`.
    </ResponseField>
  </Expandable>
</ResponseField>

<ResponseField name="transactions" type="object[]">
  The transactions that were created, in the order they were sent. Each one has the same
  shape as a transaction returned by [List Transactions](/api-reference/transactions/list-charger-transactions),
  including the generated `total_kwh` and the assigned `id`.
</ResponseField>
