---
title: SmartPOS Integration
slug: cp-sdconn
docTags: 
createdAt: 2026-03-11T02:07:58.837Z
---

Device connect permite conectar todos nuestros dispositivos para ser utilizados en modalidad PinPad o controlado.

Este servicio podrá ser utilizado en:

:::Paragraph{listStyleType="disc" indent="2"}
**macOS (Apple Silicon)**
:::

:::Paragraph{listStyleType="disc" listStart="2" indent="2"}
**macOS (Intel)**
:::

:::Paragraph{listStyleType="disc" listStart="3" indent="2"}
**Windows**
:::

:::Paragraph{listStyleType="disc" listStart="4" indent="2"}
**Linux:**&#x20;
:::

:::Paragraph{listStyleType="disc" indent="3"}
**Linux amd64** -- PC o Linux tradicional
:::

:::Paragraph{listStyleType="disc" listStart="2" indent="3"}
**Linux arm64** — Raspberry Pi 3/4/5 con OS de 64 bits (Raspberry Pi OS 64-bit)
:::

:::Paragraph{listStyleType="disc" listStart="3" indent="3"}
**Linux armv7** — Raspberry Pi 3/4 con OS de 32 bits (Raspberry Pi OS 32-bit)
:::

:::Paragraph{listStyleType="disc" listStart="5" indent="2"}
**Android**
:::

## Versiones

Versión para PC o Raspberry Pi: [Windows, Linux, Mac, Raspberry Pi](docId\:WOShlA3gZ9q5_gFLbkIhQ)

Versión Android: [Android](docId\:YCTNsE5fQa9SIg72lHIbK)

# Flujo Procesamiento

Guía completa del flujo de procesamiento de pagos con tarjeta presente utilizando SDConn (Desktop o Android) junto con la API de Mobbex/SUGA.

## Resumen del flujo

El procesamiento de un pago con tarjeta presente consta de 4 pasos:

```mermaid
flowchart LR
    A["1. Obtener<br/>Intent Token"] --> B["2. Detectar tarjeta<br/>(opcional)"]
    A --> C["3. Leer tarjeta<br/>con SDConn"]
    B --> C
    C --> D["4. Procesar<br/>operación"]
    D --> E["5. Mostrar<br/>resultado"]

    style A fill:#4a90d9,color:#fff
    style B fill:#f5a623,color:#fff
    style C fill:#7ed321,color:#fff
    style D fill:#4a90d9,color:#fff
    style E fill:#9b59b6,color:#fff
```

```mermaid
flowchart TD
    START([Inicio]) --> TOKEN_CHOICE{Intent Token}
    TOKEN_CHOICE -->|Opción A: Automático| AUTO["SDConn genera token<br/>internamente"]
    TOKEN_CHOICE -->|Opción B: Externo| EXT["Tu backend genera token<br/>POST /p/pos/physical"]

    AUTO --> READ["SDConn lee tarjeta<br/>del dispositivo POS"]
    EXT --> READ

    READ --> DETECT{Detectar cuotas?}
    DETECT -->|Sí| DET_API["POST /p/sources/detect/{token}<br/>Obtener planes de cuotas"]
    DETECT -->|No| PROCESS

    DET_API --> SELECT["Usuario elige<br/>plan de cuotas"]
    SELECT --> PROCESS

    PROCESS["Procesar operación<br/>POST /p/operations/{token}<br/>source: { ...sourceData }"]
    PROCESS --> RESULT{Resultado}
    RESULT -->|Aprobado| DISPLAY_OK["display(status: 200)<br/>Círculo verde ✓"]
    RESULT -->|Rechazado| DISPLAY_ERR["display(status: 400)<br/>Círculo rojo ✗"]

    style START fill:#333,color:#fff
    style TOKEN_CHOICE fill:#4a90d9,color:#fff
    style AUTO fill:#7ed321,color:#fff
    style EXT fill:#f5a623,color:#fff
    style READ fill:#7ed321,color:#fff
    style DETECT fill:#f5a623,color:#fff
    style DET_API fill:#f5a623,color:#fff
    style SELECT fill:#f5a623,color:#fff
    style PROCESS fill:#4a90d9,color:#fff
    style RESULT fill:#9b59b6,color:#fff
    style DISPLAY_OK fill:#2ecc71,color:#fff
    style DISPLAY_ERR fill:#e74c3c,color:#fff
```

| Paso                    | Responsable          | Descripción                            |
| ----------------------- | -------------------- | -------------------------------------- |
| 1. Intent Token         | API o Backend propio | Crear la intención de pago             |
| 2. Detección de tarjeta | API (opcional)       | Identificar tarjeta y planes de cuotas |
| 3. Lectura de tarjeta   | SDConn (SDK/Desktop) | Leer datos encriptados de la tarjeta   |
| 4. Procesamiento        | API                  | Ejecutar el cobro                      |

