> ## Documentation Index
> Fetch the complete documentation index at: https://docs.play2sell.com/llms.txt
> Use this file to discover all available pages before exploring further.

# API de Misiones

> Lea el progreso de las misiones de su equipo en SalesOS desde su propio backend — objetivos del día, contadores de finalización y la próxima misión a destacar, diseñada para pantallas de inicio de súper apps y paneles de socios.

# API de Misiones

<Note>
  Los ejemplos siguientes muestran el encabezado en formato de red `Authorization: P2S-SIGN-V1 API_KEY:TIMESTAMP:SIGNATURE`. Para calcular la firma en su código, use el helper `signedRequest` en [Autenticación](/es/api/authentication).
</Note>

La API de Misiones permite que su backend lea el **estado de las misiones de gamificación** de sus vendedores en SalesOS — qué objetivos están abiertos hoy, cuánto ha avanzado cada uno, qué se completó ya y qué misión destacar a continuación. Fue diseñada para **componer sus propias pantallas** (por ejemplo, un bloque en la home que muestre "3 de 6 misiones completadas") antes de que el usuario abra el módulo de SalesOS.

Es una API **de solo lectura, servidor a servidor**: usted consulta colaboradores por CPF o correo, en lote, y SalesOS responde con las misiones cuya ventana de período contiene el día de hoy, calculado en la zona horaria de su empresa.

## Cómo funciona

1. **Usted recibe una API Key** con el alcance `missions:read` (Admin > Integraciones > API Keys)
2. **Su backend consulta** el estado de las misiones de uno o varios colaboradores (por CPF o correo)
3. **SalesOS responde** con las misiones de hoy por colaborador — contadores de progreso, la lista completa y la próxima misión activa

<Note>
  Las misiones **avanzan** por la actividad dentro de SalesOS: el motor escucha eventos (una visita agendada, una venta cerrada) e incrementa la misión correspondiente. Esta API es para **leer** ese estado — combínela con un enlace profundo al módulo de SalesOS para la acción en sí.
</Note>

<Warning>
  Este endpoint nunca crea misiones. Si las misiones del día de un colaborador aún no se han aprovisionado, la respuesta es una lista vacía con `progress.total = 0` — no es un error, y no es una escritura silenciosa.
</Warning>

***

## Autenticación

Todas las solicitudes requieren una API Key en el encabezado `Authorization`:

```
Authorization: P2S-SIGN-V1 API_KEY:TIMESTAMP:SIGNATURE
```

Consulte la [página de Autenticación](/es/api/authentication) para detalles sobre cómo crear y gestionar API Keys.

| Propiedad             | Detalles                                                       |
| --------------------- | -------------------------------------------------------------- |
| **Encabezado**        | `Authorization: P2S-SIGN-V1 API_KEY:TIMESTAMP:SIGNATURE`       |
| **Alcance requerido** | `missions:read`                                                |
| **Límite de uso**     | Configurable por clave (predeterminado: 1000 solicitudes/hora) |
| **Formato de clave**  | `sk_live_` (producción) o `sk_test_` (pruebas)                 |

***

## Entornos

<Tabs>
  <Tab title="Producción">
    **URL base:** `https://api.play2sell.com`
  </Tab>

  <Tab title="Staging">
    **URL base:** `https://api-staging.play2sell.com`
  </Tab>
</Tabs>

***

## Referencia del endpoint

```
POST https://api.play2sell.com/functions/v1/missions-partner-api
```

El endpoint acepta dos acciones en el campo `action`: `missions_status` y `missions_summary`.

Cada colaborador se identifica por **CPF** (en cualquier formato — los dígitos se normalizan) o **correo**. Cuando se envían ambos, prevalece el CPF.

***

### Acción: missions\_status

Las misiones cuya ventana de período contiene el día de hoy, por colaborador. "Hoy" se calcula en la zona horaria de su empresa (devuelta en `timezone` / `reference_date` en la respuesta) — nunca en UTC.

#### Esquema de la solicitud

<ParamField body="action" type="string" required>
  Debe ser `"missions_status"`
</ParamField>

<ParamField body="collaborators" type="array" required>
  Lista de referencias de colaboradores (máximo 500 — 100 cuando `include_missions` está activo)
</ParamField>

