Con l'API propform puoi gestire i tuoi moduli, gli invii e le statistiche da applicazioni esterne, ad esempio dai tuoi strumenti, script o piattaforme di automazione come Zapier, Make o n8n.
> URL di base: https://propform.io/api/v1
>
> Tutte le richieste e le risposte sono in formato JSON (Content-Type: application/json). I timestamp sono in formato ISO-8601 (ad es. 2026-07-07T08:30:00+00:00).
Creare una chiave API: Vai su Impostazioni → Chiavi API, clicca su Crea chiave API e copia la chiave visualizzata (formato pf_live_…). Per motivi di sicurezza, ti verrà mostrata solo questa volta.
Verifica la connessione: sostituisci pf_live_DEIN_KEY e accedi a:
curl https://propform.io/api/v1/me \
-H "Authorization: Bearer pf_live_DEIN_KEY"
Risposta:
{ "data": { "id": 42, "name": "Max Makler", "email": "max@makler.de" } }
Prima richiesta effettiva – elenca i tuoi moduli:
curl https://propform.io/api/v1/forms \
-H "Authorization: Bearer pf_live_DEIN_KEY"
L’API utilizza le chiavi API come token bearer. Ogni richiesta richiede la chiave nell’intestazione Authorization (Authorization: Bearer pf_live_…). In assenza di chiave o in caso di chiave non valida, l’API risponde con 401.
In caso di superamento del limite, l’API risponde con 429 Too Many Requests e un’intestazione Retry-After (secondi che mancano al prossimo tentativo consentito). Inserisci una breve pausa nelle automazioni quando visualizzi questo stato.
Le risposte andate a buon fine forniscono i dati nel campo data.
Gli elenchi sono impaginati. Gestiscili tramite per_page (impostazione predefinita 25, max. 100) e page. La risposta contiene inoltre links e meta:
{
"data": [ { "id": 14, "internal_title": "Kontaktformular", "active": true } ],
"links": { "first": "...", "last": "...", "prev": null, "next": "...?page=2" },
"meta": { "current_page": 1, "per_page": 25, "total": 63, "last_page": 3 }
}
Gli errori hanno sempre un campo message; in caso di errori di convalida (422), i dettagli per ciascun campo sono riportati in errors:
{
"message": "The url field is required.",
"errors": { "url": ["The url field is required."] }
}
| Stato | Significato |
|---|---|
200 / 201 |
Operazione riuscita (201 = nuovo record creato) |
204 |
Operazione riuscita, nessun dato di risposta (ad es. cancellazione) |
401 |
Chiave API assente o non valida |
403 |
Il record non appartiene al tuo account (o funzione non inclusa nel piano tariffario) |
404 |
Il record non esiste |
409 |
Azione attualmente non possibile (ad es. onOffice non connesso) |
422 |
Errore di convalida – Dettagli nel campo errors |
429 |
Limite di rate raggiunto – Vedi Retry-After |
| Metodo | Endpoint | Descrizione |
|---|---|---|
GET |
/forms |
Elenca i propri moduli. Filtri: active (0/1), updated_since (data), per_page, page |
POST |
/forms |
Crea un nuovo modulo – è necessario solo internal_title, si avvia inattivo |
GET |
/forms/{id} |
Leggi il modulo per intero (compresi i campi, l’e-mail e la configurazione di ChatGPT) |
PATCH |
/forms/{id} |
Configurare il modulo – vengono modificati solo i campi inviati |
POST |
/forms/{id}/copy |
Copia del modulo (compresi campi, regole, configurazione e-mail); la copia si avvia inattiva |
Il modulo è una risorsa nell’API: puoi leggere e modificare le impostazioni relative all’invio delle e-mail e all’integrazione con ChatGPT direttamente sul modulo. I nomi dei campi corrispondono esattamente alle impostazioni nell’editor del modulo.
curl -X PATCH https://propform.io/api/v1/forms/123 \
-H "Authorization: Bearer pf_live_DEIN_KEY" \
-H "Content-Type: application/json" \
-d '{"title": "Neuer Titel", "active": true}'
Caratteristiche importanti:
"active": true) funziona solo finché non viene raggiunto il limite del tuo piano relativo ai moduli attivi (altrimenti 422). La disattivazione è sempre possibile.slug, i contatori e i flag dei modelli. Le password (ad es. la password del modulo) sono modificabili, ma non compaiono mai nelle risposte.url pubblico del modulo.Un modulo dispone di oltre 100 impostazioni (tutte quelle offerte anche dall’editor). Le più importanti:
| Campo | Significato |
|---|---|
internal_title |
Nome interno (visibile solo nella dashboard) |
title |
Titolo pubblico del modulo |
custom_slug |
Parte descrittiva dell’URL (deve essere univoca nel tuo account) |
active |
Modulo online (true) o offline (false) |
description |
Testo introduttivo sopra il modulo |
submit_button_label |
Etichetta del pulsante di invio |
thankyou_headline / thankyou_text |
Titolo e testo della pagina di ringraziamento |
redirect |
URL di reindirizzamento dopo l’invio (al posto della pagina di ringraziamento) |
background_color / accent_color |
Colori di design (esadecimali, ad es. #0d6efd) |
subject / body / receiver |
Oggetto, testo e destinatario dell’e-mail di conferma |
send_email_via_onoffice |
Invia l’e-mail di conferma tramite onOffice |
Puoi visualizzare l’oggetto completo in qualsiasi momento tramite GET /forms/{id}.
👉 Trovi l'elenco completo di tutti i campi e formati nella referenza dei campi API.
| Metodo | Endpoint | Descrizione |
|---|---|---|
GET |
/forms/{id}/fields |
Campi di un modulo (ordinati per posizione) |
POST |
/forms/{id}/fields |
Crea campo – onoffice_module è obbligatorio, la posizione viene aggiunta automaticamente alla fine |
GET |
/fields/{id} |
Leggere un singolo campo |
PATCH |
/fields/{id} |
Modificare un campo (solo proprietà inviate) |
DELETE |
/fields/{id} |
Elimina campo |
PATCH |
/forms/{id}/fields/reorder |
Riordinare i campi – field_ids deve contenere tutti gli ID dei campi del modulo nell'ordine desiderato |
curl -X POST https://propform.io/api/v1/forms/123/fields \
-H "Authorization: Bearer pf_live_DEIN_KEY" \
-H "Content-Type: application/json" \
-d '{"onoffice_module": "address", "onoffice_field_name": "Vorname", "label": "Vorname", "required": true}'
| Campo | Significato |
|---|---|
onoffice_module |
Modulo di destinazione: address, estate, task, calendar, agentsLog (obbligatorio al momento della creazione) |
onoffice_field_name |
Nome del campo di destinazione in onOffice (vedi Configurazione dei campi onOffice) |
label |
Etichetta del campo nel modulo |
hint / placeholder |
Testo di aiuto o segnaposto nel campo di immissione |
required |
Campo obbligatorio (true/false) |
hidden / disabled / read_only |
Nascosto / disattivato / di sola lettura |
default_value |
Valore predefinito |
half_size |
Visualizza il campo a mezza larghezza sugli schermi di grandi dimensioni |
datalist |
Valori di selezione come elenco separato da punti e virgola (Rot;Grün;Blau) |
Ordinamento: nel caso di reorder, l’ordine nell’array field_ids determina la nuova posizione. L'array deve contenere esattamente tutti gli ID dei campi del modulo (se ne manca uno o ne è presente uno estraneo → 422):
curl -X PATCH https://propform.io/api/v1/forms/123/fields/reorder \
-H "Authorization: Bearer pf_live_DEIN_KEY" \
-H "Content-Type: application/json" \
-d '{"field_ids": [4712, 4711, 4713]}'
GET /onoffice/fields fornisce la configurazione dei campi del tuo account onOffice – per ogni modulo (address, estate, task, calendar, agentsLog, file, project) tutti i campi con etichetta, tipo, lunghezza e valori consentiti. In questo modo puoi trovare i valori validi per onoffice_field_name. Con ?module=address puoi filtrare per un modulo.
{
"data": {
"address": {
"Vorname": { "label": "Vorname", "type": "varchar", "length": 50, "default": null, "permittedvalues": null },
"Anrede": { "label": "Anrede", "type": "singleselect", "length": null, "default": null,
"permittedvalues": { "HERR": "Herr", "FRAU": "Frau" } }
}
}
}
> È necessario che la connessione all’API di onOffice funzioni correttamente; in caso contrario, l’endpoint risponde con 409.
| Metodo | Endpoint | Descrizione |
|---|---|---|
GET |
/forms/{id}/rules |
Regole di un modulo (ordinate per priorità) |
PUT |
/forms/{id}/rules |
Sostituisci tutte le regole del modulo (array vuoto = elimina tutte) |
L'endpoint di scrittura funziona come l'editor delle condizioni nella dashboard: tutte le regole vengono sempre salvate in una volta sola (non è possibile aggiungerne una singola alla volta). Quindi, leggi prima con GET, modifica l’elenco e invialo per intero tramite PUT. Una regola è costituita da clauses (condizioni «Se», collegate a mode = all/any) e actions (azioni "allora"):
curl -X PUT https://propform.io/api/v1/forms/123/rules \
-H "Authorization: Bearer pf_live_DEIN_KEY" \
-H "Content-Type: application/json" \
-d '{"rules": [{
"title": "Zusatzfeld einblenden",
"mode": "all", "priority": 10, "is_enabled": 1, "run_on_init": 1,
"clauses": [{"when_field_id": "4711", "operator": "equals", "value": "Ja"}],
"actions": [{"order": 10, "action": "show", "target_field_id": "4712"}]
}]}'
equals, not_equals, empty, not_empty, starts_with, not_starts_with, contains, not_containsshow, hide, enable, disable, require, optional, hide_option, unhide_option, set_value, set_label, make_readonly, unmake_readonly, enable_rules_by_tag, disable_rules_by_tag__form_title, __form_description, __submit, __submit_spinner, __multistep_back, __multistep_next (in questo caso solo set_label, show, hide; per lo spinner solo set_label).403).Per i dettagli sul funzionamento delle regole, consulta Condizioni, regole e calcoli.
| Metodo | Endpoint | Descrizione |
|---|---|---|
GET |
/forms/{id}/submissions |
Invii di un modulo. Filtro: created_after, created_before, sort (asc/desc), per_page |
GET |
/submissions/{id} |
Invio singolo |
GET |
/forms/{id}/stats |
Visualizzazioni, invii e tasso di conversione; opzionale from/to (data) |
Il contenuto di un invio (content) è raggruppato in base ai moduli di onOffice:
{
"data": {
"id": 456, "form_id": 123, "index": 42,
"content": { "address": { "Vorname": "Max", "Name": "Mustermann" }, "estate": { "Id": "131" } },
"ip_address": "203.0.113.7",
"created_at": "2026-07-07T08:30:00+00:00"
}
}
Se nelle impostazioni sulla privacy hai disattivato il salvataggio dei dati degli invii, content è sempre null – l’invio viene comunque conteggiato nelle statistiche. La risposta stats contiene views, submissions e conversion_rate.
Invece di interrogare regolarmente gli invii, puoi ricevere notifiche tramite webhook: propform invia immediatamente un POST al tuo URL ogni volta che viene effettuato un nuovo invio.
💡 Puoi gestire i webhook anche nel frontend, senza chiave API: nelle impostazioni alla voce «Webhooks» (per tutti i moduli) oppure direttamente nell'editor dei moduli alla voce «Webhook (Zapier, n8n, Make …)».
| Metodo | Endpoint | Descrizione |
|---|---|---|
GET |
/webhooks |
Elenca i tuoi abbonamenti ai webhook |
POST |
/webhooks |
Crea un abbonamento: url (obbligatorio), form_id (facoltativo – se non specificato, l’abbonamento si applica a tutti i tuoi moduli), payload_template (facoltativo – vedi sotto), message_key (facoltativo – nome del campo del messaggio risolto, predefinito text) |
DELETE |
/webhooks/{id} |
Elimina abbonamento |
Requisiti per l’URL: deve essere accessibile pubblicamente e utilizzare http:// o https://. Gli indirizzi interni o locali (ad es. localhost, 127.0.0.1, IP di reti private) vengono rifiutati per motivi di sicurezza (422). Poiché i dati inviati vengono trasmessi, utilizza se possibile https://.
La risposta generata al momento della creazione contiene l’secret, con cui viene firmata ogni consegna (puoi recuperarlo in qualsiasi momento tramite GET /webhooks):
{
"data": {
"id": 7, "event": "submission.created",
"url": "https://example.com/hook", "form_id": 123,
"secret": "a1b2c3…", "payload_template": null, "message_key": "text", "is_active": true,
"failure_count": 0, "last_success_at": null, "last_failure_at": null,
"created_at": "2026-07-07T08:30:00+00:00"
}
}
Ogni consegna contiene due intestazioni:
X-Propform-Event – il tipo di evento (attualmente sempre submission.created)X-Propform-Signature – sha256=<HMAC-SHA256 des Request-Bodys mit deinem secret>Esempio di payload:
{
"event": "submission.created",
"created_at": "2026-07-07T08:30:00+00:00",
"form": { "id": 123, "slug": "aB3x…", "custom_slug": "kontakt", "title": "…", "internal_title": "…" },
"submission": { "id": 456, "index": 42, "content": { "address": { "Vorname": "Max" } } },
"onoffice_ids": { "address": { "ID": "789" } }
}
payload_template)Facoltativamente, puoi salvare un modello di testo libero per ogni abbonamento. Dopo ogni invio del modulo, propform vi risolve le macro onOffice (sui record creati o modificati dall'invio) e include il risultato nel payload come campo di messaggio dedicato: ideale come messaggio pronto per Slack e simili, senza dover assemblare nulla nel flusso di lavoro ricevente. Il nome del campo è text per impostazione predefinita (vedi sotto).
Esempio di modello:
Nuova richiesta di _Vorname _Name per _objekttitel → _getEstateLink
nel payload diventa:
"text": "Nuova richiesta di Max Mustermann per Traumwohnung am Stadtpark → https://smart.onoffice.de/…"
Nome del campo del messaggio (message_key): Per impostazione predefinita il campo si chiama text: così Slack, Microsoft Teams e Google Chat interpretano il payload direttamente come messaggio. Discord si aspetta content. Per Zapier/n8n/Make il nome è libero. Puoi modificarlo per ogni webhook tramite il parametro message_key (nel frontend alla voce «Nome del campo del messaggio»).
Da tenere presente:
_getAddressLink, _getEstateLink, …)._objekttitel richiede un immobile collegato). Senza contesto, la macro resta non risolta nel testo.Verifica la firma per assicurarti che la richiesta provenga effettivamente da propform. Calcola l’HMAC sul corpo della richiesta grezzo (non sul JSON analizzato) e confrontalo in tempo reale.
PHP:
$secret = 'DEIN_WEBHOOK_SECRET';
$body = file_get_contents('php://input');
$signature = $_SERVER['HTTP_X_PROPFORM_SIGNATURE'] ?? '';
$expected = 'sha256=' . hash_hmac('sha256', $body, $secret);
if (!hash_equals($expected, $signature)) {
http_response_code(403);
exit('Ungültige Signatur');
}
// ab hier: $body ist echt – json_decode($body, true) verarbeiten
Node.js (Express):
const crypto = require('crypto');
// WICHTIG: express.raw() nutzen, damit der Body unverändert bleibt
app.post('/hook', express.raw({ type: 'application/json' }), (req, res) => {
const secret = process.env.PROPFORM_WEBHOOK_SECRET;
const expected = 'sha256=' + crypto.createHmac('sha256', secret).update(req.body).digest('hex');
const got = req.header('X-Propform-Signature') || '';
if (expected.length !== got.length ||
!crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(got))) {
return res.status(403).send('Ungültige Signatur');
}
const payload = JSON.parse(req.body.toString());
res.sendStatus(200);
});
2xx. In caso di errori, propform tenta la consegna fino a 3 volte (con un intervallo di attesa).is_active: false, visibile tramite GET /webhooks). A quel punto basta ricrearlo.GET /form-groups elenca i tuoi gruppi di moduli con i relativi ID. Puoi assegnare gli ID nel PATCH del modulo come form_groups (array).
GET /forms/{id}/submissions?sort=desc e del valore più alto già elaborato id.GET /me.GET /forms?updated_since=….429 inserire una breve attesa e rispettare l’intestazione Retry-After.La versione attuale è v1 ed è fissata nel percorso (/api/v1). Aggiungiamo nuovi campi ed endpoint in modo retrocompatibile senza modificare la versione; pertanto, il tuo client dovrebbe semplicemente ignorare i campi sconosciuti presenti nelle risposte. Modifiche fondamentali e non retrocompatibili verrebbero pubblicate con una nuova versione (/api/v2).