## Paso 1: Obtener el Intent Token

El Intent Token define las características de la operación. Hay **dos formas** de obtenerlo:

### Opción A: Generación a través de SDConn (automático)

SDConn genera el Intent Token internamente al llamar a la operación de lectura. Solo se necesita tener configuradas las credenciales de Mobbex.

**Desktop (HTTP):**

:::BlockQuote
curl -X POST http\://localhost:8484/api/v1/read \\
&#x20; -H "Content-Type: application/json" \\
&#x20; -d '\{
&#x20;   "total": 15.00,
&#x20;   "currency": "ARS",
&#x20;   "test": false
&#x20; }'
:::

**Android (SDK):**

:::BlockQuote
val result = sdconn.read(ReadRequest(
&#x20;   total = 15.00,
&#x20;   currency = "ARS",
&#x20;   test = false
))
:::

En ambos casos, SDConn internamente:

1. Obtiene serialNumber del dispositivo
2. Obtiene la geolocalización
3. Llama a POST https\://api.mobbex.com/p/pos/physical con los datos
4. Usa el token recibido para iniciar la lectura

### Opcion B: Generación externa (desde tu backend)

Tu backend genera el Intent Token directamente contra la API de Mobbex y se lo envía a SDConn.

**Endpoint:** POST https\://api.mobbex.com/p/pos/physical

**Headers:**

| Header       | Valor                 | Descripción                 |
| ------------ | --------------------- | --------------------------- |
| api-key      | tu\_api\_key\_privada | Clave privada de la entidad |
| Content-Type | application/json      |                             |

**Cuerpo de la petición:**

:::BlockQuote
\{
&#x20; "total": 15.00,
&#x20; "serialNumber": "SN12345",
&#x20; "currency": "ARS",
&#x20; "test": false,
&#x20; "description": "Venta #1234",
&#x20; "reference": "orden-1234",
&#x20; "webhook": "https\://tu-servidor.com/webhook/mobbex",
&#x20; "geolocation": \[-31.4201, -64.1888],
&#x20; "intent": "payment.v2"
}
:::

**Campos:**

| Campo        | Tipo    | Requerido | Descripción                                                                                       |
| ------------ | ------- | --------- | ------------------------------------------------------------------------------------------------- |
| total        | number  | Sí        | Monto de la operación                                                                             |
| serialNumber | string  | Sí        | Número de serie del lector (lo obtiene SDConn del dispositivo)                                    |
| test         | boolean | No        | true para operaciones de prueba                                                                   |
| currency     | string  | No        | Moneda en formato ISO 4217 (ej: "ARS", "USD")                                                     |
| otherAmount  | number  | No        | Monto adicional para cashback (requiere habilitación)                                             |
| intent       | string  | No        | Flujo de operación: "payment.v2" (captura automática) o "payment.2-step" (autorización + captura) |
| reference    | string  | No        | Referencia externa de la operación                                                                |
| description  | string  | No        | Descripción de la operación                                                                       |
| webhook      | string  | No        | URL para notificaciones de actualización                                                          |
| geolocation  | array   | No        | Coordenadas \[latitud, longitud]                                                                  |

**Objeto submerchant** (requerido para agregadores/PayFac):

:::BlockQuote
\{
&#x20; "submerchant": \{
&#x20;   "reference": "comercio-123",
&#x20;   "country": "ARG",
&#x20;   "legalName": "Razón Social SA",
&#x20;   "name": "Nombre Comercial",
&#x20;   "taxIdType": "arg.cuit",
&#x20;   "taxId": "30-12345678-9",
&#x20;   "mcc": "5411",
&#x20;   "city": "Córdoba",
&#x20;   "state": "Córdoba",
&#x20;   "zipCode": "X5000ABC",
&#x20;   "currency": "ARS",
&#x20;   "address": \{
&#x20;     "street": "Av. Colón",
&#x20;     "number": "1234",
&#x20;     "notes": "Piso 2, Of. B"
&#x20;   },
&#x20;   "owner": \{
&#x20;     "name": "Juan",
&#x20;     "lastname": "Pérez",
&#x20;     "identification": "30123456789",
&#x20;     "identificationType": "arg.cuit"
&#x20;   }
&#x20; }
}
:::

| Campo     | Descripción                                                                           |
| --------- | ------------------------------------------------------------------------------------- |
| reference | Identificador único del subcomercio                                                   |
| country   | País en formato ISO 3166-3 (ARG, CHL, URY, MEX)                                       |
| taxIdType | Tipo de identificación fiscal: arg.cuit, arg.cuil, arg.dni, chl.rut, ury.rut, mex.rfc |
| mcc       | Código de categoría del comercio                                                      |
| zipCode   | Código postal (Argentina: CPA de 8 dígitos)                                           |

**Respuesta:**