<ParamField body="include_missions" type="boolean" default="false">
  Devuelve la lista completa `missions[]`. Desactivado por defecto: cada colaborador tiene varias misiones, así que un lote grande con la lista activa produce una respuesta de megabytes. `progress` y `next_mission` siempre llegan.
</ParamField>

<ParamField body="collaborators[].cpf" type="string">
  CPF, en cualquier formato (`52998224725` o `529.982.247-25`). Debe contener exactamente 11 dígitos.
</ParamField>

<ParamField body="collaborators[].email" type="string">
  Correo — usado solo cuando `cpf` está ausente
</ParamField>

#### Ejemplo

```bash theme={null}
curl -X POST https://api.play2sell.com/functions/v1/missions-partner-api \
  -H "Authorization: P2S-SIGN-V1 API_KEY:TIMESTAMP:SIGNATURE" \
  -H "Content-Type: application/json" \
  -d '{
    "action": "missions_status",
    "collaborators": [
      { "cpf": "529.982.247-25" },
      { "email": "juan@suempresa.com" }
    ]
  }'
```

**Respuesta (200):**

```json theme={null}
{
  "data": {
    "timezone": "America/Sao_Paulo",
    "reference_date": "2026-08-11",
    "collaborators": [
      {
        "cpf": "52998224725",
        "found": true,
        "user_id": "8f14e45f-0000-0000-0000-000000000001",
        "name": "Maria Santos",
        "membership_status": "active",
        "progress": {
          "total": 6,
          "completed": 3,
          "pending_approval": 1,
          "active": 2,
          "expired": 0,
          "points_earned": 90,
          "points_available": 235,
          "points_pending_approval": 0
        },
        "next_mission": {
          "id": "b1a2c3d4-0000-0000-0000-000000000010",
          "key": "schedule_visit",
          "name": "Agendar 1 visita",
          "description": "Agende una visita con un lead",
          "category": "sales",
          "icon": "calendar",
          "current_count": 0,
          "target_count": 1,
          "points_reward": 35,
          "nominal_reward": 70,
          "action": { "route": "/leads", "label": "Ver leads", "params": null }
        },
        "missions": [
          {
            "id": "b1a2c3d4-0000-0000-0000-000000000009",
            "key": "call_3_leads",
            "name": "Llamar a 3 leads",
            "category": "sales",
            "period_type": "daily",
            "period_start": "2026-08-11",
            "period_end": "2026-08-11",
            "icon": "phone",
            "status": "completed",
            "current_count": 3,
            "target_count": 3,
            "points_reward": 30,
            "nominal_reward": 30,
            "points_credited_so_far": 30,
            "points_awarded": 30,
            "completed_at": "2026-08-11T13:20:04Z",
            "action": null
          }
        ]
      },
      { "email": "juan@suempresa.com", "found": false }
    ],
    "total": 2,
    "found": 1
  },
  "meta": {
    "request_id": "1f6c1b2e-0000-4a1b-8c2d-000000000001",
    "timestamp": "2026-08-11T13:45:00.000Z"
  }
}
```

#### Campos de la respuesta

