# Gestión de comercios

Un **comercio** representa un punto de venta asociado a un **emisor** (RFC).
Cada comercio puede tener sus propias llaves CSD para facturar, un logotipo
personalizado y una API Key para operar con los endpoints de generación de QR.

## Crear comercio

### Endpoint

```
POST /v1/qrs/merchants
```

**Host (DEV):**

```
https://api-dev.qrwey.com
```

**Host (PROD):**

```
https://api.qrwey.com
```

### Headers requeridos

```http
Authorization: Bearer {{access_token}}
Content-Type: application/json
```

### Request body

| Campo | Descripción |
|  --- | --- |
| `issuerId` | ID del emisor al que se asocia el comercio (requerido) |
| `merchantName` | Nombre del comercio |
| `billingProfile` | Perfil de facturación (ej. `FUEL`, `GENERAL`) |
| `billingProfileData` | Datos adicionales del perfil de facturación (opcional) |
| `contactEmail` | Correo electrónico de contacto |
| `contactPhoneNumber` | Teléfono de contacto |
| `address` | Objeto con los datos del domicilio |
| `address.street` | Calle del domicilio |
| `address.exteriorNumber` | Número exterior |
| `address.interiorNumber` | Número interior |
| `address.neighborhood` | Colonia |
| `address.city` | Ciudad |
| `address.state` | Estado |
| `address.zipCode` | Código postal |
| `status` | Estado inicial: `ACTIVE` o `INACTIVE` |


### Ejemplo de request (DEV)

```bash
curl -X POST "https://api-dev.qrwey.com/v1/qrs/merchants" \
  -H "Authorization: Bearer {{access_token}}" \
  -H "Content-Type: application/json" \
  -d '{
    "issuerId": "inv_data_4aca0361cfcd41c097663db44008fbb9",
    "merchantName": "Estación Reforma Centro",
    "billingProfile": "FUEL",
    "contactEmail": "contacto@estacion-reforma.com",
    "contactPhoneNumber": "5551234567",
    "address": {
      "street": "Av. Paseo de la Reforma",
      "exteriorNumber": "222",
      "interiorNumber": null,
      "neighborhood": "Juarez",
      "city": "Ciudad de México",
      "state": "CDMX",
      "zipCode": "06600"
    },
    "status": "ACTIVE"
  }'
```

### Respuesta

```json
{
  "merchantId": "mer_4aca0361cfcd41c097663db44008fbb9",
  "externalMerchantId": "ext_001",
  "merchantName": "Estación Reforma Centro",
  "billingProfile": "FUEL",
  "billingProfileData": null,
  "contactEmail": "contacto@estacion-reforma.com",
  "contactPhoneNumber": "5551234567",
  "invoiceLogoUrl": null,
  "invoiceLogoFileName": null,
  "appLogoUrl": null,
  "appLogoFileName": null,
  "logoAnimation": "NONE",
  "address": {
    "street": "Av. Paseo de la Reforma",
    "exteriorNumber": "222",
    "interiorNumber": null,
    "neighborhood": "Juarez",
    "city": "Ciudad de México",
    "state": "CDMX",
    "zipCode": "06600"
  },
  "status": "ACTIVE"
}
```

### Campos de la respuesta (Merchant)

| Campo | Descripción |
|  --- | --- |
| `merchantId` | Identificador único del comercio |
| `externalMerchantId` | Identificador externo del comercio |
| `merchantName` | Nombre del comercio |
| `billingProfile` | Perfil de facturación |
| `billingProfileData` | Datos adicionales del perfil de facturación |
| `contactEmail` | Correo electrónico de contacto |
| `contactPhoneNumber` | Teléfono de contacto |
| `invoiceLogoUrl` | URL del logotipo para facturas |
| `invoiceLogoFileName` | Nombre del archivo del logotipo de factura |
| `appLogoUrl` | URL del logotipo para la app |
| `appLogoFileName` | Nombre del archivo del logotipo de la app |
| `logoAnimation` | Tipo de animación del logo |
| `address` | Objeto con los datos del domicilio |
| `status` | Estado del comercio: `ACTIVE` o `INACTIVE` |


## Listar comercios

### Endpoint

```
GET /v1/qrs/merchants
```

### Headers requeridos

```http
Authorization: Bearer {{access_token}}
```

### Query params

| Parámetro | Descripción |
|  --- | --- |
| `issuerId` | ID del emisor (requerido) |
| `filter` | Texto para filtrar por nombre (default: vacío) |
| `page` | Número de página (default: 0) |
| `size` | Elementos por página (default: 20) |


### Ejemplo de request (DEV)

