Integraciones

Crea y gestiona conexiones con bases de datos, servicios de envío de correo, CRM y Google Drive, y úsalas para consultar, enviar, buscar y escribir: son las mismas conexiones que usan el chat, los agentes y los flujos de trabajo.

11 min de lectura · Actualizado el 28 de septiembre de 2026

Las integraciones permiten que StickyPrompts actúe sobre tus propios sistemas. Con la API puedes crear conexiones y usarlas directamente: ejecutar SQL en una base de datos, enviar un correo electrónico, buscar o actualizar datos en un CRM y mover archivos desde y hacia Google Drive. Todo lo que se describe aquí es el mismo mecanismo que usa la aplicación cuando alguien lo pide en el chat.

Todas las rutas son relativas a https://api.stickyprompts.com/api/v1. La clave actúa en nombre de su propietario: se aplican las mismas reglas de compartición y de administración que en la aplicación.

Conceptos

Proveedores

:provider en las rutas y provider en las respuestas usan exactamente estas cadenas:

ProveedorFamiliaCómo se conectaConexiones
mysql, mariadb, postgres, sqlserverbase de datoscredencialesilimitadas
smtp, postmark, resend, sendgridcorreo electrónicocredencialesuna sola conexión de correo electrónico en total por propietario, sea cual sea el proveedor
pipedriveCRMcredenciales1
activecampaignCRMcredenciales1
brevoCRMcredenciales1
google_drivealmacenamientoOAuth en un navegador1, solo personal

Los límites se cuentan por propietario: por usuario en las conexiones personales y por espacio de trabajo en las compartidas.

Ámbito

Cada conexión es personal (solo su propietario la ve y la usa) o workspace (todos los miembros del espacio de trabajo pueden usarla). Solo los propietarios y administradores del espacio de trabajo pueden crear, modificar o eliminar una conexión workspace, o leer sus datos guardados; cualquier miembro puede usarla: consultarla, enviar a través de ella, leer registros del CRM y, cuando la conexión tiene acceso de escritura, escribirlos. Una conexión que no puedes ver responde 404, nunca 403.

Credenciales frente a OAuth

  • Las conexiones de bases de datos, correo electrónico y CRM se crean en una sola llamada con las credenciales en el cuerpo. Antes, el servidor las verifica con el proveedor: abre la conexión con la base de datos, se autentica en SMTP o envía un mensaje de prueba a través de Postmark, Resend o SendGrid. Un cliente que solo use la API puede hacer todo el proceso de principio a fin.
  • Google Drive usa OAuth. La llamada de conexión devuelve una auth_url; una persona debe abrirla y aceptar la pantalla de consentimiento de Google. Tu código puede pasar el enlace a un usuario y consultar periódicamente GET /integration/connections?provider=google_drive hasta que aparezca la conexión.

Ningún endpoint devuelve nunca los secretos.

Estado

El status de una conexión es active, needs_reauth, revoked o error. Cualquier ruta de conexión que se llame sobre una conexión no activa responde 409 {"error":"reconnect_required"}. Actualmente, solo las conexiones de Google Drive pueden dejar de estar en active; repáralas con el endpoint reconnect.

Errores

EstadoEjemplo de cuerpoSignificado
400"invalid request", "query is required"Entrada mal formada.
403"you do not have permission to manage this connection"Es una conexión del espacio de trabajo y no eres propietario ni administrador.
403"this connection is read-only; enable write access on the connection to create or edit records"Escritura en el CRM sin acceso de escritura.
404"integration is not connected or does not exist"Conexión desconocida o que no es tuya.
409"reconnect_required", "connection limit reached for this integration"Hay que volver a autorizarla, o se ha superado el límite.
413"the attachments are too large to send"
422"failed to connect to the integration with the given credentials: ..."Credenciales rechazadas al conectar o al actualizar.
422"query is not a single read-only select statement"SQL no permitido con el nivel de permiso de la conexión.
422"the message was rejected: ..."El proveedor de correo electrónico rechazó el mensaje.
501"integration provider does not support this capability: ..."Por ejemplo, tratos en un CRM que no tiene tratos.
502"failed to send the message: ...", "failed to reach the crm provider: ..."Ha fallado el proveedor externo.
504"query timed out"La consulta a la base de datos superó su tiempo de espera.
500"internal server error"Errores no mapeados, incluidos los errores de SQL que genera la propia base de datos.

Catálogo y conexiones

GET /integration

GET /api/v1/integration

El catálogo de proveedores, con lo que puede hacer cada uno y cuántas conexiones tienes ya.