:::BlockQuote
\{
&#x20; "result": true,
&#x20; "data": \{
&#x20;   "intent": \{
&#x20;     "type": "payment.v2",
&#x20;     "token": "620198a7-291e-4bde-9248-43b34d59e8c9"
&#x20;   },
&#x20;   "test": true
&#x20; }
}
:::

:::BlockQuote
**Importante:** Guardar el valor de data.intent.token. Este es el Intent Token que se usará en los pasos siguientes.
:::

**Ejemplo cURL:**

:::BlockQuote
curl -X POST 'https\://api.mobbex.com/p/pos/physical' \\
&#x20; -H 'api-key: \_8bjoCPu4xW5GCHsp5yDHzSmhMnQU1kfw7nw' \\
&#x20; -H 'Content-Type: application/json' \\
&#x20; -d '\{
&#x20;   "total": 3.21,
&#x20;   "serialNumber": "2GKJ23H1324",
&#x20;   "currency": "ARS",
&#x20;   "description": "Venta en sucursal",
&#x20;   "test": true
&#x20; }'
:::

## Paso 2: Detección de tarjeta ingresada (opcional)

Permite identificar el tipo de tarjeta y los planes de cuotas disponibles a partir del BIN (primeros 8 dígitos del PAN).

:::BlockQuote
**Nota:** Esta API está restringida a comercios que hayan solicitado el módulo de cálculo de promociones.
:::

**Endpoint:** POST https\://api.mobbex.com/p/sources/detect/&#x7B;intent\_token}

**Headers:**

| Header       | Valor                 | Descripción                     |
| ------------ | --------------------- | ------------------------------- |
| api-key      | tu\_api\_key\_publica | Clave **pública** de la entidad |
| Content-Type | application/json      |                                 |

**Cuerpo:**

:::BlockQuote
\{
&#x20; "type": "card",
&#x20; "data": \{
&#x20;   "bin": "451700"
&#x20; },
&#x20; "options": \{
&#x20;   "installments": true
&#x20; }
}
:::

| Campo                | Tipo    | Requerido | Descripción                               |
| -------------------- | ------- | --------- | ----------------------------------------- |
| type                 | string  | Sí        | Tipo de medio de pago. Valor fijo: "card" |
| data.bin             | string  | No        | Primeros 6 dígitos del número de tarjeta  |
| options.installments | boolean | No        | Habilitar cálculo de planes de cuotas     |

**Respuesta:**

:::BlockQuote
\{
&#x20; "result": true,
&#x20; "data": \{
&#x20;   "type": "card",
&#x20;   "source": \{
&#x20;     "reference": "visa",
&#x20;     "name": "Visa",
&#x20;     "shortName": "Visa",
&#x20;     "card": \{
&#x20;       "level": "classic",
&#x20;       "product": \{
&#x20;         "name": "Visa",
&#x20;         "variant": "credit",
&#x20;         "lengths": \[16],
&#x20;         "gaps": \[4, 8, 12],
&#x20;         "code": \{
&#x20;           "name": "CVV",
&#x20;           "length": 3,
&#x20;           "position": 1
&#x20;         },
&#x20;         "logo": "https\://res.mobbex.com/images/sources/png/visa.png",
&#x20;         "validation": \["length", "exp", "cvv", "luhn"]
&#x20;       },
&#x20;       "issuer": \{
&#x20;         "name": "Visa",
&#x20;         "color": "#122d98",
&#x20;         "logo": "https\://res.mobbex.com/images/sources/png/visa.png"
&#x20;       }
&#x20;     }
&#x20;   },
&#x20;   "installments": \[
&#x20;     \{
&#x20;       "name": "1 Pago",
&#x20;       "reference": "1",
&#x20;       "count": 1,
&#x20;       "totals": \{
&#x20;         "installment": \{ "amount": 5.00, "count": 1 },
&#x20;         "total": 5.00,
&#x20;         "financial": \{ "percentage": 0, "amount": 0 }
&#x20;       }
&#x20;     },
&#x20;     \{
&#x20;       "name": "3 Cuotas",
&#x20;       "reference": "3",
&#x20;       "count": 3,
&#x20;       "totals": \{
&#x20;         "installment": \{ "amount": 1.92, "count": 3 },
&#x20;         "total": 5.75,
&#x20;         "financial": \{ "percentage": 15, "amount": 0.75 }
&#x20;       }
&#x20;     },
&#x20;     \{
&#x20;       "name": "6 Cuotas",
&#x20;       "reference": "6",
&#x20;       "count": 6,
&#x20;       "totals": \{
&#x20;         "installment": \{ "amount": 1.08, "count": 6 },
&#x20;         "total": 6.50,
&#x20;         "financial": \{ "percentage": 30, "amount": 1.50 }
&#x20;       }
&#x20;     },
&#x20;     \{
&#x20;       "name": "Ahora 12",
&#x20;       "reference": "ahora\_12",
&#x20;       "count": 12,
&#x20;       "totals": \{
&#x20;         "installment": \{ "amount": 0.48, "count": 12 },
&#x20;         "total": 5.75,
&#x20;         "financial": \{ "percentage": 15, "amount": 0.75 }
&#x20;       }
&#x20;     }
&#x20;   ]
&#x20; }
}
:::

