Datos de EarthRanger utilizando la API.

La API de EarthRanger permite el acceso programático directo a datos de seguimiento, observaciones y eventos, lo que le permite crear integraciones personalizadas, canales de automatización o paneles externos.

Para Empezar

Explore la API de EarthRanger a través de las siguientes herramientas y documentación oficiales:

Autenticación

EarthRanger utiliza tokens OAuth2 para el acceso a la API.

  • Puedes crear un token de larga duración a través de tu portal de administración 
  • o solicitar uno al equipo de soporte de EarthRanger.

Visita Crear y administrar tokens de autenticación para integraciones seguras para aprender cómo crear un token de autenticación en el portal de administración.  

 

Eventos

Los eventos representan incidentes, actividades u observaciones en el campo, como avistamientos de vida silvestre, incidentes de seguridad o actividades de patrullaje.

Lista de eventos

GET /api/v1.0/activity/events/

Parámetros de consulta:

Parametro Tipo Descripción
page_size Optional integer Número de resultados por página (predeterminado: 25, máximo: 4000)
state Optional string Filtrar por estado: nuevo, activo, resuelto
event_type Optional UUID Filtrar por ID de tipo de evento
bbox Optional string Cuadro delimitador: oeste, sur, este, norte
sort_by Optional string

Los valores válidos son event_time, updated_at, created_at y serial_number (con el prefijo '-' para orden inverso).

El valor predeterminado es '-sort_at', un valor especial que representa el orden inverso de updated_at.

include_updates Optional boolean Incluir historial de actualizaciones de eventos
include_notes Optional boolean Incluir notas del evento
include_files Optional boolean Incluir archivos adjuntos

Ejemplos de código:

cURL

Solicitud básica:

curl --location 'https://your-domain.pamdas.org/api/v1.0/activity/events/ \
--header 'Authorization: Bearer YOUR_TOKEN_HERE' \
--header 'Accept: application/json'

Con filtros:

curl --location 'https://your-domain.pamdas.org/api/v1.0/activity/events/?state=new&page_size=3&sort_by=-updated_at' \
--header 'Authorization: Bearer YOUR_TOKEN_HERE' \
--header 'Accept: application/json'

Con rango de fechas y cuadro delimitador:

curl -X GET "https://your-domain.pamdas.org/api/v1.0/activity/events/?bbox=34.5,-2.5,34.6,-2.3&since=2024-10-01T00:00:00Z&until=2024-10-19T23:59:59Z" \
  -H "Authorization: Bearer YOUR_TOKEN_HERE" \
  -H "Accept: application/json"
 
 

Python

Usando el cliente Python oficial de EarthRanger (er-client):

Instalar con: pip install earthranger-client

from erclient.client import ERClient

# Initialize client with token (recommended)
client = ERClient(
    service_root='https://your-domain.pamdas.org/api/v1.0',
    token='YOUR_TOKEN_HERE'
)

# OR initialize with username/password
client = ERClient(
    service_root='https://your-domain.pamdas.org/api/v1.0',
    username='your_username',
    password='your_password',
    token_url='https://your-domain.pamdas.org/oauth2/token',
    client_id='your_client_id'
)

# Basic request - get_events() returns a generator
# It automatically handles pagination and fetches all events
# Note: This may take time if you have many events
for event in client.get_events():
    print(f"Event: {event.get('title', 'No title')} - {event['event_type']}")
    print(f"Location: {event.get('location')}")
    print(f"Time: {event['time']}")
    print("---")
    
# TIP: Use max_results to limit the number of events fetched
for event in client.get_events(max_results=100):
    print(event['title'])

# With filters - supported parameters:
# state, page_size, page, event_type, filter, include_notes,
# include_related_events, include_files, include_details, 
# updated_since, include_updates, max_results, oldest_update_date, event_ids
events_list = []
for event in client.get_events(
    state='active',
    page_size=50,
    include_notes=True,
    include_files=True
):
    events_list.append(event)
    
print(f"Found {len(events_list)} active events")

# Limit results with max_results
count = 0
for event in client.get_events(state='active', max_results=10):
    count += 1
    print(f"{count}. {event['title']}")
    
# Filter by event type
for event in client.get_events(event_type='wildlife_sighting_rep'):
    print(f"Wildlife sighting: {event['title']}")

Uso del cliente asíncrono (AsyncERClient) para un mejor rendimiento:

Nota: Requiere Python 3.7+ con soporte asyncio

from erclient.client import AsyncERClient
import asyncio  # Built-in Python module

