How to
Web forms
On this page
A web connector lets a form on your website create tickets in an installed app. People without a chat account can then submit requests. This page is for the builder who owns both the app and the form. The key list is in Connectors, and the request contract in Endpoints.
Add a web connector
The connector is a top-level webConnector key in the app YAML, and you edit it on the Expert tab. Leave id empty. Conclude generates an ID when it is missing, or when it belongs to another channel.
webConnector:
id:
disabled: true stops submissions and returns disabled_error without removing the configuration.
Submit the form
Send a POST to /v1/form/<cid>, where <cid> is the connector ID. The older /v1/activity.form/<cid> path reaches the same handler.
The body is either application/json or application/x-www-form-urlencoded. JSON must be a flat object of string values. In a form-encoded body, Conclude reads the first value of each field. Any other content type is rejected with HTTP 400, and so is malformed JSON. Cross-origin requests are allowed.
Map fields to attributes
A form field named like an attribute needs no mapping. An attributeMap entry renames a form field (external) to an attribute (internal). Its defaultValue applies when the field is empty or absent. A default may use macros that read other form fields.
webConnector:
id: <generated>
attributeMap:
- internal: title
defaultValue: Message from ${name} ${email}
- external: message
internal: body
defaultValue: <no message>
Values are cut at 3000 characters. A mandatory string or text attribute that is still empty is set to -. Every value then passes input validation. If one fails, the request returns validation_error.
Restrict domains and rate
domain is a comma-separated list of hostnames. When you set it, the request’s Origin header must match one of them, or a subdomain of one. The match ignores case. Any other origin fails with domain_error. A script can send any Origin, so this is a filter, not security.
settings.rateLimit caps ticket creation for the whole app, and you write it in N/min form. The default is 10 per minute, and saving clamps the value to between 1 and 120. See Settings. Over the limit, the endpoint returns rate_limit_error. A submission identical to one received in the last five minutes returns duplicate_request_error. A general per-client limit also applies.
Block bots with reCAPTCHA v3
Run /c app secrets in the app’s channel and store your Google reCAPTCHA v3 private key. The dialog works in Slack only, because Microsoft Teams has no secrets dialog. Your page must obtain a token with the matching site key and post it as a field named recaptcha.
Once a key is stored, every submission must carry a token. A missing token returns recaptcha_error and sends a system alert to the app. A token that Google rejects or scores below 0.5 fails the same way, and so does a token sent when no key is stored.
Log accepted and rejected submissions
logMessage and logJunk are optional chat messages. Each one has a to field, which holds a role expression or a channel, and a body field, where form values are macros.
logMessage fires with the mapped values for each submission that passes reCAPTCHA and validation. It fires before the duplicate and rate checks. logJunk fires with the raw fields when reCAPTCHA or validation fails.
Read the response
A created ticket returns:
{"status": "ok", "xid": "<external ticket id>"}
xid is the new ticket’s external ID. Posting xid back to the form endpoint does not update the ticket.
Otherwise status is one of disabled_error, validation_error, recaptcha_error, rate_limit_error, duplicate_request_error, not_found_error or internal_error. These still arrive with HTTP 200, so check the body. An unknown connector ID (config_error) and domain_error return HTTP 400 instead.
Related pages
- Macros and roles for the macro syntax in default values and log messages