Introducción

Usar el API de Perfit 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 el API, debemos hacer un pedido a la URL base del API, seguido de la versión (en este caso v2), seguido del nombre de nuestra cuenta y el namespace correspondiente, es decir, el nombre del recurso al cual deseamos acceder. Los namespaces están en inglés, pero es muy sencillo reconocerlos. Podés ver un listado completo de los namespaces disponibles en nuestro listado de llamadas.

Por ejemplo, si necesitamos leer información de los contactos, entonces el namespace será contacts y la URL completa será algo como:

https://api.myperfit.com/v2/micuenta/contacts

Y si tenemos que administrar listas, el namespace a utilizar es lists. Por ende, la URL será:

https://api.myperfit.com/v2/micuenta/lists

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 /[account]/[namespace] Obtener un listado de elementos
GET /[account]/[namespace]/[id] Obtener el detalle de un elemento
POST /[account]/[namespace] Crear un nuevo elemento
PUT /[account]/[namespace]/[id] Modificar un elemento
DELETE /[account]/[namespace]/[id] Eliminar un elemento

Cada namespace funciona como una colección de elementos. Cada uno de esos elementos tiene un ID único. Al crear un elemento con un POST, el elemento recibe un ID automáticamente. Ese ID nos servirá para luego acceder a sus datos (GET), modificarlo (PUT) o eliminarlo (DELETE) utilizando la URL del namespace seguida del ID del elemento. Por ejemplo, si se trata del contacto 21, la URL sería:

https://api.myperfit.com/v2/micuenta/contacts/21

Ejemplo de pedido

Para hacer estos llamados en nuestro código podemos hacer lo siguiente:

$lists = file_get_contents(
    // URL a consultar
    'https://api.myperfit.com/v2/lists',
    false,
    stream_context_create(['http'=> [
        // Metodo del pedido
        'method'=>'GET',
        // Headers
        'header' => "X-Auth-Token: $access_token"
    ]])
);
$.ajax({
    // Metodo del pedido
    type: 'GET',
    // URL del API
    url: 'https://api.myperfit.com/v2/lists',
    // Parametros
    data: {
        limit: 100,
        token: 'Shjg23Asd4Sdg8fd23F4eg8rF83kgd2s'
    },
    // Callback a ejecutar en caso de exito
    success: function (response) {
        var data = response.data;
    },
    // Callback a ejecutar en caso de error
    error: function (xhr, text, error) {
        alert('Ha ocurrido un error, intente nuevamente');
    }
});

Content Type

El header Content-Type indica el formato que estamos utilizando en el contenido de un pedido POST o PUT. Por defecto, el Content-Type es x-www-form-urlencoded. Al utilizar este content-type, los parámetros deben ser enviados como query string.

email=john@example.com&lists[0][id]=1&lists[1][id]=2&tags[]=tag1&tags[]=tag2

Tambien podemos especificar el Content-Type: application/json y enviar los parámetros en JSON, de esta forma:

{"email": "john@example.com", "lists": [{"id": 1}, {"id": 2}], "tags": ["tag1", "tag2"]}

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

Method override

Si tu entorno de desarrollo no te permite realizar métodos PUT o DELETE, podés imitarlos usando method override. Para hacerlo, debés enviar un POST con el método deseado como parámetro de url method o bien en el header X-HTTP-Method-Override.

Por ejemplo, un PUT con method override utilizando el parámetro sería:

$contact = file_get_contents(
    'https://api.myperfit.com/v2/contacts/3?method=PUT',
    false,
    stream_context_create(['http'=> [
        'method'=>'POST',
        'header' => 'Content-Type: application/x-www-form-urlencoded',
        'content' => http_build_query([
            'firstName' => 'Billy',
            'token' => 'Shjg23Asd4Sdg8fd23F4eg8rF83kgd2s'
        ])
    ]])
);
$.ajax({
    type: 'POST',
    url: 'https://api.myperfit.com/v2/contacts/3?method=PUT',
    data: {
        firstName: 'Billy',
        token: 'Shjg23Asd4Sdg8fd23F4eg8rF83kgd2s'
    },
    success: function (response) {
        var data = response.data;
    }
});

