# Persat API v1.0

Documentación de la primer versión de la API.

## Bienvenido/a

Te damos la bienvenida al sitio para desarrolladores de Persat. En estas páginas encontrarás toda la información necesaria para utilizar nuestra **API**, que te permitirá desarrollar integraciones a medida.

Si no tienes ni idea de lo que es una API, entonces lo mejor será que comiences por: [¿Qué es una API?](/introduccion-1/que-es-una-api) y [¿Cómo funciona?](/introduccion-1/como-funciona) en donde te damos una breve introducción.

Si ya tienes algo de experiencia, puedes empezar directamente por la sección [Introducción](/como-usar-la-api/introduccion) en donde se introducen conceptos comunes al uso de toda la API, como su estructura, organización, listados, paginación, tipos de respuestas, errores, configuración de webhooks, etc.

Te recomendamos leer todas las secciones de este documento para aprovechar al máximo las funcionalidades.

Si hay algo que no encuentras en la documentación o tienes alguna duda, puedes contactarte con nuestro [equipo de desarrollo](mailto:info@persat.com.ar).


# ¿Qué es una API?

Una API es un servicio que se usa para leer y escribir datos de una aplicación desde un sitio externo. Esto permite que todos puedan integrar en su propio sitio o aplicación las funcionalidades ofrecidas a través de su API.

Muchas plataformas ofrecen una API pública para sus usuarios. Por ejemplo, con la API de Facebook podemos mostrar amigos, fotos y eventos; con la API de Twitter podemos leer tweets; con la de Flickr podemos obtener fotos; con la de Wikipedia obtener el contenido de un artículo... y mucho más, en muchos otros servicios.

Además de poder leer datos, una API nos pemite también escribir y subir nuevo contenido.

## Pero... ¿no es lo mismo que entrar al sitio?

No, porque una API otorga únicamente los datos, mientras que al entrar a un sitio vemos el HTML completo (con estilos, footer, header, sidebar, publicidad y muchos elementos extra). Al consultar una API obtenemos sólo los datos en crudo, sin ningún tipo de diseño. Esto nos permite procesar esos datos puros y mostrarlos de la forma que querramos, en nuestro sitio web o aplicación.

Y, como dijimos antes, una API sirve para subir contenido. Esto significa que podemos crear o actualizar contenido de una aplicación sin necesidad de entrar a su web y postearlo manualmente: si integramos una API a nuestro sitio web, podemos automatizar el proceso.


# ¿Cómo funciona?

Hasta el momento hablamos mucho de las APIs, pero puede ser difícil de imaginar su funcionamiento si nunca se trabajó con una. Pero es muy simple.

Al igual que un sitio web, una API tiene una URL. Generalmente, es un subdominio del dominio principal. Se indica también la versión de la API a utilizar, para evitar problemas de compatibilidades con otras versiones disponibles. Por ejemplo:

```
https://api.persat.com.ar/v1
```

Luego el tipo de objeto que queremos obtener. Por ejemplo, tus clientes:

```
https://api.persat.com.ar/v1/clients
```

A esa URL podemos hacerles diferentes tipos de llamadas, o métodos HTTP:

* **GET** para leer los datos de los elementos
* **POST** para crear un elemento nuevo
* **PUT** para modificar los datos de un elemento
* **DELETE** para eliminar un elemento

## ¿En que formato se recibe la información?

La respuesta a cada una de estas llamadas será un conjunto de datos en formato JSON. Este tipo de formato permite estructurar información a partir de texto plano. Por ejemplo, si pedimos los datos de un cliente veríamos algo así:

```json
{
    "success": true,
    "data": {
        "uid_client": "CL-0044",
        "company_name": "Persat",
        "company_description": "Logistica GPS",
        "latitude": -34.598236,
        "longitude": -58.507811,
        "street": "San Nicolás",
        "street_nbr": "3940",
        "neighborhood": "Devoto",
        "city": "CABA",
        "country": "Argentina",
        "custom_fields": {
            "1": {
                "name": "Teléfono",
                "value": "11-4504-5300"
            }
        }
    }
}
```

Lo mejor es que el formato JSON puede ser comprendido y utilizado por cualquier lenguaje de programación: PHP, Java, .NET, Javascript, Phyton y más. Por eso, JSON se ha convertido en el lenguaje por defecto de todos las APIs en la actualidad.

## ¿Quienes pueden utilizar la API?

La API puede ser usada mientras tengas una cuenta activa en Persat. Solo necesitás un API key para poder acceder a los recursos.&#x20;


# Introducción

Usar el API de Persat es muy sencillo. Si usaste un **API REST** alguna vez, vas a sentirte como en casa. Si no, en esta guía vas a encontrar todo lo necesario para hacerlo.

Para comunicarnos con la API, debemos hacer un pedido a la URL base, seguido de la versión (en este caso v1), seguido del **namespace** correspondiente, es decir, el nombre del recurso al cual deseamos acceder. Los namespaces están en inglés, pero es muy sencillo reconocerlos. Por ejemplo, si necesitamos leer información de los clientes, entonces el namespace será `clients` y la URL completa será algo como:

```
https://api.persat.com.ar/v1/clients
```

## Métodos REST

Para leer o escribir información a través del API debemos hacer pedidos HTTP. Como las convenciones de REST indican, los métodos utilizados son los siguientes:

| Método     | URL               | Efecto                            |
| ---------- | ----------------- | --------------------------------- |
| **GET**    | `/[namespace]`    | Obtener un listado de elementos   |
| **GET**    | `/[namespace]/id` | Obtener el detalle de un elemento |
| **POST**   | `/[namespace]`    | Crear un nuevo elemento           |
| **PUT**    | `/[namespace]/id` | Modificar un elemento             |
| **DELETE** | `/[namespace]/id` | Eliminar un elemento              |

## Content type

El header Content-Type indica el formato que estamos utilizando en el contenido de un pedido POST o PUT. El único`Content-Type` que soporta la API por el momento es `application/json`

{% hint style="info" %}
Si indicamos un Content-Type no soportado, recibiremos un error 415 UNSUPPORTED\_MEDIA\_TYPE . En caso que el formato utilizado en el contenido no pueda ser interpretado correctamente, el error será 400 BAD\_REQUEST Api key
{% endhint %}

Para que nuestro pedido sea aceptado por el API, debemos enviar un **api key** válido que nos identifica como usuarios de la cuenta sobre la que queremos trabajar. Podés consultar cómo obtener un api key en la sección [autenticación](/como-usar-la-api/autenticacion).

En el siguiente ejemplo, mostramos como obtener los datos de un cliente particular con número de cliente "CL-0044", suponiendo además que nuestra api key es `YOUR_API_KEY`

```
curl --location --request GET "https://api.persat.com.ar/v1/clients/CL-0044" \
  --header "Authorization: Bearer YOUR_API_KEY"
```


# Niveles de Acceso y Consideraciones Importantes

## Niveles de acceso

Exiten hoy en día dos niveles de acceso para las API keys.

* Acceso TOTAL
* Acceso restringido a insertar datos de Rastreo únicamente

En caso de tener acceso TOTAL, se pueden realizar acciones sin restricción alguna de permisos.

{% hint style="danger" %}
Muchas de estas acciones no se pueden deshacer, como por ejemplo: borrar un cliente y todo su historial.
{% endhint %}

## Consideración a tener en cuenta

Cualquiera sea la integración se debe tener en cuenta que, en post de mejorar las prestaciones, Persat se reserva el derecho de agregar campos extra en los objetos JSON. Por lo que es importante preparar el soft integrador a recibir campos desconocidos e ignorarlos.

{% hint style="danger" %}
Ignorar campos extra
{% endhint %}


# Formato de Respuesta

Todas las respuestas de la API respetan el formato descripto en esta página.

### Encabezado de la respuesta (header)

Los posibles codigos del header de las respuestas son los siguientes:

| Code | Status                   | Significado                                                                                                                                                            |
| ---- | ------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| 200  | OK                       | Operación realizada con éxito                                                                                                                                          |
| 401  | UNAUTHORIZED             | No autorizado para realizar la operación. Api key incorrecta                                                                                                           |
| 404  | NOT\_FOUND               | El recurso no existe. Ya sea porque la url en si no existe, o porque el recurso que estamos buscando no esta disponible. Por ej: Si buscamos un cliente que no existe. |
| 400  | BAD\_REQUEST             | Error en el formato de la consulta. Puede haber campos faltantes o con valores erroneos.                                                                               |
| 409  | CONFLICT                 | Conflicto con campos únicos. Por ej: Quiero crear un cliente con un número que ya posee otro cliente en el sistema.                                                    |
| 415  | UNSUPPORTED\_MEDIA\_TYPE | El único media type soportado es application/json                                                                                                                      |
| 500  | INTERNAL\_ERROR          | Error interno del servidor. Algo salió mal.                                                                                                                            |

### Contenido de la respuesta (body)

El contenido de las respuestas de la API se recibe en formato JSON, y tiene esta estructura genérica:

{% hint style="warning" %}
A excepción de los PDFs que pueden ser en formato binario
{% endhint %}

```json
{    
    "success": true,    
    "paging": {
        "offset": 0,
        "limit": 20,
        "result": 20,
        "total": 195
    },
    "data": {} || [{}, {}, ...],
    "error": {
        "status": 404,
        "type": "BAD_REQUEST",
        "userMessage": "El campo x es obligatorio"    
    }
}
```

‌No siempre estarán presentes todas las propiedades, depende de que tipo de pedido se haya realizado y el resultado del mismo. Se constituye por los siguientes elementos:‌

**success** - Presente en todas las respuestas. Indica `true` si la llamada ha sido procesada con éxito, `false` en caso contrario. Es útil para hacer un chequeo general más allá del status code del header y saber si la respuesta contiene las propiedades data o error.‌

**paging** - En las respuestas de pedidos GET a las colecciones, la propiedad paging nos indicará los límites del listado con datos útiles como `offset` (a partir de qué elemento inicia el listado), `limit` (la cantidad de elementos en el listado actual recibido), `result` (la cantidad total de elementos coincidentes con la búsqueda) y `total` (el total de elementos en la colección).‌

**data** - En las respuestas de pedidos GET a las colecciones, la propiedad `data` es un array con los elementos requeridos. En caso de que la colección esté vacía, será un array vacío. En las respuestas de pedidos GET a un elemento, la propiedad `data`será un objeto con todos los campos del elemento en cuestión.&#x20;

**error** - Aquí se indica el detalle del error. Cada error tiene un `status` que coincide con el status de la respuesta HTTP, un`type` que lo identifica y un `userMessage` con el mensaje textual que puede mostrarse al usuario.‌

Los valores de `type` pueden ser los siguientes:

| type                         | Description                                                                                                                                  |
| ---------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------- |
| **UNAUTHORIZED**             | El api key no existe o es inválido.                                                                                                          |
| **NOT\_FOUND**               | El recurso especificado no existe, puede ser porque el ID especificado no exista. O se este haciendo una consulta a un endpoint inexistente. |
| **BAD\_REQUEST**             | El pedido tiene una estructura inválida.                                                                                                     |
| **CONFLICT**                 | El recurso que se intentó crear entra en conflicto con uno existente.                                                                        |
| **UNSUPPORTED\_MEDIA\_TYPE** | El formato de datos indicado no es soportado.                                                                                                |
| **INTERNAL\_ERROR**          | Ocurrió un error interno del servidor.                                                                                                       |


# Autenticación

La autenticación para poder acceder a los datos es por medio de un API key.&#x20;

{% hint style="danger" %}
&#x20;El API key no debe ser utilizado <mark style="color:red;">**NUNCA**</mark> desde el lado del cliente, es decir desde el navegador mediante javascript. Está diseñada para ser utlizado únicamente desde el lado servidor. Incluir el API key en el código javascript es muy inseguro ya que es visible fácilmente por cualquiera que acceda al sitio web.
{% endhint %}

{% hint style="danger" %}
Desde la API, se pueden realizar acciones sin restricción alguna de permisos. Muchas de estas acciones <mark style="color:red;">**no se pueden deshacer**</mark>, como es el caso de borrar un cliente y todo su historial.
{% endhint %}

## Uso del API key

Para realizar llamados a la API utilizando el API key debemos incluir el siguiente encabezado HTTP en cada pedido que realicemos:

```
Authorization: Bearer YOUR_API_KEY
```

Ejemplo para obtener el listado de clientes, suponiendo que nuestra Api key sea: `YOUR_API_KEY`

```
curl --location --request GET "https://api.persat.com.ar/v1/clients \
  --header "Authorization: Bearer YOUR_API_KEY"
```

## Mensajes de error

En caso que la key no sea correcta o que no este creada aún, recibirá un mensaje de este estilo.

```json
{
    "success": false,
    "error": {
        "status": 401,
        "type": "UNAUTHORIZED",
        "userMessage": "La api key utilizada es incorrecta"
    }
}
```


# Como obtener el Api key

Primero debe estar loggeado en Persat, para luego diríjase a la esquina superior derecha de la pantalla principal, hacia la barra de navegación. Presione el botón de usuario y luego seleccione "Integraciones y Partners"

<img src="/files/RV83zNvhIV9FtH9vECe5" alt="" width="268">

Una vez dentro de esta sección, presione  dentro del recuadro de la izquierda "Integra con nuestra API".

<img src="/files/BVQk5lPQikOAaizz9l2U" alt="" width="563">

Seleccione la opción **Api keys** y luego presione el botón **Crear mi primer Api Key**

{% hint style="info" %}
Se pueden crear tantas api keys como quiera. Sin embargo la eliminación de las mismas no es posible desde la web.&#x20;

Si desea eliminar un api key, debe enviar un mail a **<clientes@persat.com.ar>** solicitando la eliminación. Por una cuestión de seguridad y para poder hacer caso a dicha solicitud, el mail debe ser enviado desde la cuenta administrador de la plataforma.
{% endhint %}


# Configurar Webhooks

Gran parte de los recursos son accedidos por medio de webhooks. Por lo que en esta sección te mostraremos como configurar los endpoints para recibir eventos configurables y obtener así los datos correspondiente.

## Configuración

Para poder configurar los webhooks, debes primero estar loggeado en Persat, luego dirigirte a la esquina superior derecha de la pantalla principal, y presionar la opción "Integraciones y Partners" en la configuración de usuario.

<img src="/files/FTUNuMM2NtQRbFpnwLws" alt="" width="268">

Una vez dentro de la sección, presioná dentro del recuadro de la izquierda "Integra con nuestra API".

<img src="/files/QCQDQUGWlSki3eKvoFK5" alt="" width="563">

Seleccioná la opción Webhooks, y luego **Administrar webhooks**

Arriba a la derecha, podemos crear un nuevo endpoint con el boton "+ Add Endpoint"

![](/files/-Mf2zxlYf7LIlfM6rP5i)

Completá los datos de tus endpoints, recordá seleccionar cuales eventos van a ser escuchados por el mismo. Podés seleccionar uno, o varios. En caso de no seleccionar ninguno, se toma por defecto que se quiere escuchar a todos los eventos disponibles.

Hay 19 eventos disponibles

