NAV
shell python javascript php

Introduction

Welcome to the Seedata API documentation.

This documentation is intended for developers who want to integrate their systems with the Seedata software. Here you will find information about the endpoints available, the authentication process, and the data that can be accessed.

Authentication

This API allows you to authenticate your application and obtain a JWT token to access the other endpoints.

For all the endpoints that require authentication, you must send the JWT token in the header of the request. This must be done by adding the following header:

Authorization: Bearer TOKEN_JWT

JWT Token

To obtain the JWT token, use this code example:

import requests

url = "http://localhost:8881/authenticate"

payload = {
    "email": "your-email",
    "password": "your-password"
}
headers = {
    "Content-Type": "application/json"
}

response = requests.request("POST", url, json=payload, headers=headers)

print(response.text)
curl --request POST \
  --url http://localhost:8881/authenticate \
  --header 'Content-Type: application/json' \
  --data '{
    "email": "your-email",
    "password": "your-password"
}'
const data = JSON.stringify({
  "email": "your-email",
  "password": "your-password"
});

const xhr = new XMLHttpRequest();
xhr.withCredentials = true;

xhr.addEventListener("readystatechange", function () {
  if (this.readyState === this.DONE) {
    console.log(this.responseText);
  }
});

xhr.open("POST", "http://localhost:8881/authenticate");
xhr.setRequestHeader("Content-Type", "application/json");

xhr.send(data);
<?php

$curl = curl_init();

curl_setopt_array($curl, [
  CURLOPT_PORT => "21781",
  CURLOPT_URL => "http://localhost:8881/authenticate",
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_ENCODING => "",
  CURLOPT_MAXREDIRS => 10,
  CURLOPT_TIMEOUT => 30,
  CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
  CURLOPT_CUSTOMREQUEST => "POST",
  CURLOPT_POSTFIELDS => "{\n\t\"email\": \"your-email\",\n\t\"password\": \"your-password\"\n}",
  CURLOPT_HTTPHEADER => [
    "Content-Type: application/json"
  ],
]);

$response = curl_exec($curl);
$err = curl_error($curl);

curl_close($curl);

if ($err) {
  echo "cURL Error #:" . $err;
} else {
  echo $response;
}

Remember to replace your-email and your-password with your own credentials.

JSON response example:

{
    "success": true,
    "data": {
        "token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJhcHB...<truncated>"
    }
}

To obtain the JWT token, you must make a request to the /authenticate endpoint, sending your email and password. These may be the same email and password you use to access the Seedata Dashboard.

HTTP Request

POST http://localhost:8881/authenticate

Header Params

Body Params

Parameter Type Required Description
email String Yes Your email.
password String Yes Your password.

Response

Attribute Type Description
token String JWT token to access the other endpoints.

Flows

Flows represent the data collected form each vehicle that passed through the camera.

The Flow object

Attributes Type Description
id Integer Flow ID.
camera String Camera alias.
plate String License Plate reading value.
score Integer License Plate reading confidence.
timestamp String Date and time of the flow.
trigger_mode String Trigger mode of the camera (manual or auto).
lpr_version String License Plate Recognition software version.
image String Base64 image of the flow.
plate_image String Base64 image of the plate.

List all

List all flows:

import requests

url = "http://localhost:8881/flows"

headers = {
    "Content-Type": "application/json",
    "Authorization": "Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJhcHB...<truncated>"
}

response = requests.request("GET", url, headers=headers)

print(response.text)
curl --request GET \
  --url http://localhost:8881/flows \
  --header 'Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJhcHB...<truncated>' \
  --header 'Content-Type: application/json'
const data = JSON.stringify(false);

const xhr = new XMLHttpRequest();
xhr.withCredentials = true;

xhr.addEventListener("readystatechange", function () {
  if (this.readyState === this.DONE) {
    console.log(this.responseText);
  }
});

xhr.open("GET", "http://localhost:8881/flows");
xhr.setRequestHeader("Content-Type", "application/json");
xhr.setRequestHeader("Authorization", "Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJhcHB...<truncated>");

xhr.send(data);
<?php

$curl = curl_init();

