Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 57 additions & 1 deletion docs/content/docs/reference/components/jotform_v1.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,26 @@ Version: 1

| Name | Label | Type | Description | Required |
|:---------------:|:--------------:|:------------:|:-------------------:|:--------:|
| region | Region | STRING <details> <summary> Options </summary> <span>us</span>, <span>eu</span> </details> | | true |
| region | Region | STRING <details> <summary> Options </summary> <span>us</span>, <span>eu</span>, <span>hipaa</span> </details> | | true |
| key | Key | STRING | | true |
| value | API Key | STRING | | true |



## Connection Setup

To connect ByteChef with Jotform, you need a Jotform API key.

1. Log into your [Jotform account](https://www.jotform.com/myaccount/api).
2. Navigate to the **API** Section.
3. Click **Create New Key**.
4. In the **Permissions** dropdown, select **Full Access**.
5. Give your key a name, like `Bytechef Integration`.
6. Copy the generated API Key.

<div style={{ position: 'relative', height:0, width: '100%', overflow: 'hidden', zIndex: 49, boxSizing: 'border-box', paddingBottom: 'calc(52.69531250% + 32px)'}}>
<iframe src="https://www.guidejar.com/embed/Rv4mtrPWXI57CDcjEQ5H?type=1&controls=on" width="100%" height="100%" style={{height:'100%', position:'absolute', inset:0}} allowFullScreen frameBorder="0"></iframe>
</div>



Expand Down Expand Up @@ -96,6 +110,48 @@ Type: OBJECT



## Triggers


### New Submission
Name: newSubmission

`Triggers when someone submits a response to a form.`

Type: DYNAMIC_WEBHOOK

#### Properties

| Name | Label | Type | Description | Required |
|:---------------:|:--------------:|:------------:|:-------------------:|:--------:|
| formId | Form ID | STRING | The ID of the form to watch for new submissions. | true |


#### Output

The output for this action is dynamic and may vary depending on the input parameters. To determine the exact structure of the output, you need to execute the action.

#### JSON Example
```json
{
"label" : "New Submission",
"name" : "newSubmission",
"parameters" : {
"formId" : ""
},
"type" : "jotform/v1/newSubmission"
}
```
#### How to find Form ID

1. Log into your Jotform Account.
2. Hover over the form in your dashboard and click **Edit Form**.
3. Look at the URL in your browser's address bar. The URL will look similar to: `https://www.jotform.com/build/1111111111111`.
4. The long number in the URL (between `/build/` and anything that follows) is your **Form ID**. In the example, the Form ID is `1111111111111`.





## What to do if your action is not listed here?

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -321,7 +321,7 @@ public Double getTemperature() {
}

public List<String> getStop() {
return stop;
return stop == null ? null : new ArrayList<>(stop);
}

public Integer getSeed() {
Expand Down Expand Up @@ -353,7 +353,7 @@ public Boolean getLogprobs() {
}

public Map<String, Double> getLogitBias() {
return logitBias;
return logitBias == null ? null : new HashMap<>(logitBias);
}

public Double getFrequencyPenalty() {
Expand Down
1 change: 1 addition & 0 deletions server/libs/modules/components/jotform/openapi.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ paths:
summary: "Get Form Submissions"
description: "Get all submissions for a specific form."
operationId: "getFormSubmissions"
x-help: "https://docs.bytechef.io/reference/components/jotform_v1#get-form-submissions"
parameters:
- name: "formId"
description: "ID of the form to retrieve submissions for."
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,9 @@
import com.bytechef.component.definition.ComponentDsl.ModifiableAuthorization;
import com.bytechef.component.definition.ComponentDsl.ModifiableComponentDefinition;
import com.bytechef.component.definition.ComponentDsl.ModifiableConnectionDefinition;
import com.bytechef.component.definition.ComponentDsl.ModifiableTriggerDefinition;
import com.bytechef.component.definition.Property;
import com.bytechef.component.jotform.trigger.JotformNewSubmissionTrigger;
import com.google.auto.service.AutoService;
import java.util.ArrayList;
import java.util.List;
Expand All @@ -39,6 +41,11 @@ public class JotformComponentHandler extends AbstractJotformComponentHandler {

private static final String REGION = "region";

@Override
public List<ModifiableTriggerDefinition> getTriggers() {
return List.of(JotformNewSubmissionTrigger.TRIGGER_DEFINITION);
}

@Override
public ModifiableComponentDefinition modifyComponent(ModifiableComponentDefinition modifiableComponentDefinition) {
return modifiableComponentDefinition
Expand Down Expand Up @@ -66,7 +73,8 @@ public ModifiableConnectionDefinition modifyConnection(
.label("Region")
.options(
option("US (jotform.com)", "us"),
option("EU (eu.jotform.com)", "eu"))
option("EU (eu.jotform.com)", "eu"),
option("HIPAA (hipaa-api.jotform.com)", "hipaa"))
.required(true));

modifiableAuthorization.properties(properties);
Expand All @@ -76,7 +84,14 @@ public ModifiableConnectionDefinition modifyConnection(
.baseUri((connectionParameters, context) -> {
String region = connectionParameters.getRequiredString(REGION);

return region.equals("us") ? "https://api.jotform.com" : "https://eu-api.jotform.com";
});
return switch (region) {
case "us" -> "https://api.jotform.com";
case "eu" -> "https://eu-api.jotform.com";
case "hipaa" -> "https://hipaa-api.jotform.com";
default -> throw new IllegalArgumentException("Invalid region: " + region);
};
})
.help("", "https://docs.bytechef.io/reference/components/jotform_v1#connection-setup")
.version(1);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,8 @@ public class JotformGetFormSubmissionsAction {
.required(false))
.metadata(
Map.of(
"responseType", ResponseType.JSON))));
"responseType", ResponseType.JSON))))
.help("", "https://docs.bytechef.io/reference/components/jotform_v1#get-form-submissions");