[
  {
    "provider": "postgres",
    "display_name": "PostgreSQL",
    "capabilities": ["test_connection", "schema_browse", "query"],
    "availability": "available",
    "connection_count": 1,
    "max_connections": 0
  }
]

max_connections: 0 significa ilimitadas. El límite compartido de una sola conexión de correo electrónico no se refleja aquí.

GET /integration/ssh-tunnel/public-key

GET /api/v1/integration/ssh-tunnel/public-key

Las conexiones de bases de datos pueden llegar a una base de datos privada a través de un host de salto SSH. Añade esta clave pública al authorized_keys del usuario SSH de tu host de salto y permite la dirección de StickyPrompts en tu firewall.

{ "public_key": "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAA... stickyprompts" }

POST /integration/:provider/connect

POST /api/v1/integration/:provider/connect

Crea una conexión nueva (nunca sustituye una existente). El cuerpo es un único objeto plano: los campos comunes más los propios del proveedor.

Campos comunes del cuerpo
name string obligatorio
Un nombre que la gente reconozca, por ejemplo «Northwind Retail DB».
description string opcional
Opcional.
scope string obligatorio
personal o workspace. workspace requiere un propietario o administrador del espacio de trabajo.
database_permission string opcional por defecto read_only
Solo para bases de datos: read_only, create_update o full_access. Consulta los niveles de permiso.
Campos de base de datos (mysql, mariadb, postgres, sqlserver)
host string obligatorio
Nombre del host tal como lo ve StickyPrompts o, si usas SSH, tal como lo ve el host de salto.
port integer opcional
De forma predeterminada, 3306 (MySQL, MariaDB), 5432 (PostgreSQL) o 1433 (SQL Server).
database string obligatorio
schema string opcional
De forma predeterminada, public en PostgreSQL y dbo en SQL Server.
username string obligatorio
Usa un usuario dedicado con los privilegios mínimos que necesite la tarea.
password string obligatorio
ssl_mode string opcional
PostgreSQL: disable, require (predeterminado), verify-ca, verify-full. MySQL/MariaDB: true, false, skip-verify, preferred (predeterminado). SQL Server: true (predeterminado), skip-verify, false.
ssh_host string opcional
Enruta la conexión a través de este host de salto SSH.
ssh_port integer opcional
ssh_username string opcional
Obligatorio con ssh_host.
Campos de correo electrónico (smtp, postmark, resend, sendgrid)
default_from_email string obligatorio
El remitente predeterminado. En Postmark, Resend y SendGrid debe ser ya un remitente que tu proveedor acepte, porque la prueba de conexión envía un mensaje de prueba real.
default_from_name string opcional
default_reply_to string opcional
server_token string opcional
Postmark.
api_key string opcional
Resend y SendGrid.
host, port, username, password, encryption various opcional
SMTP. encryption es starttls (predeterminado), ssl o none; port es 587 de forma predeterminada, o 465 con ssl.
Campos de CRM
api_token string opcional
Pipedrive (obligatorio).
api_url, api_key string opcional
ActiveCampaign (ambos obligatorios; api_url es la URL de tu cuenta).
api_key string opcional
Brevo (obligatorio).
allow_write boolean opcional por defecto false
Sin este campo, la conexión es de solo lectura: añadir o editar contactos y crear tratos responde 403.
curl -X POST https://api.stickyprompts.com/api/v1/integration/postgres/connect \
  -H "Authorization: Bearer $STICKY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Northwind Retail DB",
    "scope": "workspace",
    "database_permission": "read_only",
    "host": "localhost",
    "port": 5432,
    "database": "retail",
    "schema": "public",
    "username": "sp_reader",
    "password": "********",
    "ssl_mode": "disable",
    "ssh_host": "bastion.northwind.example",
    "ssh_port": 22,
    "ssh_username": "stickyprompts"
  }'
import os, requests

r = requests.post(
    "https://api.stickyprompts.com/api/v1/integration/postmark/connect",
    headers={"Authorization": f"Bearer {os.environ['STICKY_API_KEY']}"},
    json={
        "name": "Northwind Mailer",
        "scope": "workspace",
        "default_from_email": "team@northwind.example",
        "default_from_name": "Northwind Team",
        "server_token": os.environ["POSTMARK_SERVER_TOKEN"],
    },
)
print(r.status_code, r.json())   # 200 {"connection_id": 42}
const res = await fetch("https://api.stickyprompts.com/api/v1/integration/pipedrive/connect", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.STICKY_API_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    name: "Pipedrive - Sales",
    scope: "workspace",
    api_token: process.env.PIPEDRIVE_TOKEN,
    allow_write: true,
  }),
});
console.log(res.status, await res.json()); // 200 {"connection_id": 43}