:::BlockQuote
**Importante:** Guardar el valor de installments\[].uid del plan de cuotas elegido por el usuario para usarlo al procesar la operación.
:::

**Ejemplo cURL:**

:::BlockQuote
curl -X POST 'https\://api.mobbex.com/p/sources/detect/620198a7-291e-4bde-9248-43b34d59e8c9' \\
&#x20; -H 'api-key: xxxxxxxxxxxxxxxxxxxxxx' \\
&#x20; -H 'Content-Type: application/json' \\
&#x20; -d '\{
&#x20;   "type": "card",
&#x20;   "data": \{ "bin": "45170000" },
&#x20;   "options": \{ "installments": true }
&#x20; }'
:::

## Paso 3: Lectura de tarjeta con SDConn

Este paso lo realiza SDConn (Desktop o Android SDK). El SDK se encarga de enviar el Intent Token al dispositivo POS y esperar a que el usuario pase/inserte la tarjeta.

### Con Intent Token externo (Opción B del Paso 1)

Cuando se generó el token externamente, se envía a SDConn con el campo intentToken:

**Desktop (HTTP):**

:::BlockQuote
curl -X POST http\://localhost:8484/api/v1/read \\
&#x20; -H "Content-Type: application/json" \\
&#x20; -d '\{
&#x20;   "total": 15.00,
&#x20;   "currency": "ARS",
&#x20;   "intentToken": "620198a7-291e-4bde-9248-43b34d59e8c9"
&#x20; }'
:::

**Android (SDK):**

:::BlockQuote
val result = sdconn.read(ReadRequest(
&#x20;   total = 15.00,
&#x20;   currency = "ARS",
&#x20;   intentToken = "620198a7-291e-4bde-9248-43b34d59e8c9"
))
:::

:::BlockQuote
**Nota:** Cuando se usa un token externo, SDConn **no contacta** a la API de Mobbex y no requiere credenciales configuradas. Además, incluye la geolocation del dispositivo en la respuesta.
:::

### Sin Intent Token (Opción A del Paso 1)

SDConn genera el token automáticamente (requiere credenciales configuradas):

:::BlockQuote
curl -X POST http\://localhost:8484/api/v1/read \\
&#x20; -H "Content-Type: application/json" \\
&#x20; -d '\{ "total": 15.00, "currency": "ARS" }'
:::

### Respuesta de SDConn

**Flujo estándar (token generado por SDConn):**

:::BlockQuote
\{
&#x20; "result": true,
&#x20; "intentToken": "620198a7-291e-4bde-9248-43b34d59e8c9",
&#x20; "sourceData": \{
&#x20;   "pin": "D4F2A1...",
&#x20;   "emvData": "9F26089C4A...",
&#x20;   "cryptogram": "ARQC...",
&#x20;   "ksn": "FFFF9876...",
&#x20;   "track2": "4517001234..."
&#x20; }
}
:::

**Flujo con token externo:**

:::BlockQuote
\{
&#x20; "result": true,
&#x20; "intentToken": "620198a7-291e-4bde-9248-43b34d59e8c9",
&#x20; "geolocation": \[-31.4201, -64.1888],
&#x20; "sourceData": \{
&#x20;   "pin": "D4F2A1...",
&#x20;   "emvData": "9F26089C4A...",
&#x20;   "cryptogram": "ARQC...",
&#x20;   "ksn": "FFFF9876...",
&#x20;   "track2": "4517001234..."
&#x20; }
}
:::

**Campos de la respuesta:**

| Campo       | Tipo    | Descripción                                             |
| ----------- | ------- | ------------------------------------------------------- |
| result      | boolean | true si la lectura fue exitosa                          |
| intentToken | string  | Token utilizado (generado o externo)                    |
| geolocation | array   | \[latitud, longitud] — solo cuando se usa token externo |
| sourceData  | object  | Datos encriptados de la tarjeta leída                   |
| error       | string  | Descripción del error (solo si result es false)         |

**Contenido de sourceData:**

| Campo      | Descripción                       |
| ---------- | --------------------------------- |
| pin        | PIN encriptado (si fue ingresado) |
| emvData    | Datos EMV del chip                |
| cryptogram | Criptograma de la transacción     |
| ksn        | Key Serial Number para DUKPT      |
| track2     | Datos del Track 2 encriptados     |

:::BlockQuote
**Importante:** Los datos de sourceData están encriptados por el dispositivo POS. No pueden ser leídos directamente — deben enviarse al procesador en el Paso 4.
:::