```bash
curl -X GET "https://api-dev.qrwey.com/v1/qrs/merchants?issuerId=inv_data_4aca0361cfcd41c097663db44008fbb9&page=0&size=10" \
  -H "Authorization: Bearer {{access_token}}"
```

### Respuesta

El listado devuelve una versión resumida del comercio (`MerchantSummary`):

```json
{
  "content": [
    {
      "merchantId": "mer_4aca0361cfcd41c097663db44008fbb9",
      "merchantName": "Estación Reforma Centro",
      "city": "Ciudad de México",
      "state": "CDMX",
      "invoiceLogoUrl": "https://cdn.qrwey.com/logos/mer_invoice_4aca0361.png",
      "appLogoUrl": "https://cdn.qrwey.com/logos/mer_app_4aca0361.png",
      "status": "ACTIVE"
    }
  ],
  "totalElements": 1,
  "totalPages": 1,
  "number": 0,
  "size": 10
}
```

### Campos de MerchantSummary

| Campo | Descripción |
|  --- | --- |
| `merchantId` | Identificador único del comercio |
| `merchantName` | Nombre del comercio |
| `city` | Ciudad del comercio |
| `state` | Estado del comercio |
| `invoiceLogoUrl` | URL del logotipo para facturas |
| `appLogoUrl` | URL del logotipo para la app |
| `status` | Estado del comercio: `ACTIVE` o `INACTIVE` |


## Obtener comercio por ID

### Endpoint

```
GET /v1/qrs/merchants/{merchantId}
```

### Headers requeridos

```http
Authorization: Bearer {{access_token}}
```

### Ejemplo de request (DEV)

```bash
curl -X GET "https://api-dev.qrwey.com/v1/qrs/merchants/mer_4aca0361cfcd41c097663db44008fbb9" \
  -H "Authorization: Bearer {{access_token}}"
```

## Actualizar comercio

### Endpoint

```
PUT /v1/qrs/merchants/{merchantId}
```

### Headers requeridos

```http
Authorization: Bearer {{access_token}}
Content-Type: application/json
```

Los campos del request body son los mismos que al crear (excepto `issuerId`).

### Ejemplo de request (DEV)

```bash
curl -X PUT "https://api-dev.qrwey.com/v1/qrs/merchants/mer_4aca0361cfcd41c097663db44008fbb9" \
  -H "Authorization: Bearer {{access_token}}" \
  -H "Content-Type: application/json" \
  -d '{
    "merchantName": "Estación Reforma Centro Actualizado",
    "contactEmail": "nuevo-contacto@estacion-reforma.com"
  }'
```

## Subir logos del comercio

Sube o actualiza los logotipos (factura y app) de un comercio existente.

### Endpoint

```
POST /v1/qrs/merchants/{merchantId}/logos
```

> Este endpoint usa `multipart/form-data` para la carga de archivos.


### Headers requeridos

```http
Authorization: Bearer {{access_token}}
Content-Type: multipart/form-data
```

### Campos del formulario

| Campo | Descripción |
|  --- | --- |
| `invoiceLogo` | Archivo de imagen para el logo de factura (opcional) |
| `appLogo` | Archivo de imagen para el logo de la app (opcional) |
| `logoAnimation` | Tipo de animación del logo (ej. `NONE`, `BOUNCE`) (opcional) |


### Ejemplo de request (DEV)

```bash
curl -X POST "https://api-dev.qrwey.com/v1/qrs/merchants/mer_4aca0361cfcd41c097663db44008fbb9/logos" \
  -H "Authorization: Bearer {{access_token}}" \
  -F "invoiceLogo=@/path/to/invoice-logo.png" \
  -F "appLogo=@/path/to/app-logo.png" \
  -F "logoAnimation=NONE"
```

### Respuesta

Retorna el objeto `Merchant` completo con las URLs de los logos actualizadas.

## Activar comercio

### Endpoint

```
PUT /v1/qrs/merchants/{merchantId}/status/active
```

### Ejemplo de request (DEV)

```bash
curl -X PUT "https://api-dev.qrwey.com/v1/qrs/merchants/mer_4aca0361cfcd41c097663db44008fbb9/status/active" \
  -H "Authorization: Bearer {{access_token}}"
```

## Desactivar comercio

### Endpoint

```
PUT /v1/qrs/merchants/{merchantId}/status/inactive
```

### Ejemplo de request (DEV)

```bash
curl -X PUT "https://api-dev.qrwey.com/v1/qrs/merchants/mer_4aca0361cfcd41c097663db44008fbb9/status/inactive" \
  -H "Authorization: Bearer {{access_token}}"
```

> Desactivar un comercio impide que genere nuevos QRs y facture. Las transacciones existentes no se afectan.