Respuesta 200 {"connection_id": 42}. Con google_drive, la respuesta es 200 {"auth_url": "..."}: envía a una persona a esa URL para terminar.

GET /integration/connections

GET /api/v1/integration/connections

Todas las conexiones que puedes ver (las tuyas y las compartidas de tu espacio de trabajo), de la más reciente a la más antigua. Opcionalmente, ?provider=<provider>.

[
  {
    "id": 42,
    "provider": "postgres",
    "name": "Northwind Retail DB",
    "description": "Demo retail data: stores, orders, products, customers.",
    "scope": "workspace",
    "status": "active",
    "account_name": "sp_reader@localhost:5432/retail",
    "connected_at": "2026-09-28T12:55:00Z",
    "database_permission": "read_only"
  }
]

account_name es una etiqueta que no contiene secretos: user@host:port/database en las bases de datos, el remitente predeterminado en el correo electrónico y la URL de la cuenta en ActiveCampaign. El acceso de escritura del CRM no aparece en esta lista; consúltalo en GET .../crm/connection.

PATCH /integration/connections/:connectionId

PATCH /api/v1/integration/connections/:connectionId

Cambia el nombre o el nivel de permiso de la base de datos, o rota las credenciales. Envía name siempre (el actual si no le cambias el nombre). description se escribe siempre, así que si lo omites, se borra. Solo cambian los campos del proveedor que envías; si hay algún campo de credenciales, la configuración combinada se vuelve a verificar antes de guardarla (422 si falla). En las bases de datos, "ssh_host": "" desactiva el túnel SSH. Devuelve 200 con el cuerpo vacío.

DELETE /integration/connections/:connectionId

DELETE /api/v1/integration/connections/:connectionId

Elimina la conexión y sus credenciales guardadas. En Google Drive, primero se revoca la autorización en Google. Devuelve 204.

POST /integration/connections/:connectionId/reconnect

POST /api/v1/integration/connections/:connectionId/reconnect

Inicia un nuevo consentimiento OAuth para una conexión de Google Drive y conserva su ID y su nombre. Devuelve 200 {"auth_url": "..."}. Los proveedores con credenciales responden 501; actualízalos con PATCH.

Bases de datos

Niveles de permiso

El database_permission de la conexión determina qué SQL acepta el endpoint de consulta, con independencia de lo que pueda hacer la clave de API:

NivelSe permite
read_onlyExactamente una sentencia SELECT o WITH.
create_updateExactamente una sentencia SELECT, WITH, INSERT o UPDATE.
full_accessTodo lo que pueda ejecutar el usuario de la base de datos. Sin filtrado de sentencias.

Con read_only y create_update se analiza toda la sentencia en busca de palabras clave prohibidas, así que se rechaza una consulta de solo lectura que simplemente mencione una palabra como update en el nombre de una columna o en una cadena. En MySQL, MariaDB y PostgreSQL, las sesiones de solo lectura también se abren en modo de solo lectura; SQL Server depende únicamente de la comprobación de palabras clave. En todos los casos, conéctate con un usuario de base de datos que solo tenga los permisos que quieras conceder.

GET /integration/connections/:connectionId/database/schema

GET /api/v1/integration/connections/:connectionId/database/schema

Todas las tablas y vistas del esquema de la conexión, con sus columnas:

{
  "schema": {
    "name": "public",
    "tables": [
      {
        "schema": "public",
        "name": "demo_orders",
        "columns": [
          { "name": "id", "data_type": "integer", "nullable": false },
          { "name": "customer_id", "data_type": "integer", "nullable": false },
          { "name": "status", "data_type": "text", "nullable": true }
        ]
      }
    ]
  }
}

GET /integration/connections/:connectionId/database/connection

GET /api/v1/integration/connections/:connectionId/database/connection

Los datos de conexión guardados, sin la contraseña. En las conexiones del espacio de trabajo, solo para propietarios y administradores. Los campos que dejaste vacíos se devuelven como 0 o "", aunque se usara un valor predeterminado para conectar.

POST /integration/connections/:connectionId/database/query

