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-emailandyour-passwordwith 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
Content-Type: application/json
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
Authorization: Bearer <your-JWT-token>
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
Authorization: Bearer <your-JWT-token>
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
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
Authorization: Bearer <your-JWT-token>
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
timestampANDcamera(request body example):
{
"filter": {
"timestamp": { ">=": "2024-11-18 00:00:00" },
"camera": { "like": "camera_1" }
}
}
Filtering Flows by
plateANDcamera(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
Authorization: Bearer <your-JWT-token>
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
Authorization: Bearer <your-JWT-token>
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. |