curl_setopt_array($curl, [
  CURLOPT_PORT => "21781",
  CURLOPT_URL => "http://localhost:8881/flows",
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_ENCODING => "",
  CURLOPT_MAXREDIRS => 10,
  CURLOPT_TIMEOUT => 30,
  CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
  CURLOPT_CUSTOMREQUEST => "GET",
  CURLOPT_POSTFIELDS => "",
  CURLOPT_HTTPHEADER => [
    "Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJhcHB...<truncated>",
    "Content-Type: application/json"
  ],
]);

$response = curl_exec($curl);
$err = curl_error($curl);

curl_close($curl);

if ($err) {
  echo "cURL Error #:" . $err;
} else {
  echo $response;
}

JSON response example:

[
    {
        "id": 465,
        "camera": "camera_1",
        "plate": "aaa1a11",
        "score": 0.952351,
        "timestamp": "2025-02-08 22:52:46",
        "trigger_mode": "manual",
        "lpr_version": "1.8.0",
    },
    {
        "id": 463,
        "camera": "camera_1",
        "plate": "bbb2b22",
        "score": 0,
        "timestamp": "2025-02-08 19:47:02",
        "trigger_mode": "auto",
        "lpr_version": "1.8.0"
    },
    .
    .
    .
]

By default, this endpoint is paginated and will return a maximum of 20 flows per page. You can use the page query parameter to navigate through the pages.

By default, the results are ordered by the timestamp attribute in descending order, followed by the id attribute, also in descending order.

HTTP Request

GET http://localhost:8881/flows

Header Params

Query Params

Parameter Type Required Description
page Integer No Page number .

Response

Attribute Type Description
[].id Integer Flow ID.
[].camera String Camera alias.
[].plate String License Plate reading value.
[].score Float License Plate reading confidence.
[].timestamp String Date and time of the flow.
[].trigger_mode String Trigger mode of the camera (manual or auto).
[].lpr_version String License Plate Recognition software version.

Response Header

Attribute Type Description
X-Pagination-Current-Page Integer Current page number.
X-Pagination-Page-Count Integer Total number of pages.
X-Pagination-Per-Page Integer Number of flows per page.
X-Pagination-Total-Count Integer Total number of flows.

Get

Get a single flow:

import requests

url = "http://localhost:8881/flows/<Id>"

headers = {
    "Content-Type": "application/json",
    "Authorization": "Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJhcHB...<truncated>"
}

response = requests.request("GET", url, headers=headers)

print(response.text)
curl --request GET \
  --url http://localhost:8881/flows/<Id> \
  --header 'Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJhcHB...<truncated>' \
  --header 'Content-Type: application/json'
const data = JSON.stringify(false);

const xhr = new XMLHttpRequest();
xhr.withCredentials = true;

xhr.addEventListener("readystatechange", function () {
  if (this.readyState === this.DONE) {
    console.log(this.responseText);
  }
});

xhr.open("GET", "http://localhost:8881/flows/<Id>");
xhr.setRequestHeader("Content-Type", "application/json");
xhr.setRequestHeader("Authorization", "Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJhcHB...<truncated>");

xhr.send(data);
<?php

$curl = curl_init();

curl_setopt_array($curl, [
  CURLOPT_PORT => "21781",
  CURLOPT_URL => "http://localhost:8881/flows/<Id>",
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_ENCODING => "",
  CURLOPT_MAXREDIRS => 10,
  CURLOPT_TIMEOUT => 30,
  CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
  CURLOPT_CUSTOMREQUEST => "GET",
  CURLOPT_POSTFIELDS => "",
  CURLOPT_HTTPHEADER => [
    "Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJhcHB...<truncated>",
    "Content-Type: application/json"
  ],
]);

$response = curl_exec($curl);
$err = curl_error($curl);

curl_close($curl);

if ($err) {
  echo "cURL Error #:" . $err;
} else {
  echo $response;
}

JSON response example:


  {
      "id": 1,
      "camera": "camera_1",
      "plate": "aaa1a11",
      "score": 0.952351,
      "timestamp": "2025-02-08 22:52:46",
      "trigger_mode": "manual",
      "lpr_version": "1.8.0",
      "image": "/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAIBAQEBAQIBAQECAgICAgQDAgICAgUE...<truncated>",
      "plate_image": "/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAIBAQEBAQIBAQECAgICAgQDAgICAgUE...<truncated>"
  }

