Tucan Orders API - Documentación (1.0.0)

Download OpenAPI specification:Download

Tucan Development Team: integraciones@tucan.la URL: https://tucan.la License: MIT License

📚 Documentación de la API

Esta documentación cubre los endpoints de la API de órdenes y autenticación.

🔒 Autenticación

  • JWT: Para endpoints de autenticación y gestión de tokens

📊 Endpoints Disponibles

  • Orders: Gestión de órdenes
  • Auth: Autenticación y gestión de tokens
  • Health: Monitoreo y estado del servicio

📖 Uso

  1. Autenticarse con tu JWT
  2. Usar los endpoints según tu rol
  3. Respuestas en formato JSON estándar

1. Authentication

Endpoints para autenticación y gestión de tokens JWT

Renovar tokens de acceso

Renueva un access token usando un refresh token válido. Solo requiere el refresh token en el body — no es necesario el header Authorization. Devuelve un nuevo access token y un nuevo refresh token. El refresh token se obtiene del endpoint de login y tiene una duración de 7 días. El refresh token solo puede usarse en este endpoint; intentar usarlo en otros endpoints devuelve 401.

Authorizations:
BearerAuth
Request Body schema: application/json
required
refreshToken
required
string

Responses

Request samples

Content type
application/json
{
  • "refreshToken": "string"
}

Response samples

Content type
*/*

Refresh exitoso

{
  "success": true,
  "data": {
    "access_token": "eyJhbGciOiJIUzI1NiJ9...",
    "refresh_token": "eyJhbGciOiJIUzI1NiJ9...",
    "token_type": "Bearer",
    "expires_in": 86400,
    "user_id": 12345,
    "email": "usuario@tucan.la",
    "user_type": "ADMIN"
  },
  "message": "Token refreshed successfully",
  "code": "OK"
}

Autenticación de usuario

Autentica un usuario con email y contraseña contra el servicio centralizado de usuarios, devolviendo un access token JWT y un refresh token para renovación automática. El access token debe incluirse en el header Authorization como 'Bearer {token}' para las siguientes requests. El refresh token se usa para renovar el access token cuando esté próximo a expirar.

Authorizations:
BearerAuth
Request Body schema: application/json
required
email
required
string

Email del usuario para autenticación

password
required
string [ 6 .. 2147483647 ] characters

Contraseña del usuario (mínimo 6 caracteres)

Responses

Request samples

Content type
application/json
{
  • "email": "usuario@tucan.la",
  • "password": "miPassword123"
}

Response samples

Content type
*/*

Login exitoso

{
  "success": true,
  "data": {
    "access_token": "eyJhbGciOiJIUzI1NiJ9...",
    "refresh_token": "eyJhbGciOiJIUzI1NiJ9...",
    "token_type": "Bearer",
    "expires_in": 86400,
    "user_id": 12345,
    "email": "usuario@tucan.la",
    "user_type": "ADMIN"
  },
  "message": "Authentication successful",
  "code": "OK"
}

2. Menu

Endpoints para consulta y actualización de menús

Obtener menú por ID

Retorna la estructura completa del menú: categorías, ítems con sus tamaños y grupos de extras. Cada ítem, extra y tamaño incluye el campo externalReferenceId con el ID del sistema POS externo.

Authorizations:
BearerAuth
path Parameters
menuId
required
integer <int64>

ID del menú

Responses

Response samples

