This guide is for technical and IT users who want to integrate an existing or developing Digital Asset Management (DAM) system with Specify.
If your institution uses a custom Digital Asset Management (DAM) system and you want Specify to connect to it directly, you can do this by having your DAM act like the default Web Asset Server (WAS).
Some institutions choose to manage a drive of high-quality originals detached from the Specify instance, while others seek to use the same DAM between the collections management system and elsewhere in their institution.
By either building an adapter in your DAM or placing a proxy layer between Specify and the DAM, Specify can use your external system to store, retrieve, and delete attachments.
[!caution] Support Warning
Support for the integration, development, or maintenance of third-party Digital Asset Management (DAM) systems is not included in the scope of the support services offered to members.Specify Cloud users can contact support@specifysoftware.org directly to configure their instance to use a custom DAM or WAS alternative.
For assistance with integration, please contact membership@specifysoftware.org for more information about consulting costs.
Before you begin, please review:
Integration Approaches
If it is not viable to use the WAS provided by the SCC, you have three main options for bridging your custom DAM to Specify:
- Adapter: Implement the required asset-server endpoints directly within your DAM application so Specify can communicate with it natively.
- Proxy / Translator: Keep your DAM API exactly as it is, but stand up a small proxy service that exposes the asset-server endpoints to Specify and translates those requests to your DAM.
- Hybrid: Serve heavy asset operations (like downloads and thumbnails) directly from the DAM, but expose a lightweight compatibility layer solely for token signing and API discovery.
Before beginning any of these approaches, we recommend thoroughly reviewing the WAS repository to get a clear idea of how the asset server works:
Implementation
To integrate successfully, your DAM (or proxy) must implement the following endpoints with the expected semantics. Each endpoint must accept the token authentication used by the WAS and return compatible responses.
1. Discovery (/web_asset_store.xml)
Specify requests an XML document to discover the endpoint URLs. See the template in views/web_asset_store.xml.
<?xml version="1.0" encoding="UTF-8"?>
<urls>
<url type="read"><![CDATA[http://{{host}}/fileget]]></url>
<url type="write"><![CDATA[http://{{host}}/fileupload]]></url>
<url type="delete"><![CDATA[http://{{host}}/filedelete]]></url>
<url type="getmetadata"><![CDATA[http://{{host}}/getmetadata]]></url>
<url type="testkey">http://{{host}}/testkey</url>
</urls>
2. Uploads (/fileupload)
Implementation reference: server.py
- Accepts: Multipart uploads containing the file payload, plus form fields
store,type, andcoll. - Auth: Requires
token(see below). - Returns: Plain text
Ok.on success.
3. Downloads (/fileget)
Implementation reference: server.py
- Accepts: Query params
filename,coll,type(for thumbnails,type=Tandscaleare used), plustokenwhen required. - Returns: The file bytes with the correct
Content-Typeand optionalContent-Disposition.
4. Deletions (/filedelete)
Implementation reference: server.py
- Accepts:
POSTform fieldsfilenameandcoll. - Returns: Plain text
Ok.after deleting the original and any derived thumbnails.
5. Metadata (/getmetadata)
Implementation reference: server.py
- Accepts: Query params
filename,coll, and optionaldt=date. - Returns: JSON containing EXIF fields, or plain text date when
dt=dateis provided.
6. Storage Layout & Thumbnails
Implementation reference: server.py
Organize originals and thumbnails in predictable paths, for example:
/data/originals/{store}/{filename}/data/thumbnails/{store}/{filename}(thumbnails are cached with a_<size>suffix)
Thumbnails should be generated on demand, cached, and invalidated upon deletion. If your DAM already has a thumbnail API, simply expose a compatible path or translate the requests in your proxy. See this guide to learn more about how thumbnails are generated on the default WAS.
Token Signing & Authentication
Implementation reference: server.py
Specify secures WAS requests by generating time-limited signed tokens. Your custom integration needs to correctly re-compute and verify these tokens.
- Canonical String:
"<timestamp><filename>"(string concatenation). - Algorithm: Sign with
HMAC-MD5using your shared attachment key, then encode as hex. The token value is"<hexdigest>:<timestamp>". - Request Format: Specify sends the token as a
tokenquery or form field; there is no separatetsparameter. - Verification: Recompute the HMAC on your end, compare using a constant-time check, and ensure the timestamp falls within your allowed window (e.g.,
abs(now - ts) <= 150s).
Configuration
To connect Specify to your DAM:
- Point Specify’s asset configuration to the DAM base URL (or to the proxy that handles Specify attachments).
ASSET_SERVER_URL=http://host.docker.internal/web_asset_store.xml # Make sure to set the `ASSET_SERVER_KEY` to a unique value ASSET_SERVER_KEY=your_asset_server_access_key - Set the shared attachment key in Specify to match the secret used by your DAM/token verifier.
- Ensure your web server routes the specific asset paths to your DAM or proxy.
Testing Checklist
Once your endpoints are live, walk through this checklist to confirm the integration:
-
GET /web_asset_store.xml— Discovery returns the correct XML. -
GET /testkey?token=...— Verify the test key. Implementation reference for test key: server.py -
POST /fileupload(with token) — File is stored and returnsOk.. -
GET /fileget(with token when required) — Returns correct file bytes and headers. -
GET /getmetadata— Metadata (e.g., EXIF capture date) is successfully retrieved for the uploaded file. -
POST /filedelete— ReturnsOk., removing both the original and its thumbnails. Test with a follow-upGET /filegetto confirm it returns404 Not Found.
If all is working as expected, your DAM has successfully replaced the default WAS for Specify attachments!