### Cancelar lectura

Si el usuario desea cancelar mientras espera la tarjeta:

**Desktop:** DELETE http\://localhost:8484/api/v1/read

**Android:** sdconn.cancelRead()

## Paso 4: Procesar la operación

Con el intentToken y los datos de sourceData obtenidos en el paso anterior, se envía la operación al procesador para ejecutar el cobro.

### Procesamiento simplificado

En este esquema se envían los datos de la tarjeta directamente dentro del campo source, sin necesidad de tokenizar previamente.

**Endpoint:** POST https\://api.mobbex.com/p/operations/&#x7B;intent\_token}

**Cuerpo:**

:::BlockQuote
\{
&#x20; "source": \{
&#x20;   "pin": "D4F2A1...",
&#x20;   "emvData": "9F26089C4A...",
&#x20;   "cryptogram": "ARQC...",
&#x20;   "ksn": "FFFF9876...",
&#x20;   "track2": "4517001234..."
&#x20; },
&#x20; "installmentCount": 1,
&#x20; "customer": \{
&#x20;   "name": "Juan Pérez",
&#x20;   "identification": "30123456789",
&#x20;   "email": "juan\@ejemplo.com",
&#x20;   "phone": "3511234567"
&#x20; }
}
:::

Es decir: todo el contenido de sourceData que devolvió SDConn se envía dentro del campo source.

**Campos:**

| Campo                   | Tipo   | Requerido | Descripción                                                 |
| ----------------------- | ------ | --------- | ----------------------------------------------------------- |
| source                  | object | Sí        | Contenido completo de sourceData devuelto por SDConn        |
| installmentCount        | number | No        | Cantidad de cuotas (cuando no se usa detección automática)  |
| installment             | string | No        | Referencia del plan de cuotas (obtenido en el Paso 2)       |
| customer                | object | No        | Datos del comprador                                         |
| customer.name           | string | No        | Nombre del comprador                                        |
| customer.identification | string | No        | Documento de identidad                                      |
| customer.email          | string | No        | Email del comprador                                         |
| customer.phone          | string | No        | Teléfono del comprador                                      |
| authCode                | string | No        | Código de autenticación (para operaciones que lo requieran) |

:::BlockQuote
**Recomendación:** Si se utiliza procesamiento simplificado, enviar la información del customer al crear el Intent Token (Paso 1) para optimizar el flujo.
:::

**Respuesta exitosa:**

:::BlockQuote
\{
&#x20; "result": true,
&#x20; "data": \{
&#x20;   "id": "kS6D18unD",
&#x20;   "status": \{
&#x20;     "code": "200",
&#x20;     "text": "Aprobado",
&#x20;     "message": "Transacción Aprobada"
&#x20;   }
&#x20; }
}
:::

**Códigos de estado comunes:**

| Código | Texto     | Significado               |
| ------ | --------- | ------------------------- |
| 200    | Aprobado  | Transacción aprobada      |
| 3      | Aprobado  | Aprobado (variante)       |
| 4      | Aprobado  | Aprobado (variante)       |
| 400    | Rechazado | Transacción rechazada     |
| 500    | Error     | Error en el procesamiento |

## Paso 5: Mostrar resultado en el dispositivo

Después de procesar el pago, se debe informar al usuario en la pantalla del dispositivo POS.

**Desktop (HTTP):**

:::BlockQuote
curl -X POST http\://localhost:8484/api/v1/display \\
&#x20; -H "Content-Type: application/json" \\
&#x20; -d '\{
&#x20;   "status": "success",
&#x20;   "title": "Pago Aprobado",
&#x20;   "total": 15.00,
&#x20;   "currency": "ARS",
&#x20;   "text": "ID: kS6D18unD",
&#x20;   "timeout": 10
&#x20; }'
:::

**Android (SDK):**

:::BlockQuote
sdconn.display(DisplayRequest(
&#x20;   status = "success",   *// o el código numérico de status.code*
&#x20;   title = "Pago Aprobado",
&#x20;   total = 15.00,
&#x20;   currency = "ARS",
&#x20;   text = "ID: kS6D18unD",
&#x20;   timeout = 10
))
:::

Se puede enviar directamente el status.code de la respuesta del procesador y el dispositivo lo resuelve automáticamente a la animación correspondiente:

| Códigos                      | Animación                           |
| ---------------------------- | ----------------------------------- |
| 3, 4, 200, 300-302, 605, 800 | Círculo verde con check (success)   |
| 400-417, 500, 603, 604       | Círculo rojo con X (error)          |
| 1, 2, 100, 210, 600-602, 610 | Círculo naranja con reloj (neutral) |

## Devoluciones (Refunds)

Para realizar devoluciones de operaciones procesadas se requiere generar un nuevo Intent Token de devolución.