Use this endpoint to get a single flow. You need to know the flow ID to make the request.

Using this endpoint, you can retrieve the base64 image of the flow and the base64 image of the plate, if detected.

HTTP Request

GET http://localhost:8881/flows/<Id>

Header Params

Response

Attribute Type Description
id Integer Flow ID.
camera String Camera alias.
plate String License Plate reading value.
score Float License Plate reading confidence.
timestamp String Date and time of the flow.
trigger_mode String Trigger mode of the camera (manual or auto).
lpr_version String License Plate Recognition software version.
image String Base64 image of the flow.
plate_image String Base64 image of the plate.

Search for flows:

import requests

url = "http://localhost:8881/flows/search"

payload = {"filter": {
        "timestamp": {">=": "2024-11-18 00:00:00"},
        "camera": {"like": "camera_1"}
    }}
headers = {
    "Content-Type": "application/json",
    "Authorization": "Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJhcHB...<truncated>"
}

response = requests.request("POST", url, json=payload, headers=headers)

print(response.text)
curl --request POST \
  --url http://localhost:8881/flows/search \
  --header 'Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJhcHB...<truncated>' \
  --header 'Content-Type: application/json' \
  --data '{
    "filter": {
                "timestamp": {">=": "2024-11-18 00:00:00"},
                "camera": {"like": "camera_1"}
    }
}'
const options = {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    Authorization: 'Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJhcHB...<truncated>'
  },
  body: '{"filter":{"timestamp":{">=":"2024-11-18 00:00:00"},"camera":{"like":"camera_1"}}}'
};

fetch('http://localhost:8881/flows/search', options)
  .then(response => response.json())
  .then(response => console.log(response))
  .catch(err => console.error(err));
<?php

$curl = curl_init();

curl_setopt_array($curl, [
  CURLOPT_PORT => "21781",
  CURLOPT_URL => "http://localhost:8881/flows/search",
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_ENCODING => "",
  CURLOPT_MAXREDIRS => 10,
  CURLOPT_TIMEOUT => 30,
  CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
  CURLOPT_CUSTOMREQUEST => "POST",
  CURLOPT_POSTFIELDS => "{\n    \"filter\": {\n\t\t\t\t\"timestamp\": {\">=\": \"2024-11-18 00:00:00\"},\n\t\t\t\t\"camera\": {\"like\": \"camera_1\"}\n    }\n}",
  CURLOPT_HTTPHEADER => [
    "Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJhcHB...<truncated>",
    "Content-Type: application/json"
  ],
]);

$response = curl_exec($curl);
$err = curl_error($curl);

curl_close($curl);

if ($err) {
  echo "cURL Error #:" . $err;
} else {
  echo $response;
}

JSON response example:

[
    {
        "id": 465,
        "camera": "camera_1",
        "plate": "aaa1a11",
        "score": 0.952351,
        "timestamp": "2025-02-08 22:52:46",
        "trigger_mode": "manual",
        "lpr_version": "1.8.0"
    },
    {
        "id": 463,
        "camera": "camera_1",
        "plate": "bbb2b22",
        "score": 0,
        "timestamp": "2025-02-08 19:47:02",
        "trigger_mode": "auto",
        "lpr_version": "1.8.0"
    },
    .
    .
    .
]

By default, this endpoint is paginated and will return a maximum of 20 flows per page. You can use the page query parameter to navigate through the pages.

By default, the results are ordered by the timestamp attribute in descending order, followed by the id attribute, also in descending order.

HTTP Request

POST http://localhost:8881/flows/search

Header Params

Body Params

Parameter Type Required Description
page Integer No Page number .
filter Object No Filter object.

For details on how to use the filter object, see the Filtering section.

Response

Attribute Type Description
[].id Integer Flow ID.
[].camera String Camera alias.
[].plate String License Plate reading value.
[].score Float License Plate reading confidence.
[].timestamp String Date and time of the flow.
[].trigger_mode String Trigger mode of the camera (manual or auto).
[].lpr_version String License Plate Recognition software version.

Response Header

