API Introduction
API to allow ropeless gear manufacturers to exchange anonymized data with each other and with regulators.
Base URL
| Environment | Base URL | Country |
|---|---|---|
| Test | https://buoy.staging.pamdas.org | |
| Production | https://buoy.pamdas.org | US |
| Production | https://dfo.pamdas.org | Canada |
Headers
- Content-Type: application/json
- Accept: application/json
Changelog
Get Gear by Location
Returns Gear within 5 nautical miles of the latitude and longitude.
/api/v1.0/gear/
Query Parameters
| page | integer | Page number within the paginated result set. |
| page_size | integer | Number of results per page. |
| lat | float | Include gear within a range of 5 nautical miles from this latitude; latitude must be between -90 and 90. |
| lon | float | Include gear within a range of 5 nautical miles from this longitude; longitude must be between -180 and 180. |
| updated_since | ISO 8601 datetime | Return items updated since the given timestamp. |
| state | string | Filter by state. Use “deployed” for in-water gear or “hauled” for recovered gear. |
Example Request
cURL Command
curl --location '{{site}}/api/v1.0/gear?state=deployed&lat={{latitude}}&lon={{longitude}}' \
--header 'Authorization: Bearer {{your_token}}'
{{site}}: Use the site you have been granted access to.
{{your_token}}: EarthRanger will provide you with a bearer token to authenticate your requests. This token will not expire.
Response Shape
{
"id": "<set_id>",
"display_id": "<mfr_set_id or set_id>",
"status": "deployed | hauled",
"type": "single | trawl",
"manufacturer": "<manufacturer_name>",
"last_updated": "<ISO 8601>",
"devices": [
{
"device_id": "<device_id>",
"mfr_device_id": "<mfr_device_id>",
"label": "a | b | c ...",
"location": {"latitude": float, "longitude": float},
"last_updated": "<ISO 8601>",
"last_deployed": "<ISO 8601>"
}
]
}Response Example
{
"data": {
"count": 2,
"next": null,
"previous": null,
"results": [
{
"id": "6b5ac585-76fe-4af8-9813-f6f56a2c6c32",
"display_id": "6b5ac585-76fe-4af8-9813-f6f56a2c6c32",
"status": "deployed",
"devices": [
{
"device_id": "fe5b4705-0b36-422c-846b-620d4aae983b",
"mfr_device_id": "buoy001",
"label": "a",
"location": {
"latitude": 5.55,
"longitude": 5.55
},
"last_updated": "2026-04-08T07:25:15-07:00",
"last_deployed": "2026-04-08T14:25:15.123456+00:00"
}
],
"type": "single",
"manufacturer": "Testing",
"last_updated": "2026-04-09T23:37:14.935411+00:00"
},
{
"id": "6b5ac585-76fe-4af8-9813-f6f56a2c6cab",
"display_id": "6b5ac585-76fe-4af8-9813-f6f56a2c6cab",
"status": "deployed",
"devices": [
{
"device_id": "fe5b4705-0b36-422c-846b-620d4aae98dd",
"mfr_device_id": "buoy002",
"label": "a",
"location": {
"latitude": 5.54,
"longitude": 5.54
},
"last_updated": "2026-04-08T07:25:15-07:00",
"last_deployed": "2026-04-08T14:25:15.123456+00:00"
},
{
"device_id": "fe5b4705-0b36-422c-846b-620d4aae98ee",
"mfr_device_id": "buoy003",
"label": "b",
"location": {
"latitude": 5.53,
"longitude": 5.53
},
"last_updated": "2026-04-08T07:25:15-07:00",
"last_deployed": "2026-04-08T14:25:15.123456+00:00"
}
],
"type": "trawl",
"manufacturer": "Testing",
"last_updated": "2026-04-09T23:35:21.221668+00:00"
}
]
},
"status": {
"code": 200,
"message": "OK"
}
}
Get Gear by ID
Returns a single trawl with a matching ID
/api/v1.0/gear/{id}
Example Request
cURL Command
Basic request:
curl -X 'GET' \
'https://{{site}}/api/v1.0/gear/{{your_gear_id}}' \
-H 'accept: application/json' \
-H 'Authorization: Bearer {{your_token}}'
{{site}}: Use the site you have been granted access to.
{{your_token}}: EarthRanger will provide you with a bearer token to authenticate your requests. This token will not expire.
Example Response
API Response
{
"id": "6b5ac585-76fe-4af8-9813-f6f56a2c6c32",
"display_id": "6b5ac585-76fe-4af8-9813-f6f56a2c6c32",
"status": "deployed",
"devices": [
{
"device_id": "fe5b4705-0b36-422c-846b-620d4aae983b",
"mfr_device_id": "buoy001",
"label": "a",
"location": {
"latitude": 5.55,
"longitude": 5.55
},
"last_updated": "2026-04-08T07:25:15-07:00",
"last_deployed": "2026-04-08T14:25:15.123456+00:00"
}
],
"type": "single",
"manufacturer": "Testing",
"last_updated": "2026-04-09T23:37:14.935411+00:00"
}Submit Gear Location
This API allows users to submit a single trawl with either single or multiple devices.
/api/v1.0/gear/
I. Trawl Information
Field |
Allowed Values |
Required |
Notes |
set_id |
RFC-4122 UUIDs |
Yes |
Unique identifier for the gear set.
|
deployment_type |
trawl, single, surface | Yes |
Type of deployment for this set. |
initial_deployment_date |
ISO 8601 datetime |
Yes |
Required when creating a new gear set for the first time.
|
manufacturer_name |
Existing identifier defined by EarthRanger. |
Yes |
Identifies the manufacturer. Will be provided by EarthRanger during the initial setup. |
devices |
array<gear> |
Yes |
Gear that is part of the set. Can be single or multiple. See table below.
Example: |
Optional Fields (click to expand)
Field |
Allowed Values |
Notes |
set_additional_data |
JSON object |
Freeform key-value data about the gear set (e.g. vessel name, trip info).
Example: {
|
mfr_set_id |
string (max 100) | Manufacturer's string reference for the gear set. |
II. Gear Information
Property |
Allowed Values |
Required |
Notes |
device_id |
UUID |
Yes |
Unique identifier for the device. Used as the primary key in the system. |
mfr_device_id |
string (max 100) |
No |
Gear Serial Number.
|
last_deployed |
ISO 8601 datetime |
Yes* |
Timestamp when the device was last deployed.
|
last_updated |
ISO 8601 datetime | Yes* |
Timestamp of the last update to this device.
|
device_status |
deployed, hauled, lost |
Yes |
Current state of the device. Drives gear set active/inactive logic.
|
location |
Latitude: -90 to 90 Longitude: -180 to 180 |
Yes |
Deployed latitude and longitude { |
Optional Fields (click to expand)
Property |
Allowed Values |
Notes |
|
gps, acoustic |
How the device determines its position. Defaults to gps. |
|
timed, acoustic, galvanic |
The mechanism used to release the device. |
|
JSON object |
Freeform key-value data about the device (e.g. battery level, firmware version). Stored but not actively processed.
{ |
III. Examples
Python
import requests
url = "https://<site>/api/v1.0/gear"
headers = {
"Authorization": "Bearer <your_token>",
"Content-Type": "application/json",
}
payload = {
"deployment_type": "trawl",
"manufacturer_name": "<identifier provided by our team>",
"set_id": "a1b2c3d4-0001-0001-0001-000000000001",
"devices_in_set": 2,
"initial_deployment_date": "2025-12-30T21:34:19+00:00",
"devices": [
{
"device_id": "b1b2c3d4-0002-0002-0002-000000000001",
"last_deployed": "2025-12-30T21:34:19+00:00",
"last_updated": "2025-12-30T21:34:19+00:00",
"device_status": "deployed",
"release_type": "acoustic",
"location": {
"latitude": 20.622157,
"longitude": -103.471536,
},
},
{
"device_id": "b1b2c3d4-0002-0002-0002-000000000002",
"last_deployed": "2025-12-30T21:34:27+00:00",
"last_updated": "2025-12-30T21:34:27+00:00",
"device_status": "deployed",
"release_type": "acoustic",
"location": {
"latitude": 20.622158,
"longitude": -103.471537,
},
"device_additional_data": {
"sequence": 2,
"serial_number": "SN-00123",
"battery_pct": 85,
},
},
],
}cURL Command
curl --location 'https://{{site}}/api/v1.0/gear' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer <your token>' \
--data '{
"deployment_type": "trawl",
"manufacturer_name": "<identifier provided by our team>",
"set_id": "<single-use UUID>",
"devices_in_set": 2,
"devices": [
{
"device_id": "<UUID>",
"last_deployed": "2025-12-30T21:34:19+00:00",
"last_updated": "2025-12-30T21:34:19+00:00",
"device_status": "deployed",
"location": {
"latitude": 20.622157,
"longitude": -103.471536
},
"release_type": "acoustic"
},
{
"device_id": "<UUID>",
"last_deployed": "2025-12-30T21:34:27+00:00",
"last_updated": "2025-12-30T21:34:27+00:00",
"device_status": "deployed",
"location": {
"latitude": 20.622158,
"longitude": -103.471537
}
}
],
"initial_deployment_date": "2025-12-30T21:34:19+00:00"
}
'
IV. Response
Example
{
"data": {
"detail": "Gears successfully processed",
"set_id": "cf94d09d-b2b5-43cf-be2b-40f8d663b22f"
},
"status": {
"code": 201,
"message": "Created"
}
}Considerations
Auto-Haul Behavior
When any device in a gearset is hauled, the system automatically hauls all other deployed devices in the same gearset.
Why Auto-Haul?
Fishing gear sets (trawls) are hauled as a unit - all devices come up together
Manufacturers may only report one device in haul notifications due to operational constraints
This prevents “orphaned” deployed devices when the gearset is physically retrieved
Edge Case: Moving a Device Between Gear Sets
When a device is deployed in Set A and then included in a new gearset Set B (with a different set_id), the system accepts the new deployment and closes the previous one.
The latest deployment is always the current one; the previous gearset is closed out automatically when the payload time is strictly after the existing deployment’s start. You do not need to explicitly haul from SET_A before deploying to SET_B—posting the new gearset does both. Posting an older gearset (payload recorded_at earlier than the current deployment’s start) is rejected with HTTP 400 so that a newer deployment is not overwritten.
Optional explicit workflow: You can still haul from SET_A first and then deploy to SET_B; the result is consistent. The accept-and-close behavior is for cases where the client only sends the new deployment.
Older gearset rejected: If the device is already deployed on SET_B (newer) and a request is sent for SET_A with an earlier recorded_at, the request is rejected with HTTP 400 (OlderGearsetRejectedError). The response body explains that the device is already deployed on a newer gearset and the payload’s deployment time is before that deployment.
Error Handling
The serializer validates and raises ValidationError for:
- Missing required fields
- Hauling a device already hauled
- User permission violations
- Future dates for deployment/updated timestamps
Device moved to another gearset: If a device is deployed in a new gearset while still deployed elsewhere, the previous deployment is closed automatically when the new deployment’s time is strictly after the existing deployment’s start (see “Edge Case: Moving a Device Between Gear Sets”). If the new payload’s deployment time is at or before the existing deployment’s start (older or same-time gearset), the request is rejected with 400.
All validation errors return HTTP 400 with detailed error messages.
April 9, 2026