Content type
*/*

Menú con categorías e ítems

{
  "success": true,
  "data": {
    "id": 492,
    "name": "Menu Integración",
    "categories": [
      {
        "id": 2816,
        "name": "Entradas",
        "order": 16,
        "visibleInMenu": true,
        "withImage": false,
        "showName": "Entradas",
        "items": [
          {
            "id": 19605,
            "externalReferenceId": "425",
            "name": "Provoleta de la casa a la leña",
            "description": "Provolone asado a la leña, cherrys confitados y rúcula.",
            "order": 0,
            "isVisibleInMenu": true,
            "withImage": true,
            "showName": "Provoleta de la casa a la leña",
            "maxQuantity": null,
            "isCombo": false,
            "discountedPrice": null,
            "imageUrl": "https://sandbox.images.tucan.la/media/78/images/plates/19605",
            "sizes": [
              {
                "id": 20199,
                "externalReferenceId": "425",
                "name": "Único",
                "price": 17650,
                "discountedPrice": null,
                "isVisibleInMenu": true
              }
            ],
            "extraGroups": [
              {
                "id": 1021,
                "name": "Acompañamientos",
                "minAmount": 0,
                "maxAmount": 2,
                "mandatory": false,
                "multipleSelection": true,
                "order": 1,
                "extras": [
                  {
                    "id": 4412,
                    "externalReferenceId": "101",
                    "name": "Papas fritas",
                    "price": 2500,
                    "description": null,
                    "visible": true
                  },
                  {
                    "id": 4413,
                    "externalReferenceId": "102",
                    "name": "Ensalada mixta",
                    "price": 1800,
                    "description": null,
                    "visible": true
                  }
                ]
              }
            ]
          }
        ]
      }
    ]
  },
  "message": "Menu retrieved successfully",
  "code": "OK"
}

Actualizar menú

Sincroniza la estructura del menú indicado: categorías, ítems, tamaños y grupos de extras. El campo storeId corresponde al ID del BranchContact (no del Branch). Los ítems raíz son tratados como productos (PRODUCT). Los toppings van en el campo extras del ítem padre y requieren maxLimit.

Procesamiento asincrónico: la respuesta es inmediata (HTTP 202 Accepted) y devuelve un trackingId; el menú se aplica en segundo plano (recomendado para menús grandes, evita timeouts). La validación de estructura del request sí es inmediata (400 si es inválida). Para conocer el resultado final de la sincronización, consultá GET /api/v1/menu/sync/{trackingId}.

Authorizations:
BearerAuth
path Parameters
menuId
required
integer <int64>

ID del menú a actualizar

header Parameters
Authorization
required
string
Request Body schema: application/json
required
storeId
string
required
Array of objects (V1MenuItemDTO)
menuId
string
storeIdOrMenuIdProvided
boolean

Responses

Request samples

Content type
application/json

Menú con producto y toppings

{
  • "storeId": "254",
  • "items": [
    ]
}

Response samples

Content type
*/*
{
  "success": true,
  "data": {
    "status": "success",
    "message": "Menú recibido y en proceso de sincronización",
    "trackingId": "3b1d2fd7-52ba-4714-ae56-3cd5adf2d397"
  },
  "message": "Menú recibido y en proceso de sincronización",
  "code": "OK"
}

Listar menús

Retorna los menús activos del branch asociado al usuario autenticado.

Authorizations:
BearerAuth
query Parameters
branchId
integer <int64>
page
integer <int32>
Default: 0
size
integer <int32>
Default: 50

Responses

Response samples

Content type
*/*

Lista de menús

{
  "success": true,
  "data": [
    {
      "id": 492,
      "name": "Menu Integración",
      "branchId": 78
    }
  ],
  "message": "Menus retrieved successfully",
  "code": "OK"
}

Estado de sincronización de menú

Devuelve el estado del sync async iniciado por PUT /api/v1/menu/{menuId}, identificado por el trackingId que devolvió esa llamada. Estados posibles: PENDING (encolado), PROCESSING (aplicándose), DONE (aplicado OK), FAILED (falló — ver el mensaje de error).

Authorizations:
BearerAuth
path Parameters
trackingId
required
string

trackingId devuelto por PUT /api/v1/menu/{menuId}

Responses

Response samples

Content type
*/*
{
  "success": true,
  "data": {
    "syncId": "3b1d2fd7-52ba-4714-ae56-3cd5adf2d397",
    "status": "DONE",
    "menuId": "492",
    "attempts": 1,
    "errorMessage": null,
    "updatedAt": "2026-06-14T16:21:24Z"
  },
  "message": "Sync status retrieved",
  "code": "OK"
}

3. Orders

Endpoints para gestión de órdenes internas

Obtener órdenes

Obtiene todas las órdenes con paginación y filtros opcionales por estado, cliente y tienda. Los resultados se filtran automáticamente por la compañía del usuario autenticado. El parámetro size debe estar entre 1 y 100. El parámetro status acepta únicamente los valores indicados — si se envía un valor inválido se retorna 400.

Authorizations:
BearerAuth
query Parameters
page
integer <int32> >= 0
Default: 0

Número de página (0-based)

size
integer <int32> [ 1 .. 100 ]
Default: 20
Example: size=20

Tamaño de la página (entre 1 y 100)

status
string
Enum: "UNCONFIRMED" "GENERATED" "ACCEPTED" "READY" "DELIVERED" "CANCELED"
Example: status=ACCEPTED

Filtrar por estado de la orden. Case-insensitive.

customerId
string
Example: customerId=12345

ID del cliente para filtrar

store_id
integer <int64>
Example: store_id=254

ID de la tienda

