[✅ Solution] Get "url" from Webhook

I’m using GoZen Forms to create an E-Sign form that would be integrated with my “Proposals” app on Tape. The goal is to send clients to the form, validate their email, get their signature and send the image of the signature back to Tape via webhook.

To get the signature I added the Tape webhook into GoZen Forms custom webhook and Tape is receiving the data successfully. However the signature image link that Tape gets from the webhook is received as so:

https://api.forms.gozen.io/response/download?formId=bk7IGJQTeR9x4DJpWjbE&fileId=R2B7OA-eSign-b9651c00-aca1-4a84-91e0-cf0ee6f8ccfd.png&link=0

When you open that link it changes to this:

{"url":"https://gz-prod-forms-file-storage.s3.amazonaws.com/uploads/bk7IGJQTeR9x4DJpWjbE/R2B7OA-eSign-b9651c00-aca1-4a84-91e0-cf0ee6f8ccfd.png?AWSAccessKeyId=AKIA6P2R47GRVQB4O7MA&Expires=1710200204&Signature=%2BHO9w5iQ%2B9k3N76KSp93aHAO9K8%3D"}

Here is a screenshot of what I got so far:

My idea was to execute a script in Tape to get the url value, but I ran into two issues:

  1. When defining the const webhookUrl to get the webhook url received from GoZen Forms, Tape doesn’t allow me to input the @Webhook payload / Signature variable in the execute a script action. For testing purposes I added the full URL, but how can I input the variable coming from the webhook in my script?

  2. The code I created is not getting all the id’s from the image url. Is not putting AWSAccessKeyId, Expires and Signature leaving those values as “null”.

Here the code:

// Webhook URL
const webhookUrl = "https://api.forms.gozen.io/response/download?formId=bk7IGJQTeR9x4DJpWjbE&fileId=R2B7OA-eSign-b9651c00-aca1-4a84-91e0-cf0ee6f8ccfd.png&link=0";
paylo

// Extracting the file ID and form ID from the webhook URL
const fileId = webhookUrl.split("fileId=")[1].split("&")[0];
const formId = webhookUrl.split("formId=")[1].split("&")[0];

// Constructing the base URL for the desired URL dynamically using the form ID
const baseUrl = `https://gz-prod-forms-file-storage.s3.amazonaws.com/uploads/${formId}/${fileId}`;

// Extracting the accessKeyId, expires, and signature from the baseUrl
const accessKeyIdMatch = baseUrl.match(/AWSAccessKeyId=([^&]+)/);
const expiresMatch = baseUrl.match(/Expires=([^&]+)/);
const signatureMatch = baseUrl.match(/Signature=([^&]+)/);

// Checking if matches were found before accessing the first group (index 1) of the match array
const accessKeyId = accessKeyIdMatch ? accessKeyIdMatch[1] : null;
const expires = expiresMatch ? expiresMatch[1] : null;
const signature = signatureMatch ? signatureMatch[1] : null;

// Constructing the desired URL using the base URL and the extracted file ID,
// accessKeyId, expires, and signature
const desiredUrl = `${baseUrl}?AWSAccessKeyId=${accessKeyId}&Expires=${expires}&Signature=${signature}`;

// Use the desired URL stored in the variable
console.log(desiredUrl); // Output the desired URL
console.log(fileId);
console.log(formId);
console.log(accessKeyId);
console.log(expires);
console.log(signature);

Is there an easier way to accomplish what I’m looking for?

After getting the image url I will Load Image From URL and Save it to an image field and then attach it accordingly to the signed proposal pdf.

Hi @Luis
you could try something like:

const url = jsonata(`data.fields[type = 'SIGNATURE'].value[0].url`).evaluate(webhook_payload_parsed);

const { data: file_content } = await http.get(url, {responseEncoding: 'binary'});

// upload the downloaded image to Tape
const encoded_file_content = Buffer.from(file_content, 'binary');
const { data: uploaded_file } = await tape.File.upload({filename: 'signiture.png', source: encoded_file_content});

// update current record using the uploaded file reference
const uploaded_image_file_id = uploaded_file.file_id;

var_tape_file_id =uploaded_image_file_id

My payload is more complex than yours:

