DAM Wiki

Portfolio DAM (ex-Extensis Portfolio) API

Portfolio DAM, LLC (Axle AI) · Woburn, MA, USA · Founded 2026 · subsidiary of Axle AI, Inc.Verified 2026-10-01 · 89 sources
  • On-premise
  • Private cloud
  • SMB to enterprise workgroups (on-premise, archives, creative and print teams)
  • REST + SOAP API
  • OpenAPI spec
  • No webhooks
  • LDAP · kerberos SSO
Complete · 7 of 7 pages
89sources
3API specs
10-01verified 2026
Official website ↗Portfolio DAM alternatives →

Scope: the APIs of Portfolio Server 4.x — the REST API (primary), the SOAP API (deprecated) and server-side JavaScript scripting. Portfolio is self-hosted: every API call goes to the customer's own server, there is no vendor cloud endpoint. The documentation still lives on Extensis' doc host (doc.extensis.com) after the 2026 transfer of the product to Portfolio DAM, LLC (Axle AI) S10 S11.

At a glance

API styles
REST/JSON ("the primary API for Portfolio DAM") S10 S1; SOAP (WSDL AssetSEIService) plus a few plain-HTTP servlets, documented as deprecated S3 S4 S9 S11; server-side JavaScript scripting S8, "no longer actively supported" S10. No GraphQL
Base URL(s)
REST: http://{server}:8090/api/… or https://{server}:9443/api/… (spec servers: /api; ports shared with Portfolio Web) S1 S13 S14. Live spec on a running server: http://{server}:8090/api/openapi.json S2. SOAP endpoint: http://{server}:8090/ws/1.0/AssetService; servlets `…/FileTransfer/upload
Current version(s) & deprecations
REST API version 1.0 (paths under /v1/; GET/_api_version returns {"Server API": "1.0"}) S1. SOAP "Portfolio API v1.0 / Code Reference 2.0r01" is deprecated S3 S11. Public REST reference file last modified 2018-11-21 S1 Unverified (may lag the 4.0.1 / 4.1.1 servers)
Auth methods
(1) POST/v1/auth/login with user name + password RSA-encrypted with the server's public key (GET/v1/auth/public-key) → session ID S1; (2) API Token — a pseudo-user created in Portfolio Administration whose token is used in place of a session ID S12. Both are passed as the session query parameter S1. No OAuth
Token lifetime / refresh
Sessions time out on inactivity and must be renewed (default duration Not public; SOAP exposes setSessionInactivityTimeout) S12 S4. API Tokens never time out S12. Logout: POST/v1/auth/logout S1
Scopes / permission model
No scopes. A session or token has the role (Catalog Administrator, Publisher, Editor, Reader + permission toggles) its account holds in each catalog S12 S15. API Token connections do not consume licensed user connections S12; normal logins can fail with LicenseCountExceeded S1
Official spec
OpenAPI 3.0.1 "Portfolio REST API" v1.0 — 63 paths, 73 operations, 42 schemas S1, rendered with Swagger UI at doc.extensis.com/api/portfolio/rest S2; SOAP WSDL (79 operation names, 2014) S4. Archived copies on DAM Wiki: API spec downloads. No Postman collection
Rate limits
Not public — no throttle is documented; capacity depends on the customer's hardware and licensed connections S1 S19
Pagination
Offset: startingIndex + pageSize in the asset query body; default page size 1,000 when omitted; response gives totalNumberOfAssets S1
Webhooks / events
None (no outbound HTTP callbacks). Event hooks exist only as server-side scripts (onCataloged, onMetadataUpdated, onGalleryChanged, schedules) S8; polling aids: deletion audit (sinceDate), job status S1
Official SDKs
None for REST. Legacy SOAP sample client libraries (Java dam-client.jar, C#, PHP, VB) dated 2013–2015 S6. Community samples on GitHub S74
Sandbox / trial access
30-day evaluation system "with full API access" on request S10. 4.1.1 allows sandbox installs on Windows 10/11 desktops S52. No public demo server. The API was sold as a "licensed add-on" by Extensis S9; current packaging Not public

Authentication

Session login S1 S5

  1. GET/v1/auth/public-key → {modulusBase16, exponent} (RSA public key).
  2. Encrypt the password with that key, Base64-encode it.
  3. POST/v1/auth/login with JSON {"userName": "…", "encryptedPassword": "…"} → {"session": "<id>"}. Errors: 401 InvalidCredentials; 500 LicenseCountExceeded | UnexpectedError | OperationTimedOut.
  4. Pass ?session=<id> on every call (66 of 73 operations declare it; the unauthenticated ones are /_api_version, /v1/auth/login, /v1/auth/public-key, /v1/server/status, /v1/videoExtensions, /v1/audioExtensions, /v1/branding-settings).
  5. POST/v1/auth/logout ends the session.

The SOAP API uses the same pattern (getRSAPublicEncryptionKey → login → session ID) S4 S5.

API Token S12

  • Created in Portfolio Administration: Users → Add → Add New API Token, choosing a role to apply in all catalogs; per-catalog roles can be changed afterwards.
  • The token value is used instead of a session ID, so no login call is needed and the connection never times out.
  • Directory-service (AD) accounts cannot log in to Portfolio Administration; administration needs native accounts S13.

Transport: HTTPS on 9443 requires a custom (non-self-signed) certificate configured by the administrator S13.

Core resources

Paths are relative to {server}:8090/api. Inventory parsed from the spec S1.

ResourceEndpointsNotes
Auth & serverGET/_api_version; GET/v1/auth/public-key; POST/v1/auth/login; POST/v1/auth/logout; GET/v1/server/status; GET/v1/branding-settings; GET/v1/videoExtensions, GET/v1/audioExtensionsServer status lists server errors
CatalogsGET/v1/catalog; GET/v1/catalog/{catalog_id}/properties/{property_list}; GET/v1/catalog/{catalog_id}/taskPresetProperties: Smart Keywords settings, exclusions, cataloging options, ingest config
Metadata schemaGET/v1/catalog/{catalog_id}/field-definition; POST/v1/catalog/{catalogId}/field-definition/{fieldDefinitionId}/predefined-value; POST/DELETE…/nested-valueRead field definitions; edit predefined and nested (hierarchical) values. No field creation endpoint
Asset searchPOST/v1/catalog/{catalog_id}/asset (also GET with a JSON body)assetQuery with term, fields, sortOptions, paging; see Search
Asset metadataPOST/v1/catalog/{catalog_id}/asset/updateFieldValuesAdd/remove/append/replace by query; optional embed into files
Asset deletionDELETE/v1/catalog/{catalog_id}/asset (JSON body with a query)Removes catalog entries
Binaries & renditionsGET…/asset/{asset_id}/thumbnail (version), …/preview, …/_content, …/_video (range); GET…/asset/{asset_ids}/_original, …/asset/_original?query=; GET…/asset/{asset_ids}/_derivative, …/asset/_derivative?query=&imageOptions=Multiple assets → ZIP; async=true → job ID
UploadsPOST/v1/catalog/{catalog_id}/upload; POST…/watchfolder/{watchfolder_id}/upload; POST/v1/catalog/{catalog_id}/importDataMultipart; ingestFields for metadata at upload; importData loads a metadata file as a job
GalleriesGET/POST/v1/catalog/{catalog_id}/galleries; POST/PUT/v1/catalog/{catalog_id}/gallery; DELETE…/gallery/{gallery_id}; POST/DELETE…/gallery/{gallery_id}/_assetsTypes saved / smart; access publicAccess / privateAccess / lockedAccess
Watch foldersGET/POST/v1/catalog/{catalog_id}/watchfolder; GET/PUT/DELETE…/watchfolder/{watchfolder_id}; GET…/_details; POST…/_sync; POST…/subfolder; PUT/DELETE…/subfolder/_delete; POST…/watchfolder/subfolder/_moveSync modes manual, whenChangesAreFound, onSchedule, atSpecificTime
Versioning & lockingPOST/v1/catalog/{catalog_id}/checkout, …/checkin (comment), …/revert; GET…/asset/{asset_id}/checkout; GET…/asset/{asset_id}/versions; GET…/asset/{asset_id}/diff/left/{versionId_left}/right/{versionId_right}; POST…/lock, …/unlockVault catalogs only; lock failures reported per ID (ASSET_CHECKED_OUT, ASSET_LOCKED, NOT_FOUND)
Jobs (conversion / batch)POST/v1/job/run; GET/v1/job; GET/v1/job/_status, GET/v1/job/{job_ids}/_status; GET/v1/job/{job_id}/_errorDetails; PUT/v1/job/{job_ids}/_cancelJob = asset query + tasks (e.g. convert with output format, colour mode, quality)
ReportsGET/v1/report/asset-uploads, asset-downloads, asset-deletions, asset-most-downloaded, asset-most-previewed, file-types, search-terms, keyword-statistics, netpublish-usage, netpublish-download-frequencyParams catalog_id, startingDate, endingDate, locale, includeHeader, format
AuditGET/v1/audit/asset/assetDeletions?catalogId=&sinceDate=sinceDate in Unix seconds

Not exposed in the documented REST API S1: user/role/group administration, catalog creation, field creation, directory-service and licence settings, NetPublish site management, Smart Keyword execution. The SOAP WSDL additionally covers presets, view settings, user preferences, ingest config, server features and addAssetsByPath S4.

Data model

S1 unless noted.

  • Catalog — catalogId (GUID-style string), name, details[]. Access and roles are granted per catalog S15.
  • Asset — assetId (string; numeric IDs appear in examples), locked, and attributes[]: a list of {name, values[]} pairs keyed by field name (e.g. Filename, File Size, Keywords), i.e. every field is multi-valued in transport. The fields returned are those listed in the query's fields array, otherwise a default set. The internal asset ID is also exported as RID S45.
  • Field definition — id, systemName, internalName, localizedNames[], numeric type, multivalued, hierarchical, hasPredefinedValues, predefinedValues[], nestedPredefinedValues[], usePredefinedOnly, maxLength, precision, defaultValues[], searchable, sortable, embeddable, extractable, systemField.
  • Gallery — galleryId, name, owner, type (saved/smart), accessType, and savedFind (an AssetQueryTerm, so smart galleries are stored queries).
  • Watch folder — watchFolderId, path, sync settings; folder paths use a Portfolio path syntax (::FileServer:Volume:folder) in SOAP examples S7.
  • Job — jobId, catalogId, description, status ∈ retrieving, queued, inProgress, complete, canceled, timestamps, details.
  • Errors — {faultCode, message}; fault codes include InvalidCredentials, InvalidParameters, ItemNotFound, LicenseCountExceeded, UnexpectedError, OperationTimedOut.

Search & querying

AspectBehaviour
Query shapeJSON assetQuery: optional galleryId (search inside a gallery), term (tree of AssetQueryTerm with operator, fieldName, values[], subqueries[]), fields[], sortOptions {field, order}, startingIndex, pageSize S1
OperatorsBoolean operatorAnd / operatorOr; assetsById / assetsNotHavingId; equalValue, notEqualValue, containsValue, startsWithValue, endsWithValue and their negations; lessThan…, greaterThan… (incl. or-equal); nullValue / notNullValue; dates inPast, inFuture, inNextDays, inPreviousDays, today, thisMonth, thisYear; valueCountEquals/GreaterThan/LessThan; matchUnparsedQueryString; intersectsGeometry S1
SortingOne field, asc / desc S1
ClusteringResults may include clusters[] and totalNumberOfClusteredAssets (map-view clustering) S1 S35
FacetsNot available in the REST API (Unknown in UI)
Page sizeDefault 1,000; maximum and deep-paging limits Not public S1
Date semanticsSearches on date fields always include the time component, even if hidden in the UI S32

Uploads & binaries

  • Upload: multipart/form-data POST to /v1/catalog/{catalog_id}/upload (fields path, file, ingestFields) or to a specific watch folder (…/watchfolder/{id}/upload, plus filename) S1. Single request per file; chunked/resumable upload is not documented. The SOAP-era servlet POST/FileTransfer/upload (fields sessionId, catalogId, destinationFolder, filename, action=upload|customPreview, Filedata) returns the new asset ID and also sets custom previews S7.
  • Download: original (_content, _original), preview, thumbnail (optionally a given version), video stream with HTTP Range (source=preview|original) S1.
  • On-the-fly conversion: _derivative with imageOptions JSON (outputFileFormat, colorMode RGB/CMYK/Grayscale, resizeWidth/resizeHeight, compressionQuality 1–100, source preview/original, videoFrameTime, resolution, compressionType, endian); single asset → streamed file, several → ZIP, async=true → job ID S1. Extra output formats need a Media Engine licence S25.
  • Batch jobs: POST/v1/job/run with an asset query and task list (e.g. convert with settings), then poll /_status and fetch results; client-side jobs are retained 24 h S39 S1.
  • No signed/expiring public URLs or CDN; all binary access goes through the authenticated server S1.

Events & webhooks

  • No webhook subscription API and no outbound HTTP events in the REST or SOAP specs S1 S4.
  • Server-side scripting (alternative): JavaScript files in Portfolio Server/data/custom-scripts declare triggerPoints (onCataloged, onMetadataUpdated, onGalleryChanged, onJobInitialize, onJobEachAsset, onJobFinalize), an optional cron scheduleInfo, required permissions and a client menu label; a global portfolio object exposes server functions S8. Since 4.0.1, Java reflection from scripts is blocked (CVE-2022-24252 fix) and can only be re-enabled by disabling that protection S41. The new owner lists scripting as "no longer actively supported" S10.
  • Built-in non-API notifications: daily "query to email" digest, email on gallery changes/backups S10 S40.

Limits & quirks

  • Self-hosted endpoints: base URL, ports and TLS depend on each installation; default ports 8090 (HTTP) / 9443 (HTTPS) are shared by Portfolio Web and the API S14. Exposing the server to the Internet is possible but "not necessarily recommended"; VPN is the advised pattern S37 S80.
  • Session in the query string: session= (or the API Token) travels as a URL parameter on every call, so it can end up in proxy/server logs S1 Unverified (observation from the spec, not a vendor statement).
  • GET with a JSON body: GET/v1/catalog/{id}/asset and DELETE/v1/catalog/{id}/asset take their query in the request body; prefer POST…/asset for search S1.
  • Spec inconsistency: prose examples write the query term key as field, while the schema names it fieldName S1 Unverified (test against your server).
  • Stale references: several operations link to the SOAP docs for details (externalDocs → soap_assets_AssetSEIService.html), and many responses are typed only as JSONObject / default response S1.
  • Licensed connections: logins count against licensed user connections (LicenseCountExceeded); API Tokens don't S12 S1.
  • Versioning/locking endpoints only work on Vault catalogs S1 S26.
  • Rate limits / payload limits: Not public.
  • Doc ownership: the API reference is still hosted by Extensis (doc.extensis.com) and API support links still point to an Extensis form after the sale S11 Unverified (possible future move).

SDKs, tools & code samples

LibraryLanguageMaintainerStatus
dam-client.jar, assetSEIService-cs, assetSEIService-php, assetSEIService-vb (SOAP)Java, C#, PHP, VBExtensis (sample libraries)Dated 2013–2015; SOAP deprecated S6
Server-side scripting examplesJavaScriptExtensis docsExample scripts page S8
jelmore49/extensis-portfolio-api-samplesPHP (SOAP + REST samples)CommunityLast push 2022 S74
jamesgrace/* (REST reports-to-email, Uppy uploader, scripting and backup samples)Python, HTML/JS, Bash, Windows batchCommunity2021 S74
tomasc/extensis_portfolio, wags/PortfolioRestTokenRuby, C#Community2016–2017, inactive S74

No npm/PyPI/NuGet/Maven package from the vendor was found; the Extensis GitHub organisation holds no Portfolio SDK S75.

Changelog of the API

DateChangeSource
2026-03Portfolio 4.1.1 beta (Tomcat 9.0.115, Azul JRE 1.8.0_481); no API changes announced S52
20224.0.1: scripting engine loses Java reflection access (CVE-2022-24252); file-upload RCE flaws fixed S65 S41
2018-11-21Current public REST OpenAPI document (file date) S1
2014-09-19SOAP WSDL file date; SOAP later marked deprecated in favour of REST S4 S11

Stored API specs

3 files · 179 KB · verbatim copies of public vendor filesSpecs README & provenance
FileFormatSizeDownload
portfolio-rest_openapi_v1.0_swagger-ui-embed.jsSwagger / OpenAPI84 KBDownload
portfolio-rest_openapi_v1.0.jsonOpenAPI84 KBDownload
portfolio-soap_AssetService_wsdl.zipZIP11 KBDownload
Search the wiki