Scripting Custom Scripts

Like Validations, Procedures are run server-side. However, while validations are triggered automatically when a submission is created or updated, Procedures are triggered manually with a POST Request. Procedures use the same server-side API as Validations do, both generally the same as the client-side API. Most of the same objects are available in all three formats. This page has information on the API for writing the procedure scripts themselves. For information on the procedure editor, see the feature documentation.

If you enable Development Mode, the output of console.log will be returned in an array with the request's response. You can view it from the Networking tab of any modern browser's developer console (F12).


Calling Procedures

If a procedure is triggered from a client-side or server-side script, it will be called as the currently logged-in user."procedure_name", { ... parameters ... }).done(function(response) {

Procedures can also be called with the REST API. See Getting Started with the REST API for information on calling procedures with an authorized user account.

POST https://{{organization}}{{form}}/procedures/{{procedure_endpoint}}

An optional submission parameter can be passed with the request, containing a submission's permalink. If the permalink is valid, its Submission object will be set to the self variable. Procedures are not limited to a single submission, and can query or trigger integrations.

Procedure Errors

If there's an issue that prevents the procedure server from functioning, an error will be returned with the Development Mode log output. Procedure Server error messages are listed below:

  • The procedure server timed out: Your custom script took too long, or was not resolved using the render method. Scripts are currently limited to 10 seconds.
  • The procedure server could not be reached: The procedure server is down or inaccessible. If this message appears, contact


The params method returns an object containing the parameters passed with the procedure's request. Both GET (query) and POST (data) parameters are included.

POST https://{{organization}}{{form}/procedures/{{procedure_endpoint}}?foo=bar

params().foo == "bar"

render(options = {})

The render method sets the response for the request made to trigger the procedure. By default it will render with HTTP status 200 "OK", and an empty response body. You are required to call it when your script is finished, or it will time out.

// Renders a response with the HTTP Status 200 "OK" and an empty body
render({ status: "ok" });

// Renders a response with the HTTP Status 400 "Bad Request", and the body in the format given.
render({ status: "bad_request", json: { error: "Invalid Parameters" } });
render({ status: 400, xml: "<error>Invalid Parameters</error>" });

The response's body and format are given by passing the format as a key and the body as a value. The response types "html", "json", "xml", "text", "yaml", and "csv" are supported.

render({ status: "ok", html: "&lt;html&gt;&lt;head&gt;&lt;title&gt;Page Title&lt;/title&gt;&lt;/head&gt;&lt;body&gt;HTML Response&lt;/body&gt;&lt;/html&gt;" });
render({ status: "ok", json: { message: "JSON Response" } });
render({ status: "ok", xml: "&lt;message&gt;XML Response&lt;/message&gt;" });
render({ status: "ok", csv: "1,CSV Response,Another Column" });

Rendering Status Codes

The render method's options takes a "status" parameter which controls the HTTP status code returned with the procedure's response. It accepts either code numbers or snake_case names derived from the status name. The accepted values are derived from Ruby on Rails standard status code list. A full list of the accepted status codes is available below, and the name or number can be used interchangeably.

100   continue
101   switching_protocols
102   processing
200   ok
201   created
202   accepted
203   non_authoritative_information
204   no_content
205   reset_content
206   partial_content
207   multi_status
208   already_reported
226   im_used
300   multiple_choices
301   moved_permanently
302   found
303   see_other
304   not_modified
305   use_proxy
307   temporary_redirect
308   permanent_redirect
400   bad_request
401   unauthorized
402   payment_required
403   forbidden
404   not_found
405   method_not_allowed
406   not_acceptable
407   proxy_authentication_required
408   request_timeout
409   conflict
410   gone
411   length_required
412   precondition_failed
413   payload_too_large
414   uri_too_long
415   unsupported_media_type
416   range_not_satisfiable
417   expectation_failed
422   unprocessable_entity
423   locked
424   failed_dependency
426   upgrade_required
428   precondition_required
429   too_many_requests
431   request_header_fields_too_large
500   internal_server_error
501   not_implemented
502   bad_gateway
503   service_unavailable
504   gateway_timeout
505   http_version_not_supported
506   variant_also_negotiates
507   insufficient_storage
508   loop_detected
510   not_extended
511   network_authentication_required


Procedures can be passed an optional "submission" parameter with a submission's permalink. If the permalink is valid and permitted, a Submission object will be provided for it. The submission can be accessed with the self variable using the same syntax as client-side scripts.

POST https://{{organization}}{{form}}/procedures/{{procedure_endpoint}}?submission=ABCDEFGHIJ

self.permalink(); // "ABCDEFGHIJ"


The submission object is an alias for the self object.