{
  "eventId": "74e0654e-78db-4fac-972e-c5a510b3e146",
  "eventType": "FORM_RESPONSE",
  "createdAt": "2024-03-12T07:02:17.048Z",
  "data": {
    "responseId": "Qx1PxA",
    "submissionId": "Qx1PxA",
    "respondentId": "qAXe12",
    "formId": "mBXz6K",
    "formName": "test",
    "createdAt": "2024-03-12T07:02:15.000Z",
    "fields": [
      {
        "key": "question_PR66j0",
        "label": "Name",
        "type": "INPUT_TEXT",
        "value": "test1"
      },
      {
        "key": "question_EqXXzL",
        "label": null,
        "type": "SIGNATURE",
        "value": [
          {
            "id": "AKlx4N",
            "name": "e3e1f54c-79b3-448e-bd4d-8d67d75e3777.png",
            "url": "https://storage.tally.so/private/e3e1f54c-79b3-448e-bd4d-8d67d75e3777.png?id=AKlx4N&accessToken=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IkFLbHg0TiIsImZvcm1JZCI6Im1CWHo2SyIsImlhdCI6MTcxMDIyNjkzN30.71UMGVJF35720sLFNyrT9_23dZKvnGFfYsk1a27Zxck&signature=901287196c974a9c14330e5bd968dc06626825e9d45e27956249cd229e1c2a35",
            "mimeType": "image/png",
            "size": 16789
          }
        ]
      }
    ]
  }
}

so your JSONata first line would not need to be as complex.

You can then add the file as the image above.

Obviously, I have used a different form provider but hopefully, you can use that to make it work for yours.

Thanks so much, Jason. That helped a lot. I was able to get the webhook signature URL using just this:

const url = webhook_payload_parsed.Signature;

However, when I enter the code to download the signature image file from the external URL, I get this error:

Action execution failed with error: The first argument must be of type string or an instance of Buffer, ArrayBuffer, Array, or an Array-like Object. We received an instance of Object.

The URL I want to retrieve is not directly in the provided payload. Instead, the “Signature” field contains a link to download the file. I’m testing a few things to attempt to download the file from the parsed link and then extract the URL from the downloaded file’s content. No success yet.

Do you have some ideas?

Hi @Luis

Yes, mine is a link as well that the code goes and downloads. As your payload URL and mine looked similar then I was hoping that the same download method would work for you.

Sorry, it has been a long day and I am not sure what code you are using when you get this error:

If you want to DM me a current and valid full payload in a code block I will see if I can get it to work (no promises :wink: ), I find that sometimes these links need slightly different methods of downloading and processing the file, not that I have any idea why.

2 Likes

Hey @Jason

Thanks so much for your help. Since I’m testing the webhook, the full Payload only has an email and a signature field. It looks as follows:

{
  "Validate your email": "newcode@email.com",
  "Signature": "https://api.forms.gozen.io/response/download?formId=bk7IGJQTeR9x4DJpWjbE&fileId=R2B7OA-eSign-1d462437-a55f-4704-b1a6-f294957cdff8.png&link=0"
}

No matter what I try, I can’t seem to get the URL inside the app.forms.gozen that is coming from the webhook payload. I need gz-prod-forms-file-storage.s3.amazonaws (you can see that one by opening the line from the payload).

I believe your code will work once it is figured out.

@Luis

I see what you mean now, how strange. however, I have tried this new code with your payload and I was able to get your signature saved to a record:

const fUrl = jsonata('Signature').evaluate(webhook_payload_parsed);
const response = await http.get(fUrl,);
const url = jsonata('data.url').evaluate(response);
console.info('url:',JSON.stringify(url);

const { data: file_content } = await http.get(url, {responseEncoding: 'binary'});

// upload the downloaded image to Tape
const encoded_file_content = Buffer.from(file_content, 'binary');
const { data: uploaded_file } = await tape.File.upload({filename: 'signiture.png', source: encoded_file_content});

// update current record using the uploaded file reference
const uploaded_image_file_id = uploaded_file.file_id;

var_tape_file_id =uploaded_image_file_id;

It is the same as my original code however I make a call to the URL that is in your payload first which gets me the URL to get the image from it then goes and gets the image and saves that ready to add to the record.

All the best

1 Like

You are the man @Jason. That worked perfectly! Thank you so much.

4 Likes