POST /api/v1/integration/connections/:connectionId/database/query
Cuerpo
query string obligatorio
Una sentencia SQL.
row_limit integer opcional por defecto 100
Máximo 1000.
timeout_seconds integer opcional por defecto 10
Máximo 30.
curl -X POST https://api.stickyprompts.com/api/v1/integration/connections/42/database/query \
  -H "Authorization: Bearer $STICKY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"query": "SELECT c.name, SUM(o.total) AS revenue FROM demo_orders o JOIN demo_customers c ON c.id = o.customer_id GROUP BY c.name ORDER BY revenue DESC LIMIT 5"}'
import os, requests

r = requests.post(
    "https://api.stickyprompts.com/api/v1/integration/connections/42/database/query",
    headers={"Authorization": f"Bearer {os.environ['STICKY_API_KEY']}"},
    json={"query": "SELECT name, city FROM demo_customers ORDER BY name", "row_limit": 50},
)
data = r.json()
rows = [dict(zip(data["columns"], row)) for row in data["rows"]]
const res = await fetch(
  "https://api.stickyprompts.com/api/v1/integration/connections/42/database/query",
  {
    method: "POST",
    headers: {
      Authorization: `Bearer ${process.env.STICKY_API_KEY}`,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({ query: "SELECT name, city FROM demo_customers ORDER BY name" }),
  },
);
const { columns, rows, truncated } = await res.json();

Respuesta a una sentencia SELECT:

{
  "columns": ["name", "revenue"],
  "rows": [["Hawthorne Goods", "18240.00"], ["Cedar & Pine Outfitters", "15110.50"]],
  "row_count": 2,
  "truncated": false
}

truncated: true significa que había más filas después de row_limit. Las columnas numéricas suelen llegar como cadenas. Las demás sentencias (permitidas en los niveles superiores) solo devuelven row_count, el número de filas afectadas. Los errores de SQL que genera la base de datos devuelven 500 sin el mensaje de la base de datos, así que prueba antes las consultas en un cliente de base de datos.

Correo electrónico

El correo siempre sale con las credenciales de la propia cuenta conectada; StickyPrompts no proporciona ningún remitente.

GET /integration/connections/:connectionId/email/connection

GET /api/v1/integration/connections/:connectionId/email/connection

La configuración del remitente (provider, default_from_email, default_from_name, default_reply_to y, en SMTP, el host, el puerto, el usuario y el cifrado). Los tokens y las contraseñas nunca se devuelven. En las conexiones del espacio de trabajo, solo para propietarios y administradores.

POST /integration/connections/:connectionId/email/send

POST /api/v1/integration/connections/:connectionId/email/send
Cuerpo
to Address[] obligatorio
Al menos un {"email": "...", "name": "..."}.
cc, bcc Address[] opcional
Entre to, cc y bcc, un máximo de 50 destinatarios.
reply_to Address[] opcional
De forma predeterminada, la dirección de respuesta de la conexión.
subject string obligatorio
html_body string opcional
Envía html_body, text_body o ambos.
text_body string opcional
from_email, from_name string opcional
Sustituyen al remitente en este mensaje. Tu proveedor puede rechazar un remitente no verificado.
attachment_file_ids integer[] opcional
Hasta 10 archivos de StickyPrompts de los que seas propietario. Límites de tamaño tras la codificación: SMTP 25 MB, Postmark 10 MB, SendGrid 30 MB, Resend 40 MB.
curl -X POST https://api.stickyprompts.com/api/v1/integration/connections/41/email/send \
  -H "Authorization: Bearer $STICKY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "to": [{ "email": "sales@northwind.example", "name": "Sales team" }],
    "subject": "Pipedrive: Deals at Proposal Made",
    "html_body": "<p>2 deals at Proposal Made, worth $28,788.</p>",
    "text_body": "2 deals at Proposal Made, worth $28,788."
  }'

Respuesta 200 {"message_id": "<...>", "provider": "postmark"}: el ID que asigna el propio proveedor, útil para encontrar el mensaje en su panel.

CRM

Las lecturas funcionan en cualquier conexión de CRM. Las escrituras (añadir o editar contactos y crear tratos) requieren allow_write en la conexión.

Contacto: email (obligatorio en todas las escrituras y clave de búsqueda en las ediciones), first_name, last_name, phone, company, custom_fields (específicos de cada proveedor), list_ids (Brevo, ActiveCampaign) y tag_ids (ActiveCampaign). Los resultados se devuelven como {"remote_id", "provider", "contact"}.

Trato (deal): title, value, currency, contact_email (debe pertenecer a un contacto existente) y stage (una etiqueta libre). Los resultados se devuelven como {"remote_id", "provider", "deal"}.

GET /integration/connections/:connectionId/crm/connection

GET /api/v1/integration/connections/:connectionId/crm/connection