| Campo                               | Significado                                                                                                                                                                                                                          |
| ----------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `timezone` / `reference_date`       | La zona horaria de su empresa y el día local al que se refiere la respuesta                                                                                                                                                          |
| `found`                             | Si el CPF/correo resolvió a un colaborador de su empresa                                                                                                                                                                             |
| `membership_status`                 | Situación del vínculo del colaborador con su empresa                                                                                                                                                                                 |
| `progress.total`                    | Misiones cuya ventana de período contiene hoy                                                                                                                                                                                        |
| `progress.completed`                | Finalizadas **y** recompensadas                                                                                                                                                                                                      |
| `progress.pending_approval`         | Finalizadas por el colaborador, esperando al responsable — puntos **aún no** acreditados                                                                                                                                             |
| `progress.active`                   | Todavía en curso                                                                                                                                                                                                                     |
| `progress.expired`                  | Período cerrado sin finalizar                                                                                                                                                                                                        |
| `progress.points_earned`            | Puntos **realmente acreditados** hasta ahora: la recompensa completa de las misiones finalizadas más las cuotas ya pagadas en las que están en curso                                                                                 |
| `progress.points_available`         | Lo que **aún se puede conquistar** en las misiones activas — la recompensa efectiva menos las cuotas ya acreditadas. Las misiones de penalización (recompensa negativa) quedan fuera: una penalización es un riesgo, no algo a ganar |
| `progress.points_pending_approval`  | Recompensas bloqueadas a la espera de aprobación. Todavía no se ha acreditado nada                                                                                                                                                   |
| `next_mission`                      | La misión activa de menor orden de visualización — la que debe destacarse. Ausente cuando no hay ninguna activa                                                                                                                      |
| `missions[]`                        | La lista completa, en el orden de visualización configurado por la empresa                                                                                                                                                           |
| `missions[].points_reward`          | La recompensa **efectiva** — lo que este colaborador recibirá realmente, escalada por su propio objetivo (ver abajo)                                                                                                                 |
| `missions[].nominal_reward`         | La recompensa configurada en la definición de la misión, antes del escalado. Mismos nombres de campo que usa el evento `mission.completed`                                                                                           |
| `missions[].points_credited_so_far` | Cuánto de la recompensa de esta misión ya se pagó por el progreso                                                                                                                                                                    |
| `missions[].action`                 | Enlace profundo opcional configurado para la misión (`route`, `label`, `params`). `null` si no hay                                                                                                                                   |

<Warning>
  **La lista completa es opt-in.** Por defecto la respuesta trae solo `progress` y `next_mission` — lo suficiente para dibujar una pantalla de inicio. Pida `include_missions: true` cuando necesite todas las misiones, y cuente con un límite de lote menor (100 en lugar de 500), porque cada colaborador lleva varias misiones.
</Warning>

<Warning>
  **Las recompensas son personalizadas — muestre siempre `points_reward`, nunca `nominal_reward`.** El objetivo de una misión puede adaptarse por colaborador, y la recompensa lo acompaña: quien tuvo el objetivo reducido a la mitad gana la mitad de los puntos. `points_reward` es lo que se acreditará realmente; `nominal_reward` es el número configurado en la definición, enviado solo para que pueda indicar "meta reducida" si lo desea. Son los mismos nombres de campo que usa el webhook `mission.completed`, así que ambos canales coinciden.
</Warning>

<Note>
  **La recompensa se paga en cuotas, así que "conquistado" y "aún por conquistar" son números distintos.** Una misión de 100 puntos con meta 5 acredita 20 en cada paso. Tras un paso, el colaborador **conquistó 20** y aún tiene **80 por conquistar** — `points_earned` cuenta los 20, `points_available` cuenta los 80. Sumar los 100 completos en ambos lados contaría los mismos puntos dos veces.
</Note>

<Tip>
  **`pending_approval` no es `completed`.** Algunas misiones requieren la aprobación de un responsable antes de acreditar los puntos, y el crédito ocurre en la fecha de aprobación. Reportarlas por separado permite mostrar "esperando aprobación" sin inventar la distinción.
</Tip>

<Warning>
  Los nombres de misión, categorías, iconos, recompensas, metas y orden de visualización se **configuran por empresa**. Nunca fije esos valores en su cliente — renderice lo que traiga la respuesta, para que un cambio en SalesOS no exija una nueva versión de la app.
</Warning>

***

### Acción: missions\_summary

Todo lo que devuelve `missions_status`, más los contadores de finalización de la semana y del mes. Útil para una franja de "su mes hasta ahora".

Las misiones se cuentan en el período al que **pertenecen** (su propia ventana), no en la fecha en que fueron aprobadas — así que una misión aprobada con retraso sigue contando en la semana en que se ganó.

#### Ejemplo

```bash theme={null}
curl -X POST https://api.play2sell.com/functions/v1/missions-partner-api \
  -H "Authorization: P2S-SIGN-V1 API_KEY:TIMESTAMP:SIGNATURE" \
  -H "Content-Type: application/json" \
  -d '{
    "action": "missions_summary",
    "collaborators": [{ "cpf": "529.982.247-25" }]
  }'
```

**Respuesta (200) — bloque adicional por colaborador:**

```json theme={null}
{
  "summary": {
    "week":  { "completed": 8,  "points": 240 },
    "month": { "completed": 31, "points": 980 }
  }
}
```

