curl --request POST \
--url https://api.listo.delivery/v1/connect_requests \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"owner_email": "rosa@lataqueria.mx",
"redirect_uri": "https://partner.example.com/listo/callback",
"state": "sess-8f21"
}
'import requests
url = "https://api.listo.delivery/v1/connect_requests"
payload = {
"owner_email": "rosa@lataqueria.mx",
"redirect_uri": "https://partner.example.com/listo/callback",
"state": "sess-8f21"
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
owner_email: 'rosa@lataqueria.mx',
redirect_uri: 'https://partner.example.com/listo/callback',
state: 'sess-8f21'
})
};
fetch('https://api.listo.delivery/v1/connect_requests', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.listo.delivery/v1/connect_requests",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'owner_email' => 'rosa@lataqueria.mx',
'redirect_uri' => 'https://partner.example.com/listo/callback',
'state' => 'sess-8f21'
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.listo.delivery/v1/connect_requests"
payload := strings.NewReader("{\n \"owner_email\": \"rosa@lataqueria.mx\",\n \"redirect_uri\": \"https://partner.example.com/listo/callback\",\n \"state\": \"sess-8f21\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.listo.delivery/v1/connect_requests")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"owner_email\": \"rosa@lataqueria.mx\",\n \"redirect_uri\": \"https://partner.example.com/listo/callback\",\n \"state\": \"sess-8f21\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.listo.delivery/v1/connect_requests")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"owner_email\": \"rosa@lataqueria.mx\",\n \"redirect_uri\": \"https://partner.example.com/listo/callback\",\n \"state\": \"sess-8f21\"\n}"
response = http.request(request)
puts response.read_body{
"url": "https://admin.listo.delivery/connect/pcr_6mT4qX8vN2kR7bW1cZ5sLdYe",
"expires_at": "2026-08-10T21:07:29Z"
}{
"error": {
"code": "read_only_key",
"message": "This API key is read-only. Use a key without the read-only setting to create, change or cancel anything.",
"param": null,
"retryable": false,
"doc_url": "https://docs.listo.delivery/en/errors/read_only_key",
"request_id": "0b1f6c9a-7e2d-4c53-9a41-5d8e3f2a6b10"
}
}{
"error": {
"code": "not_found",
"message": "No resource with that id exists for this API key.",
"param": null,
"retryable": false,
"doc_url": "https://docs.listo.delivery/en/errors/not_found",
"request_id": "0b1f6c9a-7e2d-4c53-9a41-5d8e3f2a6b10"
}
}{
"error": {
"code": "validation_failed",
"message": "No Listo account signs in with that email address. Create the store instead.",
"param": "owner_email",
"retryable": false,
"doc_url": "https://docs.listo.delivery/en/errors/validation_failed",
"request_id": "0b1f6c9a-7e2d-4c53-9a41-5d8e3f2a6b10"
}
}Pide a un restaurante que conecte la cuenta que ya tiene en Listo
Inicia el flujo que conecta la cuenta de Listo EXISTENTE de un restaurante contigo, y devuelve el enlace que hay que poner enfrente del dueño.
Envía el correo del dueño y una de las URI de redirección registradas para tu cuenta. Nosotros resolvemos el restaurante por nuestra cuenta y no te decimos nada sobre él: la respuesta es un enlace y una fecha límite, y solo sabes qué cuenta conectaste si el dueño aprueba.
Mándalos a url. Inician sesión con las credenciales de Listo que ya tienen, ven quién lo pide y qué otorga, y aprueban o cancelan. Después mandamos el navegador de regreso a tu redirect_uri:
aprobado ?code=pcc_...&state=... canjea el código en
POST /v1/connections
cancelado ?error=access_denied&state=...
state es tu propio valor opaco, que regresa sin cambios. Úsalo para ligar el navegador que regresa con la sesión que salió; una redirección sin un state que reconozcas es una sobre la que no debes actuar.
El enlace vale 30 minutos. Generar otro no tiene costo, así que trata uno vencido como un botón para volver a mostrar, no como un error que manejar.
Este endpoint es solo para modo real. Una llave de prueba recibe 404: no existe una versión de prueba de la cuenta real de un restaurante real.
curl --request POST \
--url https://api.listo.delivery/v1/connect_requests \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"owner_email": "rosa@lataqueria.mx",
"redirect_uri": "https://partner.example.com/listo/callback",
"state": "sess-8f21"
}
'import requests
url = "https://api.listo.delivery/v1/connect_requests"
payload = {
"owner_email": "rosa@lataqueria.mx",
"redirect_uri": "https://partner.example.com/listo/callback",
"state": "sess-8f21"
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
owner_email: 'rosa@lataqueria.mx',
redirect_uri: 'https://partner.example.com/listo/callback',
state: 'sess-8f21'
})
};
fetch('https://api.listo.delivery/v1/connect_requests', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.listo.delivery/v1/connect_requests",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'owner_email' => 'rosa@lataqueria.mx',
'redirect_uri' => 'https://partner.example.com/listo/callback',
'state' => 'sess-8f21'
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.listo.delivery/v1/connect_requests"
payload := strings.NewReader("{\n \"owner_email\": \"rosa@lataqueria.mx\",\n \"redirect_uri\": \"https://partner.example.com/listo/callback\",\n \"state\": \"sess-8f21\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.listo.delivery/v1/connect_requests")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"owner_email\": \"rosa@lataqueria.mx\",\n \"redirect_uri\": \"https://partner.example.com/listo/callback\",\n \"state\": \"sess-8f21\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.listo.delivery/v1/connect_requests")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"owner_email\": \"rosa@lataqueria.mx\",\n \"redirect_uri\": \"https://partner.example.com/listo/callback\",\n \"state\": \"sess-8f21\"\n}"
response = http.request(request)
puts response.read_body{
"url": "https://admin.listo.delivery/connect/pcr_6mT4qX8vN2kR7bW1cZ5sLdYe",
"expires_at": "2026-08-10T21:07:29Z"
}{
"error": {
"code": "read_only_key",
"message": "This API key is read-only. Use a key without the read-only setting to create, change or cancel anything.",
"param": null,
"retryable": false,
"doc_url": "https://docs.listo.delivery/en/errors/read_only_key",
"request_id": "0b1f6c9a-7e2d-4c53-9a41-5d8e3f2a6b10"
}
}{
"error": {
"code": "not_found",
"message": "No resource with that id exists for this API key.",
"param": null,
"retryable": false,
"doc_url": "https://docs.listo.delivery/en/errors/not_found",
"request_id": "0b1f6c9a-7e2d-4c53-9a41-5d8e3f2a6b10"
}
}{
"error": {
"code": "validation_failed",
"message": "No Listo account signs in with that email address. Create the store instead.",
"param": "owner_email",
"retryable": false,
"doc_url": "https://docs.listo.delivery/en/errors/validation_failed",
"request_id": "0b1f6c9a-7e2d-4c53-9a41-5d8e3f2a6b10"
}
}Autorizaciones
Tu llave de API, enviada como Authorization: Bearer <key>. Las llaves reales y de prueba son distintas; la llave que envías decide en qué modo actúa la llamada. Para probar llamadas, usa una llave de prueba (empieza con lst_test_): no se envía ningún repartidor real y no se mueve dinero real, pero los webhooks se disparan y el dropoff.phone que des puede recibir mensajes de WhatsApp, así que usa tu propio número. Una llave real (empieza con lst_live_) reserva y cobra envíos reales.
Cuerpo
El dueño del restaurante a quien preguntar, y a dónde regresarlo.
El correo de la persona que inicia sesión en la cuenta de Listo del restaurante.
A dónde regresa el navegador del dueño después de aprobar.
Un valor opaco que se devuelve sin cambios a redirect_uri, de hasta 255 caracteres.
255