{"provider": "pipedrive", "allow_write": true} (más api_url en ActiveCampaign).

GET /integration/connections/:connectionId/crm/contacts

GET /api/v1/integration/connections/:connectionId/crm/contacts

Busca contactos con query (obligatorio) y filtros opcionales del proveedor en notación de corchetes, por ejemplo ?query=priya&filters[organization_id]=1. Pipedrive y ActiveCampaign buscan en texto libre; Brevo busca un único correo electrónico o ID exacto.

GET /integration/connections/:connectionId/crm/contacts/list

GET /api/v1/integration/connections/:connectionId/crm/contacts/list

Recorre los contactos. Usa limit (50 de forma predeterminada) y pagina con cursor (Pipedrive: envía el next_cursor anterior) o con offset (ActiveCampaign, Brevo). Devuelve {"contacts": [...], "has_more": true, "next_cursor": "..."}.

POST /integration/connections/:connectionId/crm/contacts

POST /api/v1/integration/connections/:connectionId/crm/contacts

Añade un contacto. Siempre crea uno nuevo, aunque el correo electrónico ya exista, así que busca antes.

{ "email": "priya.raman@hawthornegoods.example", "first_name": "Priya", "last_name": "Raman", "company": "Hawthorne Goods" }

PATCH /integration/connections/:connectionId/crm/contacts

PATCH /api/v1/integration/connections/:connectionId/crm/contacts

Edita el contacto que tiene ese email; solo cambian los campos que envías (envía "" para vaciar uno). Nunca crea contactos: 404 "no matching contact was found in the crm to update".

GET /integration/connections/:connectionId/crm/deals

GET /api/v1/integration/connections/:connectionId/crm/deals

Busca tratos por título o por el correo electrónico del contacto vinculado con query, además de filtros del proveedor (en Pipedrive: status, person_id, organization_id, exact_match).

GET /integration/connections/:connectionId/crm/deals/list

GET /api/v1/integration/connections/:connectionId/crm/deals/list

Recorre los tratos, con la misma paginación que los contactos. Los filtros de Pipedrive incluyen stage_id, status, owner_id y pipeline_id.

POST /integration/connections/:connectionId/crm/deals

POST /api/v1/integration/connections/:connectionId/crm/deals
{ "title": "Cedar & Pine - Scale plan, 42 stores", "value": 4788, "currency": "USD", "contact_email": "marcus.webb@cedarpine.example", "stage": "Proposal Made" }

404 si ningún contacto tiene ese correo electrónico.

GET /integration/connections/:connectionId/crm/lists, /crm/tags

GET /api/v1/integration/connections/:connectionId/crm/lists

Listas (Brevo, ActiveCampaign) y etiquetas (ActiveCampaign) con la forma [{"id": "12", "name": "Newsletter"}], para usarlas en filtros y en los list_ids / tag_ids de un contacto. Los demás proveedores responden 501.

Google Drive

Las rutas de almacenamiento siempre actúan sobre tu propia conexión personal de Drive y llevan el proveedor en la ruta: /integration/google_drive/storage/.... Los IDs de carpetas y elementos son root o IDs de Drive.

GET /integration/:provider/storage/entries

GET /api/v1/integration/:provider/storage/entries

Lista una carpeta: folder_id (root de forma predeterminada), page_token, page_size (de 1 a 200, 100 de forma predeterminada) y kind (folder o file). Devuelve {"entries": [...], "next_page_token": "", "breadcrumbs": [...]}. Cada elemento tiene id, name, kind, mime_type, size, modified_at, web_url, importable e import_name (Docs y Drawings se importan como PDF, Sheets como XLSX y Slides como PPTX).

GET /integration/:provider/storage/search

GET /api/v1/integration/:provider/storage/search

query (obligatorio), con la misma paginación y los mismos filtros.

GET /integration/:provider/storage/entry/:entryId

GET /api/v1/integration/:provider/storage/entry/:entryId

POST /integration/:provider/storage/import

POST /api/v1/integration/:provider/storage/import

Copia entre 1 y 20 elementos de Drive (entry_ids) en StickyPrompts como archivos normales, opcionalmente vinculados a un project_id. Cada elemento se importa o falla por separado, así que comprueba siempre failed: {"files": [...], "failed": [{"entry_id": "...", "error": "..."}]}. Hasta 100 MB por archivo.

POST /integration/:provider/storage/export

POST /api/v1/integration/:provider/storage/export

Copia un archivo de StickyPrompts del que eres propietario (file_id) en una carpeta de Drive (folder_id; se admite root), con la opción de cambiarle el nombre con name.