* **checkme.check\_in**  Se genera cuando el usuario de la app [Persat Check Me](https://play.google.com/store/apps/details?id=com.pst.checkme\&hl=es_AR\&pli=1) hace click en Fichar Entrada.
* **checkme.check\_out**  Se genera cuando el usuario de la app [Persat Check Me](https://play.google.com/store/apps/details?id=com.pst.checkme\&hl=es_AR\&pli=1) hace click en Fichar Saluda.
* **client.created** Se genera, tanto cuando se crea un cliente de forma manual, como así también cuando se importa un listado de clientes desde un archivo .csv&#x20;
* **client.updated** Se genera, tanto cuando se modifica un cliente particular, como así también cuando se realiza una modificación masiva desde un archivo .csv
* **client.deleted** Se genera cuando se elimina un cliente
* **delivery.created**  Se genera, tanto cuando se crea una nueva entrega de forma manual, como así también cuando se importa un listado de entregas desde un archivo excel
* **delivery.deleted**  Se genera tanto cuando se elimina una entrega particular, como cuando se eliminan varias entregas al mismo tiempo (operaciones masivas), asi como también si se elimina una entrega desde el endpoint correspondiente de la API
* **deliveryRoute.assigned:** Se genera cuando se asigna una ruta a un dispositivo. \ <mark style="color:red;">IMPORTANTE:</mark> Solo funciona en el módulo de entregas.
* **deliveryRoute.updated:** Se genera cuando se modifique la ruta asignada, existen varios casos que pueden disparar este evento. Están definidos [acá](/modulos/gestion-de-entregas/rutas-de-entrega/eventos-webhooks/ruta-modificada).
* **deliveryRoute.canceled:** Se genera cuando el usuario administrador o quien tenga permisos suficientes cancela una Ruta ya asignada.
* **delivery.finished**  Se genera tanto cuando se finaliza una entrega desde el celular, como cuando se finaliza desde la web por el administrador o quien tenga el permiso correspondiente.
* **digitalform.created**  Se genera cuando se inserta un nuevo formulario. Esto puede realizarse tanto desde la web como desde la app de Android.
* **digitalform.updated**  Se genera cuando se modifica un formulario existente. Esto puede realizarse tanto desde la web como desde la app de Android.
* **digitalform.state\_updated**  Se genera cuando el administrador o el usuario que posea permisos necesarios, modifique el estado de un formulario. Esta operación se realiza siempre desde la web.
* **digitalform.state\_updated\_massively**  Se genera cuando el administrador o el usuario que posea permisos necesarios, modifique el estado de formulario de forma masiva(el estado al que cambian es el mismo para todos). Esta operación se realiza siempre desde la web.
* **workorder.created**  Se genera cuando crea una OT en Persat. Esta operación se realiza siempre desde la web.
* **workorder.updated**  Se genera cuando la OT es modificada. Por ejemplo cuando se modifica el formulario de instrucciones, o se modifica la fecha y el horario de asignación. \ <mark style="color:red;">IMPORTANTE</mark>: No se dispara cuando la OT es finalizada o cerrada,
* **workorder.finished**  Se genera cuando el técnico da por finalizada la Orden de trabajo desde la app de Android.
* **workorder.closed**  Se genera cuando el administrador o el usuario que posea permisos necesarios, de por cerrada una orden de trabajo. Esta operación se realiza siempre desde la web.

![](/files/-Mfi9lpnQqoH5tBGs2yY)

{% hint style="info" %}
La información que se recibe en cada uno de los eventos, se explica con más detalle en las seccione posteriores.
{% endhint %}

{% hint style="success" %}
Listo, ya tenemos creados el/los webhooks necesarios para escuchar los eventos.
{% endhint %}


# Primeros pasos

Desde Persat, recomendamos la herramienta **Beeceptor** <https://beeceptor.com/> para poder generar endpoints online de forma gratuita. De esta forma se pueden hacer las primeras pruebas sin necesidad de montar un servidor propio para poder atajar los mensajes.

Existen también otras herramientas gratuitas online para recibir webhooks. Sientanse libres de elegir la de su preferencia.&#x20;


# Lógica de reintentos

Cada mensaje será enviado respetando el siguiente cronograma

* Inmediatamente
* 5 segundos
* 5 minutos
* 30 minutos
* 2 horas
* 5 horas
* 10 horas
* 10 horas

### Falla en la entrega

Despues de realizar todos los intentos mencionados, el mensaje será marcado como "failed".

{% hint style="success" %}
Los mensajes también se pueden reintentar manualmente desde el portal. Para poder ingresar hay que estar logueados en Persat e ir hasta **Administrar webhooks** como se explica en la sección [Configuración de webhook](/como-usar-la-api/nueva-entrega)
{% endhint %}

###


# Clientes

A través de la nueva API de Persat, vas a poder gestionar clientes de forma sencilla, integrando a tu sitio el alta de clientes, por ejemplo: Agregando un cliente a Persat cada vez que creas un nuevo cliente en tu ERP o sistema de tickets y viceversa.

### Campos personalizados de la ficha de Clientes

Persat permite crear una ficha para los clientes totalmente personalizada. Donde se suele colocar el teléfono, email, o cualquier otro campo que sea pertinente para la empresa.

Estos campos personalizados (custom\_fields), tienen un identificador único (id) para poder referenciarlos. Estos campos pueden o no ser obligatorios. Es decir que a la hora de agregear clientes o modificar, se debe tener en cuenta no enviar valores vacíos si es que el campo es obligatorio.

Una forma sencilla de obtener los identificadores de cada uno de ellos es desde la pantalla de Gestión de Clientes.

<figure><img src="/files/hYEq4ryPYE8xzmaWbnA5" alt=""><figcaption></figcaption></figure>

### ¿Que podés hacer con los Clientes?

En las siguientes secciones se explica todo lo que podes hacer con los clientes.

**Respecto a los clientes en si**

> [Obtener un Cliente](/entidades-basicas/clientes/obtener-un-cliente)
>
> [Agregar un Cliente](/entidades-basicas/clientes/agregar-un-cliente)
>
> [Modificar un Cliente](/entidades-basicas/clientes/modificar-un-cliente)
>
> [Eliminar un Cliente](/entidades-basicas/clientes/eliminar-un-cliente)
>
> [Listar Clientes](/entidades-basicas/clientes/listar-clientes)
>
> [Recibir eventos por medio de webhooks](/entidades-basicas/clientes/eventos-webhooks)

**Respecto a los campos personalizados**

> [Listar Campos Personalizados](/entidades-basicas/clientes/listar-campos-personalizados)

**Respecto a los Grupos de Clientes**

> [Listar Grupos de Clientes](/entidades-basicas/clientes/listar-grupos-de-clientes)
>
> [Listar Tipos de Clientes](/entidades-basicas/clientes/listar-tipos-de-clientes)


# Obtener un cliente

Obtener un cliente particular por medio de su **uid\_client** ("nro de cliente"), se puede realizar por medio de la siguiente consulta

<mark style="color:blue;">`GET`</mark> `https://api.persat.com.ar/v1/clients/uid_client`

#### Headers

| Name                                            | Type   | Description     |
| ----------------------------------------------- | ------ | --------------- |
| Authorization<mark style="color:red;">\*</mark> | string | Bearer API\_KEY |

{% tabs %}
{% tab title="200 Se obtuvo le cliente con éxito." %}

```javascript
{
    "success": true,
    "data": {
        "uid_client": "CL-0044"
        "company_name": "Persat",
        "company_description": "Logistica GPS",
        "type_id": 2,
	"group_id": 3,
        "latitude": -34.54646,
        "longitude": -58.4324324,
        "service_time": 20,          // Opcional
        "wt": [480, 780],            // Opcional
        "street": "Av. Rivadavia",
        "street_nbr": "1000",
        "neighborhood": "Devoto",
        "city": "CABA",
        "country": "Argentina",
        "last_updated": "2021-09-09T14:30:05.000Z",
        "custom_fields": {
            "1": {
                "name": "Notas",
                "value": ""
            },
            "2": {
                "name": "Telefono",
                "value": "4504-5300"
            },
            "8": {
                "name": "Entre calle 1",
                "value": ""
            },
            "9": {
                "name": "Entre calle 2",
                "value": ""
            },
            "10": {
                "name": "Mail de notificación",
                "value": "empresa@persat.com.ar"
            },
            "13": {
                "name": "Nombre del Contacto",
                "value": "Jose Perez"
            }
        }        
    }

```

{% endtab %}

{% tab title="404 El cliente no existe" %}

```javascript
{
    "success": false,
    "error": {
        "status": 404,
        "type": "NOT_FOUND",
        "userMessage": "No existe un cliente con este número."
    }
}
```

{% endtab %}
{% endtabs %}

A continuación un ejemplo con curl, en donde quiero obtener los datos del cliente "CL-0044"

```bash
curl --location --request GET "https://api.persat.com.ar/v1/clients/CL-0044" \
  --header "Authorization: Bearer YOUR_API_KEY"
```

### Analizando la Respuesta

En caso que no haya ningun error, obtenemos para nuestro caso de ejemplo algo asi:

```json
{
    "success": true,
    "data": {
        "uid_client": "CL-0044"
        "company_name": "Persat",
        "company_description": "Logistica GPS",
        "type_id": 2,
	"group_id": 3,
        "latitude": -34.54646,
        "longitude": -58.4324324,
        "service_time": 20,    // Puede ser undefined
        "wt": [480, 780],      // Puede ser undefined
        "street": "Av. Rivadavia",
        "street_nbr": "1000",
        "neighborhood": "Devoto",
        "city": "CABA",
        "country": "Argentina",
        "last_updated": "2021-09-09T14:30:05.000Z",
        "custom_fields": {
            "1": {
                "name": "Notas",
                "value": ""
            },
            "2": {
                "name": "Telefono",
                "value": "4504-5300"
            },
            "8": {
                "name": "Entre calle 1",
                "value": ""
            },
            "9": {
                "name": "Entre calle 2",
                "value": ""
            },
            "10": {
                "name": "Mail de notificación",
                "value": "empresa@persat.com.ar"
            },
            "13": {
                "name": "Nombre del Contacto",
                "value": "Jose Perez"
            }
        }        
    }

```

**uid\_client:** Es el identificador del cliente en el que se encuentra el objeto.

**company\_name:** Nombre del cliente, razón social o nombre de fantasía. Debe ser un valor único. No puede haber dos clientes con la misma "Razon Social".

**company\_description:** Descripción del cliente. Es un campo útil dentro de Persat para hacer búsquedas. Se suele usar para indicar por ejemplo el rubro de la empresa, pero es un campo libre y puede incluso estar vacío.

**type\_id:** Es un número identificando el tipo de cliente. Los tipos de cliente en Persat, son una clasificación configurable por el usuario, y es muy útil para realizar filtrados o para visualizar sobre el mapa.

Para poder ver los types configurados, hay que ingresar al módulo de Gestión de Clientes -> Ajustes -> Tipos de Cliente, y luego seleccionar Developers en la barra superior

![](/files/6M4Q0mBZkItu6XN4cD0y)

**group\_id:** Es un número identificando el grupo de cliente. Los grupos de cliente en Persat, son una clasificación configurable por el usuario que no solo sirve para filtrar, si no que contempla niveles de permiso. Es decir que si un cliente es del grupo "Zona Norte", luego solo los usuarios que tengan permiso de ver ese grupo podrán ver ese cliente.

Para poder ver los grupos configurados, hay que ingresar al módulo de Gestión de Clientes -> Ajustes -> Grupos de Cliente, y luego seleccionar Developers en la barra superior.

![](/files/6HFkJQPVxH7s28yaORU6)

**latitude y longitude:** Posición del cliente en el globo. Son campos numéricos.

**service\_time:** Número pero puede también no estar definido y no presentarse en la respuesta. En caso de estar definido, indica el tiempo en minutos que debería durar la visita. Esto se utiliza luego por el algoritmo de ruteo para calcular el tiempo de espera en este cliente (por ejemplo: Tiempo de descarga de mercadería).

**wt:** Array\[number, number] pero puede también no estar definido y no presentarse en la respuesta. En caso de estar definido, indica el horario en que el comercio se encuentra abierto. Esto se utiliza luego por el algoritmo de ruteo para calcular en que momento hay que visitar al cliente.\
En caso de no estar definido, esto indicaría que puede ser visitado en cualquier momento del día. <br>

{% hint style="info" %}
Ejemplo wt = \[480, 780].

Hora de apertura = 480 / 60 = 08:00 AM

Hora de cierre = 780 / 60 = 13:00 PM
{% endhint %}

#### Campos de dirección:&#x20;

> **street:** Dirección del cliente (solo la calle)
>
> **street\_nbr:** Dirección del cliente (solo el número)
>
> **neighborhood:** Barrio
>
> **city:** Ciudad
>
> **country:** País

{% hint style="info" %}
Si el cliente fue creado desde Persat, los campos mencionados en general están completos, puesto que se hace uso del geocoding.

Cuando el cliente se crea desde la API, los campos son opcionales, pero es recomendable que se respete la nomenclatura mencionada.
{% endhint %}

**last\_updated** es una fecha UTC que indica la última vez que se modificó el cliente. Es un dato muy útil a la hora de sincronizar todos los clientes. Ver [Listar Clientes](/entidades-basicas/clientes/listar-clientes)

**custom\_fields** es un objeto JSON que nos detalla los campos personalizados de la ficha de clientes. Cada campo personalizado tiene un id único, que pasa a ser la key del objeto custom\_fields.&#x20;

Por ejemplo, el campo personalizado "Telefono", tiene id = 2. Es útil conocer el id de cada custom\_field, para poder crear nuevos clientes con los campos personalizados completos.

{% hint style="info" %}
Una forma rápida de averiguar los ids de los custom fields la podes obtener aqui: [Campos personalizados.](/entidades-basicas/clientes#campos-personalizados-de-la-ficha-de-clientes)

También se pueden obtener a través de dla API con este [endpoint](/entidades-basicas/clientes/listar-campos-personalizados)
{% endhint %}

{% hint style="warning" %}
Si bien cada uno de los campos personalizados tiene un **field\_type** que se usa para la validación para los usuarios web y movil. Dicha validación no se realiza desde la API.

<mark style="color:orange;">**En resumen**</mark>, todos los campos se reciben, modifican e insertan como si fueran strings, independientemente del tipo.

La validación corre por cuenta del programador
{% endhint %}


# Agregar un cliente

Así como podés agregar un cliente de forma manual a través del Panel de Control de Persat, podés hacerlo a través del API. Lo que se requiere es hacer una consulta HTTP POST con los parámetros indicados.

<mark style="color:green;">`POST`</mark> `https://api.persat.com.ar/v1/clients`

#### Headers

| Name          | Type   | Description      |
| ------------- | ------ | ---------------- |
| Content-Type  | string | application/json |
| Authorization | string | Bearer API\_KEY  |

#### Request Body

| Name                                                                                | Type              | Description                                                                                                                                                              |
| ----------------------------------------------------------------------------------- | ----------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| uid\_client<mark style="color:red;">\*</mark>                                       | string            | El número/identificador de cliente (es un valor alfanumérico). Debe ser un valor único y sirve para luego poder accederlo en otros llamados a la API                     |
| company\_name<mark style="color:red;">\*</mark>                                     | string            | Nombre del cliente, razón social o nombre de fantasía. También debe ser un valor único. No puede haber dos clientes con la misma "Razon Social"                          |
| company\_description                                                                | string            | Descripción del cliente.                                                                                                                                                 |
| latitude                                                                            | number            | Ubicación del cliente, latitud. Valor por default: 0                                                                                                                     |
| longitude                                                                           | number            | Ubicación del cliente, longitud. Valor por default: 0                                                                                                                    |
| service\_time                                                                       | number            | Tiempo de servicio. Se utiliza por el algoritmo de ruteo.                                                                                                                |
| wt                                                                                  | \[number, number] | Hora de apertura y cierre del local (en minutos). Se utiliza por el algoritmo de ruteo. Ver ejemplo en [Obtener Cliente](/entidades-basicas/clientes/obtener-un-cliente) |
| street                                                                              | string            | Calle en donde se encuentra el cliente. No incluir el número                                                                                                             |
| street\_nbr                                                                         | string            | Número de la calle. Si bien es numeración, debe ser enviado como string                                                                                                  |
| neighborhood                                                                        | string            | Barrio, por ej: "Devoto"                                                                                                                                                 |
| city                                                                                | string            | Ciudad, por ejemplo "CABA"                                                                                                                                               |
| country                                                                             | string            | País, por ejemplo: "Argentina"                                                                                                                                           |
| custom\_fields <mark style="color:red;">\*</mark> (puede haber campos obligatorios) | object            | Campos personalizados de la ficha de clientes. Se detalla más adelante en este artículo. Puede haber campos obligatorios.                                                |
| type\_id                                                                            | Number            | Identificador del tipo de cliente. En caso de no enviarse el cliente se creara con el type\_id = 0, que es el valor por defecto                                          |
| group\_id                                                                           | Number            | Identificador del grupo de cliente. En caso de no enviarse el cliente se creara con el group\_id = 0, que es el valor por defecto                                        |

{% tabs %}
{% tab title="200 El cliente fue creado" %}

```javascript
{
    "success": true,
    "data": {	
        "uid_client": "CL-0044"
        "company_name": "Persat",
        "company_description": "",
        "latitude": -34.60820392067226,
        "longitude": -58.48194122314454,
        "street": "Terrada",
        "street_nbr": "2309",
        "neighborhood": "Comuna 11",
        "city": "Buenos Aires",
        "country": "Argentina",
        "custom_fields": {
            "1": {
                "name": "Nombre",
                "value": ""
            },
            "2": {
                "name": "Teléfono",
                "value": "4504-5300"
            },
            "3": {
                "name": "Email",
                "value": ""
            },
            "4": {
                "name": "Campo 1",
                "value": ""
            },
            "5": {
                "name": "Campo 2",
                "value": ""
            },
            "6": {
                "name": "Campo n",
                "value": ""
            }
        }
    }
}
```

{% endtab %}

{% tab title="400 campos obligatorios" %}

```javascript
{
    "success": false,
    "error": {
        "status": 400,
        "type": "BAD_REQUEST",
        "userMessage": "'latitude' debe ser un número entre -90 y +90"
    }
}
```

{% endtab %}

{% tab title="409 Si el número de cliente ingresado uid\_client ya existe." %}

```javascript
{
    "success": false,
    "error": {
        "status": 409,
        "type": "CONFLICT",
        "userMessage": "Usted ya posee un cliente con este número de cliente"
    }
}
```

{% endtab %}

{% tab title="409: Conflict type\_id o group\_id invalidos. Tal vez en algun momento existian dentro de Persat pero el usuario administrador los elimino." %}

```javascript
{
    "success": false,
    "error": {
        "status": 409,
        "type": "CONFLICT",
        "userMessage": "type_id o group_id tiene un valor invalido. Enviar los campos en 0, o no enviar dichos campos"
    }
}
```

{% endtab %}
{% endtabs %}

A continuación un ejemplo con curl

```bash
curl --location --request POST "https://api.persat.com.ar/v1/clients" \
  --header "Content-Type: application/json" \
  --header "Authorization: Bearer YOUR_API_KEY" \
  --data "{
	\"uid_client\":\"CL-0044\",  
	\"company_name\":\"Persat\",
	\"company_description\":\"Logistica GPS\",
	\"type_id\": 3,
	\"group_id\": 2,
	\"latitude\":-34.54646,
	\"longitude\":-58.4324324,
	\"street\":\"Av. Rivadavia\",
	\"street_nbr\":232,
	\"neighborhood\":\"Devoto\",
	\"city\":\"CABA\",
	\"country\":\"Argentina\",
	\"custom_fields\": {
        \"2\": \"4504-5300\"
	}
  }"
```

Los campos son explicados en la sección [Obtener un cliente](/entidades-basicas/clientes/obtener-un-cliente)

Algunas aclaraciones respecto a este request.

{% hint style="warning" %}
Si bien `latitude` y `longitude` no son campos obligatorios, en Persat todos los clientes se tienen que poder representar en un mapa. Por lo cual, en caso de no enviar estos dos atributos, ambos terminan quedando en 0, dando como resultado un cliente creado en el oceano.

![](/files/pnfnfVvWeu4ZR5i1s2Y7)
{% endhint %}

{% hint style="danger" %}
IMPORTANTE: En ningún caso la dirección se calcula automáticamente en base a `latitude` y `longitude.`Esto si ocurre desde la aplicación web de Persat, o desde la app de Android. La misma aclaración vale para el caso inverso, es decir que no se calcula la latitud y longitud en base a los datos de dirección enviados.

Es responsabilidad del programador, hacer el geocoding correspondiente para poder brindar los datos de posición
{% endhint %}


# Modificar un cliente

<mark style="color:orange;">`PUT`</mark> `https://api.persat.com.ar/v1/clients/uid_client`

Modifico alguno de los campos del cliente con número de cliente `uid_client`

#### Headers

| Name                                            | Type   | Description      |
| ----------------------------------------------- | ------ | ---------------- |
| Content-Type<mark style="color:red;">\*</mark>  | string | application/json |
| Authorization<mark style="color:red;">\*</mark> | string | Bearer API\_KEY  |

#### Request Body

| Name                                                                                | Type              | Description                                                                                                                                                              |
| ----------------------------------------------------------------------------------- | ----------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| company\_name                                                                       | string            | Nombre del cliente, razón social o nombre de fantasía.                                                                                                                   |
| company\_description                                                                | string            | Descripción del cliente.                                                                                                                                                 |
| latitude                                                                            | number            | Ubicación del cliente, latitud                                                                                                                                           |
| longitude                                                                           | number            | Ubicación del cliente, longitud                                                                                                                                          |
| service\_time                                                                       | number            | Tiempo de servicio. Se utiliza por el algoritmo de ruteo.                                                                                                                |
| wt                                                                                  | \[number, number] | Hora de apertura y cierre del local (en minutos). Se utiliza por el algoritmo de ruteo. Ver ejemplo en [Obtener Cliente](/entidades-basicas/clientes/obtener-un-cliente) |
| street                                                                              | string            | Calle en donde se encuentra el cliente. No incluir el número.                                                                                                            |
| street\_nbr                                                                         | string            | Número de la calle.                                                                                                                                                      |
| neighborhood                                                                        | string            | Barrio, por ej: "Devoto"                                                                                                                                                 |
| city                                                                                | string            | Ciudad, por ejemplo "CABA"                                                                                                                                               |
| country                                                                             | string            | País, por ejemplo: "Argentina"                                                                                                                                           |
| custom\_fields <mark style="color:red;">\*</mark> (puede haber campos obligatorios) | JSON Object       | Campos personalizados de la ficha de clientes                                                                                                                            |
| type\_id                                                                            | Number            | Identificador del tipo de cliente. Debe ser un tipo válido, de lo contrario se recibira un 409 CONFLICT como respuesta                                                   |
| group\_id                                                                           | Number            | Identificador del grupo de cliente. Debe ser un grupo valido, de lo contrario se recibirá 409 CONFLICT como respuesta                                                    |

{% tabs %}
{% tab title="200 Cliente modificado. Sólo se devuelven los campos que fueron modificados" %}

```javascript
{
    "success": true,
    "data": {
        "uid_client": "CL-0044",
        "company_name": "Persat nuevo",
        "company_description": "Logistica GPS nuevo",
        "latitude": "-32"
        "custom_fields": {
            "2": "4444-5555"
        }
    }
}
```

{% endtab %}

{% tab title="400 Valor de latitude incorrecto" %}

```javascript
{
    "success": false,
    "error": {
        "status": 400,
        "type": "BAD_REQUEST",
        "userMessage": "'latitude' debe ser un número entre -90 y +90"
    }
}
```

{% endtab %}

{% tab title="404 Intento modificar un cliente que no existe." %}

```javascript
{
    "success": false,
    "error": {
        "status": 404,
        "type": "NOT_FOUND",
        "userMessage": "El cliente que desea modificar no existe."
    }
}
```

{% endtab %}

{% tab title="409: Conflict type\_id | group\_id invalidos" %}

```javascript
{
    "success": false,
    "error": {
        "status": 409,
        "type": "CONFLICT",
        "userMessage": "type_id o group_id tiene un valor invalido. Enviar los campos en 0, o no enviar dichos campos"
    }
}
```

{% endtab %}

{% tab title="409: Conflict Ya existe otro cliente con este company\_name" %}

```javascript
{
    "success": false,
    "error": {
        "status": 409,
        "type": "CONFLICT",
        "userMessage": "ER_DUP_ENTRY: Duplicate entry 'Persat' for key 'company_name'"
    }
}
```

{% endtab %}
{% endtabs %}

En caso de que la respuesta sea exitosa, sólo se devuelven los datos que fueron modificados. A diferencia de [Agregar un cliente](/entidades-basicas/clientes/agregar-un-cliente), en donde se devuelve el cliente completo

A continuación un ejemplo con curl, en donde modifico, los campos: `company_name, company_description, latitude y custom_fields` del cliente "CL-0044"

```bash
curl --location --request PUT "https://api.persat.com.ar/v1/clients/CL-0044" \
  --header "Content-Type: application/json" \
  --header "Authorization: Bearer YOUR_API_KEY" \
  --data "{
	\"company_name\":\"Persat nuevo\",
	\"company_description\":\"Logistica GPS nuevo\",
	\"latitude\":-32,
	\"group_id\": 2,
	\"custom_fields\": {
		\"2\": \"4444-5555\"
	}
  }"
```

Los campos son explicados en la sección [Obtener un cliente](/entidades-basicas/clientes/obtener-un-cliente)

{% hint style="danger" %}
IMPORTANTE: En ningún caso la dirección se calcula automáticamente en base a `latitude` y `longitude.`Esto si ocurre desde la aplicación web de Persat, o desde la app de Android
{% endhint %}

{% hint style="warning" %}
Si el custom\_field es obligatorio, y se desea modificar el valor. No se aceptará un valor vacío ""
{% endhint %}


# Eliminar un cliente

{% hint style="danger" %} <mark style="color:red;">RECUERDE</mark> que esta acción no puede ser deshecha. Todo el historial del cliente será también eliminado, incluyendo los formularios y las órdenes de trabajo que se hayan realizado sobre el mismo.
{% endhint %}

<mark style="color:red;">`DELETE`</mark> `https://api.persat.com.ar/v1/clients/uid_client`

Eliminar el cliente cuyo número es `uid_client` y todo su historial

#### Headers

| Name                                            | Type   | Description     |
| ----------------------------------------------- | ------ | --------------- |
| Authorization<mark style="color:red;">\*</mark> | string | Bearer API\_KEY |

{% tabs %}
{% tab title="200 El cliente fue borrado con éxito" %}

```json
{
    "success": true,
    "data": {
        "uid_client": "CL-0044"
    }
}
```

{% endtab %}

{% tab title="404 No existe el cliente que se desea eliminar" %}

```json
{
    "success": false,
    "error": {
        "status": 404,
        "type": "NOT_FOUND",
        "userMessage": "No existe un cliente con este número."
    }
}
```

{% endtab %}
{% endtabs %}

A continuación un ejemplo con curl, en donde elimino el cliente con número "CL-0044"

```bash
curl --location --request DELETE "https://api.persat.com.ar/v1/clients/CL-0044" \
  --header "Authorization: Bearer YOUR_API_KEY"
```


# Listar Clientes

<mark style="color:blue;">`GET`</mark> `https://api.persat.com.ar/v1/clients`

#### Path Parameters

| Name          | Type   | Description                                                                           |
| ------------- | ------ | ------------------------------------------------------------------------------------- |
| limit         | number | Cantidad de clientes a obtener partiendo desde offset. El valor máximo es 100         |
| offset        | number | Indice comenzando desde 0. Indica a partir de que elemento queremos comenzar a listar |
| last\_updated | string | Fecha en formato ISO. Ejemplo: 2021-09-09T14:30:00.000Z                               |
| group\_id     | number | Numero de id de grupo de clientes a obtener. Debe ser mayor o igual a 0               |

#### Headers

| Name                                            | Type   | Description     |
| ----------------------------------------------- | ------ | --------------- |
| Authorization<mark style="color:red;">\*</mark> | string | Bearer API\_KEY |

{% tabs %}
{% tab title="200 Se obtuvo el listado correctamente." %}

```json
{
    "success": true,
    "paging": {
        "offset": 0,
        "limit": 20,
        "result": 20,
        "total": 14785
    },
    "data": [
        {
            "uid_client": "131058",
            "company_name": "Empresa s.r.l..",
            "company_description": "Empresa de tapizados",
            "type_id": 2,
            "group_id": 3,
            "latitude": -34.90097,
            "longitude": -56.1875,
            "service_time": 20,          // Opcional
            "wt": [480, 780],            // Opcional
            "street": "CERRO LARGO",
            "street_nbr": "1350",
            "neighborhood": "",
            "city": "Buenos Aires",
            "country": "Argentina",
            "last_updated": "2021-09-09T14:30:05.000Z",
            "custom_fields": {
                "2": {
                    "name": "Telefono",
                    "value": "5555-2122"
                },
                "8": {
                    "name": "Entre calle 1",
                    "value": "11100"
                },
                "9": {
                    "name": "Entre calle 2",
                    "value": ""
                },
                "10": {
                    "name": "Mail de notificación",
                    "value": "info@empresa.com.ar"
                },
                "13": {
                    "name": "Nombre del Contacto",
                    "value": "Pedro Lopez"
                }
            }
        }, 
        { ... }      // Otro cliente
    ]
}


```

{% endtab %}

{% tab title="400 Error en alguno de los campos enviados. userMessage contiene informacipon adicional." %}

```json
{
    "success": false,
    "error": {
        "status": 400,
        "type": "BAD_REQUEST",
        "userMessage": "'offset' debe ser un número"
    }
}
```

{% endtab %}
{% endtabs %}

Los campos son explicados en la sección [Obtener un cliente](/entidades-basicas/clientes/obtener-un-cliente)

## <sub>`Parametros Opcionales`</sub>&#x20;

Por defecto, el listado devuele los primeros 20 resultados. En caso de querer los siguientes 20, debemos agregar el parámetro `offset`. También podemos obtener más de 20 resultados con el parámetro `limit`&#x20;

Curl de ejemplo con estos dos parametros:

```bash
curl --location --request GET "https://api.persat.com.ar/v1/clients?limit=5&offset=20" \
  --header "Authorization: Bearer YOUR_API_KEY"
```

Un parametro opcional, pero muy util para hacer una busqueda mas especifica a la hora de obtener los clientes, es el **group\_id** ([Grupo de clientes](/entidades-basicas/clientes/listar-grupos-de-clientes)), permitiendo obtener a los clientes que coincidan con ese **id de grupo.**

Otro parámetro opcional, es **last\_updated**, que es muy util a la hora de realizar una sincronización con otro sistema, y solo obtener los clientes que fueron modificados o creados despues de la fecha indicada incluyendola (mayor o igual)

A continuación un ejemplo con curl, en donde solicitamos 5 clientes desde la posición 20, que hayan sido modificados despues e inclusive el 10 de Septiembre de 2021 a las 14:30 UTC-0 y el Id del grupo 2.

```bash
curl --location --request GET "https://api.persat.com.ar/v1/clients?limit=5&offset=20&last_updated=2021-09-10T14:30:00.000Z&group_id=2" \
  --header "Authorization: Bearer YOUR_API_KEY"
```

## Sincronización

El procedimiento correcto para hacer la sincronización de un listado con muchos clientes es el siguiente:

La primera vez, realizamos un request sin el parametro last\_updated y/o group\_id, e iteramos modificando el offet hasta barrer todos los clientes. Una vez sincronizados guardamos la fecha UTC en que realizamos esta primer sincronización.

Luego, cada vez que queremos sincronizar, repetimos el procedimiento anterior pero indicando en el parámetro **last\_updated** la fecha guardada anteriormente. Finalizado el proceso guardamos la nueva fecha de sincronización.

De esta forma evitamos retrabajar clientes que no han sido modificados


# Listar Grupos de Clientes

{% hint style="info" %}
Para más información sobre que son los grupos de clientes, podes mirar [este tutorial](http://docs.persat.com.ar/es/articles/691860-trabajando-con-grupos-de-clientes)
{% endhint %}

Para obtener los grupos de clientes, se debe enviar un GET como el que se especifica a continuación.

<mark style="color:blue;">`GET`</mark> `https://api.persat.com.ar/v1/client-groups`

#### Headers

| Name                                            | Type   | Description     |
| ----------------------------------------------- | ------ | --------------- |
| Authorization<mark style="color:red;">\*</mark> | String | Bearer API\_KEY |

{% tabs %}
{% tab title="200: OK La consulta se ejecutó con éxito" %}

```json
{
    "success": true,
    "data": [
        {
            "id": 0,
            "name": "Sin grupo"
        },
        {
            "id": 2,
            "name": "Zona Sur"
        },
        {
            "id": 3,
            "name": "Zona Norte"
        }
    ]
}
```

{% endtab %}
{% endtabs %}

### Analizando la Respuesta

En caso que no haya ningun error, obtenemos para nuestro caso de ejemplo algo asi:

```json
{
    "success": true,
    "data": [
        {
            "id": 0,
            "name": "Sin grupo"
        },
        {
            "id": 2,
            "name": "Zona Sur"
        },
        {
            "id": 3,
            "name": "Zona Norte"
        }
    ]
}
```

**id:** Identificador del grupo de cliente. El 0 siempre representa al grupo llamado "Sin grupo", que es donde se encuentran los clientes sin grupo definido.

**name:** Nombre del grupo de cliente.


# Listar Tipos de Clientes

{% hint style="info" %}
Para más información sobre que son los tipos de clientes, podes mirar [este tutorial](https://docs.persat.com.ar/es/articles/691866-como-se-configuran-los-tipos-de-clientes)
{% endhint %}

Para obtener los tipos de clientes, se debe enviar un GET como el que se especifica a continuación.

<mark style="color:blue;">`GET`</mark> `https://api.persat.com.ar/v1/client-types`

#### Headers

| Name                                            | Type   | Description     |
| ----------------------------------------------- | ------ | --------------- |
| Authorization<mark style="color:red;">\*</mark> | String | Bearer API\_KEY |

{% tabs %}
{% tab title="200: OK La consulta se ejecutó con éxito" %}

```json
{
    "success": true,
    "data": [
        {
            "id": 0,
            "name": "Cliente"
        },
        {
            "id": 1,
            "name": "Cliente Grande"
        },
        {
            "id": 2,
            "name": "Cliente Mediano"
        },
        {
            "id": 3,
            "name": "Cliente chico"
        },
        {
            "id": 4,
            "name": "Proveedor"
        }
    ]
}
```

{% endtab %}
{% endtabs %}

### Analizando la Respuesta

En caso que no haya ningun error, obtenemos para nuestro caso de ejemplo algo asi:

```json
{
    "success": true,
    "data": [
        {
            "id": 0,
            "name": "Cliente"
        },
        {
            "id": 1,
            "name": "Cliente Grande"
        },
        {
            "id": 2,
            "name": "Cliente Mediano"
        },
        {
            "id": 3,
            "name": "Cliente chico"
        },
        {
            "id": 4,
            "name": "Proveedor"
        }
    ]
}
```

**id:** Identificador del tipo de cliente. El 0 siempre representa al tipo llamado "Cliente", que se representa con un identificador Negro con una C blanca.&#x20;

**name:** Nombre del tipo de cliente.


# Listar Campos Personalizados

Para obtener los campos personalizados de la ficha de clientes, se debe enviar un GET como el que se especifica a continuación.

<mark style="color:blue;">`GET`</mark> `https://api.persat.com.ar/v1/client-custom-fields`

#### Headers

| Name                                            | Type   | Description     |
| ----------------------------------------------- | ------ | --------------- |
| Authorization<mark style="color:red;">\*</mark> | String | Bearer API\_KEY |

{% tabs %}
{% tab title="200: OK La consulta se ejecutó con éxito" %}

```json
{
    "success": true,
    "data": [
        {
            "id": 1,
            "name": "Nombre del encargado",
            "field_type": "TEXT",
            "required": true
        },
        {
            "id": 2,
            "name": "Cuenta corriente",
            "field_type": "NUMBER",
            "required": false
        },
        {
            "id": 4,
            "name": "Teléfono",
            "field_type": "TELEPHONE",
            "required": false            
        },
        {
            "id": 5,
            "name": "email",
            "field_type": "EMAIL",
            "required": true            
        },
        {
            "id": 6,
            "name": "Link a drive",
            "field_type": "LINK",
            "required": false            
        }
    ]
}
```

{% endtab %}
{% endtabs %}

### Analizando la Respuesta

En caso que no haya ningun error, obtenemos para nuestro caso de ejemplo algo asi:

```json
{
    "success": true,
    "data": [
        {
            "id": 1,
            "name": "Nombre del encargado",
            "field_type": "TEXT",
            "required": true
        },
        {
            "id": 2,
            "name": "Cuenta corriente",
            "field_type": "NUMBER",
            "required": false
        },
        {
            "id": 4,
            "name": "Teléfono",
            "field_type": "TELEPHONE",
            "required": false
        },
        {
            "id": 5,
            "name": "email",
            "field_type": "EMAIL",
            "required": true
        },
        {
            "id": 6,
            "name": "Link a drive",
            "field_type": "LINK",
            "required": false
        }
    ]
}
```

**id:** Identificador del campo personalizado.

**name:** Nombre del campo personalizado.

**field\_type:** Tipo de campo. Como se explica en [Obtener un cliente](/entidades-basicas/clientes/obtener-un-cliente)&#x20;

**required:** Booleano indicando si es un campo obligatorio.

{% hint style="info" %}
Una forma rápida de averiguar los ids de los custom fields la podes obtener aqui: [Campos personalizados.](/entidades-basicas/clientes#campos-personalizados-de-la-ficha-de-clientes)
{% endhint %}

{% hint style="warning" %}
Si bien cada uno de los campos personalizados tiene un **field\_type** que se usa para la validación para los usuarios web y movil. Dicha validación no se realiza desde la API.

<mark style="color:orange;">**En resumen**</mark>, todos los campos se reciben, modifican e insertan como si fueran strings, independientemente del tipo.

La validación corre por cuenta del programador
{% endhint %}


# Eventos / Webhooks

En lo que respecta a clientes, también se puede trabajar configurando los webooks como se puede ver en la sección [Webhooks](/como-usar-la-api/nueva-entrega)

Los eventos disponibles son:

> [Cliente creado](/entidades-basicas/clientes/eventos-webhooks/evento-de-cliente-creado)
>
> [Cliente modificado](/entidades-basicas/clientes/eventos-webhooks/evento-de-cliente-modificado)
>
> [Cliente eliminado](/entidades-basicas/clientes/eventos-webhooks/evento-de-cliente-borrado)


# Cliente creado

El evento se dispara cada vez que se crea un nuevo cliente, ya sea de forma manual, por medio del importador masivo o desde la app de Android.

{% hint style="info" %}
El evento no se dispara si el Cliente es creado desde la API
{% endhint %}

De estar configurado el [webhook](/como-usar-la-api/nueva-entrega), se dispara el evento **client.created**

### Datos enviados en el evento

Los datos son enviados mediante una consulta HTTP POST, en donde el body contiene el siguiente texto en formato JSON.

```json
{
   "eventType":"client.created",
   "payload":{
      "uid_client":"CLA-99832",
      "company_name":"Ferreteria Fernandez s.r.l.",
      "company_description":"Ferreteria industrial",
      "type_id": 2,
      "group_id": 3,
      "latitude":-34.72792860726617,
      "longitude":-58.47013950347901,
      "service_time": 20,          // Opcional
      "wt": [480, 780],            // Opcional
      "street":"Arana Goiri",
      "street_nbr":"4295",
      "neighborhood":"Lomas de Zamora",
      "city":"Provincia de Buenos Aires",
      "country":"Argentina",
      "last_updated": "2021-09-09T14:30:05.000Z",
      "custom_fields":{
         "1":{
            "name":"Notas",
            "value":""
         },
         "2":{
            "name":"Telefono",
            "value":"4504-2323"
         },         
         "10":{
            "name":"Mail de notificación",
            "value":"pedro@empresa.com"
         },
         "11":{
            "name":"Numero de CSID",
            "value":""
         },
         "13":{
            "name":"Nombre del Contacto",
            "value":"Pedro Lopez"
         }
      }
   }
}
```

Algunos puntos a tener en cuenta son:

**eventType:** Tipo de evento. Para el caso de nuevo cliente, siempre será "**client.created**"

**payload.client:** Datos del cliente en donde se creo el formulario

**custom\_fields** Referirse a la explicación en la sección [Agregar cliente](/entidades-basicas/clientes/agregar-un-cliente)


# Cliente modificado

El evento se dispara cada vez que se modifica un cliente, ya sea de forma manual, por medio del importador masivo o desde la app de Android.

{% hint style="info" %}
El evento no se dispara si el Cliente es modificado desde el endpoint correspondiente del a API
{% endhint %}

De estar configurado el [webhook](/como-usar-la-api/nueva-entrega), se dispara el evento **client.updated**

### Datos enviados en el evento

Los datos son enviados mediante una consulta HTTP POST, en donde el body contiene el siguiente texto en formato JSON.

```json
{
   "eventType":"client.updated",
   "payload":{
      "uid_client":"CLA-99832",
      "company_name":"Ferreteria Fernandez s.r.l.",
      "company_description":"Ferreteria industrial",
      "type_id": 2,
      "group_id": 3,
      "latitude":-34.72792860726617,
      "longitude":-58.47013950347901,
      "service_time": 20,          // Opcional
      "wt": [480, 780],            // Opcional
      "street":"Arana Goiri",
      "street_nbr":"4295",
      "neighborhood":"Lomas de Zamora",
      "city":"Provincia de Buenos Aires",
      "country":"Argentina",
      "last_updated": "2021-09-09T14:30:05.000Z",
      "custom_fields":{
         "1":{
            "name":"Notas",
            "value":""
         },
         "2":{
            "name":"Telefono",
            "value":"4504-2323"
         },         
         "10":{
            "name":"Mail de notificación",
            "value":"pedro@empresa.com"
         },
         "11":{
            "name":"Numero de CSID",
            "value":""
         },
         "13":{
            "name":"Nombre del Contacto",
            "value":"Pedro Lopez"
         }
      }
   }
}
```

Algunos puntos a tener en cuenta son:

**eventType:** Tipo de evento. Para el caso de cliente modificado, siempre será "**client.updated**"

Los datos recibidos son los mismos que en [Evento de Cliente creado](/entidades-basicas/clientes/eventos-webhooks/evento-de-cliente-creado)


# Cliente eliminado

El evento se dispara cada vez que se elimina un cliente, ya sea desde la web o desde la app de Android.

{% hint style="info" %}
El evento no se dispara si el Cliente es eliminado desde el endpoint correspondiente del a API
{% endhint %}

De estar configurado el [webhook](/como-usar-la-api/nueva-entrega), se dispara el evento **client.deleted**

### Datos enviados en el evento

Los datos son enviados mediante una consulta HTTP POST, en donde el body contiene el siguiente texto en formato JSON.

```json
{
    "eventType": "client.deleted",
    "payload": {
        "uid_client": "CLA-99832"
    }
}
```

Algunos puntos a tener en cuenta son:

**eventType:** Tipo de evento. Para el caso de cliente borrado, siempre será "**client.deleted**"

**payload.uid\_client:** Nro de cliente que fue eliminado.


# Objetos en Cliente

La funcionalidad de objetos en clientes permite asociar nuestros activos en clientes, por ejemplo, equipos que nosotros entregamos en consignación o alquiler, algunas opciones pueden ser: Fotocopiadoras, Equipos de limpieza, Dispenser de agua, Cafeteras, Heladeras, Autoelevadores, etc.

Para saber más sobre esta funcionalidad te invitamos a ver nuestro centro de ayuda [Objetos en clientes](https://docs.persat.com.ar/es/articles/2411243-equipos-objetos-en-clientes)

Los objetos en cliente cuentan con plantillas que definen sus características. Por ejemplo si tengo heladeras como un tipo de equipos a entregar, es probable que quiera tener el dato de las frigorias, o del consumo. Mientras que si tengo Dispensers de agua, probablemente quiera tener el volumen del bidon.

En pocas palabras, cada objeto en cliente tiene una estructura que es definida para cada empresa, y nos sirve para poder llevar un control de nuestros equipos, asi como también en que cliente se encuentran.

Las plantillas que identifican a cada objeto en cliente solo se pueden modificar desde la web de Persat. Desde la API si podemos insertar, modificar o eliminar los elementos. Por ej: Una vez creado el objeto en cliente Matafuegos, puedo desde la API insertar un nuevo matefuego con nro de identificacion xxxxxxxx.

### Identificación de los objetos en Clientes

Cada Objeto en Cliente tiene un obj\_id, que es su identificador. La forma de obtenerlos es desde el módulo de Gestión de Clientes.

![](/files/KqL4BzphBvEIE62DWMka)

Luego para ver los campos definidos dentro del objeto, hacemos click sobre el lapiz verde en un objeto particular y luego presionamos el botón "Desarrolladores" en la configuración de usuario.

![](/files/vGFVM33ijWYSR5dQpPl4)

### ¿Que podés hacer con los Objetos en Clientes?

En las siguientes secciones se explica todo lo que podes hacer con objetos en clientes.

**Respecto al esquema (estructura de los datos)**

> [Obtener estructura/esquema de un Objeto en Cliente](/entidades-basicas/objetos-en-cliente/obtener-estructura-esquema-de-un-objeto-en-cliente)
>
> [Listar estructuras/esquemas de los Objetos en Cliente](/entidades-basicas/objetos-en-cliente/listar-estructuras-esquemas-de-los-objetos-en-cliente)

**Respecto a los elementos**

> [Obtener objeto](/entidades-basicas/objetos-en-cliente/obtener-objeto)
>
> [Insertar objeto](/entidades-basicas/objetos-en-cliente/insertar-objeto)
>
> [Modificar objeto](/entidades-basicas/objetos-en-cliente/modificar-objeto)
>
> [Eliminar objeto](/entidades-basicas/objetos-en-cliente/eliminar-objeto)
>
> [Listar objetos en un cliente particular](/entidades-basicas/objetos-en-cliente/listar-objetos-en-un-cliente-particular)
>
> [Sincronizar todos los objetos](/entidades-basicas/objetos-en-cliente/sincronizacion-completa)


# Obtener estructura/esquema de un Objeto en Cliente

Para obtener la estructura/esquema de un Objeto en Cliente particular, se debe enviar un GET como el que se especifica a continuación.

<mark style="color:blue;">`GET`</mark> `https://api.persat.com.ar/v1/clientobj/obj_id`

#### Path Parameters

| Name                                      | Type   | Description                         |
| ----------------------------------------- | ------ | ----------------------------------- |
| obj\_id<mark style="color:red;">\*</mark> | Number | Identificador del objeto en cliente |

#### Headers

| Name                                            | Type   | Description     |
| ----------------------------------------------- | ------ | --------------- |
| Authorization<mark style="color:red;">\*</mark> | String | Bearer API\_KEY |

{% tabs %}
{% tab title="200: OK La consulta se ejecutó con éxito" %}

```json
{
    "success": true,
    "data": {
        "obj_id": 1,
        "name": "Contactos",        
        "fields": [
            {
                "id": 1,
                "name": "Nombre y Apellido",
                "type": "TEXT"
            },
            {
                "id": 2,
                "name": "Puesto",
                "type": "TEXT"
            },
            {
                "id": 3,
                "name": "Telefono",
                "type": "TELEPHONE"
            },
            {
                "id": 4,
                "name": "Email",
                "type": "EMAIL"
            }
        ]
    }
}
```

{% endtab %}

{% tab title="404: Not Found no existe la Master Db con ese identificador" %}

```json
{
    "success": false,
    "error": {
        "status": 404,
        "type": "NOT_FOUND",
        "userMessage": "No existe el obj_id: 456464646546"
    }
}
```

{% endtab %}

{% tab title="400: Bad Request mdb\_id no es un número" %}

```javascript
{
    "success": false,
    "error": {
        "status": 400,
        "type": "BAD_REQUEST",
        "userMessage": "'obj_id' debe ser un number (entero) obligatorio"
    }
}
```

{% endtab %}
{% endtabs %}

### Analizando la Respuesta

En caso que no haya ningun error, obtenemos

```json
{
    "success": true,
    "data": {
        "obj_id": 1,
        "name": "Contactos",
        "fields": [
            {
                "id": 1,
                "name": "Nombre y Apellido",
                "type": "TEXT"
            },
            {
                "id": 2,
                "name": "Puesto",
                "type": "TEXT"
            },
            {
                "id": 3,
                "name": "Telefono",
                "type": "TELEPHONE"
            },
            {
                "id": 4,
                "name": "Email",
                "type": "EMAIL"
            }
        ]
    }
}
```

**obj\_id:** Identificador del Objeto en Cliente

**name:** Nombre del Objeto en Cliente. Por ej: "Contactos"

**fields:** Objeto JSON que describe la estructura del Objeto en Cliente. Esas propiedades serian como las columnas de la tabla. Por ejemplo el field "4" sería el email del contacto

{% hint style="info" %}
Los types disponibles para los fields son:

TEXT

NUMBER

TELEPHONE

EMAIL

LINK
{% endhint %}


# Listar estructuras/esquemas de los Objetos en Cliente

Para obtener un listado de las estructuras/esquemas de todos los Objetos en Cliente disponibles, se debe enviar un GET como el que se especifica a continuación.

<mark style="color:blue;">`GET`</mark> `https://api.persat.com.ar/v1/clientobj`

#### Headers

| Name                                            | Type   | Description     |
| ----------------------------------------------- | ------ | --------------- |
| Authorization<mark style="color:red;">\*</mark> | String | Bearer API\_KEY |

{% tabs %}
{% tab title="200: OK La consulta se ejecutó con éxito" %}

```json
{
    "success": true,
    "data": [
        {
            "obj_id": 1,
            "name": "Nombre y Apellido",
            "fields": [
                {
                    "id": 1,
                    "name": "Nombre y Apellido",
                    "type": "TEXT"
                },
                {
                    "id": 2,
                    "name": "Puesto",
                    "type": "TEXT"
                },
                {
                    "id": 3,
                    "name": "Telefono",
                    "type": "TELEPHONE"
                },
                {
                    "id": 4,
                    "name": "Email",
                    "type": "EMAIL"
                }
            ]
        },
        {
            "obj_id": 3,
            "name": "Fotocopiadoras",
            "fields": [
                {
                    "id": 1,
                    "name": "Identificador",
                    "type": "TEXT"
                },
                {
                    "id": 2,
                    "name": "Cantidad de copias",
                    "type": "NUMBER"
                },
                {
                    "id": 3,
                    "name": "Modelo",
                    "type": "TEXT"
                },
                {
                    "id": 6,
                    "name": "link al manual",
                    "type": "LINK"
                }
            ]
        },
        {...}
    ]
}
```

{% endtab %}

{% tab title="400: Bad Request Error en alguno de los campos enviados. userMessage contiene informacipon adicional." %}

```javascript
{
    "success": false,
    "error": {
        "status": 400,
        "type": "BAD_REQUEST",
        "userMessage": "mensaje de error correspondiente"
    }
}
```

{% endtab %}
{% endtabs %}

### Analizando la Respuesta

En caso que no haya ningun error, obtenemos

```json
{
    "success": true,
    "data": [
        {
            "obj_id": 1,
            "name": "Nombre y Apellido",
            "fields": [
                {
                    "id": 1,
                    "name": "Nombre y Apellido",
                    "type": "TEXT"
                },
                {
                    "id": 2,
                    "name": "Puesto",
                    "type": "TEXT"
                },
                {
                    "id": 3,
                    "name": "Telefono",
                    "type": "TELEPHONE"
                },
                {
                    "id": 4,
                    "name": "Email",
                    "type": "EMAIL"
                }
            ]
        },
        {
            "obj_id": 3,
            "name": "Fotocopiadoras",
            "fields": [
                {
                    "id": 1,
                    "name": "Identificador",
                    "type": "TEXT"
                },
                {
                    "id": 2,
                    "name": "Cantidad de copias",
                    "type": "NUMBER"
                },
                {
                    "id": 3,
                    "name": "Modelo",
                    "type": "TEXT"
                },
                {
                    "id": 6,
                    "name": "link al manual",
                    "type": "LINK"
                }
            ]
        },
        {...}
    ]
}
```

Lo que se recibe es un array en donde cada elemento del mismo representa la estructura/esquema del Objeto en Cliente con sus columnas y sus tipos de datos.

{% hint style="info" %}
Para ver los detalles de cada field diríjase a [Obtener estructura/esquema de un Objeto en Cliente](/entidades-basicas/objetos-en-cliente/obtener-estructura-esquema-de-un-objeto-en-cliente)
{% endhint %}


# Obtener objeto

Para obtener un objeto en cliente, se debe enviar un GET como el que se especifica a continuación.

<mark style="color:blue;">`GET`</mark> `https://api.persat.com.ar/v1/clientobjvalue/uid_client/obj_id/field_1`

#### Path Parameters

| Name                                          | Type   | Description                                                    |
| --------------------------------------------- | ------ | -------------------------------------------------------------- |
| uid\_client<mark style="color:red;">\*</mark> | String | Identificador del cliente                                      |
| obj\_id<mark style="color:red;">\*</mark>     | number | Indentificador de la plantilla del objeto en cliente.Heladeras |
| field\_1<mark style="color:red;">\*</mark>    | String | Identificador del objeto a obtener                             |

#### Headers

| Name                                            | Type   | Description     |
| ----------------------------------------------- | ------ | --------------- |
| Authorization<mark style="color:red;">\*</mark> | String | Bearer API\_KEY |

{% tabs %}
{% tab title="200: OK La consulta se ejecutó con éxito" %}

```json
{
    "success": true,
    "data": {
        "uid_client": "AABC9098",
        "obj_id": 2,
        "fields": {
            "1": "AABCSA090AA",
            "4": "No frost",
            "3": "1500",
            "6": "",
            "7": "",
            "8": ""
        },
        "updated": "2022-05-19T19:15:11.000Z"
    }
}
```

{% endtab %}

{% tab title="404: Not Found El objeto no existe" %}

```json
{
    "success": false,
    "error": {
        "status": 404,
        "type": "NOT_FOUND",
        "userMessage": "No existe el obj_id: 321321"
    }
}
```

{% endtab %}

{% tab title="400: Bad Request Error en alguno de los campos enviados. userMessage contiene informacipon adicional." %}

```javascript
{
    "success": false,
    "error": {
        "status": 400,
        "type": "BAD_REQUEST",
        "userMessage": "'obj_id' es un number (entero) obligatorio"
    }
}
```

{% endtab %}
{% endtabs %}

### Analizando la Respuesta

En caso que no haya ningun error, obtenemos

```json
{
    "success": true,
    "data": {
        "uid_client": "AABC9098",
        "obj_id": 2,
        "fields": {
            "1": "AABCSA090AA",
            "4": "No frost",
            "3": "1500",
            "6": "",
            "7": "",
            "8": ""
        },
        "updated": "2022-05-19T19:15:11.000Z"
    }
}
```

**uid\_client:** Es el identificador del cliente en el que se encuentra el objeto.

**obj\_id:** Es el identificador del tipo de objeto. Podemos tener varios objetos configurados, como "Heladeras", "Matafuegos", etc

**fields:** JSON Object, con los atributos del objeto. Son como las columnas de la tabla. En donde la columna "1" es la mas importante ya que es el identificador del objeto, y es un valor único por cliente.

{% hint style="info" %}
Para ver los identificadores de cada field [Identificación de los Objetos en Cliente](/entidades-basicas/objetos-en-cliente#identificacion-de-los-objetos-en-clientes)
{% endhint %}

**updated:** Es la fecha de inserción o modificación en UTC


# Insertar objeto

Para insertar un objeto en cliente, se debe enviar un POST como el que se especifica a continuación.

<mark style="color:green;">`POST`</mark> `https://api.persat.com.ar/v1/clientobjvalue`

#### Headers

| Name                                            | Type   | Description      |
| ----------------------------------------------- | ------ | ---------------- |
| Authorization<mark style="color:red;">\*</mark> | String | Bearer API\_KEY  |
| Content-Type<mark style="color:red;">\*</mark>  | String | application/json |

#### Request Body

| Name                                          | Type   | Description                                                                                                                                                         |
| --------------------------------------------- | ------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| uid\_client<mark style="color:red;">\*</mark> | String | Identificador del cliente                                                                                                                                           |
| obj\_id<mark style="color:red;">\*</mark>     | Number | Identificador del esquema/plantilla del Objeto en cliente. Por ej: Puedeo tener tanto Heladeras como Matafuegos. Este obj\_id es para identificar el tipo de objeto |
| fields<mark style="color:red;">\*</mark>      | Object | Los campos del objeto a insertar. Ver en el ejemplo en esta misma seccion                                                                                           |

{% tabs %}
{% tab title="200: OK La consulta se ejecutó con éxito" %}

```json
{
    "success": true,
    "data": {
        "uid_client": "AABC9098",
        "obj_id": 2,
        "fields": {
            "1": "AABCSA090AA",
            "4": "No frost",
            "3": "1500",
            "6": "",
            "7": "",
            "8": ""
        },
        "updated": "2022-05-19T19:15:11.000Z"
    }
}
```

{% endtab %}

{% tab title="400: Bad Request Error en alguno de los campos enviados. userMessage contiene informacipon adicional." %}

```json
{
    "success": false,
    "error": {
        "status": 400,
        "type": "BAD_REQUEST",
        "userMessage": "'field.1' es un campo string obligatorio que identifica el client obj value dentro del cliente"
    }
}
```

{% endtab %}

{% tab title="409: Conflict Ya existe un Objeto en este cliente con el mismo identificador" %}

{% endtab %}
{% endtabs %}

### Ejemplo de request

En este ejemplo insertamos un elemento del tipo 2 (obj\_id) en el cliente "AABC9098". Este obj\_id representa el objeto Heladeras.

### body

```json
{
	"uid_client": "AABC9098",
	"obj_id": 2,
	"fields": {
		"1": "AABCSA090AA",
		"4": "No frost",
		"3": "1500"
	}
}
```

El **field.1** es obligatorio y es el identificador de la heladera. Debe ser unico por cliente. Los otros campos son los que se corresponden a la plantilla/esquema (obj\_id) y no son obligatorios.&#x20;

{% hint style="info" %}
Los valores a insertar son siempre strings, mas alla de que en la definición de la plantilla del objeto sean de tipo Numero, email, etc.&#x20;

Por el momento, no se realizan validaciones durante la inserción o modificación de estos campos.&#x20;
{% endhint %}

### Analizando la Respuesta

En caso que no haya ningun error, obtenemos

```json
{
    "success": true,
    "data": {
        "uid_client": "AABC9098",
        "obj_id": 2,
        "fields": {
            "1": "AABCSA090AA",
            "4": "No frost",
            "3": "1500",
            "6": "",
            "7": "",
            "8": ""
        },
        "updated": "2022-05-19T19:15:11.000Z"
    }
}
```

**updated:** Es la fecha de inserción o modificación en UTC

{% hint style="info" %}
Notese que se reciben varios fields extra (6,7,8) que no enviamos durante la creación, pero que estan definidos en la plantilla del objeto. Entonces fueron completados con valor ""
{% endhint %}


# Modificar objeto

Para modificar un objeto en cliente, se debe enviar un PUT como el que se especifica a continuación.

<mark style="color:orange;">`PUT`</mark> `https://api.persat.com.ar/v1/clientobjvalue/uid_client/obj_id/field_1`

#### Path Parameters

| Name                                          | Type   | Description                                         |
| --------------------------------------------- | ------ | --------------------------------------------------- |
| uid\_client<mark style="color:red;">\*</mark> | String | Indentificador del cliente                          |
| obj\_id<mark style="color:red;">\*</mark>     | Number | Identificador del tipo de objeto. Heladeras por ej. |
| field\_1<mark style="color:red;">\*</mark>    | String | Identificador del elemento a modificar              |

#### Headers

| Name                                            | Type   | Description      |
| ----------------------------------------------- | ------ | ---------------- |
| Authorization<mark style="color:red;">\*</mark> | String | Bearer API\_KEY  |
| Content-Type<mark style="color:red;">\*</mark>  | String | application/json |

#### Request Body

| Name        | Type   | Description                                                               |
| ----------- | ------ | ------------------------------------------------------------------------- |
| uid\_client | String | Identificador del cliente al que quiero mover el objeto                   |
| fields      | Object | Los campos del objeto a insertar. Ver en el ejemplo en esta misma sección |

{% tabs %}
{% tab title="200: OK La consulta se ejecutó con éxito" %}

```json
{
    "success": true,
    "data": {
        "uid_client": "AABC9098",
        "obj_id": 2,
        "fields": {
            "1": "AABCSA090AA",
            "4": "cycle de frost",
            "3": "1500"
            "6": "",
            "7": "",
            "8": ""
        },
        "updated": "2022-05-19T19:38:44.000Z"
    }
}
```

{% endtab %}

{% tab title="404: Not Found El objeto a modificar no existe" %}

```json
{
    "success": false,
    "error": {
        "status": 404,
        "type": "NOT_FOUND",
        "userMessage": "El recurso no existe"
    }
}
```

{% endtab %}

{% tab title="400: Bad Request Error en alguno de los campos enviados. userMessage contiene informacipon adicional." %}

```javascript
{
    "success": false,
    "error": {
        "status": 400,
        "type": "BAD_REQUEST",
        "userMessage": "'obj_id' debe ser un number"
    }
}
```

{% endtab %}
{% endtabs %}

## Ejemplo Modificando un campo del Objeto

En este ejemplo queremos modificar la heladera identificada con&#x20;

* **field\_1**: <mark style="color:green;">AABCSA090AA</mark>      - Identificador de la heladera
* **obj\_id**: 2                              - Tipo de Objeto Heladera
* **uid\_client**: <mark style="color:blue;">AABC9098</mark>        - Identificador del cliente

Y modificar únicamente el tipo de heladera que es el field "4" para nuestra plantilla

La consulta PUT entonces queda así:

\*\*<https://api.persat.com.ar/v1/clientobjvalue**/><mark style="color:blue;">AABC9098</mark>/2/<mark style="color:green;">AABCSA090AA</mark>

#### body

```json
{
    "fields": {
        "4": "cycle de frost"
    }
}
```

{% hint style="info" %}
Los valores a insertar son siempre strings, mas alla de que en la definición de la plantilla sean de tipo Numero, email, etc.&#x20;

Por el momento, no se realizan validaciones durante la inserción o modificación de estos campos.&#x20;
{% endhint %}

### Analizando la Respuesta

En caso que no haya ningun error, obtenemos el objeto completo con la modificación realizada

```json
{
    "success": true,
    "data": {
        "uid_client": "AABC9098",
        "obj_id": 2,
        "fields": {
            "1": "AABCSA090AA",
            "4": "cycle de frost",
            "3": "1500"
            "6": "",
            "7": "",
            "8": ""
        },
        "updated": "2022-05-19T19:38:44.000Z"
    }
}
```

**updated:** Es la fecha de inserción o modificación en UTC

## Ejemplo Moviendo el objeto a otro cliente

En este ejemplo queremos mover la heladera a otro cliente. La heladera esta identificada por estos datos

* **field\_1**: <mark style="color:green;">AABCSA090AA</mark>      - Identificador de la heladera
* **obj\_id**: 2                              - Tipo de Objeto Heladera
* **uid\_client**: <mark style="color:blue;">AABC9098</mark>        - Identificador del cliente

Y la queremos mover al cliente con uid\_client: **BJJKJ777**. La consulta PUT entonces queda igual que en el ejemplo anterior solo que lo que cambia ahora es el body

#### body

```json
{
    "uid_client": "BJJKJ777"
}
```

### Analizando la Respuesta

En caso que no haya ningun error, obtenemos el objeto, ahora situado en el nuevo cliente

```json
{
    "success": true,
    "data": {
        "uid_client": "BJJKJ777",
        "obj_id": 2,
        "fields": {
            "1": "AABCSA090AA",
            "4": "cycle de frost",
            "3": "1500"
            "6": "",
            "7": "",
            "8": ""
        },
        "updated": "2022-05-19T19:38:44.000Z"
    }
}
```

{% hint style="success" %}
Se puede mover un objeto a otro cliente mientras se modifican los campos internos al mismo tiempo. Es cuestión de enviar en el body ambas modificaciones

**body**

```
{
    "uid_client": "BJJKJ777",
    "fields": {
        "4": "cycle de frost"
    }
}
```

{% endhint %}


# Eliminar objeto

Para eliminar un objeto en cliente, se debe enviar un DELETE como el que se especifica a continuación.

{% hint style="danger" %}
Recuerde que esta operación no se puede deshacer.
{% endhint %}

<mark style="color:red;">`DELETE`</mark> `https://api.persat.com.ar/v1/clientobjvalue/uid_client/obj_id/field_1`

#### Path Parameters

| Name                                          | Type   | Description                                         |
| --------------------------------------------- | ------ | --------------------------------------------------- |
| uid\_client<mark style="color:red;">\*</mark> | String | Identificador del cliente                           |
| obj\_id<mark style="color:red;">\*</mark>     | Number | Identificador del tipo de objeto. Heladeras por ej. |
| field\_1<mark style="color:red;">\*</mark>    | String | Identificador del elemento a borrar                 |

#### Headers

| Name                                            | Type   | Description     |
| ----------------------------------------------- | ------ | --------------- |
| Authorization<mark style="color:red;">\*</mark> | String | Bearer API\_KEY |

{% tabs %}
{% tab title="200: OK La consulta se ejecutó con éxito" %}

```json
{
    "success": true,
    "data": {
        "uid_client": "AABC9098",
        "obj_id": 2,
        "field_1": "AABCSA090AA"
    }
}
```

{% endtab %}

{% tab title="404: Not Found El objeto a borrar no existe, o el cliente no existe" %}

```json
{
    "success": false,
    "error": {
        "status": 404,
        "type": "NOT_FOUND",
        "userMessage": "No hay un cliente con este nro."
    }
}
```

{% endtab %}

{% tab title="400: Bad Request Error en alguno de los campos enviados. userMessage contiene informacipon adicional." %}

```javascript
{
    "success": false,
    "error": {
        "status": 400,
        "type": "BAD_REQUEST",
        "userMessage": "'obj_id' es un number (entero) obligatorio"
    }
}
```

{% endtab %}
{% endtabs %}

### Analizando la Respuesta

En caso que no haya ningun error, obtenemos los datos de identificación del objeto borrado

```json
{
    "success": true,
    "data": {
        "uid_client": "AABC9098",
        "obj_id": 2,
        "field_1": "AABCSA090AA"
    }
}
```


# Listar Objetos en un Cliente particular

Si quiero obtener todos los objetos de un tipo (Heladeras por ejemplo) que existen en un cliente particular.

<mark style="color:blue;">`GET`</mark> `https://api.persat.com.ar/v1/listclientobjvalues/uid_client/obj_id`

#### Path Parameters

| Name                                          | Type   | Description                                         |
| --------------------------------------------- | ------ | --------------------------------------------------- |
| uid\_client<mark style="color:red;">\*</mark> | String | Identificador del cliente                           |
| obj\_id<mark style="color:red;">\*</mark>     | Number | Identificador del tipo de objeto. Heladeras por ej. |

#### Query Parameters

| Name                                    | Type   | Description                                                                             |
| --------------------------------------- | ------ | --------------------------------------------------------------------------------------- |
| offset                                  | number | Mismo concepto de SQL para la paginación. En caso de no enviarse el valor será 0 (cero) |
| limit<mark style="color:red;">\*</mark> | number | Mismo concepto de SQL para la paginación. Max: 100                                      |

#### Headers

| Name                                            | Type   | Description     |
| ----------------------------------------------- | ------ | --------------- |
| Authorization<mark style="color:red;">\*</mark> | String | Bearer API\_KEY |

{% tabs %}
{% tab title="200: OK La consulta se ejecutó con éxito" %}

{% endtab %}

{% tab title="404: Not Found El cliente no existe" %}

```json
{
    "success": false,
    "error": {
        "status": 404,
        "type": "NOT_FOUND",
        "userMessage": "No hay un cliente con este nro."
    }
}
```

{% endtab %}

{% tab title="400: Bad Request Error en alguno de los campos enviados. userMessage contiene informacipon adicional." %}

```javascript
{
    "success": false,
    "error": {
        "status": 400,
        "type": "BAD_REQUEST",
        "userMessage": "'offset' debe ser un number >= 0"
    }
}
```

{% endtab %}
{% endtabs %}

### Ejemplo de consulta

En este ejemplo queremos listar todos los objetos de tipo Heladera de un cliente particular

* **obj\_id**: 2                              - Tipo de Objeto Heladera
* **uid\_client**: <mark style="color:green;">AABC9098</mark>        - Identificador del cliente

La url de la consulta queda asi:

**<https://api.persat.com.ar/v1/listclientobjvalues/>**<mark style="color:green;">AABC9098</mark>/<mark style="color:blue;">2</mark>?offset=0\&limit=2

### Analizando la Respuesta

```json
{
    "success": true,
    "paging": {
        "offset": 0,
        "limit": 2,
        "result": 2,
        "total": 129
    },
    "data": [
        {
            "uid_client": "AABC9098",
            "obj_id": 2,
            "fields": {
                "1": "AABCSA090AA",
                "4": "cycle de frost",
                "3": "1500"
                "6": "",
                "7": "",
                "8": "Negra"
            },
            "updated": "2022-05-19T20:21:25.000Z"
        },
        {
            "uid_client": "AABC9098",
            "obj_id": 2,
            "fields": {
                "1": "KK895600001",
                "4": "No frost",
                "3": "3000"
                "6": "",
                "7": "",
                "8": "Blanca" 

            },
            "updated": "2022-05-19T20:20:25.000Z"
        }
    ]
}
```

**paging:** Es un objeto JSON que contiene los datos de la consulta offset y limit tal cual se recibieron, y luego presenta el total de objetos en cliente de tipo Heladera para este cliente, y la cantidad devueltos en esta consulta particular. De esta forma podemos ir trayendo de forma paginada todos las "heladeras" de este cliente.

**data:** Es un array de Objetos JSON, en donde cada item es el objeto en cliente buscado. Los campos de ese objeto son los mismos que si hicieramos la consulta como en [Obtener Objeto](/entidades-basicas/objetos-en-cliente/obtener-objeto)


# Sincronizacion completa

Si quiero tener todos los objetos sincronizados contra otro sistema, existe un endpoint especial que permite listar únicamente los objetos que hayan sido modificados a partir de una fecha particular. Entonces, sobre todo para cuando hay muchos objetos, es posible ir haciendo actualizaciones parciales.

<mark style="color:blue;">`GET`</mark> `https://api.persat.com.ar/v1/listclientobjvaluesupdated/obj_id`

#### Path Parameters

| Name                                      | Type   | Description                                         |
| ----------------------------------------- | ------ | --------------------------------------------------- |
| obj\_id<mark style="color:red;">\*</mark> | Number | Identificador del tipo de objeto. Heladeras por ej. |

#### Query Parameters

| Name                                            | Type    | Description                                                                             |
| ----------------------------------------------- | ------- | --------------------------------------------------------------------------------------- |
| offset                                          | number  | Mismo concepto de SQL para la paginación. En caso de no enviarse el valor será 0 (cero) |
| limit<mark style="color:red;">\*</mark>         | number  | Mismo concepto de SQL para la paginación. Max: 100                                      |
| last\_updated<mark style="color:red;">\*</mark> | IsoDate | Fecha UTC a partir de la cual buscar. Formato yyyy-MM-ddTHH:mm:ss.SSSZ                  |

#### Headers

| Name                                            | Type   | Description     |
| ----------------------------------------------- | ------ | --------------- |
| Authorization<mark style="color:red;">\*</mark> | String | Bearer API\_KEY |

{% tabs %}
{% tab title="200: OK La consulta se ejecutó con éxito" %}

{% endtab %}

{% tab title="400: Bad Request Error en alguno de los campos enviados. userMessage contiene informacipon adicional." %}

```javascript
{
    "success": false,
    "error": {
        "status": 400,
        "type": "BAD_REQUEST",
        "userMessage": "'offset' debe ser un number >= 0"
    }
}
```

{% endtab %}
{% endtabs %}

### Ejemplo de consulta

En este ejemplo queremos listar todos los objetos de tipo Heladera que hayan sufrido una modificación o hayan sido creados a partir de last\_updated incluido.

{% hint style="info" %}
IMPORTANTE:

**last\_updated:** Es una fecha UTC.
{% endhint %}

Para este ejemplo buscamos todos los objetos de tipo obj\_id = 2 (Heladeras) que hayan sido modificados a partir del 19 de Mayo de 2022 a las 08:00 UTC.

**<https://api.persat.com.ar/v1/**&#x6C;istclientobjvaluesupdate&#x64;**/>**<mark style="color:blue;">2</mark>?offset=0\&limit=2\&last\_updated=2022-05-19T08:00:00.000Z

### Analizando la Respuesta

```json
{
    "success": true,
    "paging": {
        "offset": 0,
        "limit": 2,
        "result": 2,
        "total": 18
    },
    "data": [
        {
            "uid_client": "AAA123",
            "obj_id": 2,
            "fields": {
                "1": "KK895600001",
                "4": "No frost",
                "3": "3000"
                "6": "",
                "7": "",
                "8": "Blanca" 
            },
            "updated": "2022-05-19T09:21:25.000Z"
        },
        {
            "uid_client": "BBB6765",
            "obj_id": 2,
            "fields": {
                "1": "AABCSA090AA",
                "4": "cycle de frost",
                "3": "1500"
                "6": "",
                "7": "",
                "8": "Negra"
            },
            "updated": "2022-05-19T15:50:01.000Z"
        }
    ]
}
```

El resultado es similar al que se explica en [Listar Objetos en un Cliente particular](/entidades-basicas/objetos-en-cliente/listar-objetos-en-un-cliente-particular)

## Procedimimento para la Sincronización

El procedimiento correcto para hacer la sincronización de un listado con muchos objetos en cliente es el siguiente:

La primera vez, realizamos un request con el parametro **last\_updated** con una fecha del pasado a la contratación de Persat (ej: 2000-01-01T00:00:00.000Z), e iteramos modificando el offet hasta barrer todos los objetos. Una vez sincronizados guardamos la fecha UTC en que realizamos esta primer sincronización.

Luego, cada vez que queremos sincronizar, repetimos el procedimiento anterior pero indicando en el parámetro **last\_updated** la fecha guardada anteriormente. Finalizado el proceso guardamos la nueva fecha UTC de sincronización y repetimos cada vez que queramos sincronizar.


# Master Db

La Master Db es una base de datos configurable dentro de Persat, en donde se pueden guardar datos como por ej: Inventario, Productos, Personal, o cualquier otro recurso.

Luego estos datos pueden ser accedidos desde los distintos formularios.

{% hint style="success" %}
Se pueden crear tantas Master Db como se desee. Entonces puedo tener una base de datos de productos y tambien una de insumos. Cada una con su propia estructura (esquema) de datos.
{% endhint %}

Para saber más sobre esta funcionalidad te invitamos a ver nuestro centro de ayuda [Master Db](http://docs.persat.com.ar/es/articles/5794846-generalidades-del-componente-master-db)

Las plantillas (esquemas/estructuras) que identifican a cada Master Db solo se pueden modificar desde la web de Persat. Desde la API si podemos insertar, modificar o eliminar los elementos (cada fila de la db). Por ej: Una vez creada la MasterDb de productos, puedo desde la API insertar un nuevo producto con nro de identificacion xxxxxxxx.

### Identificación de las Master Dbs

Cada master Db mdb\_id, que es su identificador. La forma de obtenerlos es desde el módulo de Gestión de Clientes.

![](/files/hb56d4Z1DlbsbZDgKo0W)

Luego para ver los campos definidos dentro de cada mdb, hacemos click sobre el lapiz azul en una mdb particular y luego presionamos el botón "Desarrolladores" en la configuración de usuario.

![](/files/6Hl6GhwiFdVdEVTA9v3P)

### ¿Que podés hacer con las Master Dbs?

En las siguientes secciones se explica todo lo que podes hacer con las master dbs y sus elementos.

**Respecto al esquema (estructura de los datos)**

> [Obtener estructura/esquema de una Master Db](/entidades-basicas/master-db/obtener-estructura-esquema-de-una-master-db)
>
> [Listar estructuras/esquemas de las Master Dbs](/entidades-basicas/master-db/listar-estructuras-esquemas-de-las-master-dbs)

**Respecto a los elementos (Cada una de las filas de la db)**

> [Obtener elemento](/entidades-basicas/master-db/obtener-elemento)
>
> [Insertar elemento](/entidades-basicas/master-db/insertar-elemento)
>
> [Modificar elemento](/entidades-basicas/master-db/modificar-elemento)
>
> [Eliminar elemento](/entidades-basicas/master-db/eliminar-elemento)
>
> [Sincronizar todos los elementos](/entidades-basicas/master-db/sincronizacion-completa)


# Obtener estructura/esquema de una Master Db

Para obtener la estructura/esquema de una Master Db particular, se debe enviar un GET como el que se especifica a continuación.

<mark style="color:blue;">`GET`</mark> `https://api.persat.com.ar/v1/masterdbs/mdb_id`

#### Path Parameters

| Name                                      | Type   | Description                    |
| ----------------------------------------- | ------ | ------------------------------ |
| mdb\_id<mark style="color:red;">\*</mark> | Number | Identificador de la Master Db. |

#### Headers

| Name                                            | Type   | Description     |
| ----------------------------------------------- | ------ | --------------- |
| Authorization<mark style="color:red;">\*</mark> | String | Bearer API\_KEY |

{% tabs %}
{% tab title="200: OK La consulta se ejecutó con éxito" %}

```json
{
    "success": true,
    "data": {
        "mdb_id": 133,
        "name": "Productos",
        "fields": [
            {
                "id": 1,
                "name": "Nro. de serie",
                "type": "TEXT"
            },
            {
                "id": 2,
                "name": "Descripcion",
                "type": "TEXT"
            },
            {
                "id": 5,
                "name": "Telefono",
                "type": "TELEPHONE"
            },
            {
                "id": 6,
                "name": "Link",
                "type": "LINK"
            },
            {
                "id": 7,
                "name": "precio",
                "type": "NUMBER"
            },
            {
                "id": 8,
                "name": "correo electronico",
                "type": "EMAIL"
            }
        ]
    }
}
```

{% endtab %}

{% tab title="404: Not Found no existe la Master Db con ese identificador" %}

```json
{
    "success": false,
    "error": {
        "status": 404,
        "type": "NOT_FOUND",
        "userMessage": "No existe el mdb_id: 456464646546"
    }
}
```

{% endtab %}

{% tab title="400: Bad Request mdb\_id no es un número" %}

```javascript
{
    "success": false,
    "error": {
        "status": 400,
        "type": "BAD_REQUEST",
        "userMessage": "'mdb_id' debe ser un number (entero) obligatorio"
    }
}
```

{% endtab %}
{% endtabs %}

### Analizando la Respuesta

En caso que no haya ningun error, obtenemos

```json
{
    "success": true,
    "data": {
        "mdb_id": 133,
        "name": "Productos",
        "fields": [
            {
                "id": 1,
                "name": "Nro. de serie",
                "type": "TEXT"
            },
            {
                "id": 2,
                "name": "Descripcion",
                "type": "TEXT"
            },
            {
                "id": 5,
                "name": "Telefono",
                "type": "TELEPHONE"
            },
            {
                "id": 6,
                "name": "Link",
                "type": "LINK"
            },
            {
                "id": 7,
                "name": "precio",
                "type": "NUMBER"
            },
            {
                "id": 8,
                "name": "correo electronico",
                "type": "EMAIL"
            }
        ]
    }
}
```

**mdb\_id:** Identificador de la Master Db

**name:** Nombre de la Master Db. Por ej: "Productos"

**fields:** Objeto JSON que describe la estructura de la Master Db. Esas propiedades serían como las columnas de la tabla. Por ejemplo el field "7" sería el precio del procuto.

{% hint style="info" %}
Los types disponibles para los fields son:

TEXT

NUMBER

TELEPHONE

EMAIL

LINK
{% endhint %}


# Listar estructuras/esquemas de las Master Dbs

Para obtener un listado de las estructuras/esquemas de todas las Master Dbs disponibles, se debe enviar un GET como el que se especifica a continuación.

<mark style="color:blue;">`GET`</mark> `https://api.persat.com.ar/v1/masterdbs`

#### Headers

| Name                                            | Type   | Description     |
| ----------------------------------------------- | ------ | --------------- |
| Authorization<mark style="color:red;">\*</mark> | String | Bearer API\_KEY |

{% tabs %}
{% tab title="200: OK La consulta se ejecutó con éxito" %}

```json
{
    "success": true,
    "data": [
        {
            "mdb_id": 133,
            "name": "Productos",
            "fields": [
                {
                    "id": 1,
                    "name": "Nro. de serie",
                    "type": "TEXT"
                },
                {
                    "id": 2,
                    "name": "Descripcion",
                    "type": "TEXT"
                },
                {
                    "id": 5,
                    "name": "Telefono",
                    "type": "TELEPHONE"
                },
                {
                    "id": 6,
                    "name": "Link",
                    "type": "LINK"
                },
                {
                    "id": 7,
                    "name": "precio",
                    "type": "NUMBER"
                },
                {
                    "id": 8,
                    "name": "correo electronico",
                    "type": "EMAIL"
                }
            ]
        },
        {
            "mdb_id": 134,
            "name": "Insumos",
            "fields": [
                {
                    "id": 1,
                    "name": "Nro. Identificacion",
                    "type": "TEXT"
                },
                {
                    "id": 2,
                    "name": "Cantidad disponible",
                    "type": "NUMBER"
                },
                {
                    "id": 3,
                    "name": "Descripción",
                    "type": "TEXT"
                }
            ]
        }
    ]
}
```

{% endtab %}

{% tab title="400: Bad Request Error en alguno de los campos enviados. userMessage contiene informacipon adicional." %}

```javascript
{
    "success": false,
    "error": {
        "status": 400,
        "type": "BAD_REQUEST",
        "userMessage": "mensaje de error correspondiente"
    }
}
```

{% endtab %}
{% endtabs %}

### Analizando la Respuesta

En caso que no haya ningun error, obtenemos

```json
{
    "success": true,
    "data": [
        {
            "mdb_id": 133,
            "name": "Productos",
            "fields": [
                {
                    "id": 1,
                    "name": "Nro. de serie",
                    "type": "TEXT"
                },
                {
                    "id": 2,
                    "name": "Descripcion",
                    "type": "TEXT"
                },
                {
                    "id": 5,
                    "name": "Telefono",
                    "type": "TELEPHONE"
                },
                {
                    "id": 6,
                    "name": "Link",
                    "type": "LINK"
                },
                {
                    "id": 7,
                    "name": "precio",
                    "type": "NUMBER"
                },
                {
                    "id": 8,
                    "name": "correo electronico",
                    "type": "EMAIL"
                }
            ]
        }, {...}
    ]
}
```

Lo que se recibe es un array en donde cada elemento del mismo representa la estructura/esquema de la Master Db con sus columnas y sus tipos de datos.

{% hint style="info" %}
Para ver los detalles de cada field diríjase a [Obtener estructura/esquema de una Master Db](/entidades-basicas/master-db/obtener-estructura-esquema-de-una-master-db)
{% endhint %}


# Obtener elemento

Para obtener un elemento de una Master Db en Persat, se debe enviar un GET como el que se especifica a continuación.

<mark style="color:blue;">`GET`</mark> `https://api.persat.com.ar/v1/masterdbvalues/mdb_id/field_1`

#### Path Parameters

| Name                                       | Type   | Description                          |
| ------------------------------------------ | ------ | ------------------------------------ |
| mdb\_id<mark style="color:red;">\*</mark>  | Number | Identificador de la Master Db.       |
| field\_1<mark style="color:red;">\*</mark> | String | Identificador del elemento a obtener |

#### Headers

| Name                                            | Type   | Description     |
| ----------------------------------------------- | ------ | --------------- |
| Authorization<mark style="color:red;">\*</mark> | String | Bearer API\_KEY |

{% tabs %}
{% tab title="200: OK La consulta se ejecutó con éxito" %}

```json
{
    "success": true,
    "data": {
        "mdb_id": 4,
        "fields": {
            "1": "DEST-123AALK",
            "2": "Destornillador perillero",
            "5": "Rojo",
            "6": "130.76"
        },
        "updated": "2022-05-20T13:07:34.000Z"
    }
}
```

{% endtab %}

{% tab title="404: Not Found El elemento no existe" %}

```json
{
    "success": false,
    "error": {
        "status": 404,
        "type": "NOT_FOUND",
        "userMessage": "No existe el mdb_id: 2312323213"
    }
}
```

{% endtab %}

{% tab title="400: Bad Request Error en alguno de los campos enviados. userMessage contiene informacipon adicional." %}

```javascript
{
    "success": false,
    "error": {
        "status": 400,
        "type": "BAD_REQUEST",
        "userMessage": "'mdb_id' es un number (entero) obligatorio"
    }
}
```

{% endtab %}
{% endtabs %}

### Analizando la Respuesta

En caso que no haya ningun error, obtenemos

```json
{
    "success": true,
    "data": {
        "mdb_id": 4,
        "fields": {
            "1": "DEST-123AALK",
            "2": "Destornillador perillero",
            "5": "Rojo",
            "6": "130.76"
        },
        "updated": "2022-05-20T13:07:34.000Z"
    }
}
```

**mdb\_id:** Identificador de la Master Db, puedo tener varias dbs al mismo tiempo. Por ejemplo una de Productos y otra de Insumos.

**fields:** Objeto JSON que contiene las propiedades del elemento. Esas propiedades estan definidas en la Master Db. Serian como las columnas de la tabla. Por ejemplo el field "5" sería el color del producto.

{% hint style="info" %}
Para ver los identificadores de cada field [Identificación de las Master Dbs](/entidades-basicas/master-db#identificacion-de-las-master-dbs)
{% endhint %}

**updated:** Es la fecha de inserción o modificación en UTC


# Insertar elemento

Para insertar un elemento en una Master Db en Persat, se debe enviar un POST como el que se especifica a continuación.

<mark style="color:green;">`POST`</mark> `https://api.persat.com.ar/v1/masterdbvalues`

#### Headers

| Name                                            | Type   | Description      |
| ----------------------------------------------- | ------ | ---------------- |
| Authorization<mark style="color:red;">\*</mark> | String | Bearer API\_KEY  |
| Content-Type<mark style="color:red;">\*</mark>  | String | application/json |

#### Request Body

| Name                                      | Type   | Description                                          |
| ----------------------------------------- | ------ | ---------------------------------------------------- |
| mdb\_id<mark style="color:red;">\*</mark> | Number | Identificador de la Master Db. Por ejemplo Productos |
| fields<mark style="color:red;">\*</mark>  | Object | JSON Object con los campos del elemento a insertar.  |

{% tabs %}
{% tab title="200: OK La consulta se ejecutó con éxito" %}

```json
{
    "success": true,
    "data": {
        "mdb_id": 4,
        "fields": {
            "1": "DEST-123AALK",
            "2": "Destornillador perillero",
            "5": "Rojo"
            "6": ""
        },
        "updated": "2022-05-20T13:43:46.000Z"
    }
}
```

{% endtab %}

{% tab title="404: Not Found La master db especificada no existe" %}

```json
{
    "success": false,
    "error": {
        "status": 404,
        "type": "NOT_FOUND",
        "userMessage": "No existe el mdb_id: 23213123123"
    }
}
```

{% endtab %}

{% tab title="400: Bad Request Error en alguno de los campos enviados. userMessage contiene informacipon adicional." %}

```javascript
{
    "success": false,
    "error": {
        "status": 400,
        "type": "BAD_REQUEST",
        "userMessage": "'field.1' es un campo string obligatorio que identifica el master db obj value"
    }
}
```

{% endtab %}

{% tab title="409: Conflict Conflicto. Ya existe otro elemento con este field.1" %}

```javascript
{
    "success": false,
    "error": {
        "status": 409,
        "type": "CONFLICT",
        "userMessage": "Ya existe un master db value con este field.1"
    }
}
```

{% endtab %}
{% endtabs %}

### Ejemplo de request

En este ejemplo insertamos un elemento en la Master db de Productos (mdb\_id: 4). El **fields.1** es obligatorio y debe ser único, ya que pasa a ser el identificador del elemento insertado.

### body

```json
{
    "mdb_id": 4,
    "fields": {
        "1": "DEST-123AALK",
        "2": "Destornillador perillero",
        "5": "Rojo"
    }
}
```

{% hint style="info" %}
Los valores a insertar son siempre strings, mas alla de que en la definición de la Master db sean de tipo Número, email, link, etc.&#x20;

Por el momento, no se realizan validaciones durante la inserción o modificación de estos campos
{% endhint %}

### Analizando la Respuesta

En caso que no haya ningun error, obtenemos

```json
{
    "success": true,
    "data": {
        "mdb_id": 4,
        "fields": {
            "1": "DEST-123AALK",
            "2": "Destornillador perillero",
            "5": "Rojo"
            "6": ""
        },
        "updated": "2022-05-20T13:43:46.000Z"
    }
}
```

La respuesta contiene al elemento insertado como se puede ver en [Obtener elemento](/entidades-basicas/master-db/obtener-elemento)

{% hint style="info" %}
Nótese que la Master Db tiene definido un field "6", que no enviamos durante la inserción, pero si lo recibimos en la respuesta como vacío ""&#x20;

El único campo de los fields obligatorio es el **fields.1** ya que es el identificador unico del elemento en la db
{% endhint %}


# Modificar elemento

Para modificar un elemento en una Master Db en Persat, se debe enviar un PUT como el que se especifica a continuación.

<mark style="color:orange;">`PUT`</mark> `https://api.persat.com.ar/v1/masterdbvalues/mdb_id/field_1`

#### Path Parameters

| Name                                       | Type   | Description                            |
| ------------------------------------------ | ------ | -------------------------------------- |
| mdb\_id<mark style="color:red;">\*</mark>  | Number | Identificador de la Master db          |
| field\_1<mark style="color:red;">\*</mark> | String | Identificador del elemento a modificar |

#### Headers

| Name                                            | Type   | Description      |
| ----------------------------------------------- | ------ | ---------------- |
| Authorization<mark style="color:red;">\*</mark> | String | Bearer API\_KEY  |
| Content-Type<mark style="color:red;">\*</mark>  | String | application/json |

#### Request Body

| Name                                     | Type   | Description                                         |
| ---------------------------------------- | ------ | --------------------------------------------------- |
| fields<mark style="color:red;">\*</mark> | Object | JSON Object con los campos del elemento a insertar. |

{% tabs %}
{% tab title="200: OK La consulta se ejecutó con éxito" %}

{% endtab %}

{% tab title="404: Not Found La master db especificada no existe" %}

```json
{
    "success": false,
    "error": {
        "status": 404,
        "type": "NOT_FOUND",
        "userMessage": "No existe el mdb_id: 2313213"
    }
}
```

{% endtab %}

{% tab title="400: Bad Request Error en alguno de los campos enviados. userMessage contiene informacipon adicional." %}

```javascript
{
    "success": false,
    "error": {
        "status": 400,
        "type": "BAD_REQUEST",
        "userMessage": "'mdb_id' es un number (entero) obligatorio"
    }
}
```

{% endtab %}

{% tab title="409: Conflict Conflicto. Quiero modificar el field\_1 y ya existe otro elemento con este mismo field\_1" %}

```json
{
    "success": false,
    "error": {
        "status": 409,
        "type": "CONFLICT",
        "userMessage": "No se pudo modificar el field_1 del mb value, ya que existe otro con ese mismo identificador: 'pinza'"
    }
}json
```

{% endtab %}
{% endtabs %}

### Ejemplo de request

En este ejemplo vamos a modificar un campo de un elemento particular. Pero no vamos a modificar su identificador (fields.1), aunque podríamos hacerlo si enviamos ese dato en el body.

* mdb\_id: <mark style="color:blue;">4</mark>
* field\_1 (Identificador del elemento): <mark style="color:green;">DEST-123AALK</mark>

Asi sería la consulta

PUT - \*\*<https://api.persat.com.ar/v1**/masterdbvalues/><mark style="color:blue;">4</mark>/<mark style="color:green;">DEST-123AALK</mark>

### body

```json
{
    "fields": {
        "5": "Naranja"
    }
}
```

{% hint style="info" %}
Los valores a insertar son siempre strings, mas alla de que en la definición de la Master db sean de tipo Número, email, link, etc.&#x20;

Por el momento, no se realizan validaciones durante la inserción o modificación de los campos
{% endhint %}

### Analizando la Respuesta

En caso que no haya ningun error, obtenemos

```json
{
    "success": true,
    "data": {
        "mdb_id": 4,
        "fields": {
            "1": "DEST-123AALK",
            "2": "Destornillador perillero",
            "5": "Naranja"
            "6": ""
        },
        "updated": "2022-05-20T14:23:24.000Z"
    }
}
```

La respuesta contiene al elemento modificado y tiene la misma estructura que lo que se recibe en la sección [Obtener elemento](/entidades-basicas/master-db/obtener-elemento)


# Eliminar elemento

Para borrar un elemento en una Master Db en Persat, se debe enviar un DELETE como el que se especifica a continuación.

{% hint style="danger" %}
Recuerde que esta operación no se puede deshacer.
{% endhint %}

<mark style="color:red;">`DELETE`</mark> `https://api.persat.com.ar/v1/masterdbvalues/mdb_id/field_1`

#### Path Parameters

| Name                                       | Type   | Description                            |
| ------------------------------------------ | ------ | -------------------------------------- |
| mdb\_id<mark style="color:red;">\*</mark>  | Number | Identificado de la Master db           |
| field\_1<mark style="color:red;">\*</mark> | String | Identificador del elemento a modificar |

#### Headers

| Name                                            | Type   | Description     |
| ----------------------------------------------- | ------ | --------------- |
| Authorization<mark style="color:red;">\*</mark> | String | Bearer API\_KEY |

{% tabs %}
{% tab title="200: OK La consulta se ejecutó con éxito" %}

```json
{
    "success": true,
    "data": {
        "mdb_id": 4,
        "field_1": "DEST-123AALK"
    }
}
```

{% endtab %}

{% tab title="404: Not Found El elemento a borrar no existe. O no existe el mdb\_id" %}

```json
{
    "success": false,
    "error": {
        "status": 404,
        "type": "NOT_FOUND",
        "userMessage": "No se encontro el mdb value"
    }
}
```

{% endtab %}

{% tab title="400: Bad Request Error en alguno de los campos enviados. userMessage contiene informacipon adicional." %}

```javascript
{
    "success": false,
    "error": {
        "status": 400,
        "type": "BAD_REQUEST",
        "userMessage": "'mdb_id' es un number (entero) obligatorio"
    }
}
```

{% endtab %}
{% endtabs %}

### Ejemplo de request

En este ejemplo vamos a borrar el elemento identificado como DEST-123AALK de la Master Db de "Productos" (mdb\_id = 4)

* mdb\_id: <mark style="color:blue;">4</mark>
* field\_1 (Identificador del elemento): <mark style="color:green;">DEST-123AALK</mark>

Asi sería la consulta

<mark style="color:red;">**DELETE -**</mark> <https://api.persat.com.ar/v1/masterdbvalues/><mark style="color:blue;">4</mark>/<mark style="color:green;">DEST-123AALK</mark>

### Analizando la Respuesta

En caso que no haya ningun error, obtenemos los datos de identificación del objeto borrado

```json
{
    "success": true,
    "data": {
        "mdb_id": 4,
        "field_1": "DEST-123AALK"
    }
}
```


# Sincronizacion completa

Si quiero tener todos los elementos de una Master Db sincronizados contra otro sistema, existe un endpoint especial que permite listar únicamente los elementos que hayan sido modificados a partir de una fecha particular. Entonces, sobre todo para cuando hay muchos elementos, es posible ir haciendo actualizaciones parciales.

<mark style="color:blue;">`GET`</mark> `https://api.persat.com.ar/v1/masterdbvalues/mdb_id`

#### Path Parameters

| Name                                      | Type   | Description                   |
| ----------------------------------------- | ------ | ----------------------------- |
| mdb\_id<mark style="color:red;">\*</mark> | Number | Identificador de la Master db |

#### Query Parameters

| Name                                            | Type    | Description                                                                              |
| ----------------------------------------------- | ------- | ---------------------------------------------------------------------------------------- |
| offset                                          | number  | Mismo concepto de SQL para la paginación. En caso de no enviarse se considerará 0 (cero) |
| limit<mark style="color:red;">\*</mark>         | number  | Mismo concepto de SQL para la paginación. Max: 100                                       |
| last\_updated<mark style="color:red;">\*</mark> | IsoDate | Fecha a partir de la cual buscar. Formato yyyy-MM-ddTHH:mm:ss.SSSZ                       |

#### Headers

| Name                                            | Type   | Description     |
| ----------------------------------------------- | ------ | --------------- |
| Authorization<mark style="color:red;">\*</mark> | String | Bearer API\_KEY |

{% tabs %}
{% tab title="200: OK La consulta se ejecutó con éxito" %}

{% endtab %}

{% tab title="400: Bad Request Error en alguno de los campos enviados. userMessage contiene informacipon adicional." %}

```javascript
{
    "success": false,
    "error": {
        "status": 400,
        "type": "BAD_REQUEST",
        "userMessage": "'mdb_id' es un number (entero) obligatorio"
    }
}
```

{% endtab %}
{% endtabs %}

### Ejemplo de consulta

En este ejemplo queremos listar todos los elementos de la Master Db de Productos que hayan sufrido una modificación o hayan sido creados a partir de **last\_updated** incluido.

{% hint style="info" %}
IMPORTANTE:

**last\_updated:** Es una fecha UTC.
{% endhint %}

* mdb\_id = 4
* last\_updated = 19 de Mayo de 2022 a las 08:00 UTC

**<https://api.persat.com.ar/v1/**&#x6D;asterdbvalue&#x73;**/>**<mark style="color:blue;">4</mark>?offset=0\&limit=2\&last\_updated=2022-05-19T08:00:00.000Z

### Analizando la Respuesta

```json
{
    "success": true,
    "paging": {
        "offset": 0,
        "limit": 2,
        "result": 2,
        "total": 1235
    },
    "data": [
        {
            "mdb_id": 4,
            "fields": {
                "1": "DEST-123AALK",
                "2": "Destornillador perillero",
                "5": "Rojo",
                "6": "130.76"
            },
            "updated": "2022-05-20T14:05:31.000Z"
        },
        {
            "mdb_id": 4,
            "fields": {
                "1": "PINZ-998KJU",
                "2": "Pinza de Punta",
                "5": "Metal",
                "6": "200.56"
            },
            "updated": "2022-05-20T14:06:04.000Z"
        }
    ]
}
```

**paging:** Es un objeto JSON que contiene los datos de la consulta offset y limit tal cual se recibieron, y luego presenta el total de elementos en la Master Db encontrados, y la cantidad devueltos en esta consulta particular. De esta forma podemos ir trayendo de forma paginada todos los elementos modificados o creados a partir de **last\_updated**

**data:** Es un array de Objetos JSON, en donde cada item es el elemento en la Master Db. Los campos de ese elemento son los mismos que cuando hacemos la consulta [Obtener Elemento](/entidades-basicas/master-db/obtener-elemento)

## Procedimimento para la Sincronizacion

El procedimiento correcto para hacer la sincronización de un listado con muchos elementos en una Master Db es el siguiente:

La primera vez, realizamos un request con el parametro **last\_updated** con una fecha del pasado a la contratación de Persat (ej: 2000-01-01T00:00:00.000Z), e iteramos modificando el offet hasta barrer todos los elementos. Una vez sincronizados guardamos la fecha UTC en que realizamos esta primer sincronización.

Luego, cada vez que queremos sincronizar, repetimos el procedimiento anterior pero indicando en el parámetro **last\_updated** la fecha guardada anteriormente. Finalizado el proceso guardamos la nueva fecha UTC de sincronización y repetimos cada vez que queramos sincronizar.


# Dispositivos

Los dispositivos en Persat pueden ser tanto vehiculos como celulares, tengan o no activo el rastreo.

Se pueden visualizar los dispositivos disponibles en el Módulo de Rastreo Satelital > Opciones > Ajustes

<figure><img src="/files/xF9AxmZBNDSIRzaF6ql2" alt=""><figcaption></figcaption></figure>

### ¿Que podés hacer con los dispositivos?

> [Obtener dispositivo](/entidades-basicas/dispositivos/obtener-dispositivo)
>
> [Listar dispositivos](/entidades-basicas/dispositivos/listar-dispositivos)
>
> [Obtener última posición GPS](/modulos/rastreo-satelital/obtener-ultima-posicion-gps)
>
> [Obtener Visitas a Clientes por dispositivo](/modulos/rastreo-satelital/obtener-visitas-a-clientes)
>
> [Asignar Zonas](/entidades-basicas/zonas-de-trabajo/asignar-zonas)


# Obtener Dispositivo

Para obtener un dispositivo particular se debe realizar un GET como el que se muestra a continuación.

<mark style="color:blue;">`GET`</mark> `https://api.persat.com.ar/v1/devices/device_id`

#### Path Parameters

| Name                                         | Type   | Description                   |
| -------------------------------------------- | ------ | ----------------------------- |
| device\_id<mark style="color:red;">\*</mark> | Number | Identificador del dispositivo |

#### Headers

| Name                                            | Type   | Description     |
| ----------------------------------------------- | ------ | --------------- |
| Authorization<mark style="color:red;">\*</mark> | String | Bearer API\_KEY |

{% tabs %}
{% tab title="200: OK La consulta se ejecutó con éxito" %}

```json
{
    "success": true,
    "data": {
        "id": 104,    
        "type": "VEHICLE",
        "serial_number": "3213213-ABCD....",
        "first_name": "Martin Gonzalez",
        "last_name": "LKL 987",
        "working_zones": [
            {
                "id": 2,
                "created": "2013-08-16T14:27:20.000Z",
                "name": " GBA Norte"
            }, { ... }
        ],
        "working_hours": {
            "monday": [],
            "tuesday": [
                {
                    "start": "05:05",
                    "end": "06:06"
                }
            ],
            "wednesday": [],
            "thursday": [],
            "friday": [],
            "saturday": [],
            "sunday": [
                {
                    "start": "01:01",
                    "end": "02:02"
                }
            ]
        }
    }
}
```

{% endtab %}

{% tab title="404: Not Found No se encontro el dispositivo" %}

```json
{
    "success": false,
    "error": {
        "status": 404,
        "type": "NOT_FOUND",
        "userMessage": "No existe un device con este id"
    }
}
```

{% endtab %}

{% tab title="400: Bad Request device\_id no es un número" %}

```javascript
{
    "success": false,
    "error": {
        "status": 400,
        "type": "BAD_REQUEST",
        "userMessage": "'device_id' debe ser un número entero"
    }
}
```

{% endtab %}
{% endtabs %}

### Analizando la Respuesta

```json
{
    "success": true,
    "data": {
        "id": 104,    
        "type": "VEHICLE",
        "serial_number": "3213213-ABCD....",
        "first_name": "Martin Gonzalez",
        "last_name": "LKL 987",
        "working_zones": [
            {
                "id": 2,
                "created": "2013-08-16T14:27:20.000Z",
                "name": " GBA Norte"
            }, { ... }
        ],
        "working_hours": {
            "monday": [],
            "tuesday": [
                {
                    "start": "05:05",
                    "end": "06:06"
                }
            ],
            "wednesday": [],
            "thursday": [],
            "friday": [],
            "saturday": [],
            "sunday": [
                {
                    "start": "01:01",
                    "end": "02:02"
                }
            ]
        }
    }
}
```

**id:** Identificador del Dispositivo.&#x20;

**first\_name:** Nombre

**last\_name:** Apellido

{% hint style="info" %}
**first\_name** y **last\_name** se pueden usar libremente y pueden identificar a un vehiculo, por ejemplo con su modelo y patente
{% endhint %}

**type:** Tipo de dispositivo. Puede ser "VEHICLE" o "CELLPHONE"

**serial\_number:** Identificador unico del dispositivo físico. Por ejemplo, los dispositivos de tipo VEHICLE, usan como identificador el número de serie del equipo de rastreo, mientras que los de tipo CELLPHONE usan el imei o el número de serie de la placa de video del teléfono.

{% hint style="danger" %}
El <mark style="color:red;">**serial\_number**</mark> es meramente informativo, bajo ninguna circunstancia debe ser utilizado como identificador
{% endhint %}

**working\_zones**. Array con las zonas de trabajo asignadas. Los campos se describen en [Obtener Zona](/entidades-basicas/zonas-de-trabajo/obtener-zona)

**working\_hours.** Objeto json que contiene en cada key el día de la semana. Cada día de la semana es un array con objetos { start: "HH:mm", end: "HH:mm }. Indicando inicio y fin de jornada laboral.

{% hint style="warning" %}
Es un array, ya que se contempla para un futuro permitir horarios partidos. Es decir jornadas laborales con descansos intermedios.

Si el array está vacío, significa que no es un dia laborable.
{% endhint %}


# Listar Dispositivos

Para obtener un listado de los dispositivos, se debe enviar un GET como el que se especifica a continuación.

<mark style="color:blue;">`GET`</mark> `https://api.persat.com.ar/v1/devices`

#### Headers

| Name                                            | Type   | Description     |
| ----------------------------------------------- | ------ | --------------- |
| Authorization<mark style="color:red;">\*</mark> | String | Bearer API\_KEY |

{% tabs %}
{% tab title="200: OK La consulta se ejecutó con éxito" %}

```json
{
    "success": true,
    "data": [
        {
            "id": 2,        
            "type": "VEHICLE",
            "serial_number": "3213213-ABCD....",
            "first_name": "Fiorino",
            "last_name": "JKL-345",
            "working_zones": [
                {
                    "id": 2,
                    "created": "2013-08-16T14:27:20.000Z",
                    "name": " GBA Norte"
                }, { ... }
            ],
            "working_hours": {
                "monday": [],
                "tuesday": [
                    {
                        "start": "05:05",
                        "end": "06:06"
                    }
                ],
                "wednesday": [],
                "thursday": [],
                "friday": [],
                "saturday": [],
                "sunday": [
                    {
                        "start": "01:01",
                        "end": "02:02"
                    }
                ]
            }
        },
        { ... }
    ]
}
```

{% endtab %}
{% endtabs %}

### Analizando la Respuesta

En caso que no haya ningun error, obtenemos

```json
{
    "success": true,
    "data": [
        {
            "id": 2,        
            "type": "VEHICLE",
            "serial_number": "3213213-ABCD....",
            "first_name": "Fiorino",
            "last_name": "JKL-345"
            "working_zones": [
                {
                    "id": 2,
                    "created": "2013-08-16T14:27:20.000Z",
                    "name": " GBA Norte"
                }, { ... }
            ],
            "working_hours": {
                "monday": [],
                "tuesday": [
                    {
                        "start": "05:05",
                        "end": "06:06"
                    }
                ],
                "wednesday": [],
                "thursday": [],
                "friday": [],
                "saturday": [],
                "sunday": [
                    {
                        "start": "01:01",
                        "end": "02:02"
                    }
                ]
            }
        },
        { ... }
    ]
}
```

Lo que se recibe es un array en donde cada elemento del mismo representa un dispositivo.

Los campos de cada dispositivo se explican en [Obtener Dispositivo](/entidades-basicas/dispositivos/obtener-dispositivo)


# Asignar horario laboral

En Persat se puede:&#x20;

* [Asignar horario semanal para un dispositivo particular](/entidades-basicas/dispositivos/asignar-horario-laboral/asignar-horario-semanal)
* [Asignar horario por día para un dispositivo particular](/entidades-basicas/dispositivos/asignar-horario-laboral/asignar-horario-por-dia)
* [Asignar horario semanal de forma masiva](/entidades-basicas/dispositivos/asignar-horario-laboral/asignar-horario-semanal-de-forma-masiva)
* [Asignar horario por día de forma masiva](/entidades-basicas/dispositivos/asignar-horario-laboral/asignar-horario-por-dia-de-forma-masiva)


# Asignar horario semanal

Permite asignar el horario laboral de toda la semana, pisando el horario actual para un dispositivo particular

<mark style="color:green;">`POST`</mark> `https://api.persat.com.ar/v1/devices/`<mark style="color:purple;">`:device_id`</mark>`/working_hours`

#### Headers

| Name                                            | Type   | Description      |
| ----------------------------------------------- | ------ | ---------------- |
| Content-Type<mark style="color:red;">\*</mark>  | string | application/json |
| Authorization<mark style="color:red;">\*</mark> | string | Bearer API\_KEY  |

#### Path params

| Name                                         | Type   | Description                   |
| -------------------------------------------- | ------ | ----------------------------- |
| device\_id<mark style="color:red;">\*</mark> | number | Identificador del dispositivo |

#### Request Body

<table><thead><tr><th width="254">Name</th><th>Type</th><th>Description</th></tr></thead><tbody><tr><td>working_hours<mark style="color:red;">*</mark></td><td>Object</td><td>Objeto Json con 7 campos. Cada uno indicando el horario laboral para cada día de la semana</td></tr><tr><td>working_hours.monday<mark style="color:red;">*</mark></td><td>array de Objetos JSON</td><td>Ver ejemplo de request más abajo</td></tr><tr><td>working_hours.tuesday<mark style="color:red;">*</mark></td><td>array de Objetos JSON</td><td>Ver ejemplo de request más abajo</td></tr><tr><td>working_hours.wednesday<mark style="color:red;">*</mark></td><td>array de Objetos JSON</td><td>Ver ejemplo de request más abajo</td></tr><tr><td>working_hours.thursday<mark style="color:red;">*</mark></td><td>array de Objetos JSON</td><td>Ver ejemplo de request más abajo</td></tr><tr><td>working_hours.friday<mark style="color:red;">*</mark></td><td>array de Objetos JSON</td><td>Ver ejemplo de request más abajo</td></tr><tr><td>working_hours.saturday<mark style="color:red;">*</mark></td><td>array de Objetos JSON</td><td>Ver ejemplo de request más abajo</td></tr><tr><td>working_hours.sunday<mark style="color:red;">*</mark></td><td>array de Objetos JSON</td><td>Ver ejemplo de request más abajo</td></tr></tbody></table>

{% tabs %}
{% tab title="200: OK" %}

```json
{
    "success": true,
    "data": {}
}
```

{% endtab %}

{% tab title="400 BAD REQUEST" %}

```json
{
    "success": false,
    "error": {
        "status": 400,
        "type": "BAD_REQUEST",
        "userMessage": "\"monday\" is required"
    }
}
```

{% endtab %}

{% tab title="404 device NOT FOUND" %}

```json
{
    "success": false,
    "error": {
        "status": 404,
        "type": "NOT_FOUND",
        "userMessage": "No existe un device con este id: 144545"
    }
}
```

{% endtab %}
{% endtabs %}

### Ejemplo de Request

Ejemplo de body, en donde indicamos que los dos únicos días laborales son el lunes y el martes.

```json
{
    "working_hours": {
        "monday": [
            {
                "start": "09:30",
                "end": "17:00"
            }
        ],
        "tuesday": [
            {
                "start": "12:30",
                "end": "18:00"
            }
        ],
        "wednesday": [],
        "thursday": [],
        "friday": [],
        "saturday": [],
        "sunday": []
    }
}
```

{% hint style="warning" %}
Cada uno de los días de la semana es un array de objetos {start, end}. En la actualidad debe contener un único elemento.&#x20;

Se contempla de esta forma la posibilidad a futuro de que haya horarios de descanso intermedio
{% endhint %}


# Asignar horario por día

Permite asignar el horario laboral de uno o varios días para un determinado dispositivo. Sin necesidad de enviar la semana completa.&#x20;

<mark style="color:purple;">`PUT`</mark> `https://api.persat.com.ar/v1/devices/`<mark style="color:purple;">`:device_id`</mark>`/working_hours`

#### Headers

| Name                                            | Type   | Description      |
| ----------------------------------------------- | ------ | ---------------- |
| Content-Type<mark style="color:red;">\*</mark>  | string | application/json |
| Authorization<mark style="color:red;">\*</mark> | string | Bearer API\_KEY  |

#### Path params

| Name                                         | Type   | Description                   |
| -------------------------------------------- | ------ | ----------------------------- |
| device\_id<mark style="color:red;">\*</mark> | number | Identificador del dispositivo |

#### Request Body

<table><thead><tr><th width="254">Name</th><th>Type</th><th>Description</th></tr></thead><tbody><tr><td>working_hours<mark style="color:red;">*</mark></td><td>Object</td><td>Objeto Json con 7 campos. Cada uno indicando el horario laboral para cada día de la semana</td></tr><tr><td>working_hours.monday</td><td>array de Objetos JSON</td><td>Opcional. Ver ejemplo de request más abajo</td></tr><tr><td>working_hours.tuesday</td><td>array de Objetos JSON</td><td>Opcional. Ver ejemplo de request más abajo</td></tr><tr><td>working_hours.wednesday</td><td>array de Objetos JSON</td><td>Opcional. Ver ejemplo de request más abajo</td></tr><tr><td>working_hours.thursday</td><td>array de Objetos JSON</td><td>Opcional. Ver ejemplo de request más abajo</td></tr><tr><td>working_hours.friday</td><td>array de Objetos JSON</td><td>Opcional. Ver ejemplo de request más abajo</td></tr><tr><td>working_hours.saturday</td><td>array de Objetos JSON</td><td>Opcional. Ver ejemplo de request más abajo</td></tr><tr><td>working_hours.sunday</td><td>array de Objetos JSON</td><td>Opcional. Ver ejemplo de request más abajo</td></tr></tbody></table>

{% tabs %}
{% tab title="200: OK" %}

```json
{
    "success": true,
    "data": {}
}
```

{% endtab %}

{% tab title="400 BAD REQUEST" %}

```json
{
    "success": false,
    "error": {
        "status": 400,
        "type": "BAD_REQUEST",
        "userMessage": "'start' es requerido HH:mm"
    }
}
```

{% endtab %}

{% tab title="404 device NOT FOUND" %}

```json
{
    "success": false,
    "error": {
        "status": 404,
        "type": "NOT_FOUND",
        "userMessage": "No existe un device con este id: 144545"
    }
}
```

{% endtab %}
{% endtabs %}

### Ejemplo de Request

Ejemplo de body, en donde seteamos el horario laboral del día viernes, y aprovechamos para indicar que no se trabaja el sábado.

```json
{
    "working_hours": {
        "friday": [
            {
                "start": "10:00",
                "end": "16:00"
            }
        ],
        "saturday": []
    }
}
```

{% hint style="success" %}
Los campos de este body se explican con más detalle en [Asignar horario semanal](/entidades-basicas/dispositivos/asignar-horario-laboral/asignar-horario-semanal)
{% endhint %}


# Asignar horario semanal de forma masiva

Permite asignar el horario laboral de toda la semana, pisando el horario actual para uno o varios dispositivos.

<mark style="color:green;">`POST`</mark> `https://api.persat.com.ar/v1/working-hours`

#### Headers

| Name                                            | Type   | Description      |
| ----------------------------------------------- | ------ | ---------------- |
| Content-Type<mark style="color:red;">\*</mark>  | string | application/json |
| Authorization<mark style="color:red;">\*</mark> | string | Bearer API\_KEY  |

#### Request Body

<table><thead><tr><th width="254">Name</th><th>Type</th><th>Description</th></tr></thead><tbody><tr><td>devices_ids<mark style="color:red;">*</mark></td><td>Array de numbers</td><td>Identificadores de los dispositivos.</td></tr><tr><td>working_hours<mark style="color:red;">*</mark></td><td>Object</td><td>Objeto Json con 7 campos. Cada uno indicando el horario laboral para cada día de la semana</td></tr><tr><td>working_hours.monday<mark style="color:red;">*</mark></td><td>array de Objetos JSON</td><td>Ver ejemplo de request más abajo</td></tr><tr><td>working_hours.tuesday<mark style="color:red;">*</mark></td><td>array de Objetos JSON</td><td>Ver ejemplo de request más abajo</td></tr><tr><td>working_hours.wednesday<mark style="color:red;">*</mark></td><td>array de Objetos JSON</td><td>Ver ejemplo de request más abajo</td></tr><tr><td>working_hours.thursday<mark style="color:red;">*</mark></td><td>array de Objetos JSON</td><td>Ver ejemplo de request más abajo</td></tr><tr><td>working_hours.friday<mark style="color:red;">*</mark></td><td>array de Objetos JSON</td><td>Ver ejemplo de request más abajo</td></tr><tr><td>working_hours.saturday<mark style="color:red;">*</mark></td><td>array de Objetos JSON</td><td>Ver ejemplo de request más abajo</td></tr><tr><td>working_hours.sunday<mark style="color:red;">*</mark></td><td>array de Objetos JSON</td><td>Ver ejemplo de request más abajo</td></tr></tbody></table>

{% tabs %}
{% tab title="200: OK" %}

```json
{
    "success": true,
    "data": {}
}
```

{% endtab %}

{% tab title="400 BAD REQUEST" %}

```json
{
    "success": false,
    "error": {
        "status": 400,
        "type": "BAD_REQUEST",
        "userMessage": "\"monday\" is required"
    }
}
```

{% endtab %}

{% tab title="404 device NOT FOUND" %}

```json
{
    "success": false,
    "error": {
        "status": 404,
        "type": "NOT_FOUND",
        "userMessage": "No existe un device con este id: 144545"
    }
}
```

{% endtab %}
{% endtabs %}

### Ejemplo de Request

Ejemplo de body, en donde indicamos que los dos únicos días laborales son el lunes y el martes para los dispositivos 14 y 15 únicamente.

```json
{
    "devices_ids": [14,15],
    "working_hours": {
        "monday": [
            {
                "start": "09:33",
                "end": "11:01"
            }
        ],
        "tuesday": [
            {
                "start": "12:33",
                "end": "23:59"
            }
        ],
        "wednesday": [],
        "thursday": [],
        "friday": [],
        "saturday": [],
        "sunday": [
            {
                "start": "15:11",
                "end": "18:22"
            }
        ]   
    }
}
```

{% hint style="success" %}
Los campos de este body se explican con más detalle en [Asignar horario semanal](/entidades-basicas/dispositivos/asignar-horario-laboral/asignar-horario-semanal)
{% endhint %}

{% hint style="danger" %}
La consulta se realiza con éxito solo si se pudo asignar los horarios a todos los dispositivos mencionados en el request. Si por alguna razón no se pudo actualizar el horario de algún dispositivo, entonces toda la consulta se da por fallida y por ende no se modifica ningún horario de ningún dispositivo.

Prestar especial atención a que los dispositivos existan. Se puede verificar primero el endpoint \
[Listar Dispositivos](/entidades-basicas/dispositivos/listar-dispositivos)
{% endhint %}


# Asignar horario por día de forma masiva

Permite asignar el horario laboral de uno o varios días para uno o varios dispositivos. Sin necesidad de enviar la semana completa.

<mark style="color:purple;">`PUT`</mark> `https://api.persat.com.ar/v1/working-hours`

#### Headers

| Name                                            | Type   | Description      |
| ----------------------------------------------- | ------ | ---------------- |
| Content-Type<mark style="color:red;">\*</mark>  | string | application/json |
| Authorization<mark style="color:red;">\*</mark> | string | Bearer API\_KEY  |

#### Request Body

<table><thead><tr><th width="254">Name</th><th>Type</th><th>Description</th></tr></thead><tbody><tr><td>devices_ids<mark style="color:red;">*</mark></td><td>Array de numbers</td><td>Identificadores de los dispositivos.</td></tr><tr><td>working_hours<mark style="color:red;">*</mark></td><td>Object</td><td>Objeto Json con 7 campos. Cada uno indicando el horario laboral para cada día de la semana</td></tr><tr><td>working_hours.monday</td><td>array de Objetos JSON</td><td>Opcional. Ver ejemplo de request más abajo</td></tr><tr><td>working_hours.tuesday</td><td>array de Objetos JSON</td><td>Opcional. Ver ejemplo de request más abajo</td></tr><tr><td>working_hours.wednesday</td><td>array de Objetos JSON</td><td>Opcional. Ver ejemplo de request más abajo</td></tr><tr><td>working_hours.thursday</td><td>array de Objetos JSON</td><td>Opcional. Ver ejemplo de request más abajo</td></tr><tr><td>working_hours.friday</td><td>array de Objetos JSON</td><td>Opcional. Ver ejemplo de request más abajo</td></tr><tr><td>working_hours.saturday</td><td>array de Objetos JSON</td><td>Opcional. Ver ejemplo de request más abajo</td></tr><tr><td>working_hours.sunday</td><td>array de Objetos JSON</td><td>Opcional. Ver ejemplo de request más abajo</td></tr></tbody></table>

{% tabs %}
{% tab title="200: OK" %}

```json
{
    "success": true,
    "data": {}
}
```

{% endtab %}

{% tab title="400 BAD REQUEST" %}

```json
{
    "success": false,
    "error": {
        "status": 400,
        "type": "BAD_REQUEST",
        "userMessage": "'start' es requerido HH:mm"
    }
}
```

{% endtab %}

{% tab title="404 device NOT FOUND" %}

```json
{
    "success": false,
    "error": {
        "status": 404,
        "type": "NOT_FOUND",
        "userMessage": "No existe un device con este id: 144545"
    }
}
```

{% endtab %}
{% endtabs %}

### Ejemplo de Request

Ejemplo de body, en donde seteamos el horario laboral del día viernes, y aprovechamos para indicar que no se trabaja el sábado, para los dispositivos 14 y 15

```json
{
    "devices_ids": [14,15],
    "working_hours": {
        "friday": [
            {
                "start": "10:00",
                "end": "16:00"
            }
        ],
        "saturday": []
    }
}
```

{% hint style="success" %}
Los campos de este body se explican con más detalle en [Asignar horario semanal](/entidades-basicas/dispositivos/asignar-horario-laboral/asignar-horario-semanal)
{% endhint %}

{% hint style="danger" %}
La consulta se realiza con éxito solo si se pudo asignar los horarios a todos los dispositivos mencionados en el request. Si por alguna razón no se pudo actualizar el horario de alguún dispositivo, entonces toda la consulta se da por fallida y por ende no se modifica ningún horario de ningún dispositivo.

Prestar especial atención a que los dispositivos exitan. Se puede verificar primero el endpoint \
[Listar Dispositivos](/entidades-basicas/dispositivos/listar-dispositivos)
{% endhint %}


# Asignar zonas de trabajo

Para poder trabajar con las zonas de trabajo, dirijase a la sección [Zonas de Trabajo](/entidades-basicas/zonas-de-trabajo)


# Zonas de trabajo

Las zonas en Persat son áreas geográficas definidas en el mapa, con límites específicos, para distintos usos. Sirven para varias funcionalidades relacionadas con el rastreo satelital, seguimiento del personal, supervisión de rutas, alertas, etc.

{% hint style="info" %}
Las zonas se pueden crear únicamente desde la web. No es posible aún crear zonas desde la API.
{% endhint %}

## Para qué sirven

**Monitoreo del personal dentro / fuera de zonas**\
Permite saber si un vehículo, técnico, vendedor u operario está dentro de una zona de trabajo determinada o si salió de ella. Eso ayuda a controlar cumplimiento de rutas, tiempos, áreas de responsabilidad.

**Alertas automáticas**\
Podés configurar notificaciones para que te avise cuando alguien entre o salga de una zona. Esto sirve para asegurarte de que se cumplen las asignaciones geográficas, o detectar desvíos.<br>

**Control y eficacia operativa**\
Ayudan a organizar el trabajo, optimizar las recorridas, asegurarte de que todas las zonas asignadas estén siendo cubiertas apropiadamente. También facilitan identificar zonas descuidadas.<br>

**Reportes y análisis**\
Las zonas permiten segmentar datos geográficos: cuántas visitas, recorridos, clientes atendidos, etc. por zona. Esto te da métricas por región/área.<br>

**Asignación de zonas de trabajo**\
Para planificar qué operario, vendedor o unidad se encarga de qué zona. Esto da claridad en la distribución territorial, evitás solapamientos, mejorás cobertura.<br>

**Gestión de rutas y eficiencia**\
Permiten definir rutas más lógicas, asignar prioridades, reducir tiempos muertos o recorridos

### Como crear Zonas

Para poder administrar las zonas. Debemos dirigirnos al módulo de Rastreo Satelital > Más > Zonas&#x20;

<figure><img src="/files/QpwlsBScchRyHpuntmTF" alt=""><figcaption></figcaption></figure>

### ¿Qué podés hacer con las Zonas desde la API?

En las siguientes secciones se explica todo lo que podes hacer&#x20;

> [Obtener Zona](/entidades-basicas/zonas-de-trabajo/obtener-zona)
>
> [Listar Zonas](/entidades-basicas/zonas-de-trabajo/listar-zonas)
>
> [Asignar Zonas](/entidades-basicas/zonas-de-trabajo/asignar-zonas)
>
> [Asignar zonas masivamente](/entidades-basicas/zonas-de-trabajo/asignar-zonas-masivamente)


# Obtener Zona

Para obtener una zona particular se debe realizar un GET como el que se muestra a continuación.

<mark style="color:blue;">`GET`</mark> `https://api.persat.com.ar/v1/zones/zone_id`

#### Path Parameters

| Name                                       | Type   | Description              |
| ------------------------------------------ | ------ | ------------------------ |
| zone\_id<mark style="color:red;">\*</mark> | Number | Identificador de la zona |

#### Headers

| Name                                            | Type   | Description     |
| ----------------------------------------------- | ------ | --------------- |
| Authorization<mark style="color:red;">\*</mark> | String | Bearer API\_KEY |

{% tabs %}
{% tab title="200: OK La consulta se ejecutó con éxito" %}

```json
{
    "success": true,
    "data": {
        "id": 104,    
        "type": "VEHICLE",
        "serial_number": "3213213-ABCD....",
        "first_name": "Martin Gonzalez",
        "last_name": "LKL 987"
    }
}
```

{% endtab %}

{% tab title="404: Not Found No se encontró la zona" %}

```json
{
    "success": false,
    "error": {
        "status": 404,
        "type": "NOT_FOUND",
        "userMessage": "No existe una zona con este zoneId: 1231312."
    }
}
```

{% endtab %}

{% tab title="400: Bad Request" %}

```javascript
{
    "success": false,
    "error": {
        "status": 400,
        "type": "BAD_REQUEST",
        "userMessage": "'zone_id' debe ser un número entero"
    }
}
```

{% endtab %}
{% endtabs %}

### Analizando la Respuesta

```json
{
    "success": true,
    "data": {
        "id": 1,
        "name": " Cordoba (Capital)",        
        "created": "2013-08-16T13:37:31.000Z"
    }
}
```

**id:** Identificador de la zona

**name:** Nombre de la zona

create&#x64;**:** Fecha de creación.


# Listar Zonas

Se pueden listar todas las zona, o también se pueden obtener las zonas asignadas a un determinado dispositivo.

<mark style="color:blue;">`GET`</mark> `https://api.persat.com.ar/v1/zones?device_id=12`

#### Query Parameters

| Name       | Type   | Description                                |
| ---------- | ------ | ------------------------------------------ |
| device\_id | Number | \[Opcional]. Identificador del dispositivo |

#### Headers

| Name                                            | Type   | Description     |
| ----------------------------------------------- | ------ | --------------- |
| Authorization<mark style="color:red;">\*</mark> | String | Bearer API\_KEY |

{% tabs %}
{% tab title="200: OK La consulta se ejecutó con éxito" %}

```json
{
    "success": true,
    "data": [
        {
            "id": 1,
            "created": "2013-08-16T13:37:31.000Z",
            "name": " Cordoba (Capital)"
        },
        {
            "id": 2,
            "created": "2013-08-16T14:27:20.000Z",
            "name": " GBA Norte"
        },
        {
            "id": 3,
            "created": "2013-08-16T14:44:31.000Z",
            "name": " Au. BsAs - Rosario"
        },
        {
            "id": 4,
            "created": "2013-08-16T13:40:08.000Z",
            "name": " Mendoza (Capital)"
        },
        {
            "id": 5,
            "created": "2013-08-16T13:18:06.000Z",
            "name": " Rosario"
        },
        {
            "id": 6,
            "created": "2013-08-16T13:42:48.000Z",
            "name": " SM de Tucuman"
        },
        {
            "id": 7,
            "created": "2013-08-16T15:31:39.000Z",
            "name": "Argentina"
        },
        {
            "id": 8,
            "created": "2011-02-18T21:26:39.000Z",
            "name": "GBA Oeste"
        },
        {
            "id": 9,
            "created": "2011-02-14T01:13:05.000Z",
            "name": "GBA Sur"
        },
        {
            "id": 10,
            "created": "2025-09-09T14:47:44.000Z",
            "name": " Pedro"
        }
    ]
}
```

{% endtab %}

{% tab title="404: Not Found No se encontró el dispositivo" %}

```json
{
    "success": false,
    "error": {
        "status": 404,
        "type": "NOT_FOUND",
        "userMessage": "No existe un device con este id: 3123233213"
    }
}
```

{% endtab %}

{% tab title="400: Bad Request" %}

```javascript
{
    "success": false,
    "error": {
        "status": 400,
        "type": "BAD_REQUEST",
        "userMessage": "device_id. Not a number"
    }
}
```

{% endtab %}
{% endtabs %}

### Analizando la Respuesta

```json
{
    "success": true,
    "data": [
        {
            "id": 1,
            "created": "2013-08-16T13:37:31.000Z",
            "name": " Cordoba (Capital)"
        },
        {
            "id": 2,
            "created": "2013-08-16T14:27:20.000Z",
            "name": " GBA Norte"
        }, { ... }
    ]
}
```

**data:** Array de Zonas. Cada item del array identifica la zona como se encuentra definido en [Obtener Zona](/entidades-basicas/zonas-de-trabajo/obtener-zona)


# Asignar zonas

En Persat se puede:&#x20;

* [Setear zonas a dispositivo](/entidades-basicas/zonas-de-trabajo/asignar-zonas/setear-zonas-a-dispositivo)
* [Asignar zonas a dispositivo](/entidades-basicas/zonas-de-trabajo/asignar-zonas/asignar-zonas-a-dispositivo)
* [Desasignar zonas a dispositivos](/entidades-basicas/zonas-de-trabajo/asignar-zonas/desasignar-zonas-a-dispositivo)


# Setear zonas a dispositivo

Este endpoint permite asignar zonas a un dispositivo. El dispositivo "pierde" las zonas que tenía asignada anteriormente. Si sólo quiere [Asignar zonas](/entidades-basicas/zonas-de-trabajo/asignar-zonas) o [Desasignar zonas](/entidades-basicas/zonas-de-trabajo/asignar-zonas/desasignar-zonas-a-dispositivo), revise los endpoints correspondientes.

<mark style="color:green;">`POST`</mark> `https://api.persat.com.ar/v1/devices/`<mark style="color:purple;">`:device_id`</mark>`/zones`

#### Headers

| Name          | Type   | Description      |
| ------------- | ------ | ---------------- |
| Content-Type  | string | application/json |
| Authorization | string | Bearer API\_KEY  |

#### Path parameters

| Name                                          | Type   | Description                                                       |
| --------------------------------------------- | ------ | ----------------------------------------------------------------- |
| :device\_id<mark style="color:red;">\*</mark> | number | Identificador del dispositivo al cual le quiero asignar las zonas |

#### Request Body

| Name                                        | Type      | Description                                                                        |
| ------------------------------------------- | --------- | ---------------------------------------------------------------------------------- |
| zone\_ids<mark style="color:red;">\*</mark> | number\[] | Array con enteros. Cada uno de los enteros es el id de la zona que quiero asignar. |

{% tabs %}
{% tab title="200 Zonas asignadas" %}

```javascript
{
    "success": true,
    "data": {}
}
```

{% endtab %}

{% tab title="400 Alguna de las zonas no existe" %}

```javascript
{
    "success": false,
    "error": {
        "status": 400,
        "type": "BAD_REQUEST",
        "userMessage": "La zone o el device_id no existe/n"
    }
}
```

{% endtab %}

{% tab title="404: Dispositivo no encontrado" %}

```javascript
{
    "success": false,
    "error": {
        "status": 404,
        "type": "NOT_FOUND",
        "userMessage": "No existe un device con este id: 1433"
    }
}
```

{% endtab %}
{% endtabs %}

### Ejemplo de Request

Ejemplo de body, en donde seteamos las 3 zonas que definimos para este dispositivo.

```json
{
    "zone_ids": [2,3,4]
}
```

### Analizando la Respuesta

```json
{
    "success": true,
    "data": {}
}
```

**data:** Es un objeto JSON vacío

{% hint style="info" %}
Si alguna de las zonas no se puede asignar. Entonces no se asigna ninguna zona y se recibe un error. Es decir que basta con revisar status 200 para verificar que las zonas fueron asignadas.
{% endhint %}

{% hint style="warning" %}
IMPORTANTE: El dispositivo "pierde" las zonas que tenia asignada anteriormente. Es decir que si quiero solo asignar una zona pero sin perder las anteriores. Tengo que primero [Listar Zonas](/entidades-basicas/zonas-de-trabajo/listar-zonas) para este dispositivo, y así asegurarme de enviar el array con todas las zonas
{% endhint %}


# Asignar zonas a dispositivo

Este endpoint permite asignar a un dispositivo una o varias zonas.

Este endpoint permite asignar nuevas zonas a un dispositivo. Agregando la zona a su lista de zonas asignadas.

<mark style="color:purple;">`PUT`</mark> `https://api.persat.com.ar/v1/devices/`<mark style="color:purple;">`:device_id`</mark>`/zones`

#### Headers

| Name          | Type   | Description      |
| ------------- | ------ | ---------------- |
| Content-Type  | string | application/json |
| Authorization | string | Bearer API\_KEY  |

#### Path parameters

| Name                                          | Type   | Description                                                       |
| --------------------------------------------- | ------ | ----------------------------------------------------------------- |
| :device\_id<mark style="color:red;">\*</mark> | number | Identificador del dispositivo al cual le quiero asignar las zonas |

#### Request Body

| Name                                        | Type      | Description                                                                        |
| ------------------------------------------- | --------- | ---------------------------------------------------------------------------------- |
| zone\_ids<mark style="color:red;">\*</mark> | number\[] | Array con enteros. Cada uno de los enteros es el id de la zona que quiero asignar. |

{% tabs %}
{% tab title="200 Zonas asignadas" %}

```javascript
{
    "success": true,
    "data": {}
}
```

{% endtab %}

{% tab title="400 Alguna de las zonas no existe" %}

```javascript
{
    "success": false,
    "error": {
        "status": 400,
        "type": "BAD_REQUEST",
        "userMessage": "La zone o el device_id no existe/n"
    }
}
```

{% endtab %}

{% tab title="404: Dispositivo no encontrado" %}

```javascript
{
    "success": false,
    "error": {
        "status": 404,
        "type": "NOT_FOUND",
        "userMessage": "No existe un device con este id: 14213123"
    }
}
```

{% endtab %}
{% endtabs %}

### Ejemplo de Request

Ejemplo de body, en donde agregamos las zonas 5 y 6 al dispositivo

```json
{
        "zone_ids": [5,6]
}
```

### Analizando la Respuesta

Esta respuesta se corresponde a la asignación de la zona 1 y 2.&#x20;

```json
{
    "success": true,
    "data": {}
}
```

**data:** Es un objeto JSON vacío

{% hint style="warning" %}
Si alguna de las zonas no se puede asignar. Entonces no se asigna ninguna zona y se recibe un error. Es decir que basta con revisar status 200 para verificar que las zonas fueron asignadas.
{% endhint %}


# Desasignar zonas a dispositivo

Este endpoint permite asignar a un dispositivo una o varias zonas.

Este endpoint permite desasignar zonas a un dispositivo. <br>

<mark style="color:red;">`DELETE`</mark> `https://api.persat.com.ar/v1/devices/`<mark style="color:purple;">`:device_id`</mark>`/zones`

#### Headers

| Name          | Type   | Description      |
| ------------- | ------ | ---------------- |
| Content-Type  | string | application/json |
| Authorization | string | Bearer API\_KEY  |

#### Path parameters

| Name                                          | Type   | Description                                                       |
| --------------------------------------------- | ------ | ----------------------------------------------------------------- |
| :device\_id<mark style="color:red;">\*</mark> | number | Identificador del dispositivo al cual le quiero asignar las zonas |

#### Request Body

| Name                                        | Type      | Description                                                                        |
| ------------------------------------------- | --------- | ---------------------------------------------------------------------------------- |
| zone\_ids<mark style="color:red;">\*</mark> | number\[] | Array con enteros. Cada uno de los enteros es el id de la zona que quiero asignar. |

{% tabs %}
{% tab title="200 Zonas asignadas" %}

```javascript
{
    "success": true,
    "data": {}
}
```

{% endtab %}

{% tab title="404: Dispositivo no encontrado" %}

```javascript
{
    "success": false,
    "error": {
        "status": 404,
        "type": "NOT_FOUND",
        "userMessage": "No existe un device con este id: 14213123"
    }
}
```

{% endtab %}
{% endtabs %}

### Ejemplo de Request

Ejemplo de body, en donde desasignamos las zonas 1,2 y 3 del dispositvo

```json
{
        "zone_ids": [1,2,3]
}
```

### Analizando la Respuesta

La respuesta, en caso que la consulta sea exitosa es la siguiente

```json
{
    "success": true,
    "data": {}
}
```

**data.** Es un Json vacio

{% hint style="info" %}
Si alguna de las zonas ya estaba desasignada, se continúa con la siguiente, sin que este hecho se registre como un error.

Si ocurre un error en alguna de las zonas, se cancela toda la operación quedando sin efecto la request.
{% endhint %}


# Asignar zonas másivamente

En Persat se puede:&#x20;

* [Definir las zonas de varios dispositivos](/entidades-basicas/zonas-de-trabajo/asignar-zonas-masivamente/setear-zonas-a-varios-dispositivos)
* [Asignar nuevas zonas a varios dispositivos](/entidades-basicas/zonas-de-trabajo/asignar-zonas-masivamente/asignar-zonas-a-varios-dispositivos)
* [Desasignar zonas de varios dispositivos](/entidades-basicas/zonas-de-trabajo/asignar-zonas-masivamente/desasignar-zonas-a-varios-dispositivos)


# Setear zonas a varios dispositivos

Este endpoint permite asignar zonas a varios dispositivos. Los dispositivos "pierden" las zonas que tenían asignadas anteriormente. Si sólo quiere [Asignar zonas a dispositivos](/entidades-basicas/zonas-de-trabajo/asignar-zonas-masivamente/asignar-zonas-a-varios-dispositivos) o [Desasignar zonas a dispositivos](/entidades-basicas/zonas-de-trabajo/asignar-zonas/desasignar-zonas-a-dispositivo), revise los endpoints correspondientes.

<mark style="color:green;">`POST`</mark> `https://api.persat.com.ar/v1/zones`

#### Headers

| Name          | Type   | Description      |
| ------------- | ------ | ---------------- |
| Content-Type  | string | application/json |
| Authorization | string | Bearer API\_KEY  |

#### Request Body

| Name                                           | Type      | Description                                                                                             |
| ---------------------------------------------- | --------- | ------------------------------------------------------------------------------------------------------- |
| zone\_ids<mark style="color:red;">\*</mark>    | number\[] | Array con enteros. Cada uno de los enteros es el id de la zona que quiero asignar.                      |
| devices\_ids<mark style="color:red;">\*</mark> | number\[] | Array con enteros. Cada uno de los enteros es el id del dispositivo al cual quiero asignarle las zonas. |

{% tabs %}
{% tab title="200 Zonas asignadas" %}

```javascript
{
    "success": true,
    "data": {}
}
```

{% endtab %}

{% tab title="400 Alguna de las zonas no existe" %}

```javascript
{
    "success": false,
    "error": {
        "status": 400,
        "type": "BAD_REQUEST",
        "userMessage": "device_id or zone_id no existe/n"
    }
}
```

{% endtab %}

{% tab title="404: Dispositivo no encontrado" %}

```javascript
{
    "success": false,
    "error": {
        "status": 404,
        "type": "NOT_FOUND",
        "userMessage": "No existe un device con este id: 1423123213"
    }
}
```

{% endtab %}
{% endtabs %}

### Ejemplo de Request

Ejemplo de body, en donde definimos que los dispositivos 15 y 14, tienen como zona de trabajo la zona 3 y 4 únicamente

```json
{
    "zone_ids": [3,4],
    "devices_ids": [15,14]
}
```

### Analizando la Respuesta

La respuesta, en caso que la consulta sea exitosa es la siguiente

```json
{
    "success": true,
    "data": {}
}
```

{% hint style="info" %}
Si alguna de las zonas no se puede asignar. Entonces no se asigna ninguna zona y se recibe un error. Es decir que basta con revisar status 200 para verificar que las zonas fueron asignadas.
{% endhint %}

{% hint style="warning" %}
IMPORTANTE: Los dispositivos "pierden" las zonas que tenían asignadas anteriormente.
{% endhint %}


# Asignar zonas a varios dispositivos

Este endpoint permite asignar a un dispositivo una o varias zonas.

Este endpoint permite asignar nuevas zonas a varios dispositivos. Agregando la zona a su lista de zonas asignadas.

<mark style="color:purple;">`PUT`</mark> `https://api.persat.com.ar/v1/zones`

#### Headers

| Name          | Type   | Description      |
| ------------- | ------ | ---------------- |
| Content-Type  | string | application/json |
| Authorization | string | Bearer API\_KEY  |

#### Request Body

| Name                                           | Type      | Description                                                                                             |
| ---------------------------------------------- | --------- | ------------------------------------------------------------------------------------------------------- |
| zone\_ids<mark style="color:red;">\*</mark>    | number\[] | Array con enteros. Cada uno de los enteros es el id de la zona que quiero asignar.                      |
| devices\_ids<mark style="color:red;">\*</mark> | number\[] | Array con enteros. Cada uno de los enteros es el id del dispositivo al cual quiero asignarle las zonas. |

{% tabs %}
{% tab title="200 Zonas asignadas" %}

```javascript
{
    "success": true,
    "data": {}
}
```

{% endtab %}

{% tab title="400 Alguna de las zonas no existe" %}

```javascript
{
    "success": false,
    "error": {
        "status": 400,
        "type": "BAD_REQUEST",
        "userMessage": "device_id or zone_id no existe/n"
    }
}
```

{% endtab %}

{% tab title="404: Dispositivo no encontrado" %}

```javascript
{
    "success": false,
    "error": {
        "status": 404,
        "type": "NOT_FOUND",
        "userMessage": "No existe un device con este id: 1532131231"
    }
}
```

{% endtab %}
{% endtabs %}

### Ejemplo de Request

Ejemplo de body, en donde agregamos las zonas 5 y 6 a los dispositivos 15 y 14. De esta forma mantienen además sus zonas previas, si las hubiera.

```json
{
    "zone_ids": [5,6],
    "devices_ids": [15,14]
}
```

### Analizando la Respuesta

Esta respuesta se corresponde a la asignación de la zona 1 y 2.&#x20;

```json
{
    "success": true,
    "data": {}
}
```

**data.** Es un Json vacio

{% hint style="warning" %}
Si alguna de las zonas no se puede asignar. Entonces no se asigna ninguna zona y se recibe un error. Es decir, que basta con revisar status 200 para verificar que las zonas fueron asignadas.
{% endhint %}


# Desasignar zonas a varios dispositivos

Este endpoint permite asignar a un dispositivo una o varias zonas.

Este endpoint permite desasignar zonas a varios dispositivos.<br>

<mark style="color:red;">`DELETE`</mark> `https://api.persat.com.ar/v1/zones`

#### Headers

| Name          | Type   | Description      |
| ------------- | ------ | ---------------- |
| Content-Type  | string | application/json |
| Authorization | string | Bearer API\_KEY  |

#### Request Body

| Name                                           | Type      | Description                                                                                             |
| ---------------------------------------------- | --------- | ------------------------------------------------------------------------------------------------------- |
| zone\_ids<mark style="color:red;">\*</mark>    | number\[] | Array con enteros. Cada uno de los enteros es el id de la zona que quiero asignar.                      |
| devices\_ids<mark style="color:red;">\*</mark> | number\[] | Array con enteros. Cada uno de los enteros es el id del dispositivo al cual quiero asignarle las zonas. |

{% tabs %}
{% tab title="200 Zonas asignadas" %}

```javascript
{
    "success": true,
    "data": {}
}
```

{% endtab %}

{% tab title="404: Dispositivo no encontrado" %}

```javascript
{
    "success": false,
    "error": {
        "status": 404,
        "type": "NOT_FOUND",
        "userMessage": "No existe un device con este id: 14213123"
    }
}
```

{% endtab %}
{% endtabs %}

### Ejemplo de Request

Ejemplo de body, en donde desasignamos las zonas 3, 8 y 9 de los dispositivos 15 y 14.

```json
{
    "zone_ids": [3,8,9],
    "devices_ids": [15,14]
}
```

### Analizando la Respuesta

La respuesta, en caso que la consulta sea exitosa es la siguiente

```json
{
    "success": true,
    "data": {}
}
```

**data.** Es un Json vacio

{% hint style="info" %}
Si alguna de las zonas ya se encontraba sin asignar para el dispositivo, se continúa con la siguiente, sin que este hecho se registre como un error.&#x20;

Si ocurre un error en alguno de los dispositivos o zonas, se cancela toda la operación quedando sin efecto la request.
{% endhint %}


# Usuarios

Los usuarios en Persat son representados por los correos electrónicos de las personas (técnicos, vendedores, inspectores, choferes, administrativos) que tienen acceso al sistema.&#x20;

Son los responsables de la configuración de los permisos y de la visualización de los [Dispositivos](/entidades-basicas/dispositivos).

Se pueden visualizar los usuarios disponibles desde la barra superior > Usuarios y Permisos, como se muestra en la imágen.

<figure><img src="/files/Nzb5zk3zTMeSTo9P0HQ7" alt=""><figcaption></figcaption></figure>

### ¿Que podés hacer con los usuarios?

> [Listar usuarios y sus dispostivos asignados](/entidades-basicas/usuarios/listar-usuarios)
>
> [Listar técnicos activos y sus dispostivos asignados](/entidades-basicas/usuarios/listar-tecnicos-activos)


# Listar Usuarios

Para obtener un listado de los usuarios y sus [Dispositivos](/entidades-basicas/dispositivos) asignados, se debe enviar un GET como el que se especifica a continuación.

<mark style="color:blue;">`GET`</mark> `https://api.persat.com.ar/v1/users`

#### Headers

| Name                                            | Type   | Description     |
| ----------------------------------------------- | ------ | --------------- |
| Authorization<mark style="color:red;">\*</mark> | String | Bearer API\_KEY |

{% tabs %}
{% tab title="200: OK La consulta se ejecutó con éxito" %}

```json
{
    "success": true,
    "data": [
        {
            "user_id": 23
            "group_id": 1,
            "name": "administrativo1@gmail.com",
            "real_name": "Juan Perez",
            "admin": true,
            "verified": true,
            "deleted": false,
        },
        {
            "user_id": 24,        
            "group_id": 1,
            "name": "supervisor@gmail.com",
            "real_name": "Sebastian Gonzalez",
            "admin": false,
            "verified": true,
            "deleted": false,
            "devices": [
                2,
                5,
                3,
                10
            ]
        },     
        {
            "user_id": 27,        
            "group_id": 1,
            "name": "chofer1@gmail.com",
            "real_name": "Diego Rodriguez",
            "admin": false,
            "verified": true,
            "deleted": false,
            "devices": [
                2
            ]
        }, {...}       
    ]
}
```

{% endtab %}
{% endtabs %}

### Analizando la Respuesta

En caso que no haya ningun error, obtenemos

```json
{
    "success": true,
    "data": [
        {
            "user_id": 23
            "group_id": 1,
            "name": "administrativo1@gmail.com",
            "real_name": "Juan Perez",
            "admin": true,
            "verified": true,
            "deleted": false,
        },
        {
            "user_id": 24,        
            "group_id": 1,
            "name": "supervisor@gmail.com",
            "real_name": "Sebastian Gonzalez",
            "admin": false,
            "verified": true,
            "deleted": false,
            "devices": [
                2,
                5,
                3,
                10
            ]
        },     
        {
            "user_id": 27,        
            "group_id": 1,
            "name": "chofer1@gmail.com",
            "real_name": "Diego Rodriguez",
            "admin": false,
            "verified": true,
            "deleted": false,
            "devices": [
                2
            ]
        }, {...}       
    ]
}
```

Lo que se recibe es un array en donde cada elemento son los datos de un usuario.

**user\_id:** Es un Number, identificando inequivocamente al usuario.

**group\_id:** <mark style="color:red;">No usar</mark>. Es un field interno por el momento.

**name:** Email del usuario. Con este email y su contraseña, puede acceder al sistema tanto en la web como en Android.

**real\_name:** Nombre de pila de la persona. Puede ser Nombre y Apellido, o el modelo y la patente del vehículo, o cualquier indicador que sea de utilidad para la empresa.

**admin:** Es un Boolean. En caso de true, el usuario es un Administrador del sistema, con lo cual tiene acceso total y visualización total.

**verified:** Es un Boolean, indicando si el email del usuario fue verificado. No tiene un uso particular específico.&#x20;

**deleted:** Es un Boolean. Indicando si el usuario está activo actualmente.

**devices:** Es un Array de Numbers. Indica cuales [Dispositivos](/entidades-basicas/dispositivos) puede visualizar este usuario.

{% hint style="info" %}
Los usuarios **admin**, no poseen el field **devices**, ya que pueden visualizar todo.

Generalmente, los usuarios que son choferes, o técnicos poseen un solo dispositivo asignado (su propio celular o equipo de rastreo en su vehiculo), mientras que los supervisores suelen tener varios **devices** asignados para poder visualizar y generar los reportes correspondientes
{% endhint %}


# Listar Técnicos Activos

Para obtener un listado de los técnicos activos (usuarios con permisos de completar OTs que no hayan sido borrados) y sus [Dispositivos](/entidades-basicas/dispositivos) asignados, se debe enviar un GET como el que se especifica a continuación.

<mark style="color:blue;">`GET`</mark> `https://api.persat.com.ar/v1/technician-users`

#### Headers

| Name                                            | Type   | Description     |
| ----------------------------------------------- | ------ | --------------- |
| Authorization<mark style="color:red;">\*</mark> | String | Bearer API\_KEY |

{% tabs %}
{% tab title="200: OK La consulta se ejecutó con éxito" %}

```json
{
    "success": true,
    "data": [
        {
            "user_id": 23
            "group_id": 1,
            "name": "administrativo1@gmail.com",
            "real_name": "Juan Perez",
            "admin": true,
            "verified": true,
            "deleted": false,
        },
        {
            "user_id": 24,        
            "group_id": 1,
            "name": "supervisor@gmail.com",
            "real_name": "Sebastian Gonzalez",
            "admin": false,
            "verified": true,
            "deleted": false,
            "devices": [
                2,
                5,
                3,
                10
            ]
        },     
        {
            "user_id": 27,        
            "group_id": 1,
            "name": "chofer1@gmail.com",
            "real_name": "Diego Rodriguez",
            "admin": false,
            "verified": true,
            "deleted": false,
            "devices": [
                2
            ]
        }, {...}       
    ]
}
```

{% endtab %}
{% endtabs %}

### Analizando la Respuesta

En caso que no haya ningun error, obtenemos

```json
{
    "success": true,
    "data": [
        {
            "user_id": 23
            "group_id": 1,
            "name": "administrativo1@gmail.com",
            "real_name": "Juan Perez",
            "admin": true,
            "verified": true,
            "deleted": false,
        },
        {
            "user_id": 24,        
            "group_id": 1,
            "name": "supervisor@gmail.com",
            "real_name": "Sebastian Gonzalez",
            "admin": false,
            "verified": true,
            "deleted": false,
            "devices": [
                2,
                5,
                3,
                10
            ]
        },     
        {
            "user_id": 27,        
            "group_id": 1,
            "name": "chofer1@gmail.com",
            "real_name": "Diego Rodriguez",
            "admin": false,
            "verified": true,
            "deleted": false,
            "devices": [
                2
            ]
        }, {...}       
    ]
}
```

Lo que se recibe es un array en donde cada elemento son los datos de un usuario.

**user\_id:** Es un Number, identificando inequivocamente al usuario, que para este endpoint es un Técnico activo.

**group\_id:** <mark style="color:red;">No usar</mark>. Es un field interno por el momento.

**name:** Email del usuario. Con este email y su contraseña, puede acceder al sistema tanto en la web como en Android.

**real\_name:** Nombre de pila de la persona. Puede ser Nombre y Apellido, o el modelo y la patente del vehículo, o cualquier indicador que sea de utilidad para la empresa.

**admin:** Es un Boolean. En caso de true, el usuario es un Administrador del sistema, con lo cual tiene acceso total y visualizacion total.

**verified:** Es un Boolean, indicando si el email del usuario fue verificado. No tiene un uso particular específico.&#x20;

**deleted:** Es un Boolean. Indicando si el usuario está activo actualmente.

**devices:** Es un Array de Numbers. Indica cuales [Dispositivos](/entidades-basicas/dispositivos) puede visualizar este usuario.

{% hint style="info" %}
Los usuarios **admin**, no poseen el field **devices**, ya que pueden visualizar todo.

Generalmente, los usuarios que son choferes, o técnicos poseen un solo dispositivo asignado (su propio celular o equipo de rastreo en su vehiculo), mientras que los supervisores suelen tener varios **devices** asignados para poder visualizar y generar los reportes correspondientes
{% endhint %}


# Seguimientos

Los seguimientos en Persat ayudan a organizar actividades a realizar en clientes en el futuro.

Se pueden visualizar en conjunto desde Gestión de clientes > Seguimientos, o por cada cliente: Gestión de clientes > cliente > seguimientos

### ¿Qué podés hacer con los seguimientos?

> [Crear seguimientos](/entidades-basicas/seguimientos/crear-seguimientos)


# Crear seguimientos

Para crear un seguimiento se debe realizar un POST como el que se muestra a continuación.

<mark style="color:green;">`POST`</mark> `https://api.persat.com.ar/v1/follow_ups`

#### Headers

| Name                                            | Type   | Description      |
| ----------------------------------------------- | ------ | ---------------- |
| Content-Type<mark style="color:red;">\*</mark>  | string | application/json |
| Authorization<mark style="color:red;">\*</mark> | string | Bearer API\_KEY  |

#### Request Body

<table><thead><tr><th width="254">Name</th><th>Type</th><th>Description</th></tr></thead><tbody><tr><td>uid_client<mark style="color:red;">*</mark></td><td>string</td><td>El número/identificador de cliente (es un valor alfanumérico).</td></tr><tr><td>title<mark style="color:red;">*</mark></td><td>string</td><td>Título del seguimiento.</td></tr><tr><td>responsible_user_ids<mark style="color:red;">*</mark></td><td>number[]</td><td>Listado de ids de usuarios responsables del seguimiento. Mínimo 1 responsable.</td></tr><tr><td>color<mark style="color:red;">*</mark></td><td>string</td><td>Color identificador del seguimiento. Ver colores disponibles en la siguiente sección.</td></tr><tr><td>date<mark style="color:red;">*</mark></td><td>string</td><td>Fecha del seguimiento en formato ISO, debe ser una fecha futura. Ejemplo: 2021-09-09T14:30:00.000Z.</td></tr><tr><td>description</td><td>string</td><td>Descripción del seguimiento.</td></tr><tr><td>send_email_minutes_before</td><td>number</td><td>Minutos previos a la fecha en los que se envía un email a los responsables. Ver minutos disponibles en la siguiente sección. Si no está presente no se envía mail.</td></tr></tbody></table>

### Aclaraciones sobre el request

**Listado de colores disponibles.**

<figure><img src="/files/B1KsJp69WQC4nOw6rq0S" alt=""><figcaption><p>Listado en la app web</p></figcaption></figure>

* RED
* ORANGE
* YELLOW
* GREEN
* BLUE
* PINK
* BLACK

**Listado de minutos disponibles.**

<div align="center" data-full-width="false"><figure><img src="/files/EO6dmE88RNmX7OzzwKPn" alt="" width="296"><figcaption><p>Listado en la app web</p></figcaption></figure></div>

* 0 (en el momento del seguimiento)
* 10
* 20
* 30
* 45
* 60 (1 hora)
* 120 (2 horas)
* 180 (3 horas)
* 240 (4 horas)
* 300 (5 horas)
* 1440 (1 día)
* 2880 (2 días)
* 4320 (3 días)
* 5760 (4 días)
* 10080 (1 semana)

{% hint style="danger" %}
IMPORTANTE: los usuarios responsables deben tener habilitado el grupo de cliente correspondiente al cliente que se le asigna el seguimiento. Ver "**group\_id**" en [Obtener un Cliente](/entidades-basicas/clientes/obtener-un-cliente).
{% endhint %}

{% tabs %}
{% tab title="200 El seguimiento fue creado" %}

```javascript
{
    "success": true,
    "data": {
        "id": 33,
        "uid_client": "CL-0044",
        "title": "Llamar",
        "description": "",
        "color": "RED",
        "responsible_user_ids": [
            1,
            2,
            3
        ],
        "send_email": false,
        "date": "2026-01-01T00:00:00.000Z"
    }
}

```

{% endtab %}

{% tab title="400 campos obligatorios" %}

```javascript
{
    "success": false,
    "error": {
        "status": 400,
        "type": "BAD_REQUEST",
        "userMessage": "'uid_client' debe ser un string"
    }
}
```

{% endtab %}

{% tab title="404 Cliente no encontrado" %}

```javascript
{
    "success": false,
    "error": {
        "status": 409,
        "type": "CONFLICT",
        "userMessage": "No existe el cliente con uid: 'CL-0044'"
    }
}
```

{% endtab %}

{% tab title="409: Conflict los responsables no tienen permitido ver el grupo de cliente" %}

```javascript
{
    "success": false,
    "error": {
        "status": 409,
        "type": "CONFLICT",
        "userMessage": "Los usuarios con id 1,2. No tienen permitido ver el cliente"
    }
}
```

{% endtab %}
{% endtabs %}

### Ejemplo de request

En este ejemplo insertamos un seguimiento, que incluye envío de email 2 horas antes de la fecha del seguimiento.

### body

```json
{
    "title": "Llamar",
    "description": "Realizar nota de pedido",
    "uid_client": "CL-0044",
    "color": "ORANGE",
    "date": "2030-02-01T20:00:00.000Z",
    "responsible_user_ids": [1,2,52],
    "send_email_minutes_before": 120 
}
```

{% hint style="info" %}
**date:** Si bien la fecha esta representada en UTC, hay que considerarla en <mark style="color:blue;">**horario local**</mark>. Entonces para el caso del ejemplo, y sin importar si soy un cliente de Argentina, Ecuardor o Mexico, la fecha del evento representa el día 1 de Febrero de 2023 hora de mi país

```
"date": "2030-02-01T20:00:00.000Z",
```

{% endhint %}

### Analizando la Respuesta

En caso que no haya ningun error, obtenemos

```json
{
    "success": true,
    "data": {
        "id": 35,
        "uid_client": "CL-0044",
        "title": "Llamar",
        "description": "Realizar nota de pedido",
        "color": "ORANGE",
        "responsible_user_ids": [
            1,
            2,
            52
        ],
        "date": "2030-02-01T20:00:00.000Z",
        "send_email_minutes_before": 120,
        "send_email": true
    }
}
```

**id:** Identificador del seguimiento.

**uid\_client:** identificador alfanumérico del cliente.

&#x20;**title:** título del seguimiento.

**description:** descripción del seguimiento.

**color:** color del seguimiento.

**responsible\_user\_ids:** ids de los usuarios responsables del seguimiento.

**date:** fecha del seguimiento.

{% hint style="info" %}
Si bien la fecha esta representada en UTC, hay que considerarla en <mark style="color:blue;">**horario local**</mark>. Entonces para el caso del ejemplo, y sin importar si soy un cliente de Argentina, Ecuardor o Mexico, la fecha mostrada representa el día 1 de Febrero de 2023 hora de mi país

```
"date": "2030-02-01T20:00:00.000Z",
```

{% endhint %}

**send\_email:** booleano que indica si se enviará email

**send\_email\_minutes\_before:** los minutos previos a la fecha en los que se va a enviar un mail a los responsables en forma de aviso del seguimiento. En este ejemplo se enviaría el 2030-02-01T18:00:00.000Z.

{% hint style="danger" %}
**send\_email\_minutes\_before** solo estará presente cuando send\_email sea 'true'
{% endhint %}


# Rastreo Satelital

El módulo de Rastreo Satelital, permite visualizar tanto en tiempo real como en modo de historial, la ubicación de los dispositivos configurados. También permite configurar alertas de distinto tipo y visualizar reportes de desempeño.

## Cómo accedo al módulo

Una vez logueados en Persat, podemos acceder al mismo haciendo click en alguna de sus opciones. Lo podemos visualizar en la siguiente imágen arriba al centro con el nombre **Rastreo Satelital**

![Módulos de Persat](/files/HgJ4zA0FbxTZA9cHHBim)

Podés visitar nuestra ayuda para conocer mas los alcances de este modulo [Módulo de Rastreo Satelital](http://docs.persat.com.ar/es/articles/5185220-modulo-de-rastreo-satelital)

### ¿Que podés hacer desde la api?

> [Obtener última posición GPS](/modulos/rastreo-satelital/obtener-ultima-posicion-gps)
>
> [Obtener estadísticas de Rastreo](/modulos/rastreo-satelital/obtener-estadisticas-de-rastreo)
>
> [Obtener Visitas a Clientes](/modulos/rastreo-satelital/obtener-visitas-a-clientes)
>
> [Integrar Dispositivos de Rastreo a Persat](/modulos/rastreo-satelital/integrar-dispositivos-de-rastreo-a-persat)
>
> [Recibir eventos por medio de webhooks](/modulos/rastreo-satelital/webhooks)


# Obtener última posición GPS

Mediante este endpoint, se puede obtener el ultimo dato de posición válido para un dispositivo determinado.&#x20;

Los dispositivos se pueden ver en los endpoints de [Dispositivos](/entidades-basicas/dispositivos)

El dato de posición se obtiene haciendo una consulta GET como la que se define a continuación.

<mark style="color:blue;">`GET`</mark> `https://api.persat.com.ar/v1/devices-lasttrackingpoint/device_id`

#### Path Parameters

| Name                                         | Type   | Description                   |
| -------------------------------------------- | ------ | ----------------------------- |
| device\_id<mark style="color:red;">\*</mark> | Number | Identificador del dispositivo |

#### Headers

| Name                                            | Type   | Description     |
| ----------------------------------------------- | ------ | --------------- |
| Authorization<mark style="color:red;">\*</mark> | String | Bearer API\_KEY |

{% tabs %}
{% tab title="200: OK La consulta se ejecutó con éxito" %}

```json
{
    "success": true,
    "data": {
        "device_id": 104,
        "timestamp": "2022-12-08T10:11:37.000Z",
        "latitude": -34.57554,
        "longitude": -58.56625
    }
}
```

{% endtab %}

{% tab title="404: Not Found No se encontro el dispositivo" %}

```json
{
    "success": false,
    "error": {
        "status": 404,
        "type": "NOT_FOUND",
        "userMessage": "No existe un device con este id"
    }
}
```

{% endtab %}

{% tab title="400: Bad Request device\_id no es un número" %}

```javascript
{
    "success": false,
    "error": {
        "status": 400,
        "type": "BAD_REQUEST",
        "userMessage": "'device_id' debe ser un número entero"
    }
}
```

{% endtab %}
{% endtabs %}

### Analizando la Respuesta

```json
{
    "success": true,
    "data": {
        "device_id": 104,
        "timestamp": "2022-12-08T10:11:37.000Z",
        "latitude": -34.57554,
        "longitude": -58.56625
    }
}
```

**device\_id:** Identificador del Dispositivo.&#x20;

**timestamp:** Fecha y horario del ultimo punto GPS

{% hint style="info" %}
Si bien la fecha esta representada en UTC, hay que considerarla en <mark style="color:blue;">**horario local**</mark>. Entonces para el caso del ejemplo, y sin importar si soy un cliente de Argentina, Ecuardor o Mexico, la fecha mostrada representa el día 8 de Diciembre de 2022 a las 11:37 hora de mi país

```
"timestamp": "2022-12-08T10:11:37.000Z",
```

{% endhint %}

**latitude:** Valor de latitud.

**longitude:** Valor de longitud


# Obtener estadísticas de Rastreo

Mediante este endpoint, se puede obtener los datos derivados del rastro GPS para un dispositivo determinado.&#x20;

Los dispositivos se pueden ver en los endpoints de [Dispositivos](/entidades-basicas/dispositivos)

{% hint style="info" %} <mark style="color:blue;">**IMPORTANTE:**</mark>

Debido a que la generación del recorrido, requiere de una gran demanda de computo. Los recorridos son generados y procesdados automáticamente por la madrugada. Siendo el resultado obtenido, los datos del día anterior.

Por lo que si quiero obtener los datos de rastreo de "hoy", el resultado va a ser nulo. La consulta debe hacerse a día vencido.
{% endhint %}

<mark style="color:blue;">`GET`</mark> `https://api.persat.com.ar/v1/devices-pathtrack-sumary/YYYY-MM-dd/device_id`

#### Path Parameters

| Name                                         | Type   | Description                              |
| -------------------------------------------- | ------ | ---------------------------------------- |
| device\_id<mark style="color:red;">\*</mark> | Number | Identificador del dispositivo            |
| YYYY-MM-dd<mark style="color:red;">\*</mark> | Date   | Fecha en la que quiero obtener los datos |

#### Headers

| Name                                            | Type   | Description     |
| ----------------------------------------------- | ------ | --------------- |
| Authorization<mark style="color:red;">\*</mark> | String | Bearer API\_KEY |

{% tabs %}
{% tab title="200: OK La consulta se ejecutó con éxito" %}

```json
{
    "success": true,
    "data": {
        "device_id": 3,
        "date": "2014-04-15T00:00:00.000Z",
        "distance_inside_wa": 68.3,
        "distance_outside_wa": 21.15,
        "time_inside_wa": 38368000,
        "time_outside_wa": 49242000
    }
}
```

{% endtab %}

{% tab title="404: Not Found No se encontro el dispositivo" %}

```json
{
    "success": false,
    "error": {
        "status": 404,
        "type": "NOT_FOUND",
        "userMessage": "No existe un device con este id"
    }
}
```

{% endtab %}

{% tab title="400: Bad Request device\_id no es un número" %}

```javascript
{
    "success": false,
    "error": {
        "status": 400,
        "type": "BAD_REQUEST",
        "userMessage": "'device_id' debe ser un número entero"
    }
}
```

{% endtab %}

{% tab title="400: Bad Request Error en la fecha" %}

```javascript
{
    "success": false,
    "error": {
        "status": 400,
        "type": "BAD_REQUEST",
        "userMessage": "'localdate' debe estar definido en formato YYYY-MM-DD"
    }
}
```

{% endtab %}
{% endtabs %}

### Analizando la Respuesta

```json
{
    "success": true,
    "data": {
        "device_id": 3,
        "date": "2014-04-15T00:00:00.000Z",
        "distance_inside_wa": 68.3,
        "distance_outside_wa": 21.15,
        "time_inside_wa": 38368000,
        "time_outside_wa": 49242000
    }
}
```

**device\_id:** Identificador del Dispositivo.&#x20;

**date:** Fecha de la consulta.&#x20;

{% hint style="info" %}
Si bien la fecha esta representada en UTC, hay que considerarla en <mark style="color:blue;">**horario local**</mark>. Entonces para el caso del ejemplo, y sin importar si soy un cliente de Argentina, Ecuardor o Mexico, la fecha mostrada representa el día 15 de Abril de 2014 hora de mi país

```
"timestamp": "2014-04-15T00:00:00.000Z",
```

{% endhint %}

**distance\_inside\_wa:** "Distance inside Working Area". Recorrido realizado en KM dentro de la zona de trabajo asignada.

**distance\_outside\_wa:** "Distance outside Working Area". Recorrido realizado en KM fuera de la zona de trabajo asignada.

**time\_inside\_wa:** "Time inside Working Area". Tiempo en ms (milisegundos) dentro de la zona de trabajo asignada.

**time\_outside\_wa:** "Time outside Working Area". Tiempo en ms (milisegundos) fuera de la zona de trabajo asignada.

{% hint style="warning" %}
La suma de <mark style="color:orange;">**time\_inside\_wa**</mark> y <mark style="color:orange;">**time\_outside\_wa**</mark> no necesariamente dará 24 horas. Puesto que, en el caso que el dispositivo sea un celular, el mismo solo enviará datos dentro de la jornada laboral configurada.
{% endhint %}


# Obtener Visitas a Clientes

En base al recorrido realizado por el dispositivo, se puede obtener cuales fueron los clientes visitados.&#x20;

{% hint style="info" %} <mark style="color:blue;">**IMPORTANTE:**</mark>

Debido a que la generación del recorrido para el cálculo de las visitas, requiere de una gran demanda de computo. Las visitas son calculadas automáticamente por la madrugada. Siendo el resultado obtenido, las visitas del día anterior.

Por lo que si quiero obtener las visitas de "hoy", el resultado va a ser nulo. La consulta debe hacerse a día vencido.
{% endhint %}

Se pueden hacer dos tipos de consulta:

1. Consulta de visitas en una fecha particular
2. Consulta de visitas en un mes entero

### Consulta de visitas en una fecha particular

<mark style="color:blue;">`GET`</mark> `https://api.persat.com.ar/v1/devices-visits/YYYY-MM-dd/device_id`

#### Path Parameters

| Name                                         | Type   | Description                                  |
| -------------------------------------------- | ------ | -------------------------------------------- |
| YYYY-MM-dd<mark style="color:red;">\*</mark> | Date   | Fecha en la que quiero consultar las visitas |
| device\_id<mark style="color:red;">\*</mark> | Number | Identificador del dispositivo                |

#### Headers

| Name                                            | Type   | Description     |
| ----------------------------------------------- | ------ | --------------- |
| Authorization<mark style="color:red;">\*</mark> | String | Bearer API\_KEY |

{% tabs %}
{% tab title="200: OK La consulta se ejecutó con éxito" %}

```json
{
    "success": true,
    "data": [
        {
            "device_id": 104,
            "date": "2022-12-02T20:23:29.000Z",
            "duration": 321000,
            "client": {
                "uid_client": "32488095",
                "company_name": "Empresa 1 s.r.l"
            }
        },
        {
            "device_id": 104,
            "date": "2022-12-02T15:01:32.000Z",
            "duration": 675000,
            "client": {
                "uid_client": "16682996",
                "company_name": "Empresa 2 s.r.l"
            }
        }, {...} 
    ]
}
```

{% endtab %}

{% tab title="404: Not Found No se encontro el dispositivo" %}

```json
{
    "success": false,
    "error": {
        "status": 404,
        "type": "NOT_FOUND",
        "userMessage": "No existe un device con este id"
    }
}
```

{% endtab %}

{% tab title="400: Bad Request device\_id no es un número" %}

```javascript
{
    "success": false,
    "error": {
        "status": 400,
        "type": "BAD_REQUEST",
        "userMessage": "'device_id' debe ser un número entero"
    }
}
```

{% endtab %}

{% tab title="400: Bad Request Error en la fecha" %}

```javascript
{
    "success": false,
    "error": {
        "status": 400,
        "type": "BAD_REQUEST",
        "userMessage": "'localdate' debe estar definido en formato YYYY-MM | YYYY-MM-DD"
    }
}
```

{% endtab %}
{% endtabs %}

### Consulta de visitas en un mes entero

<mark style="color:blue;">`GET`</mark> `https://api.persat.com.ar/v1/devices-visits/YYYY-MM/device_id`

#### Path Parameters

| Name                                         | Type   | Description                                |
| -------------------------------------------- | ------ | ------------------------------------------ |
| YYYY-MM<mark style="color:red;">\*</mark>    | Date   | Mes en el que quiero consultar las visitas |
| device\_id<mark style="color:red;">\*</mark> | Number | Identificador del dispositivo              |

#### Headers

| Name                                            | Type   | Description     |
| ----------------------------------------------- | ------ | --------------- |
| Authorization<mark style="color:red;">\*</mark> | String | Bearer API\_KEY |

{% tabs %}
{% tab title="200: OK La consulta se ejecutó con éxito" %}

```json
{
    "success": true,
    "data": [
        {
            "device_id": 104,
            "date": "2022-12-02T20:23:29.000Z",
            "duration": 321000,
            "client": {
                "uid_client": "32488095",
                "company_name": "Empresa 1 s.r.l"
            }
        },
        {
            "device_id": 104,
            "date": "2022-12-02T15:01:32.000Z",
            "duration": 675000,
            "client": {
                "uid_client": "16682996",
                "company_name": "Empresa 2 s.r.l"
            }
        }, {...} 
    ]
}
```

{% endtab %}

{% tab title="404: Not Found No se encontro el dispositivo" %}

```json
{
    "success": false,
    "error": {
        "status": 404,
        "type": "NOT_FOUND",
        "userMessage": "No existe un device con este id"
    }
}
```

{% endtab %}

{% tab title="400: Bad Request device\_id no es un número" %}

```javascript
{
    "success": false,
    "error": {
        "status": 400,
        "type": "BAD_REQUEST",
        "userMessage": "'device_id' debe ser un número entero"
    }
}
```

{% endtab %}

{% tab title="400: Bad Request Error en la fecha" %}

```javascript
{
    "success": false,
    "error": {
        "status": 400,
        "type": "BAD_REQUEST",
        "userMessage": "'localdate' debe estar definido en formato YYYY-MM | YYYY-MM-DD"
    }
}
```

{% endtab %}
{% endtabs %}

### Analizando la Respuesta para ambos casos

```json
{
    "success": true,
    "data": [
        {
            "device_id": 104,
            "date": "2022-12-02T20:23:29.000Z",
            "duration": 321000,
            "client": {
                "uid_client": "32488095",
                "company_name": "Empresa 1 s.r.l"
            }
        },
        {
            "device_id": 104,
            "date": "2022-12-02T15:01:32.000Z",
            "duration": 675000,
            "client": {
                "uid_client": "16682996",
                "company_name": "Empresa 2 s.r.l"
            }
        }, {...} 
    ]
}
```

**data:** Array con objetos JSON. Cada elemento del array contiene los datos de la visita al cliente. Están ordenados por fecha de visita de mayor a menor. Es decir, el primer item es la última visita realizada del día o mes (dependiendo la consulta)

**device\_id:** Identificador del Dispositivo.&#x20;

**date:** Fecha y hora en que se realizó la visita

{% hint style="warning" %}
Si bien la fecha esta representada en UTC, hay que considerarla en <mark style="color:orange;">**horario local**</mark>. Entonces para el caso del ejemplo, y sin importar si soy un cliente de Argentina, Ecuardor o Mexico, la fecha mostrada representa el día 5 de Diciembre de 2022 a las 15:01 hora de mi país

```
"date": "2022-12-02T15:01:32.000Z",
```

{% endhint %}

**duration:** Duración de la visita en milisegundos

**client:** Cliente visitado. Objeto Json con los siguientes fields:

**client.uid\_client:** Nro. de cliente

**client.company\_name:** Nombre/Razón social del cliente


# Integrar Dispositivos de Rastreo a Persat

Si lo que necesita es integrar su flota actual de vehículos a Persat, y ya cuenta con dispositivos de rastreo propios o brindados por un tercero, entonces este es el lugar indicado.&#x20;

Mediante el siguiente endpoint podrá enviar datos GPS para cada uno de sus dispositivos y luego visualizar los mismos en los mapas de Persat.

{% hint style="success" %}
Persat cuenta con una variedad de Partners de Rastreo autorizados. Consulte previamente los partners de Rastreo actuales para evitar tener que realizar esta integración por su cuenta.
{% endhint %}

{% hint style="danger" %} <mark style="color:red;">IMPORTANTE</mark>

Si la integración la realiza un tercero, es imperativo <mark style="color:red;">**no compartir**</mark> la API key con acceso TOTAL, sino que se debe compartir la Api Key con <mark style="color:green;">"Acceso restringido a insertar datos de Rastreo únicamente".</mark> [Ver Niveles de Acceso y Consideraciones Importantes](/como-usar-la-api/introduccion-1)
{% endhint %}

## Endpoint para enviar datos GPS

Para enviar un dato GPS para un dispositivo en Persat, se debe enviar una consulta POST como la que se especifica a continuación.

<mark style="color:blue;">`POST`</mark> `https://api.persat.com.ar/v1/devices-geoposition/device_id`

#### Path Parameters

| Name                                         | Type   | Description                                                                                                                                     |
| -------------------------------------------- | ------ | ----------------------------------------------------------------------------------------------------------------------------------------------- |
| device\_id<mark style="color:red;">\*</mark> | Number | Identificador del device. Se puede obtener la lista de Devices desde [Listar Dispositivos](/entidades-basicas/dispositivos/listar-dispositivos) |

#### Headers

| Name                                            | Type   | Description      |
| ----------------------------------------------- | ------ | ---------------- |
| Authorization<mark style="color:red;">\*</mark> | String | Bearer API\_KEY  |
| Content-Type<mark style="color:red;">\*</mark>  | String | application/json |

#### Request Body

Objeto Json con los siguientes fields

<table><thead><tr><th width="203">Name</th><th width="128">Type</th><th>Description</th></tr></thead><tbody><tr><td>date<mark style="color:red;">*</mark></td><td>String</td><td>Fecha y hora, en formato <strong>yyyy-MM-ddTHH:mm:ss.SSSZ</strong>, indicando el momento en que se obtiene la posición GPS del vehículo.</td></tr><tr><td>lat<mark style="color:red;">*</mark></td><td>number</td><td>Número entre -90 y +90, representando la latitud</td></tr><tr><td>lng<mark style="color:red;">*</mark></td><td>number</td><td>Número entre -180 y + 180, representando la longitud</td></tr><tr><td>relative_odometer</td><td>number</td><td>Número [Opcional] representando el odómetro del vehiculo. En realidad no es el valor real del odometro, si no un valor de referencia que va aumentando con cada movimiento del vehiculo. Está representado en metros. La ventaja de utilizar este valor es que se puede hacer uso del módulo de <strong>Mantenimiento Preventivo</strong></td></tr></tbody></table>

### Ejemplo de body request

```json
{
    "date": "2024-06-06T13:35:21.000Z",
    "lat": -25.23123,
    "lng": 120.000023,
    "relative_odometer": 0
}
```

### Posbibles Respuestas

{% tabs %}
{% tab title="200: OK La consulta se ejecutó con éxito" %}

```json
{
    "success": true,
    "data": {}
}
```

{% endtab %}

{% tab title="400: Bad Request schema\_id no es un número" %}

```json
{
    "success": false,
    "error": {
        "status": 400,
        "type": "BAD_REQUEST",
        "userMessage": "'lng' invalido. Debe ser un number"
    }
}

```

{% endtab %}

{% tab title="404: Not Found No existe este tipo de formulario" %}

```json
{
    "success": false,
    "error": {
        "status": 404,
        "type": "NOT_FOUND",
        "userMessage": "No existe un device con este id"
    }
}
```

{% endtab %}
{% endtabs %}

{% hint style="warning" %} <mark style="color:orange;">**IMPORTANTE:**</mark>

Persat realiza procesamiento digital de los datos GPS recibidos para evitar fluctuaciones rápidas o fallas de intermitencia. Es decir que es posible que, sobre todo para el caso en que se esten realizando pruebas, algunos de los valores enviados no aparezcan en el mapa.&#x20;

Se debe simular un recorrido "real" de un vehículo. Por ejemplo: no se debería enviar dos puntos GPS con 1 segundo de diferencia a 1 km de distancia, dado que no hay vehículo que cumpla con esos parámetros de velocidad.&#x20;
{% endhint %}


# Eventos / Webhooks

En lo que respecta a rastreo de dispositivos (celulares), también se puede trabajar configurando los webooks como se puede ver en la sección [Webhooks](/como-usar-la-api/nueva-entrega)

Los eventos disponibles son:

> [Fichaje de Entrada (Check in)](/modulos/rastreo-satelital/webhooks/fichaje-salida-check-in)
>
> [Fichaje de Salida (Check out)](/modulos/rastreo-satelital/webhooks/fichaje-salida-check-out)


# Fichaje de Entrada (Check in)

De estar configurado el webhook, cada vez que un usuario realice el fichaje de entrada desde la app: [Persat check Me](https://play.google.com/store/apps/details?id=com.pst.checkme\&hl=es_AR\&pli=1), se disparará el evento **checkme.check\_in**&#x20;

{% hint style="info" %}
Si desea configurar los webhooks siga los pasos en [Configurar webhooks](/como-usar-la-api/nueva-entrega)
{% endhint %}

### Datos enviados en el evento

Los datos son enviados mediante una consulta HTTP POST, en donde el body contiene el siguiente texto en formato JSON.&#x20;

```json
{
  "eventType": "checkme.check_in",
  "payload": {
    "device_id": 3,
    "lat": -34.6011175,
    "lng": -58.5297386,
    "timestamp": 1754498833169
  }
}
```

### Analizando el evento recibido

**eventType:** Tipo de evento. siempre será "**checkme.check\_in**"

**payload:** Son los datos completos del evento. Se describen a continuación.

**device\_id:** Identificador del Dispositivo (celular). Ver [Obtener Dispositivo](/entidades-basicas/dispositivos/obtener-dispositivo)

**lat:** Latitud en donde se realizó el fichaje.

**lng:** Longitud en donde se realizó el fichaje.

**timestamp:** Fecha y hora en formato timestamp Unix epoch time en milisegundos UTC, en la cual se realizó el fichaje. Ver [Unix Epoc Time](https://www.epochconverter.com/) converter


# Fichaje de Salida (Check out)

De estar configurado el webhook, cada vez que un usuario realice el fichaje de salida desde la app: [Persat check Me](https://play.google.com/store/apps/details?id=com.pst.checkme\&hl=es_AR\&pli=1), se disparará el evento **checkme.check\_out**

{% hint style="info" %}
Si desea configurar los webhooks siga los pasos en [Configurar webhooks](/como-usar-la-api/nueva-entrega)
{% endhint %}

### Datos enviados en el evento

Los datos son enviados mediante una consulta HTTP POST, en donde el body contiene el siguiente texto en formato JSON.&#x20;

```json
{
  "eventType": "checkme.check_out",
  "payload": {
    "device_id": 3,
    "lat": -34.6011175,
    "lng": -58.5297386,
    "timestamp": 1754498833169
  }
}
```

### Analizando el evento recibido

**eventType:** Tipo de evento. siempre será "**checkme.check\_out**"

**payload:** Son los datos completos del evento. Se describen a continuación.

**device\_id:** Identificador del Dispositivo (celular). Ver [Obtener Dispositivo](/entidades-basicas/dispositivos/obtener-dispositivo)

**lat:** Latitud en donde se realizó el fichaje.

**lng:** Longitud en donde se realizó el fichaje.

**timestamp:** Fecha y hora en formato timestamp Unix epoch time en milisegundos UTC, en la cual se realizó el fichaje. Ver [Unix Epoc Time](https://www.epochconverter.com/) converter


# Formularios Digitales

El módulo de formularios, permite convertir cualquier tipo de información en papel a un formato digital.

## Cómo accedo al módulo

Una vez logueados en Persat, podemos acceder al mismo haciendo click en alguna de sus opciones. Lo podemos visualizar en la siguiente imágen abajo al centro con el nombre **Formularios Digitales**

![Módulos de Persat](/files/84TcgHvEmAapJGRSRz2e)

Podés visitar nuestra ayuda para conocer mas los alcances de este módulo [Formularios Digitales](http://docs.persat.com.ar/es/articles/691793-trabajando-con-los-formularios-digitales)

### Identificación de los Formularios y sus widgets

Como en Persat se pueden crear varios tipos de formularios, la forma de identificar cada plantilla o esquema, es a través de su schema\_id (identificador del esquema/plantilla). Luego, cada uno de los formularios tiene distintos componentes llamados widgets, que tienen su propio identificador.

{% hint style="info" %}
**IMPORTANTE:** Si el formulario que estoy usando contiene varias versiones, cada una de las mismas tiene un schema\_id distinto.
{% endhint %}

Para conocer los formularios disponibles y su identificación, dirijite a Administrar versiones de formulario

Módulo Formularios -> Administrar. Luego presionar el botón "Desarrolladores" en la configuración de usuario.

<figure><img src="/files/o7k83joNLSF75YAqfUgV" alt=""><figcaption></figcaption></figure>

### ¿Qué podés hacer con los formularios?

En las siguientes secciones se explica todo lo que podes hacer con los formularios digitales de Persat

**Respecto al esquema (estructura de los datos)**

> [Obtener estructura/esquema de un Formulario](/modulos/formularios-digitales/obtener-estructura-esquema-de-un-formulario)
>
> [Listar estructuras/esquemas de todos los Formularios](/modulos/formularios-digitales/listar-estructuras-esquemas-de-todos-los-formularios)

**Respecto a los formularios en sí**

> [Obtener formulario](/modulos/formularios-digitales/obtener-formulario)
>
> [Insertar formulario](/modulos/formularios-digitales/insertar-formulario)
>
> [Modificar formulario](/modulos/formularios-digitales/modificar-formulario)
>
> [Modificar estado de formulario](/modulos/formularios-digitales/estados-de-formulario/modificar-estado-de-formulario)
>
> [Listar historial de estados de un formulario](/modulos/formularios-digitales/listar-historial-de-estados-de-un-formulario)
>
> [Listar formularios](/modulos/formularios-digitales/listar-formularios)
>
> [Recibir eventos por medio de webhooks](/modulos/formularios-digitales/nuevo-formulario)

**Respecto al estado de cada formulario**

> [Obtener estado](/modulos/formularios-digitales/estados-de-formulario/obtener-estado)
>
> [Listar estados](/modulos/formularios-digitales/estados-de-formulario/listar-estados)


# Obtener estructura/esquema de un Formulario

Para obtener la estructura/esquema de un formulario, se debe enviar un GET como el que se especifica a continuación.

<mark style="color:blue;">`GET`</mark> `https://api.persat.com.ar/v1/digital-forms-schemas/schema_id`

#### Path Parameters

| Name                                         | Type   | Description                          |
| -------------------------------------------- | ------ | ------------------------------------ |
| schema\_id<mark style="color:red;">\*</mark> | Number | Identificador del tipo de formulario |

#### Headers

| Name                                            | Type   | Description     |
| ----------------------------------------------- | ------ | --------------- |
| Authorization<mark style="color:red;">\*</mark> | String | Bearer API\_KEY |

{% tabs %}
{% tab title="200: OK La consulta se ejecutó con éxito" %}

```json
{
    "success": true,
    "data": {
        "form_group": 60,
        "schema_id": 170,
        "production": true,
        "version": 1,
        "draft": false,
        "description": {
            "title": "Crear Desde API",
            "color": "RED",
            "widgets": [
                {
                    "id": "FWA3VCpeS",
                    "title": "Campo Texto",
                    "subtitle": "Complete con los datos correspondientes",
                    "widget_type": "TEXT_FIELD"
                },
                {
                    "id": "FWMS4k794",
                    "title": "Seccion Nueva",
                    "subtitle": "Subtitulo",
                    "widget_type": "NEW_SECTION"
                },
                {
                    "id": "FWNDBKSIr",
                    "title": "Campo Parrafo",
                    "subtitle": "Complete las observaciones",
                    "widget_type": "TEXT_PARAGRAPH"
                },
                {
                    "id": "FWWbOUn2z",
                    "title": "Seccion Nueva",
                    "subtitle": "Subtitulo",
                    "widget_type": "NEW_SECTION"
                },
                {
                    "id": "FW27yy7bk",
                    "title": "Campo Link",
                    "subtitle": "Acceda a la información haciendo click",
                    "widget_type": "LINK_FIELD"
                },
                {
                    "id": "FWQXPDjee",
                    "title": "Titulo",
                    "subtitle": "Subtitulo",
                    "widget_type": "STATIC_FIELD"
                },
                {
                    "id": "FWWucoyGH",
                    "title": "Campo Numero",
                    "subtitle": "Complete con el valor correspondiente",
                    "widget_type": "NUMBER_FIELD"
                },
                {
                    "id": "FWFFs0qST",
                    "title": "Campo Fecha",
                    "subtitle": "Seleccione la fecha",
                    "widget_type": "DATE_FIELD"
                },
                {
                    "id": "FWT1C5xHM",
                    "title": "Campo Hora",
                    "subtitle": "Seleccione el horario",
                    "widget_type": "TIME_FIELD"
                },
                {
                    "id": "FWVHsjhGQ",
                    "title": "Seleccion Simple",
                    "subtitle": "Seleccione alguna opción",
                    "widget_type": "SIMPLE_SELECTION",
                    "description": {
                        "options": [
                            "Opcion 1",
                            "Opcion 2",
                            "Opcion 3"
                        ]
                    }
                },
                {
                    "id": "FWgGz4CLd",
                    "title": "Seleccion Simple - Lista desplegable",
                    "subtitle": "Seleccione alguna opcion",
                    "widget_type": "DROPDOWN_SELECTION",
                    "description": {
                        "options": [
                            "Opcion 1",
                            "Opcion 2",
                            "Opcion 3"
                        ]
                    }                    
                },
                {
                    "id": "FWo7BxOeJ",
                    "title": "Seleccion Multiple",
                    "subtitle": "Seleccione las opciones",
                    "widget_type": "MULTIPLE_SELECTION",
                    "description": {
                        "options": [
                            "Opcion 1",
                            "Opcion 2",
                            "Opcion 3"
                        ]
                    }                    
                },
                {
                    "id": "FWTyR07C8",
                    "title": "Campo Foto",
                    "subtitle": "Imagen",
                    "widget_type": "IMAGE_FIELD"
                },
                {
                    "id": "FWazD9hmI",
                    "title": "Seccion Nueva",
                    "subtitle": "Subtitulo",
                    "widget_type": "NEW_SECTION"
                },
                {
                    "id": "FWZMnUuKK",
                    "title": "Firma",
                    "subtitle": "firma digital",
                    "widget_type": "SIGNATURE_FIELD"
                },
                {
                    "id": "FWMgSjrHE",
                    "title": "Etiqueta",
                    "subtitle": "Seleccione alguna opcion",
                    "widget_type": "LABEL_FIELD",
                    "description": {
                        "options": [
                            {
                                "color": "RED",
                                "option_name": "Etiqueta 1"
                            },
                            {
                                "color": "ORANGE",
                                "option_name": "Etiqueta 2"
                            },
                            {
                                "color": "YELLOW",
                                "option_name": "Etiqueta 3"
                            }
                        ]
                    }
                },
                {
                    "id": "FWhvk40T3",
                    "title": "Tabla Smart",
                    "subtitle": "Ingrese los datos correspondientes",
                    "widget_type": "POWER_TABLE_FIELD",
                    "description": {
                        "static_rows": [
                            [
                                "Texto",
                                "0",
                                "0"
                            ]
                        ],
                        "cols": [
                            {
                                "name": "Columna 1",
                                "type": "TEXT"
                            },
                            {
                                "name": "Columna 2",
                                "type": "DROPDOWN"
                            },
                            {
                                "name": "Columna 3",
                                "type": "NUMBER"
                            }
                        ]
                    }
                },
                {
                    "id": "FWId3Z25r",
                    "title": "Lista de Elementos",
                    "subtitle": "Seleccione una opción de la lista",
                    "widget_type": "CLIENT_OBJECT_DROPDOWN",
                    "description": {
                        "obj_id": 111,
                        "show_fields": [
                            1,
                            2,
                            3,
                            5,
                            6,
                            7
                        ]
                    }
                },
                {
                    "id": "FWjOLRNVB",
                    "title": "Tabla de Objetos en cliente",
                    "subtitle": "Complete los datos solicitados",
                    "widget_type": "CLIENT_OBJ_TABLE",
                    "description": {
                        "obj_id": 111,
                        "main_field": 3,
                        "show_fields": [
                            1,
                            2,
                            5
                        ],
                        "cols": [
                            {
                                "col_id": "USER_COL_oJie1649685993531",
                                "name": "Col texto",
                                "type": "TEXT"
                            },
                            {
                                "col_id": "USER_COL_tVMf1649685997315",
                                "name": "Col numero",
                                "type": "NUMBER"
                            },
                            {
                                "col_id": "USER_COL_povU1649686005054",
                                "name": "Col Lista",
                                "type": "DROPDOWN"
                            }
                        ]
                    }
                },
                {
                    "id": "FWGU2Ftw4",
                    "title": "Tabla Master Db",
                    "subtitle": "Complete los datos solicitados",
                    "widget_type": "MASTER_DB_TABLE",
                    "description": {
                        "mdb_id": 133,
                        "main_field": 2,
                        "show_fields": [
                            1,
                            3
                        ],
                        "cols": [
                            {
                                "col_id": "USER_COL_VDJD1649708416806",
                                "name": "Col texto",
                                "type": "TEXT"
                            },
                            {
                                "col_id": "USER_COL_CxbS1649708422321",
                                "name": "Col numero",
                                "type": "NUMBER"
                            },
                            {
                                "col_id": "USER_COL_jBVx1649708426690",
                                "name": "Col lista",
                                "type": "DROPDOWN"
                            },
                            {
                                "col_id": "USER_COL_UwOt1649708431360",
                                "name": "Campo calculado",
                                "type": "CALCULATED"
                            }
                        ],
                        "total_fields": [
                            {
                                "total_field_id": "USER_TOTAL_zmqh1649708466648",
                                "name": "Total texto",
                                "type": "TEXT"
                            },
                            {
                                "total_field_id": "USER_TOTAL_OjNg1649708485631",
                                "name": "Total numero",
                                "type": "NUMBER"
                            },
                            {
                                "total_field_id": "USER_TOTAL_bCpo1649708492977",
                                "name": "Total lista",
                                "type": "DROPDOWN"
                            },
                            {
                                "total_field_id": "USER_TOTAL_DbOq1649708498075",
                                "name": "Total calculado",
                                "type": "CALCULATED"
                            }
                        ]
                    }
                }
            ]
        }
    }
}
```

{% endtab %}

{% tab title="404: Not Found No existe este tipo de formulario" %}

```json
{
    "success": false,
    "error": {
        "status": 404,
        "type": "NOT_FOUND",
        "userMessage": "No hay un schema con id: 456464646546"
    }
}
```

{% endtab %}

{% tab title="400: Bad Request schema\_id no es un número" %}

```javascript
{
    "success": false,
    "error": {
        "status": 400,
        "type": "BAD_REQUEST",
        "userMessage": "'schema_id' debe ser un number (entero) obligatorio"
    }
}
```

{% endtab %}
{% endtabs %}

### Analizando la Respuesta

En este ejemplo se muestra un formulario que utiliza todos los widgets disponibles en Persat.

```json
{
    "success": true,
    "data": {
        "form_group": 60,
        "schema_id": 170,
        "production": true,
        "version": 1,
        "draft": false,
        "description": {
            "title": "Crear Desde API",
            "color": "RED",
            "widgets": [
                {
                    "id": "FWA3VCpeS",
                    "title": "Campo Texto",
                    "subtitle": "Complete con los datos correspondientes",
                    "widget_type": "TEXT_FIELD"
                },
                {
                    "id": "FWMS4k794",
                    "title": "Seccion Nueva",
                    "subtitle": "Subtitulo",
                    "widget_type": "NEW_SECTION"
                },
                {
                    "id": "FWNDBKSIr",
                    "title": "Campo Parrafo",
                    "subtitle": "Complete las observaciones",
                    "widget_type": "TEXT_PARAGRAPH"
                },
                {
                    "id": "FW27yy7bk",
                    "title": "Campo Link",
                    "subtitle": "Acceda a la información haciendo click",
                    "widget_type": "LINK_FIELD"
                },
                {
                    "id": "FWQXPDjee",
                    "title": "Titulo",
                    "subtitle": "Subtitulo",
                    "widget_type": "STATIC_FIELD"
                },
                {
                    "id": "FWWucoyGH",
                    "title": "Campo Numero",
                    "subtitle": "Complete con el valor correspondiente",
                    "widget_type": "NUMBER_FIELD"
                },
                {
                    "id": "FWFFs0qST",
                    "title": "Campo Fecha",
                    "subtitle": "Seleccione la fecha",
                    "widget_type": "DATE_FIELD"
                },
                {
                    "id": "FWT1C5xHM",
                    "title": "Campo Hora",
                    "subtitle": "Seleccione el horario",
                    "widget_type": "TIME_FIELD"
                },
                {
                    "id": "FWVHsjhGQ",
                    "title": "Seleccion Simple",
                    "subtitle": "Seleccione alguna opción",
                    "widget_type": "SIMPLE_SELECTION",
                    "description": {
                        "options": [
                            "Opcion 1",
                            "Opcion 2",
                            "Opcion 3"
                        ]
                    }
                },
                {
                    "id": "FWgGz4CLd",
                    "title": "Seleccion Simple - Lista desplegable",
                    "subtitle": "Seleccione alguna opcion",
                    "widget_type": "DROPDOWN_SELECTION",
                    "description": {
                        "options": [
                            "Opcion 1",
                            "Opcion 2",
                            "Opcion 3"
                        ]
                    }
                },
                {
                    "id": "FWo7BxOeJ",
                    "title": "Seleccion Multiple",
                    "subtitle": "Seleccione las opciones",
                    "widget_type": "MULTIPLE_SELECTION",
                    "description": {
                        "options": [
                            "Opcion 1",
                            "Opcion 2",
                            "Opcion 3"
                        ]
                    }
                },
                {
                    "id": "FWTyR07C8",
                    "title": "Campo Foto",
                    "subtitle": "Imagen",
                    "widget_type": "IMAGE_FIELD"    // deprecado
                },
                {
                    "id": "FWxblfGvY",
                    "title": "Campo Fotos",
                    "subtitle": "Subtitulo",
                    "widget_type": "MULTIPLE_IMAGES_FIELD"
                },
                {
                    "id": "FWZMnUuKK",
                    "title": "Firma",
                    "subtitle": "firma digital",
                    "widget_type": "SIGNATURE_FIELD"    // deprecado
                },
                {
                    "id": "FWGez6FvL",
                    "title": "Firmas Digitales",
                    "subtitle": "Firma y aclaración",
                    "widget_type": "SIGNATURES_FIELD_V2"
                },
                {
                    "id": "FWMgSjrHE",
                    "title": "Etiqueta",
                    "subtitle": "Seleccione alguna opcion",
                    "widget_type": "LABEL_FIELD",
                    "description": {
                        "options": [
                            {
                                "color": "RED",
                                "option_name": "Etiqueta 1"
                            },
                            {
                                "color": "ORANGE",
                                "option_name": "Etiqueta 2"
                            },
                            {
                                "color": "YELLOW",
                                "option_name": "Etiqueta 3"
                            }
                        ]
                    }
                },
                {
                    "id": "FWhvk40T3",
                    "title": "Tabla Smart",
                    "subtitle": "Ingrese los datos correspondientes",
                    "widget_type": "POWER_TABLE_FIELD",
                    "description": {
                        "static_rows": [
                            [
                                "Texto",
                                "0",
                                "0"
                            ]
                        ],
                        "cols": [
                            {
                                "name": "Columna 1",
                                "type": "TEXT"
                            },
                            {
                                "name": "Columna 2",
                                "type": "DROPDOWN"
                            },
                            {
                                "name": "Columna 3",
                                "type": "NUMBER"
                            }
                        ]
                    }
                },
                {
                    "id": "FWId3Z25r",
                    "title": "Lista de Elementos",
                    "subtitle": "Seleccione una opción de la lista",
                    "widget_type": "CLIENT_OBJECT_DROPDOWN",
                    "description": {
                        "obj_id": 111,
                        "show_fields": [
                            1,
                            2,
                            3,
                            5,
                            6,
                            7
                        ]
                    }
                },
                {
                    "id": "FWjOLRNVB",
                    "title": "Tabla de Objetos en cliente",
                    "subtitle": "Complete los datos solicitados",
                    "widget_type": "CLIENT_OBJ_TABLE",
                    "description": {
                        "obj_id": 111,
                        "main_field": 3,
                        "show_fields": [
                            1,
                            2,
                            5
                        ],
                        "cols": [
                            {
                                "col_id": "USER_COL_oJie1649685993531",
                                "name": "Col texto",
                                "type": "TEXT"
                            },
                            {
                                "col_id": "USER_COL_tVMf1649685997315",
                                "name": "Col numero",
                                "type": "NUMBER"
                            },
                            {
                                "col_id": "USER_COL_povU1649686005054",
                                "name": "Col Lista",
                                "type": "DROPDOWN"
                            }
                        ]
                    }
                },
                {
                    "id": "FWGU2Ftw4",
                    "title": "Tabla Master Db",
                    "subtitle": "Complete los datos solicitados",
                    "widget_type": "MASTER_DB_TABLE",
                    "description": {
                        "mdb_id": 133,
                        "main_field": 2,
                        "show_fields": [
                            1,
                            3
                        ],
                        "cols": [
                            {
                                "col_id": "USER_COL_VDJD1649708416806",
                                "name": "Col texto",
                                "type": "TEXT"
                            },
                            {
                                "col_id": "USER_COL_CxbS1649708422321",
                                "name": "Col numero",
                                "type": "NUMBER"
                            },
                            {
                                "col_id": "USER_COL_jBVx1649708426690",
                                "name": "Col lista",
                                "type": "DROPDOWN"
                            },
                            {
                                "col_id": "USER_COL_UwOt1649708431360",
                                "name": "Campo calculado",
                                "type": "CALCULATED"
                            }
                        ],
                        "total_fields": [
                            {
                                "total_field_id": "USER_TOTAL_zmqh1649708466648",
                                "name": "Total texto",
                                "type": "TEXT"
                            },
                            {
                                "total_field_id": "USER_TOTAL_OjNg1649708485631",
                                "name": "Total numero",
                                "type": "NUMBER"
                            },
                            {
                                "total_field_id": "USER_TOTAL_bCpo1649708492977",
                                "name": "Total lista",
                                "type": "DROPDOWN"
                            },
                            {
                                "total_field_id": "USER_TOTAL_DbOq1649708498075",
                                "name": "Total calculado",
                                "type": "CALCULATED"
                            }
                        ]
                    }
                }
            ]
        }
    }
}
```

**form\_group:** identificador del grupo al que pertenece el formulario. Cada vez que se crea una nueva versión de un formulario, el schema\_id del mismo cambia, pero el form\_group es el mismo.&#x20;

Entonces el formulario "Nota de Pedido" tiene un form\_group único, pero cada una de sus versiones tiene un schema\_id diferente.

**schema\_id:** Identificador del tipo de formulario. Es único por versión

**production:** Boolean indicando si este tipo de formulario está en producción (publicado)

**version:** Número indicando la versión

**draft:** Boolean indicando si es un tipo de formulario que está en borrador y todavia no fue publicado.

**description:** Objeto Json con los siguientes fields

**description.title:** Nombre del formulario

**description.color:** String indicando el color del formulario.

{% hint style="info" %}
Los colores disponibles son:

* RED
* ORANGE
* YELLOW
* GREEN
* BLUE
* VIOLET
  {% endhint %}

**description.widgets:** Array de objetos JSON, en donde cada item es un widget del formulario. Para ver los widgets disponibles puede acceder aqui [Tipos de Widgets](/modulos/formularios-digitales/tipos-de-widgets)

Todos los widgets tienen la siguiente estructura

* id: **Obligatorio.** Identificador del widget
* title: **Obligatorio.** Titulo del widget
* subtitle: **Obligatorio.** Subtitulo del widget. Puede contener texto vacio ""
* widget\_type: **Obligatorio.** String identificando el tipo de widget. Ver [Tipos de Widgets](/modulos/formularios-digitales/tipos-de-widgets)
* description: <mark style="color:green;">**Opcional.**</mark> Solo se utiliza para los widgets mas complejos: SIMPLE\_SELECTION, DROPDOWN\_SELECTION, MULTIPLE\_SELECTION, LABEL\_FIELD, POWER\_TABLE\_FIELD, CLIENT\_OBJECT\_DROPDOWN, CLIENT\_OBJ\_TABLE y MASTER\_DB\_TABLE.&#x20;


# Listar estructuras/esquemas de todos los Formularios

Para obtener las estructuras/esquemas de todos los formulario existentes, se debe enviar un GET como el que se especifica a continuación.

<mark style="color:blue;">`GET`</mark> `https://api.persat.com.ar/v1/digital-forms-schemas`

#### Path Parameters

| Name           | Type    | Description                                                                |
| -------------- | ------- | -------------------------------------------------------------------------- |
| includeWidgets | Boolean | true \| false. En caso de ser true, incluye la descripcion de los widgets. |

#### Headers

| Name                                            | Type   | Description     |
| ----------------------------------------------- | ------ | --------------- |
| Authorization<mark style="color:red;">\*</mark> | String | Bearer API\_KEY |

{% tabs %}
{% tab title="200: OK includeWidgets=true" %}

```json
{
	"success": true,
	"data": [{
		"form_group": 8,
		"schema_id": 52,
		"production": true,
		"version": 2,
		"draft": false,
		"description": {
			"title": "Encuesta de Satisfacción",
			"color": "GREEN",
			"widgets": [{
				"id": "FWmHGab5j",
				"title": "Nombre",
				"subtitle": "Complete el nombre y apellido",
				"widget_type": "TEXT_FIELD"
			},
			{
				"id": "FWPaMzjJt",
				"title": "Observaciones generales",
				"subtitle": "Complete las observaciones",
				"widget_type": "TEXT_PARAGRAPH"
			}, {...} 	/* Otro widget */	
			]
		}
	}, {...}	/* Otro tipo de formulario */
	]
}
```

{% endtab %}

{% tab title="400: Bad Request Error" %}

```javascript
{
    "success": false,
    "error": {
        "status": 400,
        "type": "BAD_REQUEST",
        "userMessage": "descripción del error"
    }
}
```

{% endtab %}

{% tab title="200: OK includeWidgets=false | undefined" %}

```json
{
	"success": true,
	"data": [{
		"form_group": 8,
		"schema_id": 52,
		"production": true,
		"version": 2,
		"draft": false,
		"description": {
			"title": "Encuesta de Satisfacción",
			"color": "GREEN"
		}
	}, {...}	/* Otro tipo de formulario */
	]
}
```

{% endtab %}
{% endtabs %}

### Analizando la Respuesta

La respuesta es identica a la que se obtiene en [Obtener estructura/esquema de un Formulario](/modulos/formularios-digitales/obtener-estructura-esquema-de-un-formulario), solo que "data" ahora es un array, en donde cada item, es cada tipo de formulario.

{% hint style="info" %}
En caso de no enviar el parámetro **includeWidgets**, el field "widgets" no aparecerá en la respuesta
{% endhint %}


# Obtener formulario

Los formularios en Persat pueden ser insertados tanto desde la web, la aplicación móvil, o desde la API. Una vez creados se les asigna un id único, mediante el cual podemos luego consultar su contenido.

Para obtener un formulario particular que ya ha sido insertado en Persat se debe realizar un GET como el que se muestra a continuación.

{% hint style="danger" %} <mark style="color:red;">**IMPORTANTE:**</mark> El id del formulario es un **string**, si bien hoy en día los ids de los formularios representan números, hay que considerar la posibilidad de que sean alfanuméricos a futuro.
{% endhint %}

<mark style="color:blue;">`GET`</mark> `https://api.persat.com.ar/v1/digital-forms/form_id`

#### Path Parameters

| Name                                       | Type   | Description                   |
| ------------------------------------------ | ------ | ----------------------------- |
| form\_id<mark style="color:red;">\*</mark> | String | Identificador del formulario. |

#### Headers

| Name                                            | Type   | Description     |
| ----------------------------------------------- | ------ | --------------- |
| Authorization<mark style="color:red;">\*</mark> | String | Bearer API\_KEY |

{% tabs %}
{% tab title="200: OK La consulta se ejecutó con éxito" %}

```json
{
    "success": true,
    "data": {
        "_id": "195",
        "created": "2022-05-18T15:36:27.000Z",
        "created_by_user_name": "Jose Lopez",
        "created_by_user_id": 34,
        "client": {
            "id": 12789,
            "name": "Logistica Lopez",
            "uid_client": "AABC9892"
        },
        "df_data": {
            "schema_id": 170,
            "results": {
                "last_updated": "2022-05-18T15:36:27.000Z",
                "formvalues": {
                    "FWA3VCpeS": "El cliente presenta nuestros productos en su vidriera",
                    "FWWucoyGH": 18,
                    "FWFFs0qST": "2022-04-07T00:00:00.000Z",
                    "FWgGz4CLd": "Cobrado"
                }
            }
        },
        "state": {
            "color": "RED",
            "deleted": false,
            "id": 27,
            "name": "Cancelado"
        },
    }
}
```

{% endtab %}

{% tab title="404: Not Found No se encontro el formulario requerido" %}

```json
{
    "success": false,
    "error": {
        "status": 404,
        "type": "NOT_FOUND",
        "userMessage": "No hay un formulario con este numero: 195"
    }
}
```

{% endtab %}
{% endtabs %}

### Analizando la Respuesta

```json
{
    "success": true,
    "data": {
        "_id": "195",
        "created": "2022-05-18T15:36:27.000Z",
        "created_by_user_name": "Jose Lopez",
        "created_by_user_id": 34,
        "client": {
            "id": 12789,
            "name": "Logistica Lopez",
            "uid_client": "AABC9892"
        },
        "df_data": {
            "schema_id": 170,
            "results": {
                "last_updated": "2022-05-18T15:36:27.000Z",
                "formvalues": {
                    "FWA3VCpeS": "El cliente presenta nuestros productos en su vidriera",
                    "FWWucoyGH": 18,
                    "FWFFs0qST": "2022-04-07T00:00:00.000Z",
                    "FWgGz4CLd": "Cobrado"
                }
            }
        },
        "state": {
            "color": "RED",
            "deleted": false,
            "id": 27,
            "name": "Cancelado"
        },
    }
}
```

**\_id:** Identificador del formulario. Es un string, si bien hoy en dia representa un número, puede ser modificado a futuro para ser alfanumerico.

**created:** Fecha de creación del formulario.&#x20;

{% hint style="info" %}
Si bien la fecha esta representada en UTC, hay que considerarla en <mark style="color:blue;">**horario local**</mark>. Esto se debe a un requerimiento de mantener la compatibilidad con una versión anterior de Persat. Entonces para el caso del ejemplo, y sin importar si soy un cliente de Argentina, Ecuador o México, la fecha mostrada representa el día 18 de Mayo de 2022 a las 15:36 hora de mi país

```
"created": "2022-05-18T15:36:27.000Z",
```

{% endhint %}

**created\_by\_user\_name:** Nombre del usuario que insertó el formulario. En caso que el formulario haya sido creado a través de la API, el valor será "Creado por Api"

**created\_by\_user\_id:** id del usuario nombrado arriba. En caso que el formulario haya sido creado a través de la API, el valor será -1

{% hint style="info" %}
El id de cada usuario se puede obtener en la pantalla de Usuarios y Permisos, presionando sobre el botón "Desarrolladores" en configuración de usuario.
{% endhint %}

<div align="left"><img src="/files/0ewr4MXKvPpLsWQoMvI1" alt=""></div>

**state:** Estado actual del formulario. Para ver la definción de sus propiedades, ver [Obtener estado](/modulos/formularios-digitales/estados-de-formulario/obtener-estado).

**client:** Datos del cliente en el que se encuentra el formulario

* **id:** Id interno. <mark style="color:red;">NO UTILIZAR</mark>. Preparar el sistema para incluso dejar de recibir este dato a futuro.
* **name:** Nombre del cliente
* **uid\_client:** Id del cliente. Es el que se utiliza como identificador de este cliente. Es un valor único.

**df\_data:** Datos del formulario

**df\_data.schema\_id:** Identificador del esquema (plantilla) del formulario. Por ejemplo: Puedo tener un formulario de "Nota de Pedido" y otro de "Encuesta". Para saber de que tipo de formulario estoy hablando es que se usa el schema\_id. Además, puede pasar que el formulario de "Nota de Pedido", tengas varias versiones dentro de Persat, con lo cual cada una de estas versiones es un schema\_id diferente.

{% hint style="info" %}
Para poder conocer los schema\_id de los formularios disponibles [Identificación de Formularios](/modulos/formularios-digitales#identificacion-de-los-formularios-y-sus-widgets)

También puede consultarlos mediante un endpoint de la API [Obtener esquema](/modulos/formularios-digitales/obtener-estructura-esquema-de-un-formulario)
{% endhint %}

**df\_data.results:** Datos del formulario

**df\_data.results.last\_updated:** Fecha de ultima modificación en **hora local**. Es decir, que se aplica el mismo criterio que para el created mencionado más arriba en esta misma sección.

**df\_data.results.formvalues:** Datos de cada uno de los componentes (widgets) del formulario. Cada tipo de formulario esta conformado por widgets de distinto tipo, como por ejemplo: Campo Texto, Campo Lista, Campo número, etc.&#x20;

Para el caso del ejemplo, se puede visualizar que el formulario cuenta con 4 widgets. A priori no se pude deducir exactamente que tipo de widget es cada uno, sin embargo podemos inferir que el widget con id FWFFs0qST es un CAMPO FECHA.&#x20;

```json
formvalues: {
    "FWA3VCpeS": "El cliente presenta nuestros productos en su vidriera", 
    "FWWucoyGH": 18, 
    "FWFFs0qST": "2022-04-07T00:00:00.000Z", 
    "FWgGz4CLd": "Cobrado"
}
```

{% hint style="info" %}
Dependiendo del tipo de widget, es el tipo de valor obtenido. Un widget de tipo Texto, contendrá un string, mientras que uno de tipo Numero contendra un number. Ver todos los widgets disponibles en la siguiente sección: [Tipos de Widgets](/modulos/formularios-digitales/tipos-de-widgets)
{% endhint %}

{% hint style="info" %}
Para conocer los Ids de los widgets [Identificación de Formularios](/modulos/formularios-digitales#identificacion-de-los-formularios-y-sus-widgets)
{% endhint %}


# Obtener PDF del formulario

Para obtener el PDF de un formulario particular que ya ha sido insertado en Persat se debe realizar un GET como el que se muestra a continuación.

<mark style="color:blue;">`GET`</mark> `https://api.persat.com.ar/v1/digital-forms/pdf/form_id`

#### Path Parameters

| Name                                       | Type   | Description                   |
| ------------------------------------------ | ------ | ----------------------------- |
| form\_id<mark style="color:red;">\*</mark> | String | Identificador del formulario. |

#### Query Parameters

| Name   | Type   | Description                                                                                                      |
| ------ | ------ | ---------------------------------------------------------------------------------------------------------------- |
| format | String | Si se envía `"base64"`, el PDF se devolverá en base64. Si no se envía, la API responderá con un archivo binario. |

#### Headers

| Name                                            | Type   | Description     |
| ----------------------------------------------- | ------ | --------------- |
| Authorization<mark style="color:red;">\*</mark> | String | Bearer API\_KEY |

### Ejemplo en formato binario

{% hint style="info" %}
Las respuestas en formato binario retornan directamente la descarga del archivo.
{% endhint %}

#### Request con curl

```bash
curl -H "Authorization: Bearer API_KEY" \
     -J -O \
     https://api.persat.com.ar/v1/digital-forms/pdf/197
```

#### Respuesta

{% tabs %}
{% tab title="200: OK La consulta se ejecutó con éxito" %}

```json
HTTP/1.1 200 OK
Content-Type: application/pdf
Transfer-Encoding: chunked
Content-Disposition: attachment; filename="NOTA_DE_PEDIDO_197.pdf"

<Binary Data>
```

{% endtab %}

{% tab title="404: Not Found No se encontro el formulario requerido" %}

```json
HTTP/1.1 404 NOT_FOUND
Content-Type: application/json

{
    "success": false,
    "error": {
        "status": 404,
        "type": "NOT_FOUND",
        "userMessage": "No hay un formulario con este numero: 197"
    }
}
```

{% endtab %}
{% endtabs %}

### Analizando la Respuesta en formato base64

{% tabs %}
{% tab title="200: OK La consulta se ejecutó con éxito" %}

```json
{
    "success": true,
    "data": {
        "pdf": "JVBERi0xLjQKJdPr6eEKMSAwIG9iago8PC9DcmVh[...]", // Base64
        "name": "NOTA_DE_PEDIDO_197.pdf",
    }
}
```

{% endtab %}

{% tab title="404: Not Found No se encontro el formulario requerido" %}

```json
{
    "success": false,
    "error": {
        "status": 404,
        "type": "NOT_FOUND",
        "userMessage": "No hay un formulario con este numero: 197"
    }
}
```

{% endtab %}
{% endtabs %}

**pdf:** Es un string. Representa el pdf en base64.

**name:** Es un string. Nombre sugerido del pdf.

### Ejemplo de PDF descargado

<figure><img src="/files/5MwWejNa4Q9lULLwmn2M" alt=""><figcaption><p>Ejemplo de pdf descargado</p></figcaption></figure>


# Tipos de Widgets

Los formularios dentro de Persat se pueden crear a medida de manera de adaptarse a cada rubro o necesidad específica. Para tal fin, cuenta con componentes internos denominados "widgets", que presentan distintos comportamientos.&#x20;

Los widgets disponibles son los que se pueden apreciar durante la creación de un schema (plantilla) de formulario

![](/files/BKkD1ikD1i3Scdg7ivcg)

Podemos ver la lista completa aca:

> [Campo Texto](/modulos/formularios-digitales/tipos-de-widgets/campo-texto)
>
> [Campo Párrafo](/modulos/formularios-digitales/tipos-de-widgets/campo-parrafo)
>
> [Campo Link](/modulos/formularios-digitales/tipos-de-widgets/campo-link)
>
> [Campo Número](/modulos/formularios-digitales/tipos-de-widgets/campo-numero)
>
> [Campo Fecha](/modulos/formularios-digitales/tipos-de-widgets/campo-fecha)
>
> [Campo Hora](/modulos/formularios-digitales/tipos-de-widgets/campo-hora)
>
> [Seleccion Simple](/modulos/formularios-digitales/tipos-de-widgets/seleccion-simple)
>
> [Lista Desplegable](/modulos/formularios-digitales/tipos-de-widgets/lista-desplegable)
>
> [Selección Múltiple](/modulos/formularios-digitales/tipos-de-widgets/seleccion-multiple)
>
> [Campo Foto](/modulos/formularios-digitales/tipos-de-widgets/campo-foto-deprecado) <mark style="color:red;">\*\*Deprecado Noviembre 2022</mark>
>
> [Campo Fotos](/modulos/formularios-digitales/tipos-de-widgets/campo-fotos)
>
> [Firma Digital](/modulos/formularios-digitales/tipos-de-widgets/firma-digital-deprecado) <mark style="color:red;">\*\*Deprecado Diciembre 2022</mark>
>
> [Firma Digital v2](/modulos/formularios-digitales/tipos-de-widgets/firma-digital-v2)
>
> [Etiquetas](/modulos/formularios-digitales/tipos-de-widgets/etiquetas)
>
> [Tabla Smart](/modulos/formularios-digitales/tipos-de-widgets/tabla-smart)
>
> [Tabla Master Db](/modulos/formularios-digitales/tipos-de-widgets/tabla-master-db)
>
> [Lista de Objetos en Cliente](/modulos/formularios-digitales/tipos-de-widgets/lista-de-objetos-en-cliente)
>
> [Tabla de Objetos en Cliente](/modulos/formularios-digitales/tipos-de-widgets/tabla-de-objetos-en-cliente)

{% hint style="warning" %}
\*\* El widget **Campo Foto**, fue reemplazado por una versión mejorada que permite incorporar multiples fotos.

Todas las plantillas/esquemas de formularios que sean creadas desde Noviembre 2022, contendrán el nuevo widget [Campo Fotos](/modulos/formularios-digitales/tipos-de-widgets/campo-fotos)

Los formularios viejos seguirán funcionando con normalidad, aunque recomendamos modificarlos para poder tener el nuevo widget y asi contar con sus funcionalidades.
{% endhint %}

{% hint style="warning" %}
\*\* El widget **Firma Digital**, fue reemplazado por una versión mejorada, que contempla la posibilidad de tener hasta 2 firmas junto con la aclaración

Todas las plantillas/esquemas de formularios que sean creadas desde Diciembre 2022, contendrán el nuevo widget [Firma Digital v2](/modulos/formularios-digitales/tipos-de-widgets/firma-digital-v2)

Los formularios viejos seguirán funcionando con normalidad, aunque recomendamos modificarlos para poder tener el nuevo widget y asi contar con sus funcionalidades.
{% endhint %}


# Campo Texto

### Tipo de widget

En el esquema se representa como

> "widget\_type": "TEXT\_FIELD"

### Lectura

A la hora de leer este tipo de widget, obtenemos un valor de tipo string

```json
{
    ...
    "FW9ilaip": "El cliente presenta nuestros productos en su vidriera",
    ...
}
```

### Escritura

Cuando insertamos o modificamos un formulario, en el field correspondiente a este widget, debemos colocar un string que puede estar vacio, pero que no puede superar los 100 caracteres.

```json
{
    ...
    "FW9ilaip": "El cliente presenta nuestros productos en su vidriera",
    ...
}
```


# Campo Párrafo

### Tipo de widget

En el esquema se representa como

> "widget\_type": "TEXT\_PARAGRAPH"

### Lectura

A la hora de leer este tipo de widget, obtenemos un valor de tipo string que permite saltos de linea (ENTERS), los cuales son representados por '\n'

```json
{
    ...
    "FW9ilaip": "El cliente no me dejo pasar.\nDice que no le avisaron que pasaba hoy",
    ...
}
```

### Escritura

Cuando insertamos o modificamos un formulario, en el field correspondiente a este widget, debemos colocar un string que permite saltos de línea como se explica arriba. Puede estar vacío, pero no puede superar los 500 caracteres.

```json
{
    ...
    "FW9ilaip": "El cliente no me dejo pasar.\nDice que no le avisaron que pasaba hoy",
    ...
}
```


# Campo Link

### Tipo de widget

En el esquema se representa como

> "widget\_type": "LINK\_FIELD"

### Lectura

A la hora de leer este tipo de widget, obtenemos un valor de tipo string que representa una url

```json
{
    ...
    "FW9ilaip": "https://www.persat.com.ar",
    ...
}
```

### Escritura

Cuando insertamos o modificamos un formulario, en el field correspondiente a este widget, debemos colocar un string que represente una url, que comience con "http\://" o "https\://"

```json
    ...
    "FW9ilaip": "https://www.persat.com.ar",
    ...
}
```


# Campo Número

### Tipo de widget

En el esquema se representa como

> "widget\_type": "NUMBER\_FIELD"

### Lectura

A la hora de leer este tipo de widget, obtenemos un valor de tipo number

```json
{
    ...
    "FW9ilaip": 12.5,
    ...
}
```

### Escritura

Cuando insertamos o modificamos un formulario, en el field correspondiente a este widget, debemos colocar un number

```json
    ...
    "FW9ilaip": 12.5,
    ...
}
```


# Campo Fecha

### Tipo de widget

En el esquema se representa como

> "widget\_type": "DATE\_FIELD"

### Lectura

A la hora de leer este tipo de widget, obtenemos un valor de tipo string que representa una fecha, sin horas, ni minutos, ni segundos. No importa si estoy en Argentina, Mexico o Ecuador, la fecha indicada en el ejemplo representa el día 7 de Abril de 2022.

```json
{
    ...
    "FW9ilaip": "2022-04-07T00:00:00.000Z",
    ...
}
```

### Escritura

Cuando insertamos o modificamos un formulario, en el field correspondiente a este widget, debemos colocar un string que represente una fecha como se indica arriba . En caso de enviar horas, minutos, segundos o milisegundos, serán ignorados

```json
{
    ...
    "FW9ilaip": "2022-04-07T00:00:00.000Z",
    ...
}
```


# Campo Hora

### Tipo de widget

En el esquema se representa como

> "widget\_type": "TIME\_FIELD"

### Lectura

A la hora de leer este tipo de widget, obtenemos un valor de tipo number que representa los minutos del día transcurridos desde las 00:00 hs. En el ejemplo: 777, simboliza las 12:57, ya que&#x20;

12 \* 60 + 57 = 777

```json
{
    ...
    "FW9ilaip": 777,
    ...
}
```

### Escritura

Cuando insertamos o omodificamos un formulario, en el field correspondiente a este widget, debemos colocar un number que represente los minutos del día transcurridos desde las 00:00 hs, como se menciona arriba.

```json
{
    ...
    "FW9ilaip": 777,
    ...
}
```


# Seleccion Simple

### Tipo de widget

En el esquema se representa como

> "widget\_type": "SIMPLE\_SELECTION"

### Lectura

A la hora de leer este tipo de widget, obtenemos un valor de tipo string con una de las opciones de la lista configuradas en el schema (plantilla) del formulario. Supongamos que hay 2 opciones

* "Pendiente de pago"
* "Cobrado"

```json
{
    ...
    "FW9ilaip": "Cobrado",
    ...
}
```

### Escritura

Cuando insertamos o modificamos un formulario, en el field correspondiente a este widget, debemos colocar un string que coincida con alguna de las opciones disponibles en el schema (plantilla) del formulario. Continuando con el ejemplo de arriba, podemos insertar "Pendiente de pago" o "Cobrado". Sin importar tildes ni mayúsculas. O sea que si enviase "COBRADO", luego al consultar el formulario obtendría "Cobrado", es decir que se normalizan los campos a los valores reales de la lista

```json
{
    ...
    "FW9ilaip": "COBRADO",
    ...
}
```


# Lista Desplegable

### Tipo de widget

En el esquema se representa como

> "widget\_type": "DROPDOWN\_SELECTION"

Funciona exactamente igual que la Seleccion Simple. La diferencia radica unicamente en como se muestran las opciones al usuario final tanto en el movil como en la web

Ver [Seleccion Simple](/modulos/formularios-digitales/tipos-de-widgets/seleccion-simple)


# Selección Múltiple

### Tipo de widget

En el esquema se representa como

> "widget\_type": "MULTIPLE\_SELECTION"

### Lectura

A la hora de leer este tipo de widget, obtenemos un valor de tipo array de strings. Con ninguna, una, o varias de las opciones configuradas en el schema (plantilla) del formulario. Supongamos que hay 3 opciones.

* "Mercado Libre"
* "Tienda Nube"
* "Otros"

```json
{
    ...
    "FW9ilaip": ["Mercado Libre", "Tienda Nube"],
    ...
}
```

### Escritura

Cuando insertamos o modificamos un formulario, en el field correspondiente a este widget, debemos colocar un array de strings en donde cada uno de los items del array debe coincidir con alguna de las opciones disponibles en el schema (plantilla) del formulario. Puede enviarse tambien un array vacío indicando de esta forma que no se selecciona ninguna de las opciones disponibles.

Al igual que lo que ocurre en [Seleccion Simple](/modulos/formularios-digitales/tipos-de-widgets/seleccion-simple), los valores se normalizan, con lo cual podemos enviar "MERCADO LBRE" en mayúscula, y el formulario se insertará o modificará correctamente

```json
    ...
    "FW9ilaip": ["Mercado Libre", "Tienda Nube"],
    ...
}
```


# Campo Foto (deprecado)

### Tipo de widget

En el esquema se representa como

> "widget\_type": "IMAGE\_FIELD"

{% hint style="danger" %}
Este widget ha sido DEPRECADO desde Noviembre 2022. Si bien todos los formularios que lo utilicen seguirán funcionando, recomendamos utilizar el nuevo widget [Campo Fotos](/modulos/formularios-digitales/tipos-de-widgets/campo-fotos)
{% endhint %}

### Lectura

A la hora de leer este tipo de widget, podemos obtener dos tipo de valores.

1. El string "THERE\_IS\_IMAGE" indicando de esta forma que el formulario contiene una imágen cargada.
2. null indicando que no se ha sacado foto en este formulario

```json
{
    ...
    "FW9ilaip": "THERE_IS_IMAGE",
    ...
}
```

```json
{
    ...
    "FW9ilaip": null,
    ...
}
```

{% hint style="warning" %}
Por el momento no es posible obtener las imágenes de los formularios a través de la API
{% endhint %}

### Escritura

Cuando insertamos o modificamos un formulario, en el field correspondiente a este widget, únicamente podemos enviar null.

```json
{
    ...
    "FW9ilaip": null,
    ...
}
```


# Campo Fotos

### Tipo de widget

En el esquema se representa como

> "widget\_type": "MULTIPLE\_IMAGES\_FIELD"

{% hint style="success" %}
Este widget es la versión mejorada de [Campo Foto](/modulos/formularios-digitales/tipos-de-widgets/campo-foto-deprecado), que ha sido deprecado
{% endhint %}

### Lectura

A la hora de leer este tipo de widget, obtenemos un array de strings, en donde podemos acceder a las imágenes.

```json
{
    ...
    "FW9ilaip": ["https://persat-form..AC..GetObject", 
                 "https://persat-form..KL..GetObject"]
    ...
}
```

En caso que no haya ninguna foto se recibirá un array vacío

```json
{
    ...
    "FW9ilaip": [],
    ...
}
```

{% hint style="info" %} <mark style="color:blue;">**IMPORTANTE:**</mark>

Las urls recibidas son <mark style="color:blue;">links temporales</mark>, por lo que si lo que se quiere es persistir la información, se debrá subir a su propio sistema de gestion de archivos (drive, onedrive, dropbox, etc)

La duración del link es de 1 día.&#x20;

Entonces, por ejemplo. No es recomendable enviar el link en un email, ya que al proximo día la imágen no va a estar disponible. Lo correcto sería generar un PDF en el momento y enviar luego el pdf por email.
{% endhint %}

{% hint style="danger" %} <mark style="color:red;">**Consideración Importante al utilizar webhooks**</mark>

Una de las funcionalidades más fuerte de la app movil de Persat, es que puede trabajar sin conexión. Es por esto que es importante destacar,  que más alla de que se reciban los links de las imágenes, las mismas pueden aun no estar disponibles, debido a que el celular no tiene conexión y no pudo enviarlas (tal vez pudo enviar algunas y otras no)&#x20;

Si bien esto se da en casos muy particulares en donde el formulario contiene muchas imágenes, es recomendable agregar un delay de algunos minutos al menos, entre el momento en que se recibe el webhook, y la búsqueda de las imágenes.

Otra opción, sería consultar cada una de las imágenes, y no ejecutar la siguiente acción,  hasta haber recibido con éxito todas las mismas.
{% endhint %}

### Escritura

Cuando insertamos o modificamos un formulario, en el field correspondiente a este widget, únicamente podemos enviar un array vacío.&#x20;

```json
{
    ...
    "FW9ilaip": [],
    ...
}
```


# Firma Digital (deprecado)

### Tipo de widget

En el esquema se representa como

> "widget\_type": "SIGNATURE\_FIELD"

### Lectura

A la hora de leer este tipo de widget, podemos obtener dos tipo de valores.

1. El string "THERE\_IS\_IMAGE" indicando de esta forma que el formulario contiene una firma.
2. null indicando que no hay firma disponible.

```json
{
    ...
    "FW9ilaip": "THERE_IS_IMAGE",
    ...
}
```

```json
{
    ...
    "FW9ilaip": null,
    ...
}
```

{% hint style="warning" %}
Por el momento no es posible obtener las imágenes de las firmas a través de la API
{% endhint %}

### Escritura

Cuando insertamos o modificamos un formulario, en el field correspondiente a este widget, únicamente podemos enviar null.

```json
{
    ...
    "FW9ilaip": null,
    ...
}
```


# Firma Digital v2

### Tipo de widget

En el esquema se representa como

> "widget\_type": "SIGNATURES\_FIELD\_V2"

{% hint style="success" %}
Este widget es la versión mejorada de [Firma Digital](/modulos/formularios-digitales/tipos-de-widgets/firma-digital-deprecado), que ha sido deprecado
{% endhint %}

### Lectura

A la hora de leer este tipo de widget, obtenemos un array de objetos JSON. Este array puede tener como máximo 2 items. Cada uno de los mismos representa una firma junto con su aclaración.

En caso que no se haya firmado, el item será null.

#### Ejemplo 1

El formulario requiere dos firmas (array de dos items), y una de las mismas (la segunda) no fue firmada.

```json
{
    ...
    "FW9ilaip": [
        {
             "name": "Ernesto Perez",
             "signature_url": "https://persat-form-fil...
        },
        null
    ]
    ...
}
```

#### Ejemplo 2

El formulario requiere dos firmas (array de dos items), y no se ha firmado ninguna de las dos.

```json
{
    ...
    "FW9ilaip": [null, null]
    ...
}
```

#### Ejemplo 3

El formulario requiere una firma (array de un item), y se ha firmado correctamente.&#x20;

```json
son{
    ...
    "FW9ilaip": [
        {
             "name": "Ernesto Perez",
             "signature_url": "https://persat-form-fil...
        }
    ]
    ...
}
```

{% hint style="info" %} <mark style="color:blue;">**IMPORTANTE:**</mark>

Las urls recibidas son <mark style="color:blue;">links temporales</mark>, por lo que si lo que se quiere es persistir la información, se debrá subir a su propio sistema de gestion de archivos (drive, onedrive, dropbox, etc)

La duración del link es de 1 día.&#x20;

Entonces, por ejemplo. No es recomendable enviar el link en un email, ya que al proximo día la imágen no va a estar disponible. Lo correcto sería generar un PDF en el momento y enviar luego el pdf por email.
{% endhint %}

{% hint style="danger" %} <mark style="color:red;">**Consideración Importante al utilizar webhooks**</mark>

Una de las funcionalidades más fuerte de la app movil de Persat, es que puede trabajar sin conexión. Es por esto que es importante destacar,  que más alla de que se reciban los links de las firmas, las mismas pueden aun no estar disponibles, debido a que el celular no tiene conexión y no pudo enviarlas (tal vez pudo enviar una y no la otra)&#x20;

Es recomendable agregar un delay de algunos minutos al menos, entre el momento en que se recibe el webhook, y la búsqueda de las imágenes.
{% endhint %}

### Escritura

Cuando insertamos o modificamos un formulario, en el field correspondiente a este widget, únicamente podemos enviar null. Pero tener en cuenta que si el formulairo requiere 2 firmas, entonces habrá que enviar un array con dos items

```json
{
    ...
    "FW9ilaip": [null],
    ...
}
```

```json
{
    ...
    "FW9ilaip": [null, null],
    ...
}
```


# Etiquetas

### Tipo de widget

En el esquema se representa como

> "widget\_type": "LABEL\_FIELD"

Funciona exactamente igual que la [Seleccion Simple](/modulos/formularios-digitales/tipos-de-widgets/seleccion-simple). La diferencia radica unicamente en como se muestran las opciones al usuario final tanto en el movil como en la web


# Tabla Smart

### Tipo de widget

En el esquema se representa como

> "widget\_type": "POWER\_TABLE\_FIELD"

### Lectura

A la hora de leer este tipo de widget, obtenemos un valor de tipo array de array de strings.

Cada item del array indica los datos de la fila de la tabla, luego cada item del array interno contiene los datos de cada una de las columnas.&#x20;

Sin importar el tipo de columna configurada (Texto, Numero o Lista), los datos son siempre de tipo string, para poder mantener compatibilidad con versiones anteriores. Por lo cual será cuestión del integrador entender que la columna 3 es de tipo number (para este caso de ejemplo)&#x20;

```json
{
    ...
    "FW9ilaip": [
        [
            "Texto de la columna 1",
            "Opcion 1",
            "2.232"
        ],
        [
            "Otro texto",
            "Opcion 2",
            "-0.232"
        ]
    ],
    ...
}
```

### Escritura

Cuando insertamos o modificamos un formulario, en el field correspondiente a este widget, debemos colocar un array de array de strings, basado en los mismos criterios que se mencionan arriba. También se puede enviar un array vacio \[] indicando que no hay filas en al tabla

```json
    ...
    "FW9ilaip": [ ["Texto de la columna 1", "Opcion 1", "2.232"], ["Otro texto", "Opcion 2", "-0.232"]],
    ...
}
```


# Tabla Master Db

## Tipo de widget

En el esquema se representa como

> "widget\_type": "MASTER\_DB\_TABLE"

## Lectura

A la hora de leer este tipo de widget, obtenemos un valor de tipo object que se especifica a continuacion.

El objeto JSON tiene dos campos "rows" y "totals". Donde rows es un array de Objetos Json.&#x20;

### rows

Los fields "numericos" (aunque son strings). representan las columnas en la Master Db correspondiente. El "1" es el identificador del elemento dentro de la tabla. Ver la sección [Master Db](/entidades-basicas/master-db) para comprender los campos.

Los fields que comienzan con "USER\_COL" son las columnas extras que fueron completadas por el usuario final, ya sea desde la web o desde el celular. Si bien las columnas pueden ser de varios tipos (Numero, Texto, Lista), los resultados obtenidos son siempre en formato string.

### totals

Los fields comienzan todos con USER\_TOTAL y representan los campos totales que fueron completados por el usuario desde la web o desde el celular. Al igual que las columnas mencionadas anteriormente, los resultados son todos de tipo string mas alla que los campos puedan ser de diferentes tipos.

```json
{
    ...
    "FW9ilaip": {
        "rows": [{
	    "1": "ABC9893821",
            "2": "Destornillador phillips",
            "5": "Rojo",
            "6": "55",
            "USER_COL_VDJD1649708416806": "Me pidieron 5",
	    "USER_COL_CxbS1649708422321": "18.32",
	    "USER_COL_jBVx1649708426690": "Blanco"
	},
	{
	    "1": "DJKS2321DDC",
            "2": "Llave de 10",
            "5": "Plateado",
            "6": "30",
            "USER_COL_VDJD1649708416806": "No me especifico bien",
	    "USER_COL_CxbS1649708422321": "45.30",
	    "USER_COL_jBVx1649708426690": "Rojo"
        }
	],
	"totals": {
            "USER_TOTAL_DbOq1649708498075": "Se aplica descuento",
            "USER_TOTAL_bCpo1649708492977": "5",
            "USER_TOTAL_OjNg1649708485631": "563.32"
	}
    },
    ...
}
```

## Escritura

Cuando insertamos un formulario, en el field correspondiente a este widget, debemos colocar un objeto similar al que se explica arriba, con fields **rows** y **totals**

### rows

Es un array de objetos Json con los siguientes fields

**rows\[x].field\_1:** Es el identificador del elemento de la Master Db que queremos insertar. Debe ser un elemento que exista en la tabla, caso contrario obtendremos como respuesta <mark style="color:red;">404 NOT FOUND</mark>.

**rows\[x].USER\_COL\_......:**  El valor de cada una de las columnas configuradas en la plantilla del formulario. Si bien las columnas son de distintos tipos (NUMERO, TEXTO, LISTA, CALCULADO), debemos enviar siempre valores de tipo string.&#x20;

En el caso particular de que la columna sea de tipo lista, el valor que enviamos debe ser una opción válida de dicha lista, caso contrario obtendremos como respuesta <mark style="color:red;">400 BAD REQUEST</mark>

{% hint style="danger" %}
En el caso de que haya un CAMPO CALCULADO. El calculo no se realizará cuando la inserción se hace desde la API, es decir, todo pasa como si fuese un CAMPO TEXTO, y hay que enviar el valor a guardar.
{% endhint %}

### totals

Es un objeto JSON en donde cada uno de los fields representa un campo total a insertar. Sin importar los tipos de campo, se deben enviar valores de tipo string.

En el caso particular de un campo total de tipo lista, el valor que enviamos debe ser una opción válida de dicha lista, caso contrario obtendremos como respuesta <mark style="color:red;">400 BAD REQUEST</mark>

{% hint style="danger" %}
En el caso de que haya un CAMPO CALCULADO. El calculo no se realizará cuando la inserción se hace desde la API, es decir, todo pasa como si fuese un CAMPO TEXTO, y hay que enviar el valor a guardar.
{% endhint %}

```json
{
    ...
    "FW9ilaip": {
        "rows": [{
	    "field_1": "ABC9893821",
            "USER_COL_VDJD1649708416806": "Me pidieron 5",
	    "USER_COL_CxbS1649708422321": "18.32",
	    "USER_COL_jBVx1649708426690": "Blanco"
	},
	{
	    "field_1": "DJKS2321DDC",
            "USER_COL_VDJD1649708416806": "No me especifico bien",
	    "USER_COL_CxbS1649708422321": "45.30",
	    "USER_COL_jBVx1649708426690": "Rojo"
        }
	],
	"totals": {
            "USER_TOTAL_DbOq1649708498075": "Se aplica descuento",
            "USER_TOTAL_bCpo1649708492977": "5",
            "USER_TOTAL_OjNg1649708485631": "563.32"
	}
    },
    ...
}
```

{% hint style="success" %}
Se puede enviar un valor vacio, indicando que la tabla no tiene ninguna fila

"rows": \[]. Sin embargo **totals** no puede estar vacio
{% endhint %}


# Lista de Objetos en Cliente

## Tipo de widget

En el esquema se representa como

> "widget\_type": "CLIENT\_OBJECT\_DROPDOWN"

## Lectura

A la hora de leer este tipo de widget, obtenemos un valor de tipo object que se especifica a continuacion.

Cada uno de los fields recibidos, representa la columna del objeto. Donde el "1" es el identificador unico del mismo dentro del cliente.

Ver sección de [Objetos en Cliente](/entidades-basicas/objetos-en-cliente)

```json
{
    ...
    "FW9ilaip": {
        "1": "Jose Perez",
        "2": "Ingenieria",
        "3": "+54 1166501258",
        "5": "25",
        "6": "13/03/2000"
    },
    ...
}
```

## Escritura

Se debe enviar unicamente el identificador del Objeto en cliente. En caso que dicho objeto no exista, entonces se recibirá como respuesta <mark style="color:red;">404 NOT FOUND</mark>.

En el ejemplo, estamos seleccionando el contacto Jose Perez dentro del cliente. Si "Jose Perez" no existe dentro del cliente en el que estamos insertando el formulario, entonces recibiremos <mark style="color:red;">404 NOT FOUND.</mark>

```json
{
    ...
    "FW9ilaip": "Jose Perez",
    ...    
}
```

/


# Tabla de Objetos en Cliente

## Tipo de widget

En el esquema se representa como

> "widget\_type": "CLIENT\_OBJ\_TABLE"

## Lectura

A la hora de leer este tipo de widget, obtenemos un valor de tipo object que se especifica a continuacion.

El objeto JSON tiene un unico campo "rows".

### rows

Los fields "numericos" (aunque son strings). representan las columnas en la tabla de Objetos en Cliente correspondiente. El "1" es el identificador del objeto dentro de la tabla. Ver la sección [Objetos en Cliente](/entidades-basicas/objetos-en-cliente) para comprender los campos.

Los fields que comienzan con "USER\_COL" son las columnas extras que fueron completadas por el usuario final. Si bien las columnas pueden ser de varios tipos (Numero, Texto, Lista), los resultados obtenidos son siempre en formato string.

dummy\_id es un valor interno que <mark style="color:red;">NO DEBE USARSE</mark>, y debe esperarse que se deje de recibir a futuro.

```json
{
    ...
    "FW9ilaip": {
        "rows": [
            {
                "1": "Jose Perez",
                "2": "Ingenieria",
                "3": "+54 11665011258",
                "dummy_id": 58                            
                "USER_COL_povU1649686005054": "Opcion 2",
                "USER_COL_tVMf1649685997315": "123.02"
            }, {...}
        ]
    }
    ...
}
```

## Escritura

Cuando insertamos o modificamos un formulario, en el field correspondiente a este widget, debemos colocar un objeto como el que se explica a continuación.

**rows\[x].field\_1:** Identificador del objeto dentro del cliente. En caso que no exista se recibirá como respuesta <mark style="color:red;">404 NOT FOUND</mark>

**rows\[x].USER\_COL\_.....:** El valor de cada una de las columnas configuradas en la plantilla del formulario. Si bien las columnas son de distintos tipos (NUMERO, TEXTO, LISTA), debemos enviar siempre valores de tipo string.&#x20;

En el caso particular de que la columna sea de tipo lista, el valor que enviamos debe ser una opción válida de dicha lista, caso contrario obtendremos como respuesta <mark style="color:red;">400 BAD REQUEST</mark>

```json
{
    ...
    "FW9ilaip": {
        "rows": [
            {
                "field_1": "Jose Perez",
                "USER_COL_povU1649686005054": "Opcion 2",
                "USER_COL_tVMf1649685997315": "123.02"
            }, {...}
        ]
    }
    ...
}
```

{% hint style="success" %}
Se puede enviar un valor vacio, indicando que la tabla no tiene ninguna file

"rows": \[]
{% endhint %}


# Insertar formulario

Para insertar un formulario en Persat, se debe enviar un POST como el que se especifica a continuación.

<mark style="color:green;">`POST`</mark> `https://api.persat.com.ar/v1/digital-forms`

#### Headers

| Name                                            | Type   | Description      |
| ----------------------------------------------- | ------ | ---------------- |
| Authorization<mark style="color:red;">\*</mark> | String | Bearer API\_KEY  |
| Content-Type<mark style="color:red;">\*</mark>  | String | application/json |

#### Request Body

| Name                                                  | Type   | Description                                              |
| ----------------------------------------------------- | ------ | -------------------------------------------------------- |
| uid\_client<mark style="color:red;">\*</mark>         | String | Identificador del cliente                                |
| df\_data.schema\_id<mark style="color:red;">\*</mark> | Number | Identificador de la plantilla del formulario             |
| df\_data.formvalues<mark style="color:red;">\*</mark> | Object | Cada uno de los valores para cada wiidget del formulario |

{% tabs %}
{% tab title="200: OK La consulta se ejecutó con éxito" %}

```json
{
    "success": true,
    "data": {
        "_id": "552",
        "created": "2022-05-19T09:26:26.000Z",
        "created_by_user_name": "Creado por Api",
        "created_by_user_id": -1,
        "client": {
            "id": 12796,
            "name": "Logistica Hnos.",
            "uid_client": "AABC9098"
        },
        "df_data": {
            "schema_id": 150,
            "results": {
                "last_updated": "2022-05-19T09:26:26.000Z",
                "formvalues": {
                    "FWA3VCpeS": "Visitado por la mañana",
                    "FWWucoyGH": 321.11,
                }
            }
        },
        "state": {
            "color": "BLUE",
            "deleted": false,
            "id": 26,
            "name": "Listo"
        },
    }
}
```

{% endtab %}

{% tab title="400: Bad Request Error en alguno de los campos enviados. userMessage contiene informacipon adicional." %}

```json
{
    "success": false,
    "error": {
        "status": 400,
        "type": "BAD_REQUEST",
        "userMessage": "'uid_client' debe ser un string"
    }
}
```

{% endtab %}
{% endtabs %}

### Ejemplo de request

En este ejemplo insertamos un formulario de tipo 150 (schema\_id) en el cliente "AABC9098". Este formulario es sencilllo ya que tiene un widget de CAMPO NUMERO y otro de CAMPO TEXTO. Ver seccion [Tipos de Widgets](/modulos/formularios-digitales/tipos-de-widgets) para mas detalles.

#### body

```json
{
    "uid_client": "AABC9098",
    "df_data": {
        "schema_id": 150, 
        "formvalues": {
            "FWA3VCpeS": "Visitado por la mañana",
            "FWWucoyGH": 321.11
        }
    }
}
```

### Analizando la Respuesta

En caso que no haya ningun error, obtenemos una respuesta de este estilo. La explicación de cada uno de los campos se puede ver en la sección [Obtener Formulario](/modulos/formularios-digitales/obtener-formulario)

{% hint style="info" %}
Cuando se inserta un formulario se agrega el estado inicial.
{% endhint %}

```json
{
    "success": true,
    "data": {
        "_id": "552",
        "created": "2022-05-19T09:26:26.000Z",
        "created_by_user_name": "Creado por Api",
        "created_by_user_id": -1,
        "client": {
            "id": 12796,
            "name": "Logistica Hnos.",
            "uid_client": "AABC9098"
        },
        "df_data": {
            "schema_id": 150,
            "results": {
                "last_updated": "2022-05-19T09:26:26.000Z",
                "formvalues": {
                    "FWA3VCpeS": "Visitado por la mañana",
                    "FWWucoyGH": 321.11
                }
            }
        },
        "state": {
             "color": "RED",
             "deleted": false,
             "id": 27,
             "name": "Cancelado"
        }
    }
}
```


# Modificar formulario

Para modificar un formulario en Persat, se debe enviar un PUT como el que se especifica a continuación.

<mark style="color:orange;">`PUT`</mark> `https://api.persat.com.ar/v1/digital-forms/form_id`

#### Path Parameters

| Name                                       | Type   | Description                  |
| ------------------------------------------ | ------ | ---------------------------- |
| form\_id<mark style="color:red;">\*</mark> | String | Identificador del formulario |

#### Headers

| Name                                            | Type   | Description      |
| ----------------------------------------------- | ------ | ---------------- |
| Authorization<mark style="color:red;">\*</mark> | String | Bearer API\_KEY  |
| Content-Type<mark style="color:red;">\*</mark>  | String | application/json |

#### Request Body

| Name                                                  | Type   | Description                                              |
| ----------------------------------------------------- | ------ | -------------------------------------------------------- |
| df\_data.formvalues<mark style="color:red;">\*</mark> | Object | Cada uno de los valores para cada wiidget del formulario |

{% tabs %}
{% tab title="200: OK La consulta se ejecutó con éxito" %}

```json
{
    "success": true,
    "data": {
        "_id": "195",
        "created": "2022-05-18T16:00:50.000Z",
        "created_by_user_name": "Creado por Api",
        "created_by_user_id": -1,
        "client": {
            "id": 12796,
            "name": "Persat Veinte",
            "uid_client": "CL-Test_20"
        },
        "df_data": {
            "schema_id": 150,
            "results": {
                "last_updated": "2022-05-19T10:43:22.000Z",
                "formvalues": {
                    "FWA3VCpeS": "Texto modificado",
                    "FWWucoyGH": 321.1
                }
            }
        },
        "state": {
            "color": "BLUE",
            "deleted": false,
            "id": 26,
            "name": "Listo"
        },
    }
}
```

{% endtab %}

{% tab title="400: Bad Request Error en alguno de los campos enviados. userMessage contiene informacipon adicional." %}

```json
{
    "success": false,
    "error": {
        "status": 400,
        "type": "BAD_REQUEST",
        "userMessage": "Error en el widget 'FWNDBKSIr'. Debe ser un numero"
    }
}
```

{% endtab %}

{% tab title="404: Not Found Formulario no existe" %}

```javascript
{
    "success": false,
    "error": {
        "status": 404,
        "type": "NOT_FOUND",
        "userMessage": "No hay un formulario con este numero"
    }
}
```

{% endtab %}
{% endtabs %}

### Ejemplo de request

En este ejemplo modificamos el formulario en uno de sus widgets, el FWA3VCpeS. Si quisiera modificar mas campos, solo es cuestion de colocar el widget id y su valor, de forma similar a como se hace en [Insertar Formulario](/modulos/formularios-digitales/insertar-formulario)

#### body

```json
{
    "df_data": {
        "formvalues": {
            "FWA3VCpeS": "Valor modificado"
        }
    }
}
```

### Analizando la Respuesta

En caso que no haya ningun error, obtenemos una respuesta de este estilo. La explicación de cada uno de los campos se puede ver en la sección [Obtener Formulario](/modulos/formularios-digitales/obtener-formulario)

```json
{
    "success": true,
    "data": {
        "_id": "195",
        "created": "2022-05-18T16:00:50.000Z",
        "created_by_user_name": "Creado por Api",
        "created_by_user_id": -1,
        "client": {
            "id": 12796,
            "name": "Persat Veinte",
            "uid_client": "CL-Test_20"
        },
        "df_data": {
            "schema_id": 150,
            "results": {
                "last_updated": "2022-05-19T10:43:22.000Z",
                "formvalues": {
                    "FWA3VCpeS": "Valor modificado",
                    "FWWucoyGH": 321.1
                }
            }
        },
        "state": {
            "color": "BLUE",
            "deleted": false,
            "id": 26,
            "name": "Listo"
        },
    }
}
```




---

[Next Page](/llms-full.txt/1)