Responses

Response samples

Content type
*/*

Respuesta exitosa

{
  "success": true,
  "data": [
    {
      "order_detail": {
        "order_id": "15672",
        "code": "VZS3E",
        "status": "ACCEPTED",
        "delivery_method": "TAKEAWAY",
        "cooking_time": 25,
        "created_at": "2024-01-15T10:30:00.000Z",
        "payment_method": "EF",
        "items": [
          {
            "sku": "425",
            "id": "425",
            "external_id": "19605",
            "name": "Provoleta de la casa a la leña",
            "price": 17650,
            "quantity": 1,
            "subitems": []
          }
        ],
        "totals": {
          "total_products": 17650,
          "total_discounts": 0,
          "total_order": 17650,
          "charges": {}
        },
        "discounts": [],
        "delivery_discount": {
          "total_percentage_discount": 0,
          "total_value_discount": 0
        }
      },
      "customer": {
        "first_name": "Juan",
        "phone_number": "+5491112345678",
        "email": "juan@example.com",
        "document_number": ""
      },
      "store": {
        "internal_id": "254",
        "external_id": "sucursal-centro",
        "name": "Sucursal Centro"
      }
    }
  ],
  "message": "Orders retrieved successfully",
  "code": "OK",
  "pagination": {
    "page": 0,
    "size": 20,
    "total_elements": 150,
    "total_pages": 8,
    "has_next": true,
    "has_previous": false
  }
}

Crear orden

Crea una nueva orden en el sistema. El body se procesa sin transformaciones y la respuesta se devuelve tal cual (mismo status code y body). Para órdenes DELIVERY, destination es obligatorio (con lat y lng requeridos), al igual que customerName y phone. lastName es opcional. Los campos name y price de ítems y extras son opcionales: si no se envían, se toman del catálogo según referenceId y sizeId.

Authorizations:
BearerAuth
Request Body schema: application/json
required
type
required
string
Enum: "TAKEAWAY" "DELIVERY" "IN_DINING"

Tipo de orden

paymentType
required
string
Enum: "CASH" "CARD" "NOT_SPECIFIED"

Método de pago

required
object (CreateOrderBranchContactDTO)

Local donde se crea la orden

price
number <double>

Precio total de la orden. Si no se envía, se calcula sumando price * quantity de cada ítem.

required
Array of objects (CreateOrderItemDTO)

Lista de ítems de la orden

customerName
string

Nombre del cliente. Obligatorio para órdenes DELIVERY.

lastName
string

Apellido del cliente.

phone
string

Teléfono del cliente. Obligatorio para órdenes DELIVERY.

customerEmail
string

Email del cliente

notes
string

Aclaraciones generales de la orden

partnerName
string

Nombre del partner que origina la orden

itemsPrice
number <double>

Precio total de ítems sin cargos adicionales

object (CreateOrderDestinationDTO)

Dirección de entrega. Solo requerido para órdenes DELIVERY, ignorado en otros tipos.

Responses

Request samples

Content type
application/json
Example

Mínimo requerido

{
  • "type": "TAKEAWAY",
  • "paymentType": "CASH",
  • "branchContact": {
    },
  • "price": 17650,
  • "items": [
    ]
}

Response samples

Content type
*/*

Orden creada

{
  "id": "15672",
  "code": "TVSKS",
  "type": "TAKEAWAY",
  "price": 4000,
  "paymentType": "CASH",
  "source": "API",
  "status": "GENERATED",
  "customerName": "Juan",
  "phone": "+5491112345678",
  "notes": "sin sal",
  "items": [
    {
      "quantity": 1,
      "name": "Empanada carne",
      "price": 1000,
      "referenceId": 19605,
      "extras": []
    },
    {
      "quantity": 1,
      "name": "Triple empanada",
      "price": 3000,
      "notes": "bien cocida",
      "referenceId": 19606,
      "extras": [
        {
          "groupId": "6202",
          "groupName": "gustos",
          "groupItems": [
            {
              "quantity": 1,
              "name": "queso",
              "price": 0,
              "referenceId": 5475,
              "extras": []
            }
          ]
        }
      ]
    }
  ]
}

Obtener orden por código

Obtiene una orden específica por su código alfanumérico de 5 caracteres (ej: VZS3E). Este código es el campo code devuelto al crear la orden. Es distinto del order_id numérico que aparece en el body de respuesta. Solo devuelve órdenes que pertenezcan al branch del usuario autenticado.

Authorizations:
BearerAuth
path Parameters
orderId
required
string^[A-Z0-9]{5}$
Example: VZS3E