**Endpoint:** POST https\://api.mobbex.com/p/pos/physical/&#x7B;uid}/refund

| Parámetro | Ubicación | Descripción                         |
| --------- | --------- | ----------------------------------- |
| uid       | URL path  | ID del cupón/transacción a devolver |

**Headers:**

| Header        | Valor                 | Descripción                                                           |
| ------------- | --------------------- | --------------------------------------------------------------------- |
| api-key       | tu\_api\_key\_privada | Clave privada de la entidad                                           |
| x-suga-entity | entity\_uid           | UID de la entidad (debe coincidir con submerchant.reference original) |

**Cuerpo (opcional):**

:::BlockQuote
\{
&#x20; "total": 5.00
}
:::

| Campo | Tipo   | Requerido | Descripción                                                               |
| ----- | ------ | --------- | ------------------------------------------------------------------------- |
| total | number | No        | Monto para devolución parcial. Omitir para devolución total / cancelación |

**Respuesta:**

:::BlockQuote
\{
&#x20; "intent": \{
&#x20;   "token": "nuevo-token-para-devolucion"
&#x20; },
&#x20; "requireCard": true
}
:::

Si requireCard es true, se debe leer la tarjeta nuevamente usando este token con SDConn (Paso 3) y luego procesar la devolución (Paso 4).

## Diagramas de flujo completo

### Flujo con token generado por SDConn (más simple)

```mermaid
sequenceDiagram
    participant App as Tu App
    participant SC as SDConn
    participant POS as Dispositivo POS
    participant API as API Mobbex

    App->>SC: read(total: 15.00, currency: "ARS")

    rect rgb(240, 248, 255)
        Note over SC,POS: Obtener info del dispositivo
        SC->>POS: GET /device/info
        POS-->>SC: { serialNumber, model, ... }
        SC->>POS: GET /device/location
        POS-->>SC: { latitude, longitude }
    end

    rect rgb(255, 248, 240)
        Note over SC,API: Generar Intent Token
        SC->>API: POST /p/pos/physical<br/>{ total, serialNumber, geolocation }
        API-->>SC: { intent.token }
    end

    rect rgb(240, 255, 240)
        Note over SC,POS: Lectura de tarjeta
        SC->>POS: READ_CARD { token }
        Note over POS: Usuario pasa/inserta tarjeta
        POS-->>SC: { sourceData }
    end

    SC-->>App: { result: true, intentToken, sourceData }

    rect rgb(248, 240, 255)
        Note over App,API: Procesamiento
        App->>API: POST /p/operations/{token}<br/>{ source: { ...sourceData } }
        API-->>App: { id, status: { code: "200", text: "Aprobado" } }
    end

    rect rgb(245, 245, 245)
        Note over App,POS: Mostrar resultado
        App->>SC: display(status: "200", title: "Aprobado")
        SC->>POS: DISPLAY_RESULT
        Note over POS: Pantalla verde ✓
    end
```

### Flujo con token externo (control total desde tu backend)

```mermaid
sequenceDiagram
    participant App as Tu App
    participant Back as Tu Backend
    participant SC as SDConn
    participant POS as Dispositivo POS
    participant API as API Mobbex

    rect rgb(255, 248, 240)
        Note over App,API: 1. Backend genera Intent Token
        App->>Back: Iniciar pago (total: 15.00)
        Back->>API: POST /p/pos/physical<br/>{ total, serialNumber, geolocation }
        API-->>Back: { intent.token }
        Back-->>App: intentToken
    end

    App->>SC: read(total: 15.00, intentToken: "token")

    rect rgb(240, 248, 255)
        Note over SC,POS: 2. Obtener info del dispositivo
        SC->>POS: GET /device/info
        POS-->>SC: { serialNumber, model, ... }
        SC->>POS: GET /device/location
        POS-->>SC: { latitude, longitude }
    end

    Note over SC: NO llama a API Mobbex<br/>(usa token externo)

    rect rgb(240, 255, 240)
        Note over SC,POS: 3. Lectura de tarjeta
        SC->>POS: READ_CARD { token }
        Note over POS: Usuario pasa/inserta tarjeta
        POS-->>SC: { sourceData }
    end

    SC-->>App: { result: true, intentToken, geolocation, sourceData }

    rect rgb(248, 240, 255)
        Note over App,API: 4. Procesamiento
        App->>Back: sourceData + geolocation
        Back->>API: POST /p/operations/{token}<br/>{ source: { ...sourceData } }
        API-->>Back: { id, status: { code: "200" } }
        Back-->>App: resultado
    end

    rect rgb(245, 245, 245)
        Note over App,POS: 5. Mostrar resultado
        App->>SC: display(status: "200", title: "Aprobado")
        SC->>POS: DISPLAY_RESULT
        Note over POS: Pantalla verde ✓
    end
```

### Flujo con Detección de Cuotas