async def list_events():
    # Use as async context manager (recommended)
    async with AsyncERClient(
        service_root='https://your-domain.pamdas.org/api/v1.0',
        token='YOUR_TOKEN_HERE'
    ) as client:
        
        # get_events() returns an async generator
        count = 0
        async for event in client.get_events(
            page_size=100,
            filter='{"state":"active"}'  # JSON string filter
        ):
            print(f"{event['title']} - {event['state']}")
            count += 1
            
        print(f"Total events processed: {count}")

# Run the async function
asyncio.run(list_events())

Usando la biblioteca de solicitudes directamente (sin er-client):

import requests

API_URL = 'https://your-domain.pamdas.org/api/v1.0'
TOKEN = 'YOUR_TOKEN_HERE'

headers = {
    'Authorization': f'Bearer {TOKEN}',
    'Accept': 'application/json'
}

# Make request
params = {
    'state': 'active',
    'page_size': 50,
    'sort_by': '-updated_at'
}

response = requests.get(
    f'{API_URL}/activity/events/',
    headers=headers,
    params=params
)

if response.status_code == 200:
    data = response.json()
    print(f"Total count: {data['count']}")
    
    for event in data['results']:
        print(f"{event['title']} - {event['state']}")
        
    # Handle pagination
    while data.get('next'):
        response = requests.get(data['next'], headers=headers)
        data = response.json()
        for event in data['results']:
            print(f"{event['title']} - {event['state']}")
else:
    print(f"Error: {response.status_code}")
    print(response.text)
 
 

Node.js

Usando axios:

const axios = require('axios');

const API_URL = 'https://your-domain.pamdas.org/api/v1.0';
const TOKEN = 'YOUR_TOKEN_HERE';

async function listEvents() {
  try {
    const response = await axios.get(
      `${API_URL}/activity/events/`,
      {
        headers: {
          'Authorization': `Bearer ${TOKEN}`,
          'Accept': 'application/json'
        },
        params: {
          state: 'active',
          page_size: 50,
          sort_by: '-updated_at'
        }
      }
    );
    
    console.log(`Total events: ${response.data.count}`);
    
    response.data.results.forEach(event => {
      console.log(`${event.title || 'Untitled'} - ${event.state}`);
      if (event.location) {
        console.log(`Location: ${event.location.latitude}, ${event.location.longitude}`);
      }
    });
    
    // Check if there are more pages
    if (response.data.next) {
      console.log('More results available at:', response.data.next);
    }
    
    return response.data;
  } catch (error) {
    console.error('Error fetching events:', error.response?.data || error.message);
    throw error;
  }
}

// Run the function
listEvents();

Usando la búsqueda nativa (Node.js 18+):

const API_URL = 'https://your-domain.pamdas.org/api/v1.0';
const TOKEN = 'YOUR_TOKEN_HERE';

async function listEvents() {
  const params = new URLSearchParams({
    state: 'active',
    page_size: '50',
    sort_by: '-updated_at'
  });
  
  const response = await fetch(
    `${API_URL}/activity/events/?${params}`,
    {
      method: 'GET',
      headers: {
        'Authorization': `Bearer ${TOKEN}`,
        'Accept': 'application/json'
      }
    }
  );
  
  if (!response.ok) {
    throw new Error(`HTTP error! status: ${response.status}`);
  }
  
  const data = await response.json();
  console.log(`Found ${data.count} events`);
  
  // Process results
  data.results.forEach(event => {
    console.log(`${event.title} - ${event.state}`);
  });
  
  return data;
}

listEvents()
  .then(data => console.log('Success:', data))
  .catch(error => console.error('Error:', error));
 
 

Ejemplo de respuesta:

{
  "count": 150,
  "next": "https://your-domain.pamdas.org/api/v1.0/activity/events/?page=2&state=active&page_size=50",
  "previous": null,
  "results": [
    {
      "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
      "serial_number": 12345,
      "event_type": "wildlife_sighting_rep",
      "priority": 200,
      "state": "active",
      "location": {
        "latitude": -2.345678,
        "longitude": 34.567890
      },
      "time": "2024-10-19T14:30:00Z",
      "end_time": null,
      "created_at": "2024-10-19T14:35:00Z",
      "updated_at": "2024-10-19T14:35:00Z",
      "title": "Elephant Sighting",
      "reported_by": {
        "id": "user123",
        "username": "ranger.john",
        "first_name": "John",
        "last_name": "Doe"
      },
      "event_details": {
        "species": "African Elephant",
        "number_of_individuals": 5,
        "behavior": "Feeding"
      }
    },
    {
      "id": "b2c3d4e5-f6g7-8901-bcde-f12345678901",
      "serial_number": 12346,
      "event_type": "security_incident",
      "priority": 500,
      "state": "active",
      "location": {
        "latitude": -2.456789,
        "longitude": 34.678901
      },
      "time": "2024-10-19T13:15:00Z",
      "end_time": null,
      "created_at": "2024-10-19T13:20:00Z",
      "updated_at": "2024-10-19T13:20:00Z",
      "title": "Suspicious Activity Near Boundary",
      "reported_by": {
        "id": "user456",
        "username": "ranger.jane",
        "first_name": "Jane",
        "last_name": "Smith"
      },
      "event_details": {
        "incident_type": "trespassing",
        "number_of_individuals": 3,
        "description": "Three individuals spotted near north fence"
      }
    }
  ]
}

