Integrazioni
Crea e gestisci connessioni a database, servizi di invio email, CRM e Google Drive, poi usale per eseguire query, inviare, cercare e scrivere: sono le stesse connessioni usate da chat, agenti e workflow.
Le integrazioni permettono a StickyPrompts di agire sui tuoi sistemi. Tramite l’API puoi creare connessioni e poi usarle direttamente: eseguire SQL su un database, inviare un’email, cercare o aggiornare dati in un CRM e spostare file da e verso Google Drive. Tutto ciò che trovi qui è lo stesso meccanismo che l’app usa quando qualcuno lo richiede in chat.
Tutti i percorsi sono relativi a https://api.stickyprompts.com/api/v1. La chiave agisce come il suo proprietario: valgono le stesse regole di condivisione e di amministrazione dell’app.
Concetti
Provider
:provider nei percorsi e provider nelle risposte usano esattamente queste stringhe:
| Provider | Famiglia | Modalità di connessione | Connessioni |
|---|---|---|---|
mysql, mariadb, postgres, sqlserver | database | credenziali | illimitate |
smtp, postmark, resend, sendgrid | credenziali | una sola connessione email in totale per proprietario, qualunque sia il provider | |
pipedrive | CRM | credenziali | 1 |
activecampaign | CRM | credenziali | 1 |
brevo | CRM | credenziali | 1 |
google_drive | archiviazione | OAuth nel browser | 1, solo personale |
I limiti si contano per proprietario: per utente nelle connessioni personali, per workspace in quelle condivise.
Ambito
Ogni connessione è personal (solo il proprietario la vede e la usa) oppure workspace (chiunque nel workspace può usarla). Solo i proprietari e gli amministratori del workspace possono creare, modificare, eliminare una connessione del workspace o leggerne i dettagli salvati; qualsiasi membro può usarla: eseguire query, inviare email tramite la connessione, leggere e, con l’accesso in scrittura, scrivere record nel CRM. Una connessione che non puoi vedere risponde 404, mai 403.
Credenziali o OAuth
- Le connessioni a database, email e CRM si creano con un’unica chiamata, con le credenziali nel corpo. Il server prima le verifica presso il provider: apre la connessione al database, si autentica sul server SMTP oppure invia un messaggio di prova tramite Postmark, Resend o SendGrid. Un client che usa solo l’API può completare l’intera procedura.
- Google Drive usa OAuth. La chiamata di connessione restituisce un
auth_url; una persona deve aprirlo e approvare la schermata di consenso di Google. Il tuo codice può passare il link a un utente e interrogareGET /integration/connections?provider=google_drivefinché la connessione non compare.
Nessun endpoint restituisce mai i segreti.
Stato
Lo status di una connessione vale active, needs_reauth, revoked o error. Qualsiasi route di connessione chiamata su una connessione non attiva risponde 409 {"error":"reconnect_required"}. Oggi solo le connessioni a Google Drive possono uscire dallo stato active; per ripristinarle usa la riconnessione.
Errori
| Stato | Corpo di esempio | Significato |
|---|---|---|
400 | "invalid request", "query is required" | Input non valido. |
403 | "you do not have permission to manage this connection" | Connessione del workspace e non sei né proprietario né amministratore. |
403 | "this connection is read-only; enable write access on the connection to create or edit records" | Scrittura nel CRM senza accesso in scrittura. |
404 | "integration is not connected or does not exist" | Connessione sconosciuta o non tua. |
409 | "reconnect_required", "connection limit reached for this integration" | Serve una nuova autorizzazione, oppure il limite è stato superato. |
413 | "the attachments are too large to send" | |
422 | "failed to connect to the integration with the given credentials: ..." | Credenziali rifiutate durante la connessione o l’aggiornamento. |
422 | "query is not a single read-only select statement" | SQL non consentito al livello di autorizzazione della connessione. |
422 | "the message was rejected: ..." | Il provider email ha rifiutato il messaggio. |
501 | "integration provider does not support this capability: ..." | Per esempio i deal su un CRM che non li gestisce. |
502 | "failed to send the message: ...", "failed to reach the crm provider: ..." | Il provider a monte non ha risposto correttamente. |
504 | "query timed out" | La query sul database ha superato il timeout. |
500 | "internal server error" | Errori non mappati, compresi gli errori SQL sollevati dal database stesso. |
Catalogo e connessioni
GET /integration
/api/v1/integration Il catalogo dei provider, con le capacità di ciascuno e il numero di connessioni che hai già.
[
{
"provider": "postgres",
"display_name": "PostgreSQL",
"capabilities": ["test_connection", "schema_browse", "query"],
"availability": "available",
"connection_count": 1,
"max_connections": 0
}
]
max_connections: 0 significa illimitate. Il limite condiviso di una sola connessione email non compare qui.
GET /integration/ssh-tunnel/public-key
/api/v1/integration/ssh-tunnel/public-key Le connessioni ai database possono raggiungere un database privato tramite un jump host SSH. Aggiungi questa chiave pubblica al file authorized_keys dell’utente SSH sul tuo jump host e consenti l’indirizzo di StickyPrompts nel firewall.
{ "public_key": "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAA... stickyprompts" }
POST /integration/:provider/connect
/api/v1/integration/:provider/connect Crea una nuova connessione (non ne sostituisce mai una esistente). Il corpo è un unico oggetto piatto: i campi comuni più quelli specifici del provider.
-
namestring obbligatorio - Un nome che le persone riconoscano, per esempio «Northwind Retail DB».
-
descriptionstring facoltativo - Facoltativo.
-
scopestring obbligatorio personaloworkspace.workspacerichiede un proprietario o un amministratore del workspace.-
database_permissionstring facoltativo predefinitoread_only - Solo per i database:
read_only,create_updateofull_access. Vedi livelli di autorizzazione.
-
hoststring obbligatorio - Il nome host così come lo vede StickyPrompts, oppure come lo vede il jump host se usi SSH.
-
portinteger facoltativo - Predefinita: 3306 (MySQL, MariaDB), 5432 (PostgreSQL), 1433 (SQL Server).
-
databasestring obbligatorio -
schemastring facoltativo - Predefinito per PostgreSQL:
public; per SQL Server:dbo. -
usernamestring obbligatorio - Usa un utente dedicato con i privilegi minimi necessari per il lavoro.
-
passwordstring obbligatorio -
ssl_modestring facoltativo - PostgreSQL:
disable,require(predefinito),verify-ca,verify-full. MySQL/MariaDB:true,false,skip-verify,preferred(predefinito). SQL Server:true(predefinito),skip-verify,false. -
ssh_hoststring facoltativo - Instrada la connessione attraverso questo jump host SSH.
-
ssh_portinteger facoltativo -
ssh_usernamestring facoltativo - Obbligatorio con
ssh_host.
-
default_from_emailstring obbligatorio - Il mittente predefinito. Per Postmark, Resend e SendGrid deve essere già un mittente accettato dal tuo provider: il test della connessione invia un vero messaggio di prova.
-
default_from_namestring facoltativo -
default_reply_tostring facoltativo -
server_tokenstring facoltativo - Postmark.
-
api_keystring facoltativo - Resend e SendGrid.
-
host, port, username, password, encryptionvarious facoltativo - SMTP.
encryptionvalestarttls(predefinito),sslonone;portè 587 per impostazione predefinita, oppure 465 conssl.
-
api_tokenstring facoltativo - Pipedrive (obbligatorio).
-
api_url, api_keystring facoltativo - ActiveCampaign (entrambi obbligatori;
api_urlè l’URL del tuo account). -
api_keystring facoltativo - Brevo (obbligatorio).
-
allow_writeboolean facoltativo predefinitofalse - Senza questo campo la connessione è in sola lettura: l’aggiunta o la modifica di contatti e la creazione di deal rispondono
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}Risposta 200 {"connection_id": 42}. Per google_drive la risposta è invece 200 {"auth_url": "..."}: indirizza una persona a quell’URL per completare la connessione.
GET /integration/connections
/api/v1/integration/connections Tutte le connessioni che puoi vedere (le tue più quelle condivise del tuo workspace), dalla più recente. Parametro facoltativo ?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 è un’etichetta non riservata: user@host:port/database per i database, il mittente predefinito per l’email, l’URL dell’account per ActiveCampaign. L’accesso in scrittura al CRM non compare in questo elenco; leggilo da GET .../crm/connection.
PATCH /integration/connections/:connectionId
/api/v1/integration/connections/:connectionId Rinomina la connessione, cambia il livello di autorizzazione del database o ruota le credenziali. Invia sempre name (quello attuale se non stai rinominando). description viene sempre scritto, quindi se lo ometti viene svuotato. Cambiano solo i campi del provider che invii; se è presente un qualsiasi campo di credenziali, la configurazione risultante viene verificata di nuovo prima del salvataggio (422 in caso di errore). Per i database, "ssh_host": "" disattiva il tunnel SSH. Restituisce 200 con corpo vuoto.
DELETE /integration/connections/:connectionId
/api/v1/integration/connections/:connectionId Elimina la connessione e le credenziali salvate. Per Google Drive, l’autorizzazione viene prima revocata presso Google. Restituisce 204.
POST /integration/connections/:connectionId/reconnect
/api/v1/integration/connections/:connectionId/reconnect Avvia un nuovo consenso OAuth per una connessione a Google Drive, mantenendone ID e nome. Restituisce 200 {"auth_url": "..."}. I provider basati su credenziali rispondono 501; per questi usa PATCH.
Database
Livelli di autorizzazione
Il database_permission della connessione stabilisce quali istruzioni SQL accetta l’endpoint di query, a prescindere da ciò che può fare la chiave API:
| Livello | Consentito |
|---|---|
read_only | Esattamente un’istruzione SELECT o WITH. |
create_update | Esattamente un’istruzione SELECT, WITH, INSERT o UPDATE. |
full_access | Tutto ciò che l’utente del database può eseguire. Nessun filtro sulle istruzioni. |
Con read_only e create_update l’intera istruzione viene analizzata alla ricerca di parole chiave vietate, quindi una query di sola lettura che contiene semplicemente una parola come update nel nome di una colonna o in una stringa viene rifiutata. Per MySQL, MariaDB e PostgreSQL, le sessioni di sola lettura vengono anche aperte in modalità di sola lettura; SQL Server si affida solo al controllo delle parole chiave. In ogni caso, connettiti con un utente del database che abbia soltanto i diritti che intendi concedere.
GET /integration/connections/:connectionId/database/schema
/api/v1/integration/connections/:connectionId/database/schema Tutte le tabelle e le viste dello schema della connessione, con le relative colonne:
{
"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
/api/v1/integration/connections/:connectionId/database/connection I dettagli di connessione salvati, senza la password. Per le connessioni del workspace, solo per proprietari e amministratori. I campi che hai lasciato vuoti vengono restituiti come 0 o "", anche se per la connessione è stato usato un valore predefinito.
POST /integration/connections/:connectionId/database/query
/api/v1/integration/connections/:connectionId/database/query -
querystring obbligatorio - Una sola istruzione SQL.
-
row_limitinteger facoltativo predefinito100 - Al massimo 1000.
-
timeout_secondsinteger facoltativo predefinito10 - Al massimo 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();Risposta per una SELECT:
{
"columns": ["name", "revenue"],
"rows": [["Hawthorne Goods", "18240.00"], ["Cedar & Pine Outfitters", "15110.50"]],
"row_count": 2,
"truncated": false
}
truncated: true significa che esistevano altre righe oltre row_limit. Le colonne numeriche arrivano spesso come stringhe. Le altre istruzioni (consentite ai livelli superiori) restituiscono solo row_count, cioè il numero di righe interessate. Gli errori SQL sollevati dal database restituiscono 500 senza il messaggio del database, quindi prova prima le query in un client di database.
La posta parte sempre con le credenziali dell’account collegato; StickyPrompts non fornisce un proprio mittente.
GET /integration/connections/:connectionId/email/connection
/api/v1/integration/connections/:connectionId/email/connection Le impostazioni del mittente (provider, default_from_email, default_from_name, default_reply_to, più host, porta, nome utente e crittografia per SMTP). Token e password non vengono mai restituiti. Per le connessioni del workspace, solo per proprietari e amministratori.
POST /integration/connections/:connectionId/email/send
/api/v1/integration/connections/:connectionId/email/send -
toAddress[] obbligatorio - Almeno un
{"email": "...", "name": "..."}. -
cc, bccAddress[] facoltativo to,ccebccinsieme: al massimo 50 destinatari.-
reply_toAddress[] facoltativo - Per impostazione predefinita, l’indirizzo di risposta della connessione.
-
subjectstring obbligatorio -
html_bodystring facoltativo - Invia
html_body,text_bodyo entrambi. -
text_bodystring facoltativo -
from_email, from_namestring facoltativo - Sostituiscono il mittente per questo messaggio. Il tuo provider potrebbe rifiutare un mittente non verificato.
-
attachment_file_idsinteger[] facoltativo - Fino a 10 file di StickyPrompts di tua proprietà. Limiti di dimensione dopo la codifica: 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."
}'
Risposta 200 {"message_id": "<...>", "provider": "postmark"}: l’ID assegnato dal provider, utile per trovare il messaggio nella sua dashboard.
CRM
Le letture funzionano su tutte le connessioni CRM. Le scritture (aggiunta o modifica di contatti e creazione di deal) richiedono allow_write sulla connessione.
Contatto: email (obbligatorio in ogni scrittura e chiave di ricerca per le modifiche), first_name, last_name, phone, company, custom_fields (specifici del provider), list_ids (Brevo, ActiveCampaign) e tag_ids (ActiveCampaign). I risultati vengono restituiti come {"remote_id", "provider", "contact"}.
Deal: title, value, currency, contact_email (deve appartenere a un contatto esistente) e stage (un’etichetta libera). I risultati vengono restituiti come {"remote_id", "provider", "deal"}.
GET /integration/connections/:connectionId/crm/connection
/api/v1/integration/connections/:connectionId/crm/connection {"provider": "pipedrive", "allow_write": true} (più api_url per ActiveCampaign).
GET /integration/connections/:connectionId/crm/contacts
/api/v1/integration/connections/:connectionId/crm/contacts Cerca i contatti con query (obbligatorio) e filtri facoltativi del provider in notazione con parentesi quadre, per esempio ?query=priya&filters[organization_id]=1. Pipedrive e ActiveCampaign eseguono una ricerca a testo libero; Brevo cerca un singolo indirizzo email o ID esatto.
GET /integration/connections/:connectionId/crm/contacts/list
/api/v1/integration/connections/:connectionId/crm/contacts/list Sfoglia i contatti. limit (predefinito 50), poi pagina con cursor (Pipedrive: passa il next_cursor precedente) oppure con offset (ActiveCampaign, Brevo). Restituisce {"contacts": [...], "has_more": true, "next_cursor": "..."}.
POST /integration/connections/:connectionId/crm/contacts
/api/v1/integration/connections/:connectionId/crm/contacts Aggiunge un contatto. Ne crea sempre uno nuovo, anche se l’indirizzo email esiste già: cerca prima.
{ "email": "priya.raman@hawthornegoods.example", "first_name": "Priya", "last_name": "Raman", "company": "Hawthorne Goods" }
PATCH /integration/connections/:connectionId/crm/contacts
/api/v1/integration/connections/:connectionId/crm/contacts Modifica il contatto con quell’email; cambiano solo i campi che invii (invia "" per svuotarne uno). Non crea mai contatti: 404 "no matching contact was found in the crm to update".
GET /integration/connections/:connectionId/crm/deals
/api/v1/integration/connections/:connectionId/crm/deals Cerca i deal per titolo o per indirizzo email del contatto collegato con query, più i filtri del provider (per Pipedrive: status, person_id, organization_id, exact_match).
GET /integration/connections/:connectionId/crm/deals/list
/api/v1/integration/connections/:connectionId/crm/deals/list Sfoglia i deal, con la stessa paginazione dei contatti. I filtri di Pipedrive includono stage_id, status, owner_id e pipeline_id.
POST /integration/connections/:connectionId/crm/deals
/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 se nessun contatto ha quell’indirizzo email.
GET /integration/connections/:connectionId/crm/lists, /crm/tags
/api/v1/integration/connections/:connectionId/crm/lists Liste (Brevo, ActiveCampaign) e tag (ActiveCampaign) nella forma [{"id": "12", "name": "Newsletter"}], da usare nei filtri e in list_ids / tag_ids di un contatto. Gli altri provider rispondono 501.
Google Drive
Le route di archiviazione agiscono sempre sulla tua connessione personale a Drive e richiedono il provider nel percorso: /integration/google_drive/storage/.... Gli ID di cartelle ed elementi sono root oppure ID di Drive.
GET /integration/:provider/storage/entries
/api/v1/integration/:provider/storage/entries Elenca il contenuto di una cartella: folder_id (predefinito root), page_token, page_size (da 1 a 200, predefinito 100), kind (folder o file). Restituisce {"entries": [...], "next_page_token": "", "breadcrumbs": [...]}. Ogni elemento ha id, name, kind, mime_type, size, modified_at, web_url, importable e import_name (Documenti e Disegni vengono importati come PDF, Fogli come XLSX, Presentazioni come PPTX).
GET /integration/:provider/storage/search
/api/v1/integration/:provider/storage/search query (obbligatorio) più la stessa paginazione e gli stessi filtri.
GET /integration/:provider/storage/entry/:entryId
/api/v1/integration/:provider/storage/entry/:entryId POST /integration/:provider/storage/import
/api/v1/integration/:provider/storage/import Copia da 1 a 20 elementi di Drive (entry_ids) in StickyPrompts come normali file, eventualmente collegati a un project_id. Ogni elemento riesce o fallisce indipendentemente dagli altri, quindi controlla sempre failed: {"files": [...], "failed": [{"entry_id": "...", "error": "..."}]}. Fino a 100 MB per file.
POST /integration/:provider/storage/export
/api/v1/integration/:provider/storage/export Copia un file di StickyPrompts di tua proprietà (file_id) in una cartella di Drive (folder_id, è ammesso root), eventualmente rinominandolo con name.