```mermaid
sequenceDiagram
    participant App as Tu App
    participant Back as Tu Backend
    participant SC as SDConn
    participant POS as Dispositivo POS
    participant API as API Mobbex

    rect rgb(255, 248, 240)
        Note over Back,API: 1. Generar Intent Token
        Back->>API: POST /p/pos/physical
        API-->>Back: { intent.token }
    end

    rect rgb(240, 255, 240)
        Note over App,POS: 2. Leer tarjeta
        App->>SC: read(total: 500, intentToken: "token")
        SC->>POS: GET /device/info + location
        POS-->>SC: info + location
        SC->>POS: READ_CARD { token }
        Note over POS: Usuario pasa tarjeta
        POS-->>SC: { sourceData }
        SC-->>App: { sourceData, intentToken, geolocation }
    end

    rect rgb(255, 243, 224)
        Note over App,API: 3. Detectar tarjeta y cuotas
        App->>API: POST /p/sources/detect/{token}<br/>{ type: "card", data: { bin: "451700" },<br/>options: { installments: true } }
        API-->>App: { source: "visa", installments: [...] }
        Note over App: Usuario elige plan:<br/>"3 Cuotas" → reference: "3"
    end

    rect rgb(248, 240, 255)
        Note over App,API: 4. Procesar con cuotas
        App->>API: POST /p/operations/{token}<br/>{ source: { ...sourceData },<br/>installment: "3" }
        API-->>App: { status: { code: "200", text: "Aprobado" } }
    end

    rect rgb(245, 245, 245)
        Note over App,POS: 5. Mostrar resultado
        App->>SC: display(status: "200")
        SC->>POS: DISPLAY_RESULT ✓
    end
```

### Flujo de Devolución

```mermaid
sequenceDiagram
    participant App as Tu App
    participant Back as Tu Backend
    participant SC as SDConn
    participant POS as Dispositivo POS
    participant API as API Mobbex

    rect rgb(255, 240, 240)
        Note over Back,API: 1. Solicitar devolución
        Back->>API: POST /p/pos/physical/{uid}/refund<br/>Headers: api-key, x-suga-entity<br/>Body: { total: 5.00 } (parcial, opcional)
        API-->>Back: { intent.token, requireCard: true }
    end

    alt requireCard = true
        rect rgb(240, 255, 240)
            Note over App,POS: 2. Leer tarjeta para devolución
            App->>SC: read(total: 5.00, intentToken: "refund-token")
            SC->>POS: READ_CARD { refund-token }
            Note over POS: Usuario pasa tarjeta
            POS-->>SC: { sourceData }
            SC-->>App: { sourceData, intentToken }
        end

        rect rgb(248, 240, 255)
            Note over Back,API: 3. Procesar devolución
            Back->>API: POST /p/operations/{refund-token}<br/>{ source: { ...sourceData } }
            API-->>Back: { status: { code: "200" } }
        end
    end

    rect rgb(245, 245, 245)
        Note over App,POS: 4. Mostrar resultado
        App->>SC: display(status: "200", title: "Devolución OK")
        SC->>POS: DISPLAY_RESULT ✓
    end
```

## Ejemplo completo paso a paso

### Ejemplo 1: Flujo simple con SDConn Desktop