Obtener evento único

GET /api/v1.0/activity/event/{id}/

Pedido:

GET /api/v1.0/activity/event/a1b2c3d4-e5f6-7890-abcd-ef1234567890/
Authorization: Bearer your_token_here

Respuesta (200 OK):

{
  "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "serial_number": 12345,
  "event_type": "wildlife_sighting_rep",
  "priority": 200,
  "state": "active",
  "location": {
    "latitude": -2.345678,
    "longitude": 34.567890
  },
  "time": "2024-10-19T14:30:00Z",
  "end_time": null,
  "created_at": "2024-10-19T14:35:00Z",
  "updated_at": "2024-10-19T14:35:00Z",
  "title": "Elephant Sighting",
  "reported_by": {
    "id": "user123",
    "username": "ranger.john",
    "first_name": "John",
    "last_name": "Doe"
  },
  "event_details": {
    "species": "African Elephant",
    "number_of_individuals": 5,
    "behavior": "Feeding"
  },
  "notes": [],
  "files": [],
  "event_category": "monitoring"
}

Crear un evento

POST /api/v1.0/activity/events/

Para crear un nuevo evento en EarthRanger, envíe una solicitud POST con los detalles del evento.

Campos obligatorios:

Campo Tipo Descripción
event_type string Valor del tipo de evento (debe coincidir con los tipos de eventos configurados)
time datetime Hora de ocurrencia del evento (formato ISO8601)
location object Ubicación del evento con latitud y longitud

Campos opcionales:

Campo Tipo Descripción
priority integer Prioridad del evento (0-500, valor predeterminado: 0)
state string Estado del evento: nuevo, activo o resuelto
title string Título/resumen del evento
event_details object Datos adicionales específicos del evento

Pedido:

POST /api/v1.0/activity/events/
Authorization: Bearer your_token_here
Content-Type: application/json

{
  "event_type": "mist_rep",
  "time": "2024-10-19T06:18:44.056439Z",
  "priority": 100,
  "location": {
    "latitude": 47.123,
    "longitude": -122.123
  },
  "title": "Medical Incident - Ranger Station",
  "event_details": {
    "mistrep_Method": "Air Evac",
    "mistrep_Injury": "Malaria",
    "mistrep_Symptoms": "Fever and sweating",
    "mistrep_Treatment": "Anti malarial medicine"
  }
}

Respuesta (201 creados):

{
  "id": "f1e2d3c4-b5a6-7890-cdef-123456789abc",
  "serial_number": 12346,
  "event_type": "mist_rep",
  "priority": 100,
  "state": "new",
  "location": {
    "latitude": 47.123,
    "longitude": -122.123
  },
  "time": "2024-10-19T06:18:44.056439Z",
  "created_at": "2024-10-19T15:20:00Z",
  "updated_at": "2024-10-19T15:20:00Z",
  "title": "Medical Incident - Ranger Station",
  "reported_by": {
    "id": "current_user_id",
    "username": "api.user"
  },
  "event_details": {
    "mistrep_Method": "Air Evac",
    "mistrep_Injury": "Malaria",
    "mistrep_Symptoms": "Fever and sweating",
    "mistrep_Treatment": "Anti malarial medicine"
  }
}

El event_type y cada clave en event_details deben coincidir con un campo definido en el esquema de tipo de evento configurado (consulte Admin > Activity > Event Types).

 

Actualizar un evento

PATCH /api/v1.0/activity/event/{id}/

Pedido:

PATCH /api/v1.0/activity/event/f1e2d3c4-b5a6-7890-cdef-123456789abc/
Authorization: Bearer your_token_here
Content-Type: application/json

{
  "state": "resolved",
  "priority": 50
}

Respuesta (200 OK):