Código alfanumérico de la orden (5 caracteres). Es el campo code devuelto al crear la orden — distinto del order_id numérico.

Responses

Response samples

Content type
*/*

Orden encontrada

{
  "success": true,
  "data": {
    "order_detail": {
      "order_id": "15672",
      "code": "VZS3E",
      "status": "ACCEPTED",
      "delivery_method": "TAKEAWAY",
      "cooking_time": 25,
      "created_at": "2024-01-15T10:30:00.000Z",
      "payment_method": "EF",
      "items": [
        {
          "sku": "425",
          "id": "425",
          "external_id": "19605",
          "name": "Provoleta de la casa a la leña",
          "price": 17650,
          "quantity": 1,
          "subitems": []
        }
      ],
      "totals": {
        "total_products": 17650,
        "total_discounts": 0,
        "total_order": 17650,
        "charges": {}
      },
      "discounts": [],
      "delivery_discount": {
        "total_percentage_discount": 0,
        "total_value_discount": 0
      }
    },
    "customer": {
      "first_name": "Juan",
      "phone_number": "+5491112345678",
      "email": "juan@example.com",
      "document_number": ""
    },
    "store": {
      "internal_id": "254",
      "external_id": "sucursal-centro",
      "name": "Sucursal Centro"
    }
  },
  "message": "Order retrieved successfully",
  "code": "OK"
}

Actualizar estado de orden

Actualiza el estado de una orden específica. Solo se permiten transiciones de estado válidas según el workflow configurado.

Authorizations:
BearerAuth
path Parameters
orderId
required
string^[A-Z0-9]{5}$
Example: VZS3E

Código alfanumérico de la orden (5 caracteres). Es el campo code devuelto al crear la orden — distinto del order_id numérico.

query Parameters
storeId
required
string
Example: storeId=254

ID de la tienda

state
required
string
Enum: "GENERATED" "ACCEPTED" "READY" "DELIVERED" "CANCELED"
Example: state=ACCEPTED

Nuevo estado de la orden

header Parameters
Authorization
required
string

Responses

Response samples

Content type
*/*
{
  "success": false,
  "data": null,
  "message": "Invalid state. Valid states are: GENERATED, ACCEPTED, READY, DELIVERED, CANCELED",
  "code": "INVALID_STATE"
}

Health Check

Verifica el estado de salud de la API de órdenes.

Authorizations:
BearerAuth

Responses

4. Stores

Endpoints para gestión de locales/tiendas de marcas

Obtener locales/tiendas de una marca

Obtiene los locales/tiendas de una marca específica con soporte para filtros, búsqueda y paginación. Cada local expone dos niveles de disponibilidad: 'available_for_order' indica si el local está abierto y aceptando pedidos en este momento (considera horarios, configuración de delivery y estado general); 'order_modes[].order_enabled' indica si esa modalidad específica (Delivery, Takeaway, Salón, etc.) está configurada para recibir pedidos — un local puede estar abierto pero tener ciertas modalidades deshabilitadas. Solo se retornan las modalidades visibles (active=true).

Authorizations:
BearerAuth
path Parameters
id
required
integer <int64>
Example: 78

ID único de la marca

query Parameters
limit
integer <int32>
Default: 20
Example: limit=20

Límite de resultados por página (1-200)

offset
integer <int32>
Default: 0

Desplazamiento para paginación (≥0)

sort
string
Example: sort=name

Campo de ordenamiento. Usar '-' para descendente (ej: -name)

q
string
Example: q=tienda

Término de búsqueda en name o alias (case-insensitive)

Responses

Response samples

