Documentazione
Chiedi a chi serve dal tuo agente.
Il tuo agente descrive cosa gli serve (un modulo, un sondaggio, oppure un sì o un no) e riceve un link per una persona, per ogni persona di un gruppo o per chiunque tu voglia. Le persone lo aprono dal telefono, senza registrarsi, e le loro risposte ti tornano come JSON validato.
-
Crea una richiesta. Chiama
createRequestcon un JSON Schema per un modulo, oppure con un motivo per un’approvazione. -
Manda il link. Passa
sendEmail: truee lo inviamo per email a ogni destinatario nominativo, mandalo tu su un canale che hai già (email, chat o SMS) oppure pubblica un link aperto dove vuoi. -
Ricevi la risposta. Su Builder e Pro, al tuo client MCP arriva ogni risposta appena viene data. Arriva anche al tuo webhook, per email con
notifyEmail, oppure la leggi congetStatus.
Gli stessi strumenti sono disponibili in due modi: un server MCP per gli agenti che parlano MCP e un’API REST per tutto il resto. Gli agenti possono leggere questa guida in llms.txt.
Guida rapida
Da una chiave API alla risposta di una persona in quattro passi.
1Ottieni una chiave API
Accedi con la tua email e copia la chiave dalla dashboard. Inizia con sk_live_; tienila sul tuo server. Usi Claude Code, Codex o un altro client MCP? Salta questo passo: aggiungi il server tramite URL e accedi dal client.
2Crea una richiesta
Questa chiede a Jordan un indirizzo di spedizione e una data di consegna. Lo schema è un normale JSON Schema; in Schema del modulo trovi cosa è supportato.
3Manda il link
La risposta contiene un link per persona in links[] (oppure un solo url per un link aperto). Con "sendEmail": true mandiamo a ogni destinatario nominativo che ha un’email il suo link personale, a nome del tuo account. L’email di ogni link dice cosa è successo: "sent", "failed" (la richiesta esiste comunque; chiama remind più tardi), "limit" (sono stati raggiunti i limiti di email del piano), "no address" oppure "off". Gli altri mandali come preferisci: email, chat o SMS.
4Ricevi la risposta
Quando Jordan invia, il tuo webhookUrl riceve un evento response.created con i dati, già verificati rispetto al tuo schema. Non hai un webhook? Chiama getStatus con il requestId, imposta notifyEmail e ti scriviamo quando è finita, oppure su Builder e Pro iscriviti via MCP e il tuo agente viene avvisato appena Jordan risponde. Vedi Ricevere la risposta.
Autenticazione
Ogni chiamata MCP e REST invia una chiave API come bearer token. La stessa chiave vale per entrambe. Una chiave mancante o revocata riceve un 401. Ci sono due modi per ottenerne una.
Accedi dal tuo client MCP
Aggiungi https://runitby.app/mcp senza chiave e il client ti fa accedere tramite OAuth: si apre un browser, inserisci la tua email e il link di accesso ti riporta a una pagina che ti chiede di autorizzare l’app. Prima volta? Lo stesso link crea il tuo account. L’app conserva poi una propria chiave, che porta il suo nome e che puoi revocare in Chiavi.
-
Claude Code: esegui il comando a destra, poi
/mcpin Claude Code e scegli di autenticarti. -
Codex: esegui
codex mcp add, poicodex mcp login. - Claude (web e desktop): Impostazioni, Connettori, Aggiungi connettore personalizzato, e incolla l’URL.
- Altri client che supportano l’autorizzazione MCP: aggiungi l’URL senza header.
Crea una chiave nella dashboard
Per l’API REST, gli script e i client che accettano solo un header: crea e revoca le chiavi nella dashboard e invia la chiave nell’header Authorization.
I piani contano le due cose separatamente. Free include una chiave e un’app collegata, Builder cinque di ciascuna, Pro quante ne servono.
Esempi in un solo file con una chiave: Vercel AI SDK, Mastra, LangChain.js e il Claude Agent SDK.
Strumenti ed endpoint
Ogni strumento MCP ha un endpoint REST con gli stessi input e output. Il riferimento API elenca ogni campo.
| Strumento MCP | REST | Cosa fa |
|---|---|---|
createRequest |
POST /requests | Crea un modulo o un’approvazione e restituisce il link (o i link), inviati per email al posto tuo se lo chiedi. |
previewRequest |
POST /requests/preview | Screenshot e controlli di ciò che vedrà la persona. Non crea nulla. |
getStatus |
GET /requests/{id} | Stato, esito e tutte le risposte finora. |
listRequests |
GET /requests | Le tue richieste, dalla più recente. Filtra per modalità o stato; pagina con cursor. |
updateRequest |
PATCH /requests/{id} | Cambia il contenuto, aggiungi destinatari o imposta una nuova scadenza. |
remind |
POST /requests/{id}/remind | Manda per email il link a chi non ha ancora risposto. |
closeRequest |
DELETE /requests/{id} | Smetti di accettare risposte. |
Moduli e approvazioni
Ogni richiesta ha un mode:
"form"- Raccogli dati. Invii uno
schema; la persona riceve un modulo costruito a partire da quello e tu ottieni un oggetto che lo rispetta. "approval"- Ottieni una decisione. Invii
approval.reason; ogni persona riceve una scheda con Approva e Rifiuta (o le etichette che scegli tu) e un commento facoltativo. Ottieni ogni decisione e unverdictcomplessivo.
Entrambi accettano un title (fino a 120 caratteri), una riga requester facoltativa che dice chi sta chiedendo, un locale per la pagina e le sue email ("en", "es", "pt", "fr", "de", "it", "ja" o "zh", oppure con una regione come "es-AR" per le date) e metadata, che torna invariato in ogni webhook e stato. Scrivi il titolo e le domande nella stessa lingua.
Chi risponde
audience decide chi riceve un link.
| kind | Ottieni | Usalo per |
|---|---|---|
"named" |
links[], uno per persona in recipients (da 1 a 50, ciascuno { name, email?, phone? }) |
Risposte che devi poter attribuire a qualcuno. Le approvazioni devono essere nominative. Un’email abilita sendEmail, i promemoria e i codici via email. |
"open" |
Un url che chiunque può aprire |
Iscrizioni e sondaggi. maxSubmissions limita le risposte (predefinito 1). |
A cosa serve
Una modalità e un’audience coprono quasi tutto ciò che altrimenti faresti con un form builder, un sondaggio, un’app per gli appuntamenti o una catena di email.
| Vuoi | Richiesta |
|---|---|
| I dati di una persona: un indirizzo di spedizione, l’accoglienza di un cliente, una fascia di prenotazione | "form", nominativo, un destinatario |
| Un sondaggio, una votazione, feedback o iscrizioni da chiunque |
"form", aperto con maxSubmissions. Pubblica l’unico url dove vuoi; getStatus restituisce tutte le risposte, così il tuo agente le riassume. |
| Conferme di partecipazione, disponibilità, sostituzioni di turno o check-in da un gruppo noto |
"form", nominativo (fino a 50), così ogni risposta è attribuita e remind sollecita chi manca |
| Approvazioni, via libera e votazioni |
"approval" con una policy; aggiungi verify: "email" per denaro, accessi o cancellazioni |
Stato e scadenza
| status | Significa |
|---|---|
pending |
Nessuno ha ancora risposto. |
partial |
Alcune persone indicate hanno risposto, altre no. |
complete |
Hanno risposto tutti, è stato raggiunto maxSubmissions, oppure un’approvazione ha il suo esito. |
expired |
Il link è scaduto. |
closed |
Hai chiamato closeRequest. |
Scadenza. expiresIn accetta "30m", "48h", "7d" o secondi. Il valore predefinito è 7 giorni e il massimo 90.
Modificare una richiesta. updateRequest cambia titolo, schema, sezioni, motivo o tema finché non arriva la prima risposta. Aggiungere destinatari, impostare una nuova scadenza (contata da adesso) e cambiare notifyEmail funzionano finché la richiesta non è completata, scaduta o chiusa. Ai destinatari aggiunti non viene mandata un’email; invia tu i loro link oppure chiama remind con i loro recipientIds.
Promemoria. remind manda per email il link ai destinatari nominativi che non hanno risposto e hanno un’email, al massimo una volta ogni 24 ore ciascuno. L’email di sendEmail conta come la prima.
Ricevere la risposta. Usane uno o combinane diversi:
webhookUrl- Il tuo server riceve ogni risposta man mano che arriva. Vedi Webhook.
notifyEmail- Mandiamo al tuo account un riepilogo e un link alla richiesta nella dashboard:
"each"a ogni risposta (finché non si raggiungono i limiti di email del piano, poi solo alla fine), oppure"complete"una sola volta quando si completa o scade. Le email delle approvazioni includono la decisione e il commento; le risposte dei moduli restano nella dashboard. Disattivato per impostazione predefinita;updateRequestpuò cambiarlo. getStatusconwait- Tiene la chiamata aperta fino a 25 secondi (REST:
?wait=25) e risponde appena qualcuno risponde o lo stato cambia. Richiamala per continuare ad aspettare. - MCP push (Builder e Pro)
- Ogni richiesta è la risorsa MCP
runitby://requests/{requestId}, collegata dacreateRequest; leggerla restituisce lo stesso digetStatus. Su Builder e Pro, i client sul protocollo 2026-07-28 possono iscriversi consubscriptions/listene riceverenotifications/resources/updateda ogni risposta o cambio di stato, con un’iscrizione aperta alla volta su Builder e fino a tre su Pro. Su Freesubscriptions/listenrisponde con un errore che indica gli altri modi per ricevere la risposta.
Schema del modulo
JSON Schema semplice con type: "object" in cima e fino a 40 campi. required[] viene applicato, e title e description diventano l’etichetta e il testo di aiuto.
| Tipo | Parole chiave |
|---|---|
string |
format (email, date, time, date-time, tel, uri, duration), minLength, maxLength, pattern
|
number, integer |
minimum, maximum |
boolean |
const: true crea una casella di consenso che va spuntata |
enum |
Un elenco fisso di scelte |
array |
Di primitivi o di un enum; minItems, maxItems |
Suggerimenti. Metti le opzioni per campo in "x-runitby": widget, placeholder, help, columns (1 o 2), step e currency.
Sezioni. Raggruppa i campi con sections: [{ title, fields: [...] }] accanto allo schema.
Oggetti annidati (tranne il campo di posizione), oneOf, anyOf, allOf e $ref vengono rifiutati con un messaggio che dice cosa cambiare. I campi che chiedono password, PIN, numeri di carta, CVV, codici di sicurezza, codici fiscali o codici monouso vengono rifiutati.
Tipi di campo
Campi pronti per ciò che per le persone è scomodo da digitare. Ognuno è un normale JSON Schema più un widget, quindi la risposta viene validata come qualsiasi altro campo.
| Campo | Schema | Risposta |
|---|---|---|
| Data | string, format date | "2026-11-12" |
| Ora | string, format time; step = minuti (1–60) | "14:30" |
| Data e ora | string, format date-time | "2026-11-12T14:30:00-08:00" |
| Durata | string, format duration | "PT1H30M" |
| Fasce orarie | array di enum date-time, widget slots | gli orari scelti |
| Intervallo di date | array di 2 date, widget daterange | ["2026-11-12", "2026-11-15"] |
| Posizione | object, widget location | { latitude, longitude, accuracy } |
| Importo | number, currency "USD" | 1200 |
| Cursore, valutazione | number o integer; il cursore richiede minimum e maximum | 7 |
| Chip, radio, select | enum (chips accetta anche un array di enum) | "M" |
| Classifica | array di enum, widget rank | tutte le opzioni, nell’ordine della persona |
| Sì o no | boolean, widget yesno | true |
| Colore | string, widget color | "#C2410C" |
| Paese | string, widget country | "US" (ISO 3166-1) |
| Lingua | string, widget language | "es-AR" (BCP 47) |
| Fuso orario | string, widget timezone | "America/New_York" |
Aggiungi un enum a un campo paese o lingua per limitare le scelte.
Anteprima
previewRequest accetta gli stessi campi di modulo o approvazione di createRequest (senza audience, scadenza, webhook o metadata) e restituisce screenshot larghi 390 px e 1280 px, più lint[] con tutto ciò che si leggerà male. Non viene creato nulla.
Passa sampleData per vedere il modulo compilato e viewports per ottenere una sola dimensione. Fai prima l’anteprima quando lo stesso modulo verrà inviato molte volte.
Temi
theme fa sembrare la pagina il tuo prodotto. Senza, le pagine sono inchiostro su bianco caldo, Figtree con titoli in Fraunces, angoli arrotondati.
| Chiave | Valori |
|---|---|
accent, background, surface,
text
|
Colori esadecimali |
font, headingFont |
system, Figtree, Geist, Inter, DM Sans, Manrope, Work Sans, Space Grotesk, IBM Plex Sans, Fraunces, Lora, Source Serif 4 |
radius |
sharp, soft, round |
density |
compact, comfortable |
layout |
stacked (tutti i campi in una pagina) o single (una domanda alla volta) |
logoUrl |
Il tuo logo |
heroText, thankYou |
Il saluto sopra il modulo e il messaggio dopo l’invio |
Opzioni di approvazione
Le approvazioni richiedono un’audience nominativa: ogni persona riceve il proprio link, così ogni decisione le è attribuita. L’esito è "approved", "declined" oppure "expired" quando nessuno ha deciso in tempo; mai un sì silenzioso.
| campo approval | Predefinito | Note |
|---|---|---|
reasonobbligatorio |
Cosa stai chiedendo, fino a 300 caratteri. | |
detail |
Contesto sotto il motivo, fino a 1.000 caratteri. | |
policy |
"all" |
"any", "all", "majority" o { n }: quante approvazioni servono. |
options |
Approva, Rifiuta | Da due a quattro etichette; la prima conta come approvazione. Le decisioni tornano in snake_case: «Approva con modifiche» → "approve_with_changes". |
allowComment |
true | Permetti alle persone di aggiungere un commento alla loro decisione. |
showOthers |
false |
"names" o "counts" mostra a ciascuno a che punto sono gli altri. |
verify |
false |
"email": ogni persona conferma un codice di 6 cifre inviato al proprio indirizzo prima che i pulsanti funzionino, così un link inoltrato non può decidere al suo posto. Ogni destinatario deve avere un’email. Usalo per denaro, accessi o cancellazioni. |
Webhook
Imposta webhookUrl (https) su una richiesta e ci facciamo un POST di JSON per due eventi:
response.created- Ogni invio o decisione, con la risposta in
response. request.completed- Ogni destinatario nominativo ha risposto, è stato raggiunto
maxSubmissions, un’approvazione ha il suo esito oppure la richiesta è scaduta.
Verifica la firma. X-Runitby-Signature è l’HMAC-SHA256 esadecimale del corpo grezzo con il segreto di firma del tuo account, che trovi nella dashboard. X-Runitby-Timestamp è l’ora di invio in secondi Unix.
Nuovi tentativi. Qualsiasi 2xx entro 10 secondi conta come consegnato. Altrimenti riproviamo 4 volte, 1 min, 5 min, 30 min e 2 h dopo ogni fallimento. Dopo, la risposta resta comunque disponibile in getStatus.
Errori
Gli errori sono JSON con un message leggibile e, per gli input non validi, problems[] che indica ogni campo da cambiare. Di solito gli agenti riescono a correggere la richiesta dal solo messaggio.
| Stato | Quando |
|---|---|
400 |
L’input o lo schema non è valido. |
401 |
Chiave API mancante o revocata. |
404 |
Nessuna richiesta con quell’id nel tuo account. |
409 |
La modifica non è più consentita, per esempio modificare dopo la prima risposta o sollecitare una richiesta chiusa. |
429 |
Oltre 60 creazioni al minuto, oppure le richieste mensili del piano sono esaurite. |
Piani e limiti
| Free | Builder | Pro | |
|---|---|---|---|
| Richieste al mese | 250 | 2,000 | 10,000 |
| Risposte per link aperto | 25 | 10,000 | Illimitato |
| Chiavi API | 1 | 5 | Illimitato |
| App collegate (OAuth) | 1 | 5 | Illimitato |
| Risposte conservate dopo la consegna | 30 giorni | 90 giorni | Conservate |
| Email al mese | 500 | 4,000 | 20,000 |
| Email per richiesta | 10 | 10 | 10 |
| MCP push (iscrizioni aperte) | — | 1 | 3 |
| Prezzo al mese | $0 | $9 | $29 |
Superato il limite mensile, createRequest restituisce 429 finché il periodo non si azzera o passi a un piano superiore (su Pro, il limite di uso corretto, scrivici per averne di più); i link già inviati continuano a funzionare. Senza un webhook, le risposte vengono conservate a partire dall’invio. Vedi i prezzi.
Le email che mandiamo per te (link, promemoria e aggiornamenti notifyEmail) contano per entrambi i limiti di email. Superato uno dei due, i link tornano come "limit" perché li mandi tu e gli aggiornamenti "each" si fermano. L’email che dice che una richiesta è finita parte sempre, e i codici di approvazione non contano.
Su ogni piano: 60 creazioni al minuto per chiave API, title fino a 120 caratteri, approval.reason 300, approval.detail 1.000 e metadata sotto i 4 KB.
Sei il titolare del trattamento di ciò che raccogli. Chiedi solo ciò che serve al compito.