Attribute Type Description
X-Pagination-Current-Page Integer Current page number.
X-Pagination-Page-Count Integer Total number of pages.
X-Pagination-Per-Page Integer Number of flows per page.
X-Pagination-Total-Count Integer Total number of flows.

Filtering

Filtering Flows by timestamp AND camera (request body example):

{
    "filter": {
        "timestamp": { ">=": "2024-11-18 00:00:00" },
        "camera": { "like": "camera_1" }
    }
}

Filtering Flows by plate AND camera (request body example):

{
    "filter": {
        "plate": { "like": "aaa" },
        "camera": { "like": "camera_1" }
    }
}

Filtering Flows by trigger_mode (request body example):

{
    "filter": {
        "trigger_mode": "manual"
    }
}

Filtering Flows by id, second page of the results(request body example) :

{
    "filter": {
        "id": { "in": [1, 2] }
    },
    "page": 2
}

The filter object is a JSON object that allows you to filter the results of the search. The object can contain one or more attributes, each with a specific operator.

The allowed fields to be filtered in the flows/search endpoint are: id, timestamp, camera, plate and trigger_mode.

The allowed operators are:

Attribute Allowed Operators
id =, !=, >, >=, <, <=, in, nin
timestamp =, !=, >, >=, <, <=
camera =, !=, like,
plate =, !=, like,
trigger_mode =

Create Flow (manual trigger)

Create a flow manually:

import requests

url = "http://localhost:8881/flows"

headers = {
    "Content-Type": "application/json",
    "Authorization": "Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJhcHB...<truncated>"
}

response = requests.request("POST", url, headers=headers, json={"camera_id": 1})

print(response.text)
curl --request POST \
  --url http://localhost:8881/flows \
  --header 'Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJhcHB...<truncated>' \
  --header 'Content-Type: application/json' \
  --data '{
    "camera_id": 1,
    "capture_delay": 1000,
    "max_retries": 3,
    "interval_between_retries": 500
}'
const xhr = new XMLHttpRequest();
xhr.withCredentials = true;

xhr.addEventListener("readystatechange", function () {
  if (this.readyState === this.DONE) {
    console.log(this.responseText);
  }
});

xhr.open("POST", "http://localhost:8881/flows");
xhr.setRequestHeader("Content-Type", "application/json");
xhr.setRequestHeader("Authorization", "Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJhcHB...<truncated>");

xhr.send(JSON.stringify({
    "camera_id": 1,
    "capture_delay": 1000,
    "max_retries": 3,
    "interval_between_retries": 500
}));
<?php

$curl = curl_init();

curl_setopt_array($curl, [
  CURLOPT_URL => "http://localhost:8881/flows",
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_ENCODING => "",
  CURLOPT_MAXREDIRS => 10,
  CURLOPT_TIMEOUT => 30,
  CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
  CURLOPT_CUSTOMREQUEST => "POST",
  CURLOPT_HTTPHEADER => [
    "Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJhcHB...<truncated>",
    "Content-Type: application/json"
  ],
  CURLOPT_POSTFIELDS => "{\n    \"camera_id\": 1,\n    \"capture_delay\": 1000,\n    \"max_retries\": 3,\n    \"interval_between_retries\": 500\n}"
]);

$response = curl_exec($curl);
$err = curl_error($curl);

curl_close($curl);

if ($err) {
  echo "cURL Error #:" . $err;
} else {
  echo $response;
}

JSON response example:

{
    "id": 410405,
    "camera": "camera_1",
    "plate": "dvi3a22",
    "score": 0.991873,
    "timestamp": "2025-03-30 12:20:11",
    "trigger_mode": "manual",
    "lpr_version": "1.8.0",
    "image": "/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAIBAQEBAQIBAQECAgICAgQDAgICAgUE...<truncated>",
    "plate_image": "/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAIBAQEBAQIBAQECAgICAgQDAgICAgUE...<truncated>",
    "image_source": "camera_snapshot",
    "request_received_at": "2025-03-30 12:20:10",
    "retries": 0,
    "capture_delay": 1000,
    "interval_between_retries": 500
}

Error response example:

{
    "name": "Unprocessable entity",
    "message": "Could not get current image from the camera",
    "code": 0,
    "status": 422,
}