Y utilizando el header:

$contact = file_get_contents(
    'https://api.myperfit.com/v2/contacts/3',
    false,
    stream_context_create(['http'=> [
        'method'=>'POST',
        'header' => "Content-Type: application/x-www-form-urlencoded\r\n" .
                    'X-HTTP-Method-Override: PUT',
        'content' => http_build_query([
            'firstName' => 'Billy',
            'token' => 'Shjg23Asd4Sdg8fd23F4eg8rF83kgd2s'
        ])
    ]])
);
$.ajax({
    type: 'POST',
    url: 'https://api.myperfit.com/v2/contacts/3',
    headers: {
        'X-HTTP-Method-Override': 'PUT'
    },
    data: {
        method: 'PUT',
        firstName: 'Billy',
        token: 'Shjg23Asd4Sdg8fd23F4eg8rF83kgd2s'
    },
    success: function (response) {
        var data = response.data;
    }
});

Access token

Para que nuestro pedido sea aceptado por el API, debemos enviar un access token válido que nos identifica como usuarios de la cuenta sobre la que queremos trabajar. Podés consultar cómo obtener un token en la sección de autenticación.

Podemos enviar nuestro token de dos formas:

Como parámetrode la url token

$contact = file_get_contents(
    'https://api.myperfit.com/v2/contacts/3',
    false,
    stream_context_create(['http'=> [
        'method'=>'POST',
        'header' => 'Content-Type: application/x-www-form-urlencoded',
        'content' => http_build_query([
            'firstName' => 'Billy',
            'token' => 'Shjg23Asd4Sdg8fd23F4eg8rF83kgd2s'
        ])
    ]])
);
$.ajax({
    type: 'POST',
    url: 'https://api.myperfit.com/v2/contacts',
    data: {
        token: 'Shjg23Asd4Sdg8fd23F4eg8rF83kgd2s',
        firstName: 'Billy'
    },
    success: function (response) {
        var data = response.data;
    }
});

O como encabezado X-Auth-Token

$contact = file_get_contents(
    'https://api.myperfit.com/v2/contacts',
    false,
    stream_context_create(['http'=> [
        'method'=>'POST',
        'header' => "Content-Type: application/x-www-form-urlencoded\r\n" .
                    'X-Auth-Token: Shjg23Asd4Sdg8fd23F4eg8rF83kgd2s',
        'content' => http_build_query([
            'firstName' => 'Billy'
        ])
    ]])
);
$.ajax({
    type: 'POST',
    url: 'https://api.myperfit.com/v2/contacts',
    headers: {
        'X-Auth-Token': 'Shjg23Asd4Sdg8fd23F4eg8rF83kgd2s'
    },
    data: {
        firstName: 'Billy'
    },
    success: function (response) {
        var data = response.data;
    }
});

Se debe indicar sólo una de las opciones, en caso de indicar ambas, el header X-Auth-Token tiene preponderancia.

Opciones de paginación

Por defecto, sólo los primeros elementos son listados en una respuesta. Para comenzar el listado desde otro punto, debemos especificar el parámetro offset:

$contacts = file_get_contents(
    'https://api.myperfit.com/v2/contacts?offset=20',
    false,
    stream_context_create(['http'=> [
        'method'=>'GET',
        'header' => "X-Auth-Token: $access_token"
    ]])
);
$.ajax({
    type: 'GET',
    url: 'https://api.myperfit.com/v2/contacts',
    data: {
        offset: 20,
        token: 'Shjg23Asd4Sdg8fd23F4eg8rF83kgd2s'
    },
    success: function (response) {
        var data = response.data;
    }
});

Si queremos obtener más resultados por página, debemos indicar el parámetro limit:

$contacts = file_get_contents(
    'https://api.myperfit.com/v2/contacts?limit=100',
    false,
    stream_context_create(['http'=> [
        'method'=>'GET',
        'header' => "X-Auth-Token: $access_token"
    ]])
);
$.ajax({
    type: 'GET',
    url: 'https://api.myperfit.com/v2/contacts',
    data: {
        limit: 100,
        token: 'Shjg23Asd4Sdg8fd23F4eg8rF83kgd2s'
    },
    success: function (response) {
        var data = response.data;
    }
});

Cada recurso define en particular el tamaño de página por defecto y máximo permitido. El listado de llamadas especifica cada caso.

Opciones de ordenamiento

Cada módulo del API tiene un órden por defecto. Para listar elementos en un orden diferente, debemos indicar los parámetros sortby (el campo por el cual queremos ordenar) y sortdir (el sentido en el que queremos ordenar, siendo asc para ascendente o desc para descendente).

Por ejemplo:

$contacts = file_get_contents(
    'https://api.myperfit.com/v2/contacts?sortby=quality&sortdir=desc',
    false,
    stream_context_create(['http'=> [
        'method'=>'GET',
        'header' => "X-Auth-Token: $access_token"
    ]])
);
$.ajax({
    type: 'GET',
    url: 'https://api.myperfit.com/v2/contacts',
    data: {
        sortby: 'quality',
        sortdir: 'desc',
        token: 'Shjg23Asd4Sdg8fd23F4eg8rF83kgd2s'
    },
    success: function (response) {
        var data = response.data;
    }
});

Representaciones parciales

A veces no necesitamos saber hasta el último detalle de todos los elementos de un listado. Por el contrario, un listado básico nos puede ser más útil y hasta más rápido de conseguir. Por eso, para mejorar el tiempo de proceso y transferencia, el API ofrece la opción de obtener representaciones parciales de los elementos de un listado.

Algunos recursos, como /contacts por ejemplo, aplican este método (los que no lo hacen devuelven siempre todos los campos de los elementos listados). Para hacer uso de esta distinción, debemos especificar el parámetro fields con el valor _min para obtener los campos mínimos o bien _all para obtener todos los campos (siendo este el comportamiento por defecto). También podemos indicar un listado de los campos requeridos separados por coma:

Veamos un ejemplo:

$contacts = file_get_contents(
    'https://api.myperfit.com/v2/contacts?fields=firstName,lastName',
    false,
    stream_context_create(['http'=> [
        'method'=>'GET',
        'header' => "X-Auth-Token: $access_token"
    ]])
);
$.ajax({
    type: 'GET',
    url: 'http2://api.myperfit.com/v2/contacts',
    data: {
        fields: 'firstName,lastName',
        token: 'Shjg23Asd4Sdg8fd23F4eg8rF83kgd2s'
    },
    success: function (response) {
        var data = response.data;
    }
});

La cantidad de información que se incluye para cada elemento puede variar dependiendo si se esta consultando el listado o el elemento individual. Por ejemplo, la información sobre las suscripciones a listas e intereses de un contacto no se incluye en el listado /contacts, pero sí en /contacts/id. Cada recurso especifica su comportamiento particular.

Ejemplo de respuesta

En caso de éxito, los estados posibles son los siguientes:

Code Status Significado
200 OK Operación realizada con éxito
201 Created Creación exitosa de un nuevo elemento
202 Accepted Comienzo de una acción asincrónica

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

{
    "href": "...",
    "success": true,
    "paging": {},
    "filter": {},
    "sort": {},
    "data": {},
    "task": {},
    "error": {}
}

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:

href

Presente en todas las respuestas, href indica la URL consultada. Es útil para identificar los resultados de varias llamadas realizadas en simultáneo.

success

Presente en todas las respuestas, success 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 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), results (la cantidad total de elementos coincidentes con la búsqueda) y total (el total de elementos en la colección).

filter

En las respuestas de pedidos GET a las colecciones, la propiedad filter nos indicará el filtro opcional aplicado. Si esta propiedad no aparece, ningún filtro está en uso.