## Guardar llaves CSD (modelo de facturación)

Configura las llaves del Certificado de Sello Digital (CSD) para que el comercio pueda timbrar CFDIs.

### Endpoint

```
POST /v1/qrs/merchants/{merchantId}/invoice-mode
```

### Headers requeridos

```http
Authorization: Bearer {{access_token}}
Content-Type: multipart/form-data
```

### Campos del formulario

| Campo | Descripción |
|  --- | --- |
| `csdDataRequest.cerFile` | Archivo `.cer` del CSD (requerido) |
| `csdDataRequest.keyFile` | Archivo `.key` del CSD (requerido) |
| `csdDataRequest.password` | Contraseña de la llave privada (requerido) |
| `csdDataRequest.serialNumberPrefix` | Prefijo para el número de serie de los CFDIs (opcional) |


### Ejemplo de request (DEV)

```bash
curl -X POST "https://api-dev.qrwey.com/v1/qrs/merchants/mer_4aca0361cfcd41c097663db44008fbb9/invoice-mode" \
  -H "Authorization: Bearer {{access_token}}" \
  -F "csdDataRequest.cerFile=@/path/to/certificado.cer" \
  -F "csdDataRequest.keyFile=@/path/to/llave.key" \
  -F "csdDataRequest.password=MiContrasenaSegura123"
```

## Actualizar llaves CSD

### Endpoint

```
PUT /v1/qrs/merchants/{merchantId}/invoice-mode
```

Mismos campos que al guardar. Usa este endpoint cuando necesites renovar las llaves CSD.

## Obtener modelo de facturación

### Endpoint

```
GET /v1/qrs/merchants/{merchantId}/invoice-mode
```

### Ejemplo de request (DEV)

```bash
curl -X GET "https://api-dev.qrwey.com/v1/qrs/merchants/mer_4aca0361cfcd41c097663db44008fbb9/invoice-mode" \
  -H "Authorization: Bearer {{access_token}}"
```

### Respuesta

```json
{
  "merchantId": "mer_4aca0361cfcd41c097663db44008fbb9",
  "invoiceType": "QRWEY",
  "csdDataRequest": {
    "cerFileName": "certificado.cer",
    "keyFileName": "llave.key",
    "serialNumberPrefix": "A",
    "businessCode": "BC001"
  },
  "apiDataRequest": null
}
```

### Campos de InvoiceModeResponse

| Campo | Descripción |
|  --- | --- |
| `merchantId` | Identificador del comercio |
| `invoiceType` | Tipo de facturación configurada (ej. `QRWEY`) |
| `csdDataRequest` | Datos del CSD configurado |
| `csdDataRequest.cerFileName` | Nombre del archivo `.cer` cargado |
| `csdDataRequest.keyFileName` | Nombre del archivo `.key` cargado |
| `csdDataRequest.serialNumberPrefix` | Prefijo para el número de serie de los CFDIs |
| `csdDataRequest.businessCode` | Código de negocio asociado |
| `apiDataRequest` | Datos de API de facturación externa (nullable) |


## Regenerar API Key

Regenera las llaves de acceso del comercio. La API Key anterior dejará de funcionar inmediatamente.

### Endpoint

```
PUT /v1/qrs/merchants/{merchantId}/api-key/regenerate
```

### Ejemplo de request (DEV)

```bash
curl -X PUT "https://api-dev.qrwey.com/v1/qrs/merchants/mer_4aca0361cfcd41c097663db44008fbb9/api-key/regenerate" \
  -H "Authorization: Bearer {{access_token}}"
```

> Al regenerar la API Key, cualquier integración que use la llave anterior dejará de autenticarse. Actualiza la configuración de tus sistemas antes de regenerar.


## Errores comunes

| Código | Motivo |
|  --- | --- |
| 400 | Campos requeridos faltantes, archivos CSD invalidos |
| 401 | Token inválido o expirado |
| 404 | Comercio, emisor o grupo no encontrado, o no pertenece a tu cuenta |


Consulta: [Manejo de errores](/guides/error-handling)

## Buenas prácticas

- Configura las llaves CSD antes de intentar timbrar CFDIs
- Usa nombres descriptivos para cada comercio que identifiquen la sucursal o punto de venta
- Regenera la API Key solo cuando sea necesario y actualiza todas las integraciones afectadas
- Desactiva comercios que ya no operen en lugar de eliminarlos


## ¿Qué sigue?

- Timbra un CFDI con el comercio: [Timbrar CFDI 4.0](/guides/stamp-cfdi)
- Consulta transacciones del comercio: [Gestión de Clientes](/guides/customer-portal)
- Vuelve al índice: [Gestión de Clientes](/guides/customer-portal)