This enpoint creates a new flow manually. The flow will be created with the current timestamp and the camera ID.

HTTP Request

POST http://localhost:8881/flows

Header Params

Body Params

Parameter Type Required Description
camera_id Integer Yes ID of the camera.
capture_delay Integer No Capture delay in milliseconds.
max_retries Integer No Maximum number of retries.
interval_between_retries Integer No Interval between retries in milliseconds.

Validation

Parameter Rules Default value
capture_delay 0 to 3000 Camera's manual_trigger_delay (configured at the dashboard).
max_retries 0 to 5 3
interval_between_retries 500 to 1500 500

Response

Attribute Type Description
id Integer Flow ID.
camera String Camera alias.
plate String License plate reading value.
score Float License plate reading confidence.
timestamp String Date and time of the detection.
trigger_mode String Trigger mode of the camera (manual or auto).
lpr_version String License Plate Recognition software version.
image String Base64 encoded image of the current vehicle (the most recent image available).
plate_image String Base64 encoded image of the current vehicle's license plate (the most recent image available).
image_source String The source of the image. camera_snapshot or rtsp.
request_received_at String Date and time The request was received.
retries Integer Number of retries.
capture_delay Integer Capture delay in milliseconds.
interval_between_retries Integer Interval between retries in milliseconds.

This endpoint returns an error if the camera is not enabled, if the camera is offline, or if the current image cannot be retrieved.

HTTP Status Codes

Code Description
404 Camera not found
405 Camera is not enabled
422 Could not get current image from the camera
502 Error to make alpr api request

In case the 502 status code is returned, the current image is still available in the image attribute, but it was not checked for license plate recognition.

If, for any reason, the last available image from the camera is more than 5 seconds old, the 422 status code will be returned.

Cameras

The Camera object

Attributes Type Description
id Integer Camera ID.
alias String Camera alias.
rtsp String RTSP URL or video file path.
keep_alive String Last time the camera was seen active.
capture_mode String Camera capture mode.

List all cameras

List all cameras:

import requests

url = "http://localhost:8881/cameras"

headers = {
    "Content-Type": "application/json",
    "Authorization": "Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJhcHB...<truncated>"
}

response = requests.request("GET", url, headers=headers)

print(response.text)
curl --request GET \
  --url http://localhost:8881/cameras \
  --header 'Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJhcHB...<truncated>' \
  --header 'Content-Type: application/json'
const xhr = new XMLHttpRequest();
xhr.withCredentials = true;

xhr.addEventListener("readystatechange", function () {
  if (this.readyState === this.DONE) {
    console.log(this.responseText);
  }
});

xhr.open("GET", "http://localhost:8881/cameras");
xhr.setRequestHeader("Content-Type", "application/json");
xhr.setRequestHeader("Authorization", "Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJhcHB...<truncated>");

xhr.send();
<?php

$curl = curl_init();

curl_setopt_array($curl, [
  CURLOPT_URL => "http://localhost:8881/cameras",
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_ENCODING => "",
  CURLOPT_MAXREDIRS => 10,
  CURLOPT_TIMEOUT => 30,
  CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
  CURLOPT_CUSTOMREQUEST => "GET",
  CURLOPT_HTTPHEADER => [
    "Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJhcHB...<truncated>",
    "Content-Type: application/json"
  ],
]);

$response = curl_exec($curl);
$err = curl_error($curl);

curl_close($curl);

if ($err) {
  echo "cURL Error #:" . $err;
} else {
  echo $response;
}

JSON response example:

[
    {
        "id": 1,
        "alias": "camera_1",
        "rtsp": "/path/to/video.mp4",
        "keep_alive": "2024-10-20 16:30:06",
        "capture_mode": "both"
    },
    {
        "id": 2,
        "alias": "camera_2",
        "rtsp": "rtsp://camera-url",
        "keep_alive": "2023-10-17 18:25:46",
        "capture_mode": "both"
    }
]

This endpoint retrieves all cameras registered in the system.

HTTP Request

GET http://localhost:8881/cameras

Header Params

Response

Attribute Type Description
id Integer Camera ID.
alias String Camera alias.
rtsp String RTSP URL or video file path.
keep_alive String Last time the camera was seen active.
capture_mode String Camera capture mode.