private JotformGetFormSubmissionsAction() {
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
/*
* Copyright 2025 ByteChef
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.bytechef.component.jotform.trigger;

import static com.bytechef.component.definition.ComponentDsl.string;
import static com.bytechef.component.definition.ComponentDsl.trigger;

import com.bytechef.component.definition.ComponentDsl.ModifiableTriggerDefinition;
import com.bytechef.component.definition.Context.Http;
import com.bytechef.component.definition.Parameters;
import com.bytechef.component.definition.TriggerContext;
import com.bytechef.component.definition.TriggerDefinition.HttpHeaders;
import com.bytechef.component.definition.TriggerDefinition.HttpParameters;
import com.bytechef.component.definition.TriggerDefinition.OptionsFunction;
import com.bytechef.component.definition.TriggerDefinition.TriggerType;
import com.bytechef.component.definition.TriggerDefinition.WebhookBody;
import com.bytechef.component.definition.TriggerDefinition.WebhookEnableOutput;
import com.bytechef.component.definition.TriggerDefinition.WebhookMethod;
import com.bytechef.component.definition.TypeReference;
import com.bytechef.component.jotform.util.JotformUtils;
import java.util.Map;

/**
* @author Monika Kušter
*/
public class JotformNewSubmissionTrigger {

public static final String FORM_ID = "formId";
public static final String WEBHOOK_URL = "webhookURL";

public static final ModifiableTriggerDefinition TRIGGER_DEFINITION = trigger("newSubmission")
.title("New Submission")
.description("Triggers when someone submits a response to a form.")
.help("", "https://docs.bytechef.io/reference/components/jotform_v1#new-submission")
.type(TriggerType.DYNAMIC_WEBHOOK)
.properties(
string(FORM_ID)
.label("Form ID")
.description("The ID of the form to watch for new submissions.")
.options((OptionsFunction<String>) JotformUtils::getFormIdOptions)
.required(true))
.output()
.webhookDisable(JotformNewSubmissionTrigger::webhookDisable)
.webhookEnable(JotformNewSubmissionTrigger::webhookEnable)
.webhookRequest(JotformNewSubmissionTrigger::webhookRequest);

private JotformNewSubmissionTrigger() {
}

protected static void webhookDisable(
Parameters inputParameters, Parameters connectionParameters, Parameters outputParameters,
String workflowExecutionId, TriggerContext triggerContext) {

Map<String, Object> body = triggerContext
.http(http -> http.get("/form/%s/webhooks".formatted(inputParameters.getRequiredString(FORM_ID))))
.configuration(Http.responseType(Http.ResponseType.JSON))
.execute()
.getBody(new TypeReference<>() {});

if (body.get("content") instanceof Map<?, ?> map) {
for (Map.Entry<?, ?> entry : map.entrySet()) {
Object value = entry.getValue();

if (value.equals(outputParameters.getRequiredString(WEBHOOK_URL))) {
triggerContext
.http(http -> http.delete(
"/form/%s/webhooks/%s".formatted(inputParameters.getRequiredString(FORM_ID),
entry.getKey())))
.execute();

break;
}
}
}
}

protected static WebhookEnableOutput webhookEnable(
Parameters inputParameters, Parameters connectionParameters, String webhookUrl, String workflowExecutionId,
TriggerContext triggerContext) {

triggerContext
.http(http -> http.post("/form/%s/webhooks".formatted(inputParameters.getRequiredString(FORM_ID))))
.header("Content-Type", "multipart/form-data")
.body(Http.Body.of(Map.of(WEBHOOK_URL, webhookUrl), Http.BodyContentType.FORM_DATA))
.configuration(Http.responseType(Http.ResponseType.JSON))
.execute();

return new WebhookEnableOutput(Map.of(WEBHOOK_URL, webhookUrl), null);
}

protected static Object webhookRequest(
Parameters inputParameters, Parameters connectionParameters, HttpHeaders headers,
HttpParameters parameters, WebhookBody body, WebhookMethod method, Parameters webhookEnableOutputParameters,
TriggerContext context) {

Map<String, Object> content = body.getContent(new TypeReference<>() {});

Object o = content.get("rawRequest");

if (o instanceof String s) {
content.put("parsedRawRequest", context.json(json -> json.read(s)));
}

return content;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -39,20 +39,26 @@ public static List<Option<String>> getFormIdOptions(
Parameters inputParameters, Parameters connectionParameters, Map<String, String> lookupDependsOnPaths,
String searchText, Context context) {

Map<String, Object> body = context.http(http -> http.get("/user/forms"))
.configuration(Http.responseType(Http.ResponseType.JSON))
.execute()
.getBody(new TypeReference<>() {});

List<Option<String>> options = new ArrayList<>();
int offset = 0;
List<?> list;

do {
Map<String, Object> body = context.http(http -> http.get("/user/forms"))
.queryParameters("offset", offset, "limit", 1000)
.configuration(Http.responseType(Http.ResponseType.JSON))
.execute()
.getBody(new TypeReference<>() {});

list = body.get("content") instanceof List<?> content ? content : List.of();

if (body.get("content") instanceof List<?> list) {
for (Object o : list) {
if (o instanceof Map<?, ?> map) {
options.add(option((String) map.get("title"), (String) map.get("id")));
offset++;
}
}
}
} while (!list.isEmpty());

return options;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
## Connection Setup

To connect ByteChef with Jotform, you need a Jotform API key.

1. Log into your [Jotform account](https://www.jotform.com/myaccount/api).
2. Navigate to the **API** Section.
3. Click **Create New Key**.
4. In the **Permissions** dropdown, select **Full Access**.
5. Give your key a name, like `Bytechef Integration`.
6. Copy the generated API Key.

<div style={{ position: 'relative', height:0, width: '100%', overflow: 'hidden', zIndex: 49, boxSizing: 'border-box', paddingBottom: 'calc(52.69531250% + 32px)'}}>
<iframe src="https://www.guidejar.com/embed/Rv4mtrPWXI57CDcjEQ5H?type=1&controls=on" width="100%" height="100%" style={{height:'100%', position:'absolute', inset:0}} allowFullScreen frameBorder="0"></iframe>
</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#### How to find Form ID

1. Log into your Jotform Account.
2. Hover over the form in your dashboard and click **Edit Form**.
3. Look at the URL in your browser's address bar. The URL will look similar to: `https://www.jotform.com/build/1111111111111`.
4. The long number in the URL (between `/build/` and anything that follows) is your **Form ID**. In the example, the Form ID is `1111111111111`.
Loading
Loading