POST /v1/stores. Algunos
restaurantes ya usan Listo con una cuenta propia: su propia consola, su propio
saldo, su propio historial de envíos. Para uno de esos no creas una tienda. Le
pides a su dueño que conecte la cuenta que ya tiene, la aprueba en una página de
Listo y tú recibes la tienda.
En el camino no se crea nada. Lo que terminas teniendo es una tienda común y
corriente, y todos los demás endpoints la tratan exactamente igual que a una que
tú creaste.
Crear o conectar
owner_email en POST /v1/stores es como sabes cuál de las dos cosas vas a
hacer. Es una comprobación, no un campo de la tienda: mandas la dirección de
quien lleva el local y, antes de escribir nada, Listo revisa si esa dirección ya
tiene acceso a la cuenta propia de algún restaurante en Listo.
- No hay ninguna. La tienda se crea, y de ahí el camino es el de siempre:
ajusta su
access_tier(ve el modelo de dinero) y, si alguien del restaurante va a entrar, dale un acceso. - Hay una. La creación responde
409 account_existsy no se crea nada. Una segunda cuenta para una misma cocina partiría en dos su saldo, su consola y su historial. Ese409es la puerta de entrada a esta página.
Primero registra tu URI de redirección
Cuando el dueño decide, Listo manda su navegador de regreso contigo, y solo a una dirección que tú registraste. Agrega tu callback en la página URIs de redirección del panel de socios antes de tu primera petición.- Se compara la cadena completa. Registra la URL completa de tu callback, no
solo el origen. No hay comodines ni prefijos, así que
https://partner.example.com/listo/callbackno permite tambiénhttps://partner.example.com/listo/callback/done. - Tiene que ser
https://, excepto enlocalhosty127.0.0.1, donde se permitehttp://para que puedas desarrollar en tu propia máquina. - La lista es de tu empresa, no de un modo, así que no cambia cuando cambias entre real y prueba en el panel. Registra tu callback de producción y el que usas para desarrollar.
- Una dirección que no está en la lista se rechaza cuando pides el enlace,
con
422 validation_failedyparam: "redirect_uri". Falla en tu propio servidor, antes de que a cualquier restaurante se le muestre nada.
Pide el enlace
POST /v1/connect_requests
recibe la dirección del dueño, una de tus URIs de redirección registradas y, si
quieres, un state propio:
201 con un enlace y una fecha límite:
state es tuyo: cualquier valor de hasta 255 caracteres, que Listo nunca lee y
te regresa intacto. Es como amarras el navegador que regresa con la sesión que
salió.
connect_request.rb
Qué ve el dueño
Manda el navegador del dueño aurl, con una redirección, un enlace o un botón
en tu producto. Todo lo que sigue pasa en Listo. Esto es lo que lee, con las
palabras de su pantalla, para que tú y el restaurante estén viendo las mismas
frases si te llama.
El inicio de sesión. A menos que ese navegador ya tenga abierta su sesión en
la consola de Listo, llega a una página titulada “Conecta tu cuenta”, que dice
“Inicia sesión para conectar su restaurante con tu empresa”. Escribe el
correo y la contraseña que ya usa en Listo y presiona Iniciar sesión y continuar.
Aquí no hay registro: la única otra salida de la página es “¿Sin cuenta de
Listo? Regresa a tu empresa”, que lo trae de regreso contigo con
error=access_denied.
La pantalla de consentimiento. Se titula “Tu empresa quiere conectar con
tu cuenta” y dice “Autoriza la conexión para que tu empresa envíe y administre
entregas con tu cuenta de Listo.” Muestra su restaurante y la dirección con la
que entró, y después lo que está otorgando, bajo “Al conectar, tu empresa
podrá:”
- Crear entregas a nombre de tu negocio
- Ver tus entregas y su estado
- Consultar tu saldo de entregas
El navegador regresa
Cuando el dueño decide, Listo manda su navegador a turedirect_uri:
error=access_denied significa que no se conectó nada y que ese enlace ya
terminó, ya sea que el dueño haya presionado Cancelar en la pantalla de
consentimiento, se haya regresado desde la página de inicio de sesión o haya
abierto un enlace que ya no era válido. No se puede reabrir, así que si el dueño
cambia de opinión, pide uno nuevo. Si el dueño vuelve a abrir un enlace que ya
aprobó, su navegador regresa contigo con el mismo code otra vez; canjearlo dos
veces es seguro.
Listo no le manda ningún correo al dueño por esto, apruebe o cancele. Si quieres
confirmarle la conexión, ese mensaje te toca a ti.
state regresa exactamente como lo mandaste, en los dos casos. Compáralo con el
valor que guardaste para esa sesión antes de actuar sobre la redirección, e
ignora una cuyo state no reconozcas: es tu protección contra un callback
falsificado. Si no mandaste state, no regresa ninguno. Si la URI que
registraste ya trae parámetros propios, estos se le agregan.
El webhook no espera al navegador
Cuando el dueño aprueba, un eventostore.connected va a tu endpoint de
webhooks real, y data es el objeto de tienda completo, id incluido. No
depende del navegador del dueño, así que puede llegarte antes que la redirección,
y te sigue llegando cuando la redirección nunca llega: un dueño puede aprobar en
el teléfono y cerrar la pestaña antes de que su navegador regrese contigo.
Da la tienda por conectada cuando te llegue cualquiera de los dos, lo que llegue
primero, y deduplica por el id del evento como con todos los eventos. Cómo
configurar el endpoint está en recibe webhooks.
Canjea el código
POST /v1/connections recibe el
code de la redirección:
201 con el objeto de tienda, exactamente la forma que regresa
POST /v1/stores, con el id st_... incluido. A partir de ahí es una tienda
común en todos los demás endpoints.
El canje responde con una tienda, y un restaurante con varias sucursales
llega como varias tiendas. Las demás llegan como sus propios eventos
store.connected y están en GET /v1/stores, así que arma tu lista de tiendas
conectadas con eso, nunca solo con el canje.
exchange_connection.rb
400 code_expired, pero la conexión en sí ocurrió
cuando el dueño aprobó: la tienda está en GET /v1/stores y su
store.connected se mandó en ese momento, así que tómala de ahí. No inicies una
nueva solicitud de conexión para ella, porque la cuenta ya está conectada.
Canjear un código por segunda vez regresa la misma tienda. No hay un rechazo
de “ya usado”, así que un canje cuya respuesta nunca te llegó simplemente se
repite. Solo tu llave puede canjear tus códigos: cualquier otra recibe
404 not_found por uno.
Qué es una tienda conectada
- Está en
access_tier: "full"ybilling: "store". El restaurante conserva toda su consola, su saldo y su historial, y los envíos que creas para él se pagan de su propio saldo, como decía su pantalla de consentimiento. Los pedidos que despacha desde su propia consola te llegan como cualquier otro; ve de dónde viene un envío. - Desde la siguiente renovación del restaurante, su Plan Listo se te cobra a
ti. Hasta entonces sigue pagando su propio plan, y nada se cobra dos veces.
Si no tenía un plan vigente, el plan empieza el día en que se conecta y ese mes
se te cobra ese mismo día. Si su plan está sin pagar cuando se conecta, tu plan
también empieza ese día: el mes que no había pagado se anula, así que no se le
cobra a nadie, y ese mismo día se te cobra un mes completo. El bloque
plande la tienda dice cuál es; ve plan y cobro. Si tu acuerdo hace que cada restaurante pague su propio plan, nada de esto aplica: el restaurante sigue pagando su propio plan, nada pasa a ti y no se te cobra nada; ve cuando cada restaurante paga su propio plan. - Todas las sucursales se conectan a la vez. El dueño da su consentimiento
por la cuenta, no por un local, y nada en el flujo pregunta por sucursales. Un
restaurante con tres sucursales se vuelve tres tiendas, cada una con su propio
id
st_...: el canje responde con una de ellas, cada una de las tres manda su propiostore.connected, y todas están enGET /v1/storesdesde ese momento. Un canje no significa una sola tienda. Cada una lleva el nombre del negocio y de la sucursal,Tortería La Mera Mera, Zapopan, así que tu lista sigue leyéndose como un solo restaurante. Una sucursal cuyo nombre ya empieza con el del negocio, comoTortería La Mera Mera Centro, se publica tal cual. - No tiene
external_id, porque nunca mandaste uno. Ponle uno conPATCH /v1/stores/{id}si identificas tus tiendas con tus propios ids. - Conectar no es transferir. Una cuenta que ya está conectada, contigo o con cualquier otro, no se puede volver a conectar, y esta API no tiene forma de mover una tienda de un socio a otro. Es a propósito: el restaurante cuyo saldo paga tendría que estar de acuerdo.
Cuándo se rechaza
Los dos rechazos de
owner_email comparten código, y error.message los
distingue para quien lea tus logs. Ramifica según el código, y muéstrale el
mensaje a la persona que está configurando la conexión.