{
  "id": "f1e2d3c4-b5a6-7890-cdef-123456789abc",
  "serial_number": 12346,
  "event_type": "mist_rep",
  "priority": 50,
  "state": "resolved",
  "location": {
    "latitude": 47.123,
    "longitude": -122.123
  },
  "time": "2024-10-19T06:18:44.056439Z",
  "updated_at": "2024-10-19T16:00:00Z",
  "title": "Medical Incident - Ranger Station"
}

Lista de tipos de eventos

GET /api/v2.0/activity/eventtypes/

Parámetros de consulta:

Parametro Tipo Descripción
include_inactive Optional boolean Incluir tipos de eventos inactivos en los resultados

Ejemplos de código:

cURL

curl -X GET "https://your-domain.pamdas.org/api/v2.0/activity/eventtypes/" \\
  -H "Authorization: Bearer YOUR_TOKEN_HERE" \\
  -H "Accept: application/json"
 
 

Python

import requests

API_URL = 'https://your-domain.pamdas.org/api/v2.0'
TOKEN = 'YOUR_TOKEN_HERE'

headers = {
    'Authorization': f'Bearer {TOKEN}',
    'Accept': 'application/json'
}

response = requests.get(f'{API_URL}/activity/eventtypes/', headers=headers)

if response.status_code == 200:
    data = response.json()
    for event_type in data['data']:
        print(f"{event_type['display']} ({event_type['value']})")
        print(f"  Category: {event_type['category']}")
        print(f"  Default Priority: {event_type['default_priority']}")
else:
    print(f"Error: {response.status_code}")
    print(response.text)
 
 

Node.js

const axios = require('axios');

const API_URL = 'https://your-domain.pamdas.org/api/v2.0';
const TOKEN = 'YOUR_TOKEN_HERE';