:::BlockQuote
*# 1. Leer tarjeta (SDConn genera el token automáticamente)*
RESPONSE=$(curl -s -X POST http\://localhost:8484/api/v1/read \\
&#x20; -H "Content-Type: application/json" \\
&#x20; -d '\{
&#x20;   "total": 150.00,
&#x20;   "currency": "ARS",
&#x20;   "test": true
&#x20; }')

echo $RESPONSE
*# \{*
*#   "result": true,*
*#   "intentToken": "620198a7-291e-4bde-9248-43b34d59e8c9",*
*#   "sourceData": \{*
*#     "pin": "D4F2A1...",*
*#     "emvData": "9F26089C4A...",*
*#     "cryptogram": "ARQC...",*
*#     "ksn": "FFFF9876...",*
*#     "track2": "4517001234..."*
*#   }*
*# }*

*# 2. Extraer intentToken y sourceData*
TOKEN=$(echo $RESPONSE | jq -r '.intentToken')
SOURCE=$(echo $RESPONSE | jq '.sourceData')

*# 3. Procesar el pago contra la API*
RESULT=$(curl -s -X POST "https\://api.mobbex.com/p/operations/$TOKEN" \\
&#x20; -H "Content-Type: application/json" \\
&#x20; -d "\{
&#x20;   \\"source\\": $SOURCE,
&#x20;   \\"installmentCount\\": 1
&#x20; }")

echo $RESULT
*# \{*
*#   "result": true,*
*#   "data": \{*
*#     "id": "kS6D18unD",*
*#     "status": \{ "code": "200", "text": "Aprobado", "message": "Transacción Aprobada" }*
*#   }*
*# }*

*# 4. Mostrar resultado en el dispositivo*
STATUS\_CODE=$(echo $RESULT | jq -r '.data.status.code')
curl -X POST http\://localhost:8484/api/v1/display \\
&#x20; -H "Content-Type: application/json" \\
&#x20; -d "\{
&#x20;   \\"status\\": $STATUS\_CODE,
&#x20;   \\"title\\": \\"Pago Aprobado\\",
&#x20;   \\"total\\": 150.00,
&#x20;   \\"currency\\": \\"ARS\\",
&#x20;   \\"text\\": \\"ID: kS6D18unD\\",
&#x20;   \\"timeout\\": 10
&#x20; }"
:::

### Ejemplo 2: Flujo con token externo en Android

:::BlockQuote
*// 1. Tu backend genera el intent token*
val intentToken = tuBackend.crearIntentToken(total = 150.00, currency = "ARS")

*// 2. Leer tarjeta con el token externo*
val readResult = sdconn.read(ReadRequest(
&#x20;   total = 150.00,
&#x20;   currency = "ARS",
&#x20;   intentToken = intentToken   *// Token externo → no llama a API Mobbex*
))

if (!readResult.result) \{
&#x20;   Log.e("Pago", "Error en lectura: $&#x7B;readResult.error}")
&#x20;   return
}

*// 3. readResult contiene:*
*//    - readResult.sourceData   → datos encriptados de la tarjeta*
*//    - readResult.intentToken  → mismo token enviado*
*//    - readResult.geolocation  → \[lat, lng] del dispositivo*

*// 4. Enviar sourceData a tu backend para procesar*
val processingResult = tuBackend.procesarPago(
&#x20;   intentToken = readResult.intentToken!!,
&#x20;   source = readResult.sourceData!!,       *// va dentro de "source": \{ ...sourceData }*
&#x20;   geolocation = readResult.geolocation,
&#x20;   installmentCount = 1
)

*// 5. Mostrar resultado en el dispositivo*
sdconn.display(DisplayRequest(
&#x20;   status = processingResult.statusCode,   *// "200", "400", etc.*
&#x20;   title = processingResult.message,
&#x20;   total = 150.00,
&#x20;   currency = "ARS",
&#x20;   timeout = 10
))
:::

### Ejemplo 3: Flujo con detección de cuotas

:::BlockQuote
*// 1. Generar intent token desde tu backend*
val intentToken = tuBackend.crearIntentToken(total = 500.00)

*// 2. Leer tarjeta*
val readResult = sdconn.read(ReadRequest(
&#x20;   total = 500.00,
&#x20;   intentToken = intentToken
))

*// 3. Detectar tarjeta y obtener cuotas (llamada desde tu app/backend)*
*// POST https\://api.mobbex.com/p/sources/detect/&#x7B;intentToken}*
*// \{ "type": "card", "data": \{ "bin": primeros6digitosDelTrack2 }, "options": \{ "installments": true } }*
val cuotas = tuBackend.detectarCuotas(intentToken, bin = "451700")

*// 4. Mostrar planes al usuario y obtener selección*
val planElegido = mostrarSelectorCuotas(cuotas)  *// ej: "3", "6", "ahora\_12"*

*// 5. Procesar con el plan elegido*
*// POST https\://api.mobbex.com/p/operations/&#x7B;intentToken}*
*// \{ "source": \{ ...sourceData }, "installment": "3" }*
val resultado = tuBackend.procesarPago(
&#x20;   intentToken = intentToken,
&#x20;   source = readResult.sourceData!!,
&#x20;   installment = planElegido   *// referencia del plan seleccionado*
)

*// 6. Mostrar resultado*
sdconn.display(DisplayRequest(
&#x20;   status = resultado.statusCode,
&#x20;   title = if (resultado.aprobado) "Pago Aprobado" else "Rechazado",
&#x20;   total = 500.00,
&#x20;   timeout = 10
))
:::

## Resumen de endpoints

| Paso          | Método | URL                                                                          | Responsable  |
| ------------- | ------ | ---------------------------------------------------------------------------- | ------------ |
| Intent Token  | POST   | https\://api.mobbex.com/p/pos/physical                                       | API / SDConn |
| Detección     | POST   | https\://api.mobbex.com/p/sources/detect/&#x7B;token}                        | API          |
| Lectura       | POST   | http\://localhost:8484/api/v1/read (Desktop) / sdconn.read() (Android)       | SDConn       |
| Procesamiento | POST   | https\://api.mobbex.com/p/operations/&#x7B;token}                            | API          |
| Display       | POST   | http\://localhost:8484/api/v1/display (Desktop) / sdconn.display() (Android) | SDConn       |
| Devolución    | POST   | https\://api.mobbex.com/p/pos/physical/&#x7B;uid}/refund                     | API          |

##

