API for developers: keys, scopes and examples
Create a key and read or write forms, responses and reports from your own software.
Go to API & integrations🔑 Creating a key
- 1 Go to "Settings → API & integrations" From the side menu, "Settings", tab "API & integrations".
- 2 Click "New key" and give it a name For example "Main website" or "CRM"; create a separate key for each application.
- 3 Tick only the scopes you need The three read scopes are enough for reading responses.
- 4 Set the rate limit and expiry Default: 120 requests per minute and no expiry.
- 5 Copy the key right away The full key starts with ff_live_ and is shown only once; we don't keep a copy either.
🧩 Scopes
forms:read — list forms and exams, their structure, settings and links.
forms:write — create, edit, publish and delete forms.
responses:read — list and view responses, and CSV / Excel export.
responses:write — tag, annotate, edit and delete responses.
reports:read — reports, statistics, dashboards and report exports.
📡 Base URL, header and first request
The base URL is https://porsino.com/api/v1 and every request needs the Authorization: Bearer header with your key. No cookies or CSRF token are needed.
FORM_ID is the form's id in the forms list output. Each page of responses has up to 100 rows; move on with page.
curl -s "https://porsino.com/api/v1/forms?page_size=20" \ -H "Authorization: Bearer $PORSINO_API_KEY" curl -s "https://porsino.com/api/v1/forms/FORM_ID/responses?page=1&page_size=50" \ -H "Authorization: Bearer $PORSINO_API_KEY" curl -s -o responses.csv "https://porsino.com/api/v1/forms/FORM_ID/responses/export?format=csv" \ -H "Authorization: Bearer $PORSINO_API_KEY"
🚦 Rate limits and errors
Each key has its own per-minute limit (default 120); beyond it you get 429 with a Retry-After header.
401 means the key is invalid, revoked or expired; 403 with the code insufficient_scope means the key's scope isn't enough for that action, and fields.scope says which one is needed.
Errors always have the same shape: error with three parts — code, message and fields. With the header Accept-Language: en the message is in English.
🪝 Webhooks: instant updates instead of polling
To notify your system on every new response, open the form → "Integrations" tab and enter your own address. Retries are automatic and every delivery is logged there.
Every delivery carries the X-FlowForm-Event, X-FlowForm-Delivery, X-FlowForm-Timestamp and X-FlowForm-Signature headers. The signature is sha256=HMAC-SHA256 over "timestamp.body" with that webhook's signing key; reject deliveries older than 5 minutes.
import hmac, hashlib msg = request.headers["X-FlowForm-Timestamp"].encode() + b"." + raw_body expected = "sha256=" + hmac.new(secret.encode(), msg, hashlib.sha256).hexdigest() ok = hmac.compare_digest(expected, request.headers["X-FlowForm-Signature"])
🌐 Custom domain
Forms and exams can open on a Porsino subdomain or your own domain; connect it under “Settings › Custom domain” (the security certificate is issued automatically).
To bring participants in from your site, add a button or a menu item (see the guide "Exam on your own site, with entry for authorized people only").
Want to set this up on your own form? Creating an account and using Porsino is Free .
Start for freeRelated guides
- Custom domain: your forms on your own addressOpen your forms and exams on a Porsino subdomain or your own domain (such as forms.company.ir).
- Appearance and brand kitMatch the form's layout, theme, colors, logo and font to your organization's identity.
- Organisational sign-in (Active Directory, Azure AD and LDAP)Staff sign in to Porsino with their network or organisational account — a step-by-step guide for the IT team.
- Settings and securityAnti-spam, team and roles, automatic cleanup, and security and account deletion.
- AdminSuperadmin panel: users, service health and global settings.