---
name: shopify-recuperar-carritos-abandonados
description: "Busca los checkouts abandonados de los últimos N días, crea un código de descuento único para cada cliente y lo etiqueta para volver a contactarlo. Úsala cuando quieras recuperar ventas de carritos que no se completaron."
---

## Propósito
Identifica a los clientes que iniciaron el checkout pero no completaron la compra, crea un código de descuento único para cada uno y los etiqueta en Shopify para que puedas incluirlos en campañas de seguimiento. Esta skill se encarga de la capa de datos nativa de Shopify (consultas, descuentos y etiquetas); para enviar el correo como tal necesitas una herramienta externa.

## Requisitos
- Sesión autenticada de Shopify CLI: `shopify store auth --store <tu-tienda>.myshopify.com --scopes read_checkouts,write_price_rules,write_discount_codes,write_customers`
- Las consultas se ejecutan con `shopify store execute`.
- Permisos (scopes) de la API: `read_checkouts`, `write_price_rules`, `write_discount_codes`, `write_customers`

## Parámetros

| Parámetro | Tipo | Obligatorio | Por defecto | Descripción |
|-----------|------|-------------|-------------|-------------|
| store | string | sí | — | Dominio de la tienda (p. ej., tu-tienda.myshopify.com) |
| format | string | no | human | Formato de salida: `human` o `json` |
| dry_run | bool | no | false | Muestra una vista previa de las operaciones sin ejecutar mutaciones |
| days_back | integer | no | 7 | Cuántos días hacia atrás buscar checkouts abandonados |
| min_cart_value | float | no | 0 | Total mínimo del carrito para incluirlo (en la moneda de la tienda) |
| discount_pct | integer | no | 10 | Porcentaje de descuento que se crea para cada cliente |
| code_prefix | string | no | RECOVER | Prefijo de los códigos de descuento generados |
| tag | string | no | cart-recovery | Etiqueta que se aplica a los clientes que califican |

## Seguridad

> ⚠️ Los pasos 2 y 3 ejecutan mutaciones (creación de códigos de descuento y etiquetado de clientes). Los códigos creados con `discountCodeBulkCreate` no se pueden borrar en lote con la Admin API: hay que eliminarlos uno por uno o a través de la regla de precio. Ejecuta con `dry_run: true` para verificar cuántos clientes califican antes de aplicar los cambios.

## Pasos

1. **OPERACIÓN:** `abandonedCheckouts` — consulta
   **Entradas:** `first: 250`, `query: "created_at:>='<NOW - days_back days>'"`, cursor de paginación
   **Resultado esperado:** Lista de checkouts con `email`, `totalPrice`, `createdAt`, `lineItems`; pagina hasta que `hasNextPage: false`

2. **OPERACIÓN:** `discountCodeBulkCreate` — mutación
   **Entradas:** Para cada correo de un cliente que califica: un código único `{code_prefix}-{UUID[:8].toUpperCase()}`, descuento porcentual de `discount_pct`, límite de 1 uso, vencimiento a 30 días
   **Resultado esperado:** Confirmación de la creación con `code` y `priceRule.id`; recopila los `userErrors`

3. **OPERACIÓN:** `tagsAdd` — mutación
   **Entradas:** `id` del cliente (buscado a partir del `email` del checkout), etiqueta tomada del parámetro `tag`
   **Resultado esperado:** Etiquetas del cliente actualizadas; recopila los `userErrors`

## Operaciones GraphQL

```graphql
# abandonedCheckouts:query — validado con api_version 2025-04
query AbandonedCheckouts($first: Int!, $after: String, $query: String) {
  abandonedCheckouts(first: $first, after: $after, query: $query) {
    edges {
      node {
        id
        customer {
          defaultEmailAddress {
            emailAddress
          }
        }
        totalPriceSet {
          shopMoney {
            amount
            currencyCode
          }
        }
        createdAt
        lineItems {
          edges {
            node {
              title
              quantity
              variant {
                price
              }
            }
          }
        }
      }
    }
    pageInfo {
      hasNextPage
      endCursor
    }
  }
}
```

```graphql
# discountCodeBulkCreate:mutation — validado con api_version 2025-01
mutation DiscountCodeBulkCreate($priceRuleId: ID!, $codes: [DiscountCodeInput!]!) {
  discountCodeBulkCreate(priceRuleId: $priceRuleId, codes: $codes) {
    bulkCreations {
      id
      done
    }
    userErrors {
      field
      message
    }
  }
}
```