Content type
*/*

Locales encontrados

{
  "success": true,
  "data": [
    {
      "id": 254,
      "name": "Sucursal Centro",
      "alias": "sucursalcentro",
      "available_for_order": true,
      "order_modes": [
        {
          "id": 3,
          "show_name": "Delivery",
          "order_enabled": true,
          "menu_id": 492
        },
        {
          "id": 7,
          "show_name": "Takeaway",
          "order_enabled": false,
          "menu_id": 493
        }
      ]
    },
    {
      "id": 255,
      "name": "Sucursal Norte",
      "alias": "sucursalnorte",
      "available_for_order": false,
      "order_modes": []
    }
  ],
  "message": "Branch contacts retrieved successfully",
  "code": "OK",
  "pagination": {
    "page": 0,
    "size": 20,
    "total_elements": 2,
    "total_pages": 1,
    "has_next": false,
    "has_previous": false
  }
}

5. Webhooks

Eventos que Tucan envía a tu servidor cuando cambia el estado de un pedido

Evento: cambio de estado de pedido

Webhook de cambio de estado de pedido

Tucan envía un POST a la URL que hayas configurado como suscriptor cada vez que un pedido cambia de estado.

Estados posibles (order_detail.status)

Estado Descripción
GENERATED Pedido recibido, pendiente de confirmación
ACCEPTED Pedido aceptado por el local
READY Pedido listo para retirar / despachar
DELIVERED Pedido entregado al cliente
CANCELED Pedido cancelado

Configuración

  • URL destino: la URL de tu servidor que recibirá el POST
  • Header de autenticación: podés configurar un header key/value personalizado para que tu servidor verifique que la request proviene de Tucan (ej. X-Webhook-Secret: mi-secreto)

Expectativa de respuesta

Tu servidor debe responder con HTTP 2xx. Si no responde o responde con error, Tucan reintentará el envío.

Authorizations:
BearerAuth
Request Body schema: application/json
required

Payload del evento enviado por Tucan a tu servidor

object

Responses

Request samples

Content type
application/json
Example

Pedido ACCEPTED (con descuento)

{
  • "order_detail": {
    },
  • "customer": {
    },
  • "store": {
    }
}

6. Delivery

Estimación de costos y tiempos de delivery

Estimar costo y tiempo de delivery

Obtiene las estimaciones de costo y tiempo de los proveedores de delivery junto con el tiempo de espera configurado para el local.

Authorizations:
BearerAuth
header Parameters
Authorization
required
string

Bearer token de autenticación

Request Body schema: application/json
required

Datos de la solicitud de estimación

vehicleType
string

Tipo de vehículo: CAR o BIKE

storeId
integer <int32>

ID del local

object (DropOffDTO)

Datos del punto de entrega

isCash
boolean

Indica si el pago es en efectivo

cashAmount
number <double>

Monto en efectivo (requerido si isCash es true)

roundTrip
boolean

Indica si el envío es de ida y vuelta

object (PackageDTO)

Información del paquete a enviar

longDistance
boolean

Indica si es un envío de larga distancia

Responses

Request samples

Content type
application/json

Estimación con BIKE

{
  • "vehicleType": "BIKE",
  • "storeId": 1,
  • "dropOff": {
    },
  • "isCash": false
}

Response samples

Content type
*/*

Estimación exitosa

{
  "success": true,
  "data": {
    "estimations": [
      {
        "success": true,
        "provider": "CABIFY",
        "price": 5.59,
        "currency": "ARS"
      },
      {
        "success": true,
        "provider": "RAPPI",
        "price": 6615,
        "currency": "ARS"
      },
      {
        "success": false,
        "provider": "OWN_FLEET",
        "error": "Could not get rate for provider: OWN_FLEET"
      }
    ],
    "minDelayInMinutes": 20,
    "maxDelayInMinutes": 40
  },
  "message": "Estimations retrieved successfully",
  "code": "OK"
}

7. Payments

Endpoints para gestión de pagos

Callback de confirmación de pago

Recibe la notificación de un partner externo sobre el resultado de un pago y actualiza el estado de la orden.

Flujo:

  1. El partner externo procesa su checkout
  2. El partner llama a este endpoint incluyendo from en el body
  3. El sistema procesa la notificación
  4. Se actualiza el estado de la orden (UNCONFIRMED → GENERATED/ACCEPTED)

Campos del body:

  • from — identificador del medio de pago (ej: "MORFY"). Requerido para routing correcto.
  • type — tipo de entidad. Opcional; ORDER es el valor por defecto para la mayoría de los providers. Usar CURRENT_ACCOUNT, CAMPAIGN u otros según el caso.
  • Campos específicos del provider (ej: orderId, status para MORFY)

Estados soportados (campo status, varía por provider):

  • PAID → confirma el pago, la orden pasa de UNCONFIRMED a GENERATED (o ACCEPTED)
  • REFUNDED → registra el reembolso (solo si la orden ya estaba pagada)
  • CANCELLED → registra la cancelación (solo si la orden ya estaba pagada)
  • PROCESSING → informativo, no genera cambio de estado

Backwards compat: from y type también se pueden enviar como query params.

Authorizations:
BearerAuth
Request Body schema: application/json
required
Schema not provided

Responses

Request samples

Content type
application/json
Example

Pago confirmado

{
  • "from": "MORFY",
  • "orderId": "12345",
  • "status": "PAID"
}