Bridging the Gap: Paper Scanning in Oracle APEX #JoelKallmanDay
Or how a web application can talk to its desktop counterpart

Senior (as in old) IT consultant, approaching the 20th work anniversary in the world of (mostly, but not exclusively, Oracle) technology. Wearing different hats (architect, consultant, developer…) while delivering turnkey projects aimed at creating software solutions that make a tangible business impact. An enthusiastic advocate of Oracle APEX and a wannabe educator (currently more focused on my own consistent learning path but willing and able to share the insight). Guided by the principle that simplicity can truly be “the ultimate sophistication".
Don’t worry - a quick demo video awaits at the end.
I’ve spent more than half of my career building enterprise Document Management and Business Process Management systems, mostly using Oracle APEX. More often than not, conversations with business users would stall in the early phases, when they bring a piece of paper and ask, “What should we do with this now?” — expecting clear advice on how to digitalize (scan) it. At that point, I find myself struggling to avoid a long explanation about APEX being a web application, the browser’s inability to control scanners, and the general lack of simple solutions for such a common need.
This article aims to bridge that gap. Namely, it focuses on seamlessly integrating web technologies such as Oracle APEX with desktop solutions, without the user even realizing their different nature.
Yes, but…
Q: OK, so we do need a desktop application after all?
A: Yes — but it runs quietly in the background, and users ideally never even notice it.
Q: Is it free of charge?
A: Not entirely — but it’s far more affordable than most alternatives available on the market.
Technical Architecture
At this point, it’s a good moment to reveal that I’m referring to the integration of Oracle APEX with the Soluma webScan solution (https://soluma.eu/webscan-document-digitization/). I will intentionally skip the rich feature list and, instead, focus on its technical architecture:
It is a desktop application, which means it can directly control a scanner connected via a USB port or local network.
It includes a local embedded web server, allowing it to accept REST requests.
It provides a Vue.js interface, enabling seamless communication through the browser.
There are only two things left to do…
Integration Principles
For the integration to work, we need to notify webScan of two things:
Document metadata — at minimum, the document’s ID, so that the scanned file can later be linked to the corresponding database record.
The REST endpoint — implemented in ORDS in our case, which webScan will invoke to deliver the scanned document once the process is complete.
Integration Implementation
Step 1. Install the Soluma webScan application
Once installed, webScan will appear in the system tray of your Windows OS.
As mentioned earlier, the actual user interface is built using Vue.js, so the tray application itself only allows you to see it running.
Step 2. Register your license
Go to https://webscan.solumainvoicereader.com and complete the license registration process. This address is publicly available, and once you get there, it will try to communicate to the webScan local (embedded) web server, by using web sockets. This communication should be successful as long as you installed and run Soluma webScan utility, that uses port 7788 by default (the explanation has been updated since the initial publication of the blog post, thanks to Anton Nielsen, who pointed out a flaw in the original text).

Step 3. Import the JavaScript library into your APEX application
Include the following JavaScript library in your Oracle APEX application (for example, by copying and pasting the link in the “JavaScript / File URLs“ section of your APEX page).
https://cdn.jsdelivr.net/npm/json-url/dist/browser/json-url.min.js
Step 4. Invoke the webScan URL from your application
The easiest way is to implement a button with the corresponding Dynamic Action, executing the following JavaScript code:
const lib = JsonUrl('lzma');
var rnd1 = Math.floor(Math.random() * 1000000);
var obj = { "Params": [{"Name": "ID_CONTENT", "Value": $v("P1_ID_CONTENT")}],
"BatchProperties": [],
"Classes": [],
"Indexes": [],
"Settings": [],
"ExportEndPoint": [
{
"Id": rnd1,
"Name": "Endpoint",
"Value": "https://oracleapex.com/ords/velimir_ws/webScan/checkIn",
"DataType": "string"
}
"Quick": true,
"SessionId": "",
"StatusBar": {
"Color": "primary lighten1",
"Info": ""
}
};
lib.compress(obj).then(output => { window.open("https://webscan.solumainvoicereader.com/?p=" + output,'_blank'); });
At line 5, we send the CONTENT_ID to webScan, assuming that the transaction with the given ID already exists in the database. Subsequently, at line 10, we provide the URL of the ORDS REST service that webScan should call to deliver the scanned document once it’s ready. Finally, the last line of the code invokes webScan on the local machine.
Step 5. Implement the ORDS REST service
To capture the scanned result, publish a REST service (using the POST method).
In the following example, the service receives the CONTENT_ID from the payload sent by webScan (which echoes the same ID we initially provided), along with the scanned file (as BASE64 encoded CLOB). Both are then inserted into the table DMS_WEBSCAN_INTEGRATION.
declare
v_clob clob;
v_blob blob;
v_id_content number;
v_json json_object_t;
v_json_par json_object_t;
v_params json_array_t;
begin
v_json := json_object_t.parse( apex_util.blob_to_clob(:body) );
v_params := v_json.get_array( 'Params' );
for i in 0.. v_params.get_size - 1 loop
v_json_par := json_object_t.parse (v_params.get(i).to_string());
if (v_json_par.get_string('Name') = 'ID_CONTENT') then
v_id_content := v_json_par.get_number('Value');
exit;
end if;
end loop;
v_clob := v_json.get_clob('File');
v_blob := APEX_WEB_SERVICE.CLOBBASE642BLOB (v_clob);
insert into DMS_WEBSCAN_INTEGRATION values (v_id_content, v_clob, v_blob);
end;
Step 6. (Optionally) Implement the Document Viewer Page
The easiest way is to branch to another page, with the Download with the following SQL query in the Pre-Rendering section:
select blob,
id_content,
'application/pdf'
from dms_webscan_integration
where id_content = :P2_ID_CONTENT;
The final step - see it in action
As promised at the beginning, here’s how it looks from the end user’s perspective:
Conclusion
Hopefully, this article will be useful to anyone looking to incorporate document scanning into their APEX (or, more generally, web-based) application. Beyond that, I hope it also inspires ideas on how to bridge the gap between web-based and desktop technologies — by allowing the latter to be exposed through a web interface via a locally run, embedded web server.
As always, any questions, comments, or thoughts are more than welcome — and thank you for your patience!