```graphql
# tagsAdd:mutation — validado con api_version 2025-01
mutation TagsAdd($id: ID!, $tags: [String!]!) {
  tagsAdd(id: $id, tags: $tags) {
    node {
      id
    }
    userErrors {
      field
      message
    }
  }
}
```

## Seguimiento de la sesión

**Claude DEBE mostrar esta salida en cada etapa. Es obligatorio.**

**Al iniciar**, muestra:
```
╔═══════════════════════════════════════════════╗
║  SKILL: Recuperación de carritos abandonados  ║
║  Tienda: <dominio de la tienda>               ║
║  Inicio: <YYYY-MM-DD HH:MM UTC>               ║
╚═══════════════════════════════════════════════╝
```

**Después de cada paso**, muestra:
```
[N/TOTAL] <CONSULTA|MUTACIÓN>  <NombreOperación>
          → Parámetros: <resumen breve de las entradas clave>
          → Resultado: <conteo o resultado>
```

Si `dry_run: true`, antepón `[SIMULACIÓN]` a cada paso de mutación y no lo ejecutes.

**Al terminar**, muestra:

Para `format: human` (por defecto):
```
══════════════════════════════════════════════
RESUMEN DEL RESULTADO
  Checkouts encontrados:   <n>
  Clientes que califican:  <n>
  Códigos creados:         <n>
  Clientes etiquetados:    <n>
  Errores:                 <n>
  Archivo:                 recovery_list_<fecha>.csv
══════════════════════════════════════════════
```

Para `format: json`, muestra:
```json
{
  "skill": "shopify-recuperar-carritos-abandonados",
  "store": "<dominio>",
  "started_at": "<ISO8601>",
  "completed_at": "<ISO8601>",
  "dry_run": false,
  "steps": [
    { "step": 1, "operation": "AbandonedCheckouts", "type": "query", "params_summary": "últimos 7 días, carrito >= 0", "result_summary": "<n> checkouts", "skipped": false },
    { "step": 2, "operation": "DiscountCodeBulkCreate", "type": "mutation", "params_summary": "<n> códigos, 10% de descuento, prefijo RECOVER", "result_summary": "<n> creados", "skipped": false },
    { "step": 3, "operation": "TagsAdd", "type": "mutation", "params_summary": "etiqueta: cart-recovery", "result_summary": "<n> clientes etiquetados", "skipped": false }
  ],
  "outcome": {
    "checkouts_found": 0,
    "eligible_customers": 0,
    "codes_created": 0,
    "customers_tagged": 0,
    "errors": 0,
    "output_file": "recovery_list_<fecha>.csv"
  }
}
```

## Formato de salida
Archivo CSV `recovery_list_<YYYY-MM-DD>.csv` con las columnas:
`customer_email`, `cart_total`, `abandoned_at`, `discount_code`, `discount_pct`, `tag_applied`

## Manejo de errores
| Error | Causa | Solución |
|-------|-------|----------|
| `THROTTLED` | Se superó el límite de solicitudes de la API | Espera 2 segundos y reintenta hasta 3 veces |
| `userErrors` al crear el descuento | Regla de precio inválida o código duplicado | Registra el error, omite al cliente y continúa |
| `userErrors` en tagsAdd | No se encontró el ID del cliente | Registra el error, omite la etiqueta y continúa |
| Checkout sin correo | Checkout como invitado sin correo | Omite el checkout y no lo cuentes como elegible |

## Buenas prácticas
- Ejecuta primero con `dry_run: true` y confirma cuántos clientes califican: los códigos de descuento no se pueden borrar en lote por API y se quedarán en tus reglas de precio hasta que los elimines a mano.
- Configura `min_cart_value` para enfocar la recuperación en los carritos de mayor valor (p. ej., 50 para carritos de 50 o más en la moneda de la tienda). Los carritos pequeños suelen tener menos intención de compra y quizá no justifiquen un descuento.
- Usa una `tag` distinta en cada ejecución (p. ej., `cart-recovery-2026-04-11`) para saber exactamente a qué clientes contactaste en cada campaña y no volver a contactarlos en las siguientes.
- El `code_prefix` debe tener sentido para quien revise los códigos de descuento en el admin de Shopify (p. ej., `CART10` para un descuento de recuperación de carrito del 10%).
- Esta skill genera la capa de datos. Usa Shopify Email u otra herramienta de correo para enviarles los códigos a los clientes.