async function listEventTypes() {
  try {
    const response = await axios.get(
      \`\${API_URL}/activity/eventtypes/\`,
      {
        headers: {
          'Authorization': \`Bearer \${TOKEN}\`,
          'Accept': 'application/json'
        }
      }
    );
    
    console.log('Event Types:');
    response.data.data.forEach(eventType => {
      console.log(\`\${eventType.display} (\${eventType.value})\`);
      console.log(\`  Category: \${eventType.category}\`);
    });
    
    return response.data;
  } catch (error) {
    console.error('Error:', error.response?.data || error.message);
    throw error;
  }
}

listEventTypes();
 
 

Ejemplo de respuesta:

{
  "data": [
    {
      "id": "8e2812d8-4ac9-4874-b1b2-1adc5ea192b5",
      "url": "https://your-domain.pamdas.org/api/v2.0/activity/eventtypes/snare_rep/",
      "has_events_assigned": true,
      "icon_id": "snare_rep",
      "value": "snare_rep",
      "display": "Snare",
      "ordernum": 160,
      "category": "security",
      "geometry_type": "Polygon",
      "default_priority": 0,
      "default_state": "new",
      "resolve_time": null,
      "auto_resolve": false,
      "is_collection": false,
      "is_active": true,
      "icon": "snare_rep"
    }
  ]
}

Obtener un solo tipo de evento

GET /api/v2.0/activity/eventtypes/{eventtype_value}/

Parámetros de consulta:

Parametro Tipo Descripción
include_inactive Optional boolean Incluir tipos de eventos inactivos
include_schema Optional boolean Incluir la definición completa del esquema JSON

Pedido:

GET /api/v2.0/activity/eventtypes/snare_rep/?include_schema=true
Authorization: Bearer your_token_here

Respuesta (200 OK):

{
  "data": {
    "id": "8e2812d8-4ac9-4874-b1b2-1adc5ea192b5",
    "value": "snare_rep",
    "display": "Snare",
    "category": "security",
    "default_priority": 0,
    "default_state": "new",
    "schema": {
      "json": {
        "$schema": "https://json-schema.org/draft/2020-12/schema",
        "type": "object",
        "properties": {
          "number_of_snares_found": {
            "type": "number",
            "title": "Number of Snares Found"
          },
          "status": {
            "type": "string",
            "title": "Status"
          },
          "comments": {
            "type": "string",
            "title": "Comments",
            "default": ""
          }
        }
      },
      "ui": {
        "fields": {
          "number_of_snares_found": {
            "type": "NUMERIC",
            "parent": "section-1"
          },
          "status": {
            "type": "CHOICE_LIST",
            "inputType": "DROPDOWN",
            "parent": "section-1"
          }
        }
      }
    }
  }
}

Crear tipo de evento

POST /api/v2.0/activity/eventtypes/

Cree un nuevo tipo de evento con validación de esquema JSON y configuración de UI.

Campos obligatorios:

Campo Tipo Descripción
value string Identificador único para el tipo de evento
display string Nombre para mostrar
schema string Definición del esquema JSON (JSON convertido en cadena)

Campos opcionales:

Campo Tipo Descripción
category string Categoría del evento (por ejemplo, seguridad, monitoreo, logística)
default_priority integer Prioridad predeterminada (0-500)
default_state string Estado predeterminado (nuevo, activo, resuelto)
geometry_type string Punto, cadena de líneas o polígono
icon string Identificador de icono
auto_resolve boolean Resolución automática después de resolve_time
resolve_time integer Tiempo de resolución automática en segundos
is_active boolean Si el tipo de evento está activo

Pedido:

POST /api/v2.0/activity/eventtypes/
Authorization: Bearer your_token_here
Content-Type: application/json

{
  "value": "custom_incident",
  "display": "Custom Incident",
  "category": "security",
  "default_priority": 300,
  "default_state": "new",
  "geometry_type": "Point",
  "is_active": true,
  "schema": "{\\"json\\":{\\"$schema\\":\\"https://json-schema.org/draft/2020-12/schema\\",\\"type\\":\\"object\\",\\"properties\\":{\\"description\\":{\\"type\\":\\"string\\",\\"title\\":\\"Description\\"}}}}"
}

Respuesta (201 creados):

{
  "data": {
    "resource_url": "/api/v2.0/activity/eventtypes/custom_incident/"
  }
}

Actualizar tipo de evento

PATCH /api/v2.0/activity/eventtypes/{eventtype_value}/

Pedido:

PATCH /api/v2.0/activity/eventtypes/custom_incident/
Authorization: Bearer your_token_here
Content-Type: application/json

{
  "default_priority": 400,
  "is_active": false
}

Respuesta (200 OK):

{
  "data": {
    "id": "uuid-here",
    "value": "custom_incident",
    "display": "Custom Incident",
    "default_priority": 400,
    "is_active": false
  }
}

Eliminar tipo de evento

DELETE /api/v2.0/activity/eventtypes/{eventtype_value}/

Pedido:

DELETE /api/v2.0/activity/eventtypes/custom_incident/
Authorization: Bearer your_token_here

Códigos de respuesta:

  • 204 No Content: Eliminado correctamente
  • 404 Not Found: No se encontró el tipo de evento
  • 409 Conflict: El tipo de evento tiene eventos asociados y no se puede eliminar

Nota: Los tipos de evento con eventos asociados no se pueden eliminar. Debe eliminar o reasignar todos los eventos antes de eliminarlos.

 

Publicación de datos del sensor

El concepto general es que un proveedor de fuentes es un servicio que describe una o más fuentes que proporcionan información de ubicación de un sujeto.

Por ejemplo, un fabricante de dispositivos de rastreo es un proveedor de fuentes, un rastreador de rinocerontes es una fuente y el propio rinoceronte es el sujeto.

Como es habitual, los encabezados de API:

Authorization: Bearer <token>
Accept: application/json
Content-Disposition: attachment; filename={}
Content-Type: application/json

Sujetos

Los sujetos representan entidades rastreadas, como vida silvestre, guardabosques, vehículos o cualquier activo monitoreado.

Lista de temas

GET /api/v1.0/subjects/

Parámetros de consulta:

Parametro Tipo Descripción
subject_group Optional UUID Filtrar por grupo temático
tracks Optional boolean Incluir datos de seguimiento recientes
tracks_since Optional datetime Hora de inicio de las pistas (ISO8601)
bbox Optional string Filtrar por cuadro delimitador
subject_type Optional string Filtrar por tipo de tema

Pedido:

GET /api/v1.0/subjects/?tracks=true&tracks_since=2024-10-01T00:00:00Z
Authorization: Bearer your_token_here

Respuesta (200 OK):

[
  {
    "id": "abc12345-def6-7890-ghij-klmnopqrstuv",
    "name": "Elephant_001",
    "subject_type": "wildlife",
    "subject_subtype": "elephant",
    "is_active": true,
    "region": "North Sector",
    "sex": "male",
    "additional": {
      "age_years": 15,
      "collar_id": "COL-001"
    },
    "last_position": {
      "id": "pos123",
      "location": {
        "latitude": -2.345678,
        "longitude": 34.567890
      },
      "recorded_at": "2024-10-19T14:00:00Z"
    },
    "tracks": [
      {
        "location": {
          "latitude": -2.345678,
          "longitude": 34.567890
        },
        "recorded_at": "2024-10-19T14:00:00Z"
      },
      {
        "location": {
          "latitude": -2.345123,
          "longitude": 34.568123
        },
        "recorded_at": "2024-10-19T13:00:00Z"
      }
    ]
  }
]

Obtener un solo sujeto

GET /api/v1.0/subject/{id}/

Pedido:

GET /api/v1.0/subject/abc12345-def6-7890-ghij-klmnopqrstuv/
Authorization: Bearer your_token_here

Respuesta (200 OK):

{
  "id": "abc12345-def6-7890-ghij-klmnopqrstuv",
  "name": "Elephant_001",
  "subject_type": "wildlife",
  "subject_subtype": "elephant",
  "is_active": true,
  "region": "North Sector",
  "sex": "male",
  "additional": {
    "age_years": 15,
    "collar_id": "COL-001"
  },
  "last_position": {
    "id": "pos123",
    "location": {
      "latitude": -2.345678,
      "longitude": 34.567890
    },
    "recorded_at": "2024-10-19T14:00:00Z"
  }
}

Crear un sujeto

POST /api/v1.0/subjects/

Cree un nuevo sujeto en EarthRanger. Los sujetos suelen crearse automáticamente al publicar observaciones, pero también pueden crearse manualmente.

Campos obligatorios:

Campo Tipo Descripción
name string Nombre del sujeto (debe ser único)
subject_subtype UUID or string Identificador de subtipo de sujeto

Pedido:

POST /api/v1.0/subjects/
Authorization: Bearer your_token_here
Content-Type: application/json

{
  "name": "Ranger_Vehicle_05",
  "subject_subtype": "4x4",
  "additional": {
    "plate_number": "GNP-005",
    "model": "Land Cruiser"
  }
}

Respuesta (201 creados):

{
  "id": "xyz98765-abc4-3210-defg-hijklmnopqrs",
  "name": "Ranger_Vehicle_05",
  "subject_type": "vehicle",
  "subject_subtype": "4x4",
  "is_active": true,
  "additional": {
    "plate_number": "GNP-005",
    "model": "Land Cruiser"
  },
  "created_at": "2024-10-19T15:30:00Z"
}

Observaciones

Las observaciones son puntos de datos de seguimiento/ubicación individuales recopilados de dispositivos o fuentes.

Lista de observaciones

GET /api/v1.0/observations/

Parámetros de consulta:

Parametro Tipo Descripción
subject_id Optional UUID Filtrar por tema
source_id Optional UUID Filtrar por fuente
since Optional datetime Fecha/hora de inicio (ISO8601)
until Optional datetime Fecha/hora de finalización (ISO8601)

Pedido:

GET /api/v1.0/observations/?subject_id=abc123&since=2024-10-01T00:00:00Z
Authorization: Bearer your_token_here

Respuesta (200 OK):

[
  {
    "id": "obs-12345",
    "location": {
      "latitude": -2.345678,
      "longitude": 34.567890
    },
    "recorded_at": "2024-10-19T14:00:00Z",
    "created_at": "2024-10-19T14:05:00Z",
    "source": "gps-collar-001",
    "subject": {
      "id": "abc123",
      "name": "Elephant_001"
    },
    "additional": {
      "speed": 2.5,
      "heading": 145
    }
  }
]

Crear una observación

POST /api/v1.0/observations/

Publica un punto de seguimiento o la lectura de un sensor. Si el sistema no ha detectado la combinación source-provider/manufacturer_id anteriormente, creará fuentes y sujetos automáticamente.

Campos obligatorios:

Campo Tipo Descripción
location object Objeto de ubicación con latitud y longitud
recorded_at datetime Hora en que se registró la observación (ISO8601)

Campos opcionales:

Campo Tipo Descripción
manufacturer_id string Identificador único del dispositivo
source_type string Tipo de fuente (p. ej., dispositivo_de_seguimiento)
subject_name string Nombre del sujeto que se está rastreando
subject_type string Tipo de sujeto (por ejemplo, vida silvestre, persona, vehículo)
subject_subtype string Subtipo de sujeto (p. ej., elefante, guardabosques, automóvil)
additional object Metadatos adicionales (velocidad, rumbo, etc.)

Pedido:

POST /api/v1.0/observations/
Authorization: Bearer your_token_here
Content-Type: application/json

{
  "location": {
    "lat": 47.123,
    "lon": -122.123
  },
  "recorded_at": "2024-10-19T13:59:15.000Z",
  "manufacturer_id": "COLLAR-12345",
  "subject_name": "Elephant_001",
  "subject_type": "wildlife",
  "subject_subtype": "elephant",
  "source_type": "tracking_device",
  "additional": {
    "speed": 2.5,
    "heading": 145,
    "battery_level": 85
  }
}

Respuesta (201 creados):

{
  "id": "obs-98765",
  "location": {
    "latitude": 47.123,
    "longitude": -122.123
  },
  "recorded_at": "2024-10-19T13:59:15.000Z",
  "created_at": "2024-10-19T14:00:00Z",
  "source": {
    "id": "src-12345",
    "manufacturer_id": "COLLAR-12345",
    "source_type": "tracking_device"
  },
  "subject": {
    "id": "subj-67890",
    "name": "Elephant_001",
    "subject_type": "wildlife",
    "subject_subtype": "elephant"
  },
  "additional": {
    "speed": 2.5,
    "heading": 145,
    "battery_level": 85
  }
}

Nota: Si pasa una observación en la que el sistema no ha visto antes esa combinación source-provider/manufacturer_id, creará fuentes y sujetos según sea necesario.

 

Grupos de sujetos

Los grupos de temas organizan los temas en categorías jerárquicas para su gestión y filtrado.

Lista de grupos de temas

GET /api/v1.0/subjectgroups/

Pedido:

GET /api/v1.0/subjectgroups/
Authorization: Bearer your_token_here

Respuesta (200 OK):

[
  {
    "id": "grp-12345",
    "name": "Wildlife",
    "subject_count": 45,
    "is_visible": true,
    "children": [
      {
        "id": "grp-12346",
        "name": "Elephants",
        "subject_count": 12,
        "is_visible": true
      },
      {
        "id": "grp-12347",
        "name": "Rhinos",
        "subject_count": 8,
        "is_visible": true
      }
    ]
  },
  {
    "id": "grp-12348",
    "name": "Rangers",
    "subject_count": 25,
    "is_visible": true
  }
]

Lista de sujetos en el grupo

GET /api/v1.0/subjectgroup/{id}/subjects/

Pedido:

GET /api/v1.0/subjectgroup/grp-12346/subjects/
Authorization: Bearer your_token_here

Respuesta (200 OK):

[
  {
    "id": "subj-001",
    "name": "Elephant_001",
    "subject_type": "wildlife",
    "subject_subtype": "elephant",
    "is_active": true,
    "last_position": {
      "latitude": -2.345678,
      "longitude": 34.567890,
      "recorded_at": "2024-10-19T14:00:00Z"
    }
  },
  {
    "id": "subj-002",
    "name": "Elephant_002",
    "subject_type": "wildlife",
    "subject_subtype": "elephant",
    "is_active": true,
    "last_position": {
      "latitude": -2.346789,
      "longitude": 34.568901,
      "recorded_at": "2024-10-19T14:05:00Z"
    }
  }
]

Patrullas

Las patrullas representan operaciones de campo con segmentos, puntos de referencia y eventos asociados.

Lista de patrullas

GET /api/v1.0/activity/patrols/

Parámetros de consulta:

Parametro Tipo Descripción
exclude_empty_patrols Optional boolean Excluir patrullas sin segmentos ni eventos
patrol_type Optional UUID Filtrar por tipo de patrulla
since Optional datetime Fecha/hora de inicio (ISO8601)
until Optional datetime Fecha/hora de finalización (ISO8601)

Pedido:

GET /api/v1.0/activity/patrols/?exclude_empty_patrols=true
Authorization: Bearer your_token_here

Respuesta (200 OK):

{
  "count": 10,
  "results": [
    {
      "id": "patrol-12345",
      "serial_number": 501,
      "title": "Morning Patrol - North Sector",
      "patrol_type": "routine",
      "state": "done",
      "start_time": "2024-10-19T06:00:00Z",
      "end_time": "2024-10-19T12:00:00Z",
      "patrol_segments": [
        {
          "id": "seg-001",
          "scheduled_start": "2024-10-19T06:00:00Z",
          "scheduled_end": "2024-10-19T08:00:00Z",
          "time_range": {
            "start_time": "2024-10-19T06:15:00Z",
            "end_time": "2024-10-19T07:45:00Z"
          },
          "leader": {
            "id": "user-123",
            "name": "John Ranger"
          }
        }
      ],
      "events": [
        {
          "id": "evt-456",
          "event_type": "wildlife_sighting_rep",
          "time": "2024-10-19T07:30:00Z"
        }
      ]
    }
  ]
}

Obtener una patrulla única

GET /api/v1.0/activity/patrol/{id}/

Pedido:

GET /api/v1.0/activity/patrol/patrol-12345/
Authorization: Bearer your_token_here

Respuesta (200 OK):

{
  "id": "patrol-12345",
  "serial_number": 501,
  "title": "Morning Patrol - North Sector",
  "patrol_type": "routine",
  "state": "done",
  "start_time": "2024-10-19T06:00:00Z",
  "end_time": "2024-10-19T12:00:00Z",
  "created_at": "2024-10-18T20:00:00Z",
  "updated_at": "2024-10-19T12:05:00Z",
  "patrol_segments": [
    {
      "id": "seg-001",
      "scheduled_start": "2024-10-19T06:00:00Z",
      "scheduled_end": "2024-10-19T08:00:00Z",
      "time_range": {
        "start_time": "2024-10-19T06:15:00Z",
        "end_time": "2024-10-19T07:45:00Z"
      },
      "leader": {
        "id": "user-123",
        "username": "john.ranger",
        "name": "John Ranger"
      },
      "events": [
        {
          "id": "evt-456",
          "event_type": "wildlife_sighting_rep",
          "title": "Elephant Sighting",
          "time": "2024-10-19T07:30:00Z"
        }
      ]
    }
  ],
  "notes": []
}

Seguimiento de sujetos

Los datos de seguimiento muestran el historial de movimiento de un sujeto a lo largo del tiempo.

Obtener seguimiento de sujetos

GET /api/v1.0/subject/{subject_id}/tracks/

Parámetros de consulta:

Parametro Tipo Descripción
since Optional datetime Fecha/hora de inicio (ISO8601)
until Optional datetime Fecha/hora de finalización (ISO8601)
format Optional string Formato de respuesta: json, geojson o csv

Pedido:

GET /api/v1.0/subject/abc123/tracks/?since=2024-10-01T00:00:00Z
Authorization: Bearer your_token_here

Respuesta (200 OK):

[
  {
    "id": "track-001",
    "location": {
      "latitude": -2.345678,
      "longitude": 34.567890
    },
    "recorded_at": "2024-10-19T14:00:00Z",
    "created_at": "2024-10-19T14:05:00Z",
    "source": "gps-collar-001",
    "additional": {
      "speed": 2.5,
      "heading": 145,
      "altitude": 1250
    }
  },
  {
    "id": "track-002",
    "location": {
      "latitude": -2.345123,
      "longitude": 34.568123
    },
    "recorded_at": "2024-10-19T13:00:00Z",
    "created_at": "2024-10-19T13:05:00Z",
    "source": "gps-collar-001",
    "additional": {
      "speed": 1.8,
      "heading": 150,
      "altitude": 1245
    }
  }
]

Patrones comunes

Formato de fecha y hora

Todos los parámetros de fecha y hora deben estar en formato ISO8601 con zona horaria:

2024-10-19T14:30:00Z          # UTC
2024-10-19T14:30:00-06:00     # With timezone offset

Paginación

La mayoría de los puntos finales de lista admiten la paginación con los parámetros page y page_size. La respuesta incluye los campos count, next y previous.

Solicitud Página 1:

GET /api/v1.0/activity/events/?page_size=25

Respuesta:

{
  "count": 150,
  "next": "https://your-domain.pamdas.org/api/v1.0/activity/events/?page=2&page_size=25",
  "previous": null,
  "results": [...]
}

Solicitar página siguiente:

GET /api/v1.0/activity/events/?page=2&page_size=25

Filtrado por cuadro delimitador

Formato: oeste, sur, este, norte (longitud_mínima, latitud_mínima, longitud_máxima, latitud_máxima)

?bbox=-122.5,48.4,-122.0,49.0

Obtenga todos los eventos dentro de un área geográfica:

GET /api/v1.0/activity/events/?bbox=34.5,-2.5,34.6,-2.3
Authorization: Bearer your_token_here

Esto devuelve todos los eventos con ubicaciones entre:

  • Longitud: 34,5° a 34,6° Este
  • Latitud: -2,5° a -2,3° Sur

Manejo de errores

La API devuelve códigos de estado HTTP estándar. Respuestas de error comunes:

Código de estado Significado Causas Comunes
400 Solicitud incorrecta Parámetros no válidos o JSON mal formado
401 No autorizado Token de autenticación faltante o no válido
403 Prohibido Permisos insuficientes
404 No encontrado El recurso no existe
500 Error del servidor Error Interno del Servidor

400 Solicitud incorrecta:

{
  "status": {
    "code": 400,
    "message": "Bad Request",
    "details": "Invalid datetime format for 'since' parameter"
  }
}

401 No autorizado:

{
  "detail": "Authentication credentials were not provided."
}