let $'image' = true => call 'network'::'http' with (
$'server' = $'image url'
$'path' = ""
$'authentication' = unset
$'request' = new (
'method' = option 'get'
'headers' = {
create [ "Authorization" ] var 'api key'
}
)
) || throw "HTTP request to get image failed"
The above request yields a binary response stored in $‘image’, which contains data of an image (JPEG or PNG). I’m am figuring out whether it is possible to encode this image? Can anybody help me please.
To illustrate the result I wish to achieve: the following cURL would uncode and save the image locally when executed on my OS terminal.
curl --location $'image url' \
--header 'var 'api key'' > image.jpeg
After you have downloaded an image like this in a processor.alan
, you can upload it to the “files resource” that is available for your Alan application. This would result in a “file token” that you can send back to the application, which can work with files if you create a property of the type file
. If you also report the extension (like png
or jpg
) then the browser will show a preview as well and allow the end user to download the file.
So you follow these steps in general:
- Download binary data from an external system.
- Upload the binary data to the files resource linked to your Alan app.
- You will receive a ‘file token’ from the files resource.
- You can send the ‘file token’ back to your Alan app, where you should store it in a property of the type ‘file’.
As you do not have direct file system access from a processor.alan
, this is the best way to get your file data to the end user and/or another system.
In theory you could also let your processor.alan
behave as a web proxy that accepts a request from an end user, injects the Authorization
header with an API key (that should probably be secret for the end user), performs the request and sends the response data (an image) back to the end user. This requires adding a “web hook” to your processor.alan
.
1 Like
Thank you!
I would love to have help with the second problem as well, which is the following status 302 I receive after doing the get request. Following the location of the header does not provide me with an image and seems rather explanatory instead of redirective. Looking at the headers there might be a problem with the fact I am sending the request from the Kjerner servers? Executing the same get request via my OS terminal does not yield any problems . How to prevent this?
{
"status": 302,
"headers": {
"vary": "Accept-Encoding",
"location": "https://www.facebook.com/unsupportedbrowser",
"strict-transport-security": "max-age=15552000; preload",
"content-type": "text/html; charset=\"utf-8\"",
"x-fb-debug": "mAmbm3YLlGA3ZYcXA6B6leOrzLATb/6PVh1Iq9ZZCkp1c/nsmIFjpeF1YEgEn/PQBhjtFKfMeFc6b1a2J36KLg==",
"content-length": "0",
"date": "Sat, 04 Jan 2025 23:06:54 GMT"
},
"content": ""
}
There probably is a difference in the headers that get sent with the request from our connector vs. curl
in your OS terminal.
Please share with me (in a private message) the output of your curl
command after adding the -v
flag for verbose output. This should include all request headers.
1 Like
I am now struggling with the following: my webhook receives the mime_type to describe the document type. I wish to convert this to the correct extension so it can be processed by the Alan application. Does Alan has any build-in converter? Below I illustrate what I want to achieve, I know the syntax is invalid and only for illustrative purpose. Any tips are welcome!
'Type' = create 'Attached' (
'Type' = ^ ^ $'type'
'Document' = file (
token = $'result'.'reply type'.'body'.'result'.'body'.'token'
extension = switch $'extension' => switch $'mime_type' (
| "image/jpeg" => "jpg"
| "image/png" => "png"
| "image/gif" => "gif"
| "application/pdf" => "pdf"
| "text/plain" => "txt"
| "text/html" => "html"
| "application/json" => "json"
| "audio/mpeg" => "mp3"
| "video/mp4" => "mp4"
| "image/webp" => "webp"
| "image/svg+xml" => "svg"
| _ => throw "Unsupported MIME type"
)
)
)
If you want to translate from MIME type to file extension or the other way around, then a lookup table like you describe is the best way to go.
Is this really the only information about the file that your webhook receives? If you already have a filename, it might be easier to just split that in filename + extension and send the file token + extension back to the Alan app.
That sounds like a better solution. How can I split the filename from the extension? Thank you in for your help 
This should work to split the filename in parts:
let $'filename_parts' = $'file path' => parse as pattern ( 'filename': $ text *"." 'extension': $ text ) || throw "invalid format"
1 Like
I am trying now to upload a file to an endpoint to retrieve an image id. The request should look as follows:
curl 'https://graph.facebook.com/<API_VERSION>/<PHONE_NUMBER_ID>/media' \
-H 'Authorization: Bearer <ACCESS_TOKEN>' \
-F 'messaging_product=whatsapp' \
-F 'file=@<FILE_PATH_AND_NAME>;type=<MIME_TYPE>'
I am familiar only with sending JSON data in the content. But how can I post a file within a processor?
let $'file' = $'Item.'File'
let $'Phone number ID' = $'Item'.'Phone Number ID'
let $'request_media_id' = true => call 'network'::'http' with (
$'server' = "https://graph.facebook.com"
$'path' = list ( "/v21.0/", $'Phone number ID', "/media" ) => join ( )
$'authentication' = unset
$'request' = new (
'method' = option 'post'
'headers' = {
create [ "Authorization" ] var 'api key'
}
'content' = /*HERE THE FILE NEEDS TO BE*/ => call 'unicode'::'as binary' with ( )
)
) || throw "HTTP request to WhatsApp API failed"
let $'media_id' = $'request_media_id'.'content' => call 'unicode'::'import' with ( $'encoding' = "UTF-8" ) => parse as JSON => decorate as {
'id': text
} || throw "unable to parse request data"
You should first download the file (binary data) from the files resource where it was previously uploaded. After that, you can directly POST it to the external API as binary data in the ‘content’ parameter.
I got as far as this:
let $'file' = true => call 'network'::'http' with (
$'server' = var 'files_resource_url'
$'path' = $'Item'.'Type'?'Document'.'File'.token || throw "No File found"
$'authentication' = unset
$'request' = new (
'method' = option 'get'
)
) || throw "http request failed"
let $'data' as {
'messaging_product': text
'file': binary
} = (
'messaging_product' = "whatsapp"
'file' = $'file'.'content'
)
let $'request_media_id' = true => call 'network'::'http' with (
$'server' = "https://graph.facebook.com"
$'path' = list ( "/v21.0/", $'Phone number ID', "/messages" ) => join ( )
$'authentication' = unset
$'request' = new (
'method' = option 'post'
'headers' = {
create [ "Authorization" ] var 'api key'
}
'content' = $'data' => call 'unicode'::'as binary' with ( ) //--> This does not work, but what does work to make the data suitable?
)
) || throw "HTTP request to WhatsApp API failed"
From your example and the documentation I see the curl -F
flag means that curl
will construct a multipart/form-data message, just like a browser would after filling out and submitting a form.
I didn’t notice this when I first read your question. It means you will have to construct this multipart/form-data message in the connector. It is a text-based format, so I think it should be possible, but I’m not sure whether it is the best approach.
Does the API offer other methods/protocols to make the same call?
Edit: I just checked the docs on Media - Cloud API - Documentation - Meta for Developers and it seems this is the only accepted format for the parameters.
Discussed above makes use of an “id” of a temporary stored media file to the Whatsapp API cloud. Another option to send a document by public “link”, but I assume this is not as safe?
{
"messaging_product": "whatsapp",
"recipient_type": "individual",
"to": "<WHATSAPP_USER_PHONE_NUMBER>",
"type": "document",
"document": {
"id" : "<MEDIA_ID>", /* Only if using uploaded media */
"link": "<MEDIA_URL>", /* Only if linking to your media */
"caption": "<DOCUMENT_CAPTION>",
"filename": "<DOCUMENT_FILENAME>"
}
}
<MEDIA_URL>
StringRequired if linking to your media asset (not recommended).
URL of image asset on your public server. For better performance, we recommend that you upload your media asset instead.
Is this possible to do from Kjerner? Would you recommend it?