{"id":8577,"date":"2024-01-31T10:18:08","date_gmt":"2024-01-31T10:18:08","guid":{"rendered":"https:\/\/www.satup.xyz\/index.php\/2024\/01\/31\/introducing-webhook-support-in-acrobat-services-by-raymond-camden-jan-2024\/"},"modified":"2024-01-31T10:18:08","modified_gmt":"2024-01-31T10:18:08","slug":"introducing-webhook-support-in-acrobat-services-by-raymond-camden-jan-2024","status":"publish","type":"post","link":"https:\/\/www.satup.xyz\/index.php\/2024\/01\/31\/introducing-webhook-support-in-acrobat-services-by-raymond-camden-jan-2024\/","title":{"rendered":"Introducing Webhook Support in Acrobat Services | by Raymond Camden | Jan, 2024"},"content":{"rendered":"<p><br \/>\n<\/p>\n<div>\n<div>\n<h2 id=\"a92a\" class=\"pw-subtitle-paragraph ho gq gr be b hp hq hr hs ht hu hv hw hx hy hz ia ib ic id cp dt\">Our new webhook support provides another powerful way to interact with our services.<\/h2>\n<div class=\"ie if ig ih ii\">\n<div class=\"speechify-ignore ab co\">\n<div class=\"speechify-ignore bg l\">\n<div class=\"ij ik il im in ab\">\n<div>\n<div class=\"ab io\"><a href=\"https:\/\/medium.com\/@cfjedimaster?source=post_page-----7d0606d1d35a--------------------------------\" rel=\"noopener follow\"><\/p>\n<div>\n<div class=\"bl\" aria-hidden=\"false\">\n<div class=\"l ip iq bx ir is\">\n<div class=\"l fg\"><img loading=\"lazy\" decoding=\"async\" alt=\"Raymond Camden\" class=\"l fa bx dc dd cw\" src=\"https:\/\/miro.medium.com\/v2\/resize:fill:88:88\/1*ldF-FsLonNyTUOmQ7cIV_g.jpeg\" width=\"44\" height=\"44\" loading=\"lazy\" data-testid=\"authorPhoto\"\/><\/div>\n<\/div>\n<\/div>\n<\/div>\n<p><\/a><a href=\"https:\/\/blog.developer.adobe.com\/?source=post_page-----7d0606d1d35a--------------------------------\" rel=\"noopener  ugc nofollow\"><\/p>\n<div class=\"iv ab fg\">\n<div>\n<div class=\"bl\" aria-hidden=\"false\">\n<div class=\"l iw ix bx ir iy\">\n<div class=\"l fg\"><img loading=\"lazy\" decoding=\"async\" alt=\"Adobe Tech Blog\" class=\"l fa bx bq iz cw\" src=\"https:\/\/miro.medium.com\/v2\/resize:fill:48:48\/1*riyFijvwTfGcWNf1guRNtg.png\" width=\"24\" height=\"24\" loading=\"lazy\" data-testid=\"publicationPhoto\"\/><\/div>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<p><\/a><\/div>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<figure class=\"nm nn no np nq nr nj nk paragraph-image\">\n<div role=\"button\" tabindex=\"0\" class=\"ns nt fg nu bg nv\">\n<div class=\"nj nk nl\"><picture><source srcset=\"https:\/\/miro.medium.com\/v2\/resize:fit:640\/format:webp\/1*JqAR0xExNOvXZCveEMb_yw.png 640w, https:\/\/miro.medium.com\/v2\/resize:fit:720\/format:webp\/1*JqAR0xExNOvXZCveEMb_yw.png 720w, https:\/\/miro.medium.com\/v2\/resize:fit:750\/format:webp\/1*JqAR0xExNOvXZCveEMb_yw.png 750w, https:\/\/miro.medium.com\/v2\/resize:fit:786\/format:webp\/1*JqAR0xExNOvXZCveEMb_yw.png 786w, https:\/\/miro.medium.com\/v2\/resize:fit:828\/format:webp\/1*JqAR0xExNOvXZCveEMb_yw.png 828w, https:\/\/miro.medium.com\/v2\/resize:fit:1100\/format:webp\/1*JqAR0xExNOvXZCveEMb_yw.png 1100w, https:\/\/miro.medium.com\/v2\/resize:fit:1400\/format:webp\/1*JqAR0xExNOvXZCveEMb_yw.png 1400w\" sizes=\"(min-resolution: 4dppx) and (max-width: 700px) 50vw, (-webkit-min-device-pixel-ratio: 4) and (max-width: 700px) 50vw, (min-resolution: 3dppx) and (max-width: 700px) 67vw, (-webkit-min-device-pixel-ratio: 3) and (max-width: 700px) 65vw, (min-resolution: 2.5dppx) and (max-width: 700px) 80vw, (-webkit-min-device-pixel-ratio: 2.5) and (max-width: 700px) 80vw, (min-resolution: 2dppx) and (max-width: 700px) 100vw, (-webkit-min-device-pixel-ratio: 2) and (max-width: 700px) 100vw, 700px\" type=\"image\/webp\"\/><source data-testid=\"og\" srcset=\"https:\/\/miro.medium.com\/v2\/resize:fit:640\/1*JqAR0xExNOvXZCveEMb_yw.png 640w, https:\/\/miro.medium.com\/v2\/resize:fit:720\/1*JqAR0xExNOvXZCveEMb_yw.png 720w, https:\/\/miro.medium.com\/v2\/resize:fit:750\/1*JqAR0xExNOvXZCveEMb_yw.png 750w, https:\/\/miro.medium.com\/v2\/resize:fit:786\/1*JqAR0xExNOvXZCveEMb_yw.png 786w, https:\/\/miro.medium.com\/v2\/resize:fit:828\/1*JqAR0xExNOvXZCveEMb_yw.png 828w, https:\/\/miro.medium.com\/v2\/resize:fit:1100\/1*JqAR0xExNOvXZCveEMb_yw.png 1100w, https:\/\/miro.medium.com\/v2\/resize:fit:1400\/1*JqAR0xExNOvXZCveEMb_yw.png 1400w\" sizes=\"(min-resolution: 4dppx) and (max-width: 700px) 50vw, (-webkit-min-device-pixel-ratio: 4) and (max-width: 700px) 50vw, (min-resolution: 3dppx) and (max-width: 700px) 67vw, (-webkit-min-device-pixel-ratio: 3) and (max-width: 700px) 65vw, (min-resolution: 2.5dppx) and (max-width: 700px) 80vw, (-webkit-min-device-pixel-ratio: 2.5) and (max-width: 700px) 80vw, (min-resolution: 2dppx) and (max-width: 700px) 100vw, (-webkit-min-device-pixel-ratio: 2) and (max-width: 700px) 100vw, 700px\"\/><img fetchpriority=\"high\" alt=\"\" class=\"bg mq nw c\" width=\"700\" height=\"545\" loading=\"eager\" role=\"presentation\"\/><\/picture><\/div>\n<\/div>\n<\/figure>\n<p id=\"e621\" class=\"pw-post-body-paragraph nx ny gr nz b hp oa ob oc hs od oe of og oh oi oj ok ol om on oo op oq or os gk bj\">This week the Acrobat Services team launched new support for webhooks with our APIs.<\/p>\n<p id=\"ecdc\" class=\"pw-post-body-paragraph nx ny gr nz b hp oa ob oc hs od oe of og oh oi oj ok ol om on oo op oq or os gk bj\">In this post, I\u2019ll demonstrate how they work and what they provide to developers. Before getting into the details, some notes.<\/p>\n<p id=\"4432\" class=\"pw-post-body-paragraph nx ny gr nz b hp oa ob oc hs od oe of og oh oi oj ok ol om on oo op oq or os gk bj\">First off, this new feature is <em class=\"ot\">only<\/em> available to folks using the Java SDK (updated this week to version 4) or the REST API directly. I\u2019m a Node.js developer and prefer the REST API over the SDK anyway, so the examples provided here will be Node.js-based.<\/p>\n<p id=\"f028\" class=\"pw-post-body-paragraph nx ny gr nz b hp oa ob oc hs od oe of og oh oi oj ok ol om on oo op oq or os gk bj\">Secondly, this feature only works with \u201cinternal\u201d files, or assets you upload to Adobe for processing. It isn\u2019t yet supported with cloud storage providers.<\/p>\n<p id=\"f29b\" class=\"pw-post-body-paragraph nx ny gr nz b hp oa ob oc hs od oe of og oh oi oj ok ol om on oo op oq or os gk bj\">Lastly, while this new feature is supported in all the various APIs within Acrobat Services, currently PDF Properties is <em class=\"ot\">not<\/em> supported. It will be at a later time.<\/p>\n<p id=\"70e6\" class=\"pw-post-body-paragraph nx ny gr nz b hp pq ob oc hs pr oe of og ps oi oj ok pt om on oo pu oq or os gk bj\">At a basic level, a webhook is a way for a service to let your code know something has happened. To be clear, it\u2019s to let your code, not you specifically, know something that has happened.<\/p>\n<p id=\"7c85\" class=\"pw-post-body-paragraph nx ny gr nz b hp oa ob oc hs od oe of og oh oi oj ok ol om on oo op oq or os gk bj\">For example, I can set up a webhook in GitHub so that when a person files a new issue, GitHub will make an HTTP request to a URL I specify. In order for that to work, I need a server of some sort that can listen to that and respond to the webhook.<\/p>\n<p id=\"1aa8\" class=\"pw-post-body-paragraph nx ny gr nz b hp oa ob oc hs od oe of og oh oi oj ok ol om on oo op oq or os gk bj\">In some ways, it\u2019s the opposite of an API call. Instead of my code hitting the API to do something, the service itself calls my code to do something.<\/p>\n<p id=\"10b8\" class=\"pw-post-body-paragraph nx ny gr nz b hp oa ob oc hs od oe of og oh oi oj ok ol om on oo op oq or os gk bj\">Webhooks can be especially useful for cases where operations take \u201csome time\u201d. I put that in quotes to cover the widest range of possible versions of that. Most Acrobat Services operate in seconds, but as it\u2019s not instantaneous, it does take \u201csome time.\u201d You can imagine other APIs, perhaps involving video production, where \u201csome time\u201d could instead be minutes of time, or even hours.<\/p>\n<p id=\"7ded\" class=\"pw-post-body-paragraph nx ny gr nz b hp oa ob oc hs od oe of og oh oi oj ok ol om on oo op oq or os gk bj\">With situations like this, a webhook is useful as it lets my code start the \u201cslow\u201d process and the webhook can let me know when things are done. That\u2019s <em class=\"ot\">exactly<\/em> how the webhook feature of Acrobat Services will help developers!<\/p>\n<p id=\"fa91\" class=\"pw-post-body-paragraph nx ny gr nz b hp oa ob oc hs od oe of og oh oi oj ok ol om on oo op oq or os gk bj\">Now let\u2019s take a look at how to use this new feature.<\/p>\n<p id=\"765b\" class=\"pw-post-body-paragraph nx ny gr nz b hp pq ob oc hs pr oe of og ps oi oj ok pt om on oo pu oq or os gk bj\">All of the supported APIs follow a similar format. After you\u2019ve uploaded your asset, you then create a job with any required and optional arguments. Consider the <a class=\"af pv\" href=\"https:\/\/developer.adobe.com\/document-services\/docs\/apis\/#tag\/Create-PDF\" rel=\"noopener ugc nofollow\" target=\"_blank\">Create PDF operation<\/a>. When making the REST call, the body can be as simple as this:<\/p>\n<figure class=\"nm nn no np nq nr\"\/>\n<p id=\"ee3b\" class=\"pw-post-body-paragraph nx ny gr nz b hp oa ob oc hs od oe of og oh oi oj ok ol om on oo op oq or os gk bj\">To specify a webhook, you add a new property to your request body, <code class=\"cw pz qa qb qc b\">notifiers<\/code>. <code class=\"cw pz qa qb qc b\">notifiers<\/code> is an array of objects that take this shape:<\/p>\n<figure class=\"nm nn no np nq nr\"\/>\n<p id=\"aec6\" class=\"pw-post-body-paragraph nx ny gr nz b hp oa ob oc hs od oe of og oh oi oj ok ol om on oo op oq or os gk bj\">For now, don\u2019t worry about <code class=\"cw pz qa qb qc b\">headers<\/code> or <code class=\"cw pz qa qb qc b\">type<\/code> (<code class=\"cw pz qa qb qc b\">type<\/code> will always be &#8216;CALLBACK&#8217;), but note the <code class=\"cw pz qa qb qc b\">url<\/code> property. This is the URL that you&#8217;re asking Acrobat Services to request when the process is done. At minimum, a Create PDF body with a webhook would look like so:<\/p>\n<figure class=\"nm nn no np nq nr\"\/>\n<p id=\"1a00\" class=\"pw-post-body-paragraph nx ny gr nz b hp oa ob oc hs od oe of og oh oi oj ok ol om on oo op oq or os gk bj\">This means:<\/p>\n<p id=\"48d8\" class=\"pw-post-body-paragraph nx ny gr nz b hp oa ob oc hs od oe of og oh oi oj ok ol om on oo op oq or os gk bj\">Here\u2019s an example of a function that takes an asset and webhook (along with credential information) and kicks off a Create PDF job:<\/p>\n<figure class=\"nm nn no np nq nr\"\/>\n<p id=\"1164\" class=\"pw-post-body-paragraph nx ny gr nz b hp oa ob oc hs od oe of og oh oi oj ok ol om on oo op oq or os gk bj\">I\u2019ll share complete examples of my demos at the end of this article.<\/p>\n<p id=\"822b\" class=\"pw-post-body-paragraph nx ny gr nz b hp pq ob oc hs pr oe of og ps oi oj ok pt om on oo pu oq or os gk bj\">Now that you\u2019ve seen how to specify a webhook when creating jobs, how do you actually work with them?<\/p>\n<p id=\"af6f\" class=\"pw-post-body-paragraph nx ny gr nz b hp oa ob oc hs od oe of og oh oi oj ok ol om on oo op oq or os gk bj\">That\u2019s something I can\u2019t really answer here as it\u2019s going to depend on your own architecture and setup. To be clear, you need <em class=\"ot\">something<\/em>, whether it\u2019s a web server or a serverless endpoint, that can respond to the webhook call.<\/p>\n<p id=\"f502\" class=\"pw-post-body-paragraph nx ny gr nz b hp oa ob oc hs od oe of og oh oi oj ok ol om on oo op oq or os gk bj\">There\u2019s a near infinite list of ways that you can do that, but for today, I\u2019ll share an incredibly simple Node.js script that when run, and exposed publicly, will listen and report on requests. My thanks go to <a class=\"af pv\" href=\"https:\/\/recursive.codes\/\" rel=\"noopener ugc nofollow\" target=\"_blank\">Todd Sharp<\/a> for helping me with this.<\/p>\n<p id=\"7a70\" class=\"pw-post-body-paragraph nx ny gr nz b hp oa ob oc hs od oe of og oh oi oj ok ol om on oo op oq or os gk bj\">Here\u2019s the entire server:<\/p>\n<figure class=\"nm nn no np nq nr\"\/>\n<p id=\"12bc\" class=\"pw-post-body-paragraph nx ny gr nz b hp oa ob oc hs od oe of og oh oi oj ok ol om on oo op oq or os gk bj\">When run from the command line, it will listen on port 3000 and on every request, dump out to the console and body and headers. Finally, it always returns this JSON body:<\/p>\n<figure class=\"nm nn no np nq nr\"\/>\n<p id=\"9834\" class=\"pw-post-body-paragraph nx ny gr nz b hp oa ob oc hs od oe of og oh oi oj ok ol om on oo op oq or os gk bj\"><strong class=\"nz gs\">This is required<\/strong> for your webhook so however you build it, ensure you return this response!<\/p>\n<p id=\"f854\" class=\"pw-post-body-paragraph nx ny gr nz b hp oa ob oc hs od oe of og oh oi oj ok ol om on oo op oq or os gk bj\">As mentioned in the comments, one way this script could be exposed publicly is via ngrok, so after running that, you can take the resulting URL and use that as your webhook.<\/p>\n<p id=\"2f11\" class=\"pw-post-body-paragraph nx ny gr nz b hp oa ob oc hs od oe of og oh oi oj ok ol om on oo op oq or os gk bj\">Once used in a job, the webhook will be called when the job is done, and you can see an example request body below:<\/p>\n<figure class=\"nm nn no np nq nr\"\/>\n<p id=\"1a37\" class=\"pw-post-body-paragraph nx ny gr nz b hp oa ob oc hs od oe of og oh oi oj ok ol om on oo op oq or os gk bj\">Now, looking at this, you may wonder \u2014 how do I associate the data in this request to my original job? You can see the <code class=\"cw pz qa qb qc b\">jobID<\/code> value there and it will match a portion of the URL returned from the job creation. If you remember, the job is created by the API call and returned in the <code class=\"cw pz qa qb qc b\">Location<\/code> header.<\/p>\n<p id=\"ace2\" class=\"pw-post-body-paragraph nx ny gr nz b hp oa ob oc hs od oe of og oh oi oj ok ol om on oo op oq or os gk bj\">In my last test, it looked like so:<\/p>\n<p id=\"ba74\" class=\"pw-post-body-paragraph nx ny gr nz b hp oa ob oc hs od oe of og oh oi oj ok ol om on oo op oq or os gk bj\"><a class=\"af pv\" href=\"https:\/\/pdf-services-ue1.adobe.io\/operation\/createpdf\/FAQjIUIGfuIkgcBMMunRsZ56P6qoQ4bR\/status\" rel=\"noopener ugc nofollow\" target=\"_blank\">https:\/\/pdf-services-ue1.adobe.io\/operation\/createpdf\/FAQjIUIGfuIkgcBMMunRsZ56P6qoQ4bR\/status<\/a><\/p>\n<p id=\"1b87\" class=\"pw-post-body-paragraph nx ny gr nz b hp oa ob oc hs od oe of og oh oi oj ok ol om on oo op oq or os gk bj\">You can see the <code class=\"cw pz qa qb qc b\">jobID<\/code> in the data sent to the webhook matches the string before <code class=\"cw pz qa qb qc b\">status<\/code> in the URL above. A bit of string parsing would make it possible to connect the two, but <em class=\"ot\">you must handle this yourself<\/em>. Since it&#8217;s asynchronous, you&#8217;ll need to store the job ID in a database or other persistence system.<\/p>\n<p id=\"eb1c\" class=\"pw-post-body-paragraph nx ny gr nz b hp oa ob oc hs od oe of og oh oi oj ok ol om on oo op oq or os gk bj\">Another option is the use of custom headers. Remember back when I showed you the \u2018shape\u2019 of a request that includes webhooks, it looked like so:<\/p>\n<figure class=\"nm nn no np nq nr\"\/>\n<p id=\"4d57\" class=\"pw-post-body-paragraph nx ny gr nz b hp oa ob oc hs od oe of og oh oi oj ok ol om on oo op oq or os gk bj\">The <code class=\"cw pz qa qb qc b\">headers<\/code> value is optional and can be any number of name and values. So for example:<\/p>\n<figure class=\"nm nn no np nq nr\"\/>\n<p id=\"4b81\" class=\"pw-post-body-paragraph nx ny gr nz b hp oa ob oc hs od oe of og oh oi oj ok ol om on oo op oq or os gk bj\">When Acrobat Services completes work on your job and hits your webhook, it will pass those values as custom HTTP headers. You can then check for them in your code.<\/p>\n<p id=\"5ac8\" class=\"pw-post-body-paragraph nx ny gr nz b hp oa ob oc hs od oe of og oh oi oj ok ol om on oo op oq or os gk bj\">Here\u2019s a modified version of the function shown earlier that includes a header based on the current date. This probably wouldn\u2019t be useful, but gives you an idea how it looks.<\/p>\n<figure class=\"nm nn no np nq nr\"\/>\n<p id=\"49ff\" class=\"pw-post-body-paragraph nx ny gr nz b hp oa ob oc hs od oe of og oh oi oj ok ol om on oo op oq or os gk bj\">If you remember, or server code dumps out headers too. When using the version above, here\u2019s what you can see when the webhook is executed.<\/p>\n<figure class=\"nm nn no np nq nr\"\/>\n<p id=\"ca38\" class=\"pw-post-body-paragraph nx ny gr nz b hp oa ob oc hs od oe of og oh oi oj ok ol om on oo op oq or os gk bj\">You can see the custom <code class=\"cw pz qa qb qc b\">cats<\/code> header along with the usual headers sent in a request. Again, the validation, connection, etc. between the initial request and the webhook call is up to you, but you&#8217;ve got options for how you handle that. (As a quick aside, note you can also write webhooks using PowerAutomate. I&#8217;ll have a demo of this in the future.)<\/p>\n<p id=\"9d66\" class=\"pw-post-body-paragraph nx ny gr nz b hp pq ob oc hs pr oe of og ps oi oj ok pt om on oo pu oq or os gk bj\">To get started testing this new feature out, sign up for your <a class=\"af pv\" href=\"https:\/\/acrobatservices.adobe.com\/dc-integration-creation-app-cdn\/main.html\" rel=\"noopener ugc nofollow\" target=\"_blank\">free credentials<\/a> today and hit up our <a class=\"af pv\" href=\"https:\/\/community.adobe.com\/t5\/document-services-apis\/bd-p\/Document-Cloud-SDK?page=1&amp;sort=latest_replies&amp;filter=all\" rel=\"noopener ugc nofollow\" target=\"_blank\">support forums<\/a> if you\u2019ve got any questions. You can find the complete source code for the demos in this post here: <a class=\"af pv\" href=\"https:\/\/github.com\/cfjedimaster\/document-services-demos\/tree\/main\/webhooks\" rel=\"noopener ugc nofollow\" target=\"_blank\">https:\/\/github.com\/cfjedimaster\/document-services-demos\/tree\/main\/webhooks<\/a><\/p>\n<\/div>\n<p><br \/>\n<br \/><a href=\"https:\/\/blog.developer.adobe.com\/introducing-webhook-support-in-acrobat-services-7d0606d1d35a?source=rss----9342990108af---4\">Source link <\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Our new webhook support provides another powerful way to interact with our services. This week the Acrobat Services team launched new support for webhooks with our APIs. In this post, I\u2019ll demonstrate how they work and what they provide to developers. Before getting into the details, some notes. First off, this new feature is only [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":8578,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"inline_featured_image":false,"_monsterinsights_skip_tracking":false,"_monsterinsights_sitenote_active":false,"_monsterinsights_sitenote_note":"","_monsterinsights_sitenote_category":0,"footnotes":""},"categories":[19],"tags":[],"class_list":["post-8577","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-graphics-design"],"aioseo_notices":[],"_links":{"self":[{"href":"https:\/\/www.satup.xyz\/index.php\/wp-json\/wp\/v2\/posts\/8577","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.satup.xyz\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.satup.xyz\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.satup.xyz\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.satup.xyz\/index.php\/wp-json\/wp\/v2\/comments?post=8577"}],"version-history":[{"count":0,"href":"https:\/\/www.satup.xyz\/index.php\/wp-json\/wp\/v2\/posts\/8577\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.satup.xyz\/index.php\/wp-json\/wp\/v2\/media\/8578"}],"wp:attachment":[{"href":"https:\/\/www.satup.xyz\/index.php\/wp-json\/wp\/v2\/media?parent=8577"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.satup.xyz\/index.php\/wp-json\/wp\/v2\/categories?post=8577"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.satup.xyz\/index.php\/wp-json\/wp\/v2\/tags?post=8577"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}