<Note>
  `missions_summary` recorre un mes de registros por colaborador, por eso su límite de lote es **100** en lugar de 500.
</Note>

***

## Modo self (sesión federada)

Cuando su app ya tiene un token de usuario federado de SalesOS, envíelo como `Authorization: Bearer <jwt>` y **omita** `collaborators`. La respuesta cubre solo al propio usuario del token.

```bash theme={null}
curl -X POST https://api.play2sell.com/functions/v1/missions-partner-api \
  -H "Authorization: Bearer <jwt-federado>" \
  -H "Content-Type: application/json" \
  -d '{ "action": "missions_status" }'
```

<Warning>
  Enviar `collaborators` junto con un token de usuario se rechaza con `SELF_MODE_NO_COLLABORATORS`. Las consultas en lote requieren una API Key de socio — de lo contrario, cualquier usuario autenticado podría leer el progreso de otras personas por CPF.
</Warning>

***

## Manejo de errores

Todos los errores siguen la misma estructura:

```json theme={null}
{
  "error": {
    "code": "ERROR_CODE",
    "message": "Descripción legible",
    "details": []
  }
}
```

<Warning>
  **Son dos formatos, no uno.** El bloque anterior es el error del *endpoint*. Las fallas en la **capa de autenticación** responden antes de que el endpoint corra, con `error` como **cadena**:

  ```json theme={null}
  { "error": "Missing Authorization header", "code": "header_missing" }
  ```

  El código que asume `error.code` lee `undefined` en toda falla de autenticación. Ramifique por el tipo — vea [Convenciones de la API](/es/api/conventions#formatos-de-error).
</Warning>

<AccordionGroup>
  <Accordion title="400 — VALIDATION_ERROR">
    Cuerpo inválido, lote por encima del límite, CPF sin 11 dígitos, o un elemento sin `cpf` ni `email`. La lista `details` indica el `index` del elemento.
  </Accordion>

  <Accordion title="400 — SELF_MODE_NO_COLLABORATORS">
    Se envió una lista `collaborators` junto con un token de usuario. Omítala, o use una API Key de socio.
  </Accordion>

  <Accordion title="401 — UNAUTHORIZED">
    API Key ausente, inválida o expirada, o firma que no coincide.
  </Accordion>

  <Accordion title="403 — FORBIDDEN">
    API Key válida, pero sin el alcance `missions:read`.
  </Accordion>

  <Accordion title="405 — METHOD_NOT_ALLOWED">
    Solo se acepta `POST`.
  </Accordion>

  <Accordion title="429 — RATE_LIMITED">
    Demasiadas solicitudes en esta hora. Espere `retry_after` segundos y reintente.
  </Accordion>

  <Accordion title="500 — SERVER_ERROR">
    Error interno. Reintente con espera progresiva (2s, 4s, 8s).
  </Accordion>
</AccordionGroup>

<Tip>
  **Un colaborador desconocido no es un error.** La solicitud tiene éxito con `found: false` para ese elemento, así que un CPF equivocado nunca rompe el renderizado de toda la pantalla.
</Tip>

***

## Límites de uso

| Límite                                         | Valor                            |
| ---------------------------------------------- | -------------------------------- |
| Solicitudes por hora (predeterminado)          | 1000                             |
| Máximo de colaboradores por `missions_status`  | 500 (100 con `include_missions`) |
| Máximo de colaboradores por `missions_summary` | 100 (50 con `include_missions`)  |

***

## Seguridad

* Solo lectura: esta API nunca crea, avanza ni aprovisiona misiones
* Cada clave pertenece a una sola empresa — un CPF de otra empresa responde `found: false`
* Las solicitudes se firman con HMAC (P2S-SIGN-V1) y se registran para auditoría; los documentos nunca se escriben en los logs

<Warning>
  Nunca exponga su API Key en código del lado del cliente. Esta API debe llamarse únicamente desde su servidor.
</Warning>

***

## Próximos pasos

<CardGroup cols={2}>
  <Card title="API de Check-in" icon="location-dot" href="/es/api/integrations/checkin">
    Lea la presencia en servicio para completar la misma pantalla de inicio
  </Card>

  <Card title="Autenticación" icon="key" href="/es/api/authentication">
    Aprenda a crear y gestionar API Keys
  </Card>
</CardGroup>