sort

En las respuestas de pedidos GET a las colecciones, la propiedad sort nos indica el ordenamiento aplicado. La mayoría de las colecciones son ordenadas por defecto mediante su ID. Dentro de este apartado encontraremos sortby (el nombre del campo utilizado para ordernar) y sortdir (ascendente o descendente).

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. Todos los campos son devueltos, incluso aquellos cuyo valor sea null. En las respuestas de pedidos POST, data muestra todos los campos del nuevo elemento insertado, con los valores indicados en el pedido o el valor por defecto. En las respuestas de pedidos PUT, data muestra sólo los campos modificados, ya sea por el usuario (por ejemplo, un nombre) o por el sistema (por ejemplo, la fecha de última modificación).

task

Sólo esta presente para el caso de las acciones o tareas asincrónicas, se incluye en esta propiedad la información sobre la nueva tarea creada. Por ejemplo, utilizando el id de la nueva tarea podemos consultar a /tasks para saber el estado de la misma.

error

Aquí se indica el detalle del error. Cada error tiene un type que lo identifica y un userMessage con el mensaje textual que puede mostrarse al usuario.

Errores

Desafortunadamente, ¡no siempre sale todo bien! En caso de que error, los status recibidos serán los siguientes:

Code Status Significado
400 Bad Request Petición inválida
401 Unauthorized Las credenciales de acceso no son válidas
403 Forbidden El recurso solicitado no esta dentro de los permitidos
404 Not found La URI solicitada no corresponde a ningun recurso
405 Method Not Allowed El método HTTP no está soportado
409 Conflict El recurso que se intenta crear o modificar entra en conflicto con uno existente
415 Unsupported Media Type El Content-Type del pedido no es soportado
500 Internal Server Error Error del servidor
503 Service Unavailable El servidor está limitando el acceso al recurso

Como complemento, la respuesta contendrá un objeto error con una propiedad status coincidente con la del status HTTP y un type que indica el motivos específico del error. Por ejemplo:

{
    "href": "/micuenta/contacts",
    "success": false,
    "error": {
        "status": 409,
        "type": "RESOURCE_EXISTS",
        "userMessage": "El pedido no puedo ser procesado ya que entra en conflicto con un recurso existente",
        "validationErrors": {
            "email": "Valor duplicado"
        }
    }
}

Los valores de type pueden ser los siguientes:

Type Descripción
BAD_REQUEST El pedido tiene una estructura inválida.
RESOURCE_EXISTS El recurso que se intentó crear entra en conflicto con uno existente. Se indica en validationErrors los campos en conflicto.
UNSUPPORTED_MEDIA_TYPE El formato de datos indicado no es soportado.
INTERNAL_ERROR Ocurrió un error interno del servidor.
METHOD_NOT_ALLOWED El método HTTP utilizado no es soportado por el recurso especificado.
NOT_FOUND El recurso especificado no existe, puede ser porque el ID especificado no exista.
SERVICE_UNAVAILABLE El recurso solicitado no esta disponible temporalmente, posiblemente debido a un exceso de carga.
UNAUTHORIZED No se proporcionó token de autorización, o es inválido.
FORBIDDEN No se dispone del permiso necesario para el recurso solicitado.
VALIDATION_ERROR El pedido realizado contiene errores en uno o más campos, en validationErrors se indican los campos con errores.
ACCOUNT_REQUIRED Se intentó realizar un login utilizando un email registrado en más de una cuenta, se debe repetir especificando la cuenta. En data se indican las cuentas posibles.
PASSWORD_EXPIRED Se intentó realizar un login pero la contraseña esta expirada o debe ser renovada.

Internacionalización

Los mensajes que se incluyen en las respuestas son expresados utilizando el lenguaje por defecto, que es el español. Es posible indicar que se desan recibir los mensajes en inglés utilizando el header estándar Accept-Language, o el query parameter lang. Los valoes posibles son en para inglés y es para español.