API
Customer

Customer

A customer represents your account on the platform. You only have access to one customer, so it is your effective entry point for the API. While the root entry point provides links to resources and policies that anyone can use, your Customer object provides links to your assets and policy configurations. The only interaction you can have with your Customer resource directly is updating the display name, but it provides link properties to Collections of all the other resources.

{
    "@context": "https://dlcs.github.io/vocab/context/future.json",
    "@id": "https://api.dlcs.io/customers/2",
    "@type": "vocab:Customer",
    "name": "example-customer", 
    "displayName": "Example Customer",
    "created": "2020-01-17T15:36:58.6023600Z", 
    "spaces": "https://api.dlcs.io/customers/2/spaces",
    "iiif": "https://api.dlcs.io/customers/2/iiif",
    "allImages": "https://api.dlcs.io/customers/2/allImages",
    "originStrategies": "https://api.dlcs.io/customers/2/originStrategies",
    "deliveryChannelPolicies": "https://api.dlcs.io/customers/2/deliveryChannelPolicies",
    "defaultDeliveryChannels": "https://api.dlcs.io/customers/2/defaultDeliveryChannels",
    "namedQueries": "https://api.dlcs.io/customers/2/namedQueries",
    "queue": "https://api.dlcs.io/customers/2/queue",
    "portalUsers": "https://api.dlcs.io/customers/2/portalUsers",
    "authServices": "https://api.dlcs.io/customers/2/authServices",
    "roleProviders": "https://api.dlcs.io/customers/2/roleProviders",
    "roles": "https://api.dlcs.io/customers/2/roles",
    "storage": "https://api.dlcs.io/customers/2/storage",
    "keys": "https://api.dlcs.io/customers/2/keys",
    "customHeaders": "https://api.dlcs.io/customers/2/customHeaders"
}

/customers/{customer}

MethodLabelExpectsReturnsStatus
GETRetrieve a customer record-vocab:Customer200 OK, 404 Not Found

name

The URL-friendly name of the customer, can be used in public-facing URLs (such as image requests, or IIIF info.json requests) as a slug or path element rather than the integer customerId.

domainrangereadonlywriteonly
vocab:Customerxsd:stringFalseFalse

For API operations, the integer customer identifier must only be used.

From the sample customer above, if they had an image with this API resource URL:

https://api.dlcs.io/customers/2/spaces/5/images/my-image

Then the IIIF Image Service is available on either of these URLs:

https://dlcs.io/iiif-img/2/5/my-image
https://dlcs.io/iiif-img/example-customer/5/my-image

But the following would be INVALID for API use:

// INVALID!
https://api.dlcs.io/customers/example-customer/spaces/5/images/my-image

displayName

The display name of the customer.

domainrangereadonlywriteonly
vocab:Customerxsd:stringFalseFalse

created

When the customer was added to this platform instance..

domainrangereadonlywriteonly
vocab:Customerxsd:dateTimeTrueFalse

spaces

A link to a paged Collection of all the Space resources associated with your customer. A space allows you to organise assets (like folders), and specify different default roles, tags and delivery channels per space.

See Space.

domainrangereadonlywriteonly
vocab:Customer🔗 hydra:CollectionTrueFalse

HTTP operations

/customers/{customer}/spaces

MethodLabelExpectsReturnsStatus
GETList all your spaces-🔗 hydra:Collection (of vocab:Space)200 OK
POSTAdd a new space. The platform will assign the identifier (integer) to the space, using the next available value.vocab:Spacevocab:Space201 Created, 400 Bad request

At the very least the request payload should provide a name for the Space:

POST /customers/{customer}/spaces
{ "name": "My new space" }
field
nameREQUIRED
defaultTagsOPTIONAL
defaultRolesOPTIONAL
maxUnauthorisedOPTIONAL

Do not supply an id or @id field.

See also the PUT and DELETE operations on Space itself.

iiif 🆕

A link to the root API Storage Collection for IIIF Manifests and Collections. When you make new IIIF Presentation API resources, they get created here.

domainrangereadonlywriteonly
vocab:EntryPointiiif:CollectionTrueFalse

HTTP operations

MethodLabelExpectsReturnsStatus
GETThe root Storage Collection-iiif:Collection200 OK
POSTAdd a new IIIF Collection or Manifestiiif:Collection or iiif:Manifestiiif:Collection or iiif:Manifest201 Created, 400 Bad Request

See IIIF Manifests and Collections.

allImages

domainrangereadonlywriteonly
vocab:Customer🔗 hydra:CollectionTrueFalse
⚠️

We will likely change the way this endpoint works. At the moment you POST a hydra:Collection of assets that only have id (not @id) properties and it returns a collection of the full vocab:Image.

But - this and /customers/x/spaces/y/images should work the same way, using an extended asset query syntax that takes the metadata values, tags, roles, and id(s).

So below we have Current and Future.

allImages (current)

A query endpoint for retrieving full assets from any of your spaces, given just the internal identifier.

HTTP operations

MethodLabelExpectsReturnsStatus
POSTSubmit the set of identifiers you want full information forhydra:Collectionhydra:Collection200 OK
POST /customers/2/allImages
{
    "@type": "Collection",
    "member": [ 
        {"id": "2/36/PHOTO.2.22.36.2.tif"},
        {"id": "2/17/my-image.jpg"} 
    ]
}

This request, POSTed to the endpoint, returns a hydra:Collection with two members, the full resource information for the images with the given id values. Note that the requested images are for the same customer (if they are not the request will be rejected) but different spaces.

allImages (future)

A query endpoint for retrieving full assets from any of your spaces, using asset query syntax. It's unlikely you would use this endpoint without additional query data, but if you do it will simply return a paged hydra:Collection of all your assets across all spaces.

HTTP operations

MethodLabelExpectsReturnsStatus
GETAppend a query parameter to return matching assets across all spaces.(no body, but usually a query string)hydra:Collection200 OK
PATCHMake partial update to all matching values(see below)hydra:Collection200 OK

Note that the items to be updated with PATCH can be specified either by the "member" property or query parameter syntax

PATCH /customers/2/allImages
{
    "@type": "Collection",
    "member": [ 
        {"id": "2/36/PHOTO.2.22.36.2.tif"},
        {"id": "2/17/my-image.jpg"} 
    ],
    "field": "manifests",
    "operation": "add"
    "value": ["manuscripts"]
}
PATCH /customers/2/allImages?q={"number": 101}
{
    "@type": "Collection",
    "field": "manifests",
    "operation": "replace"
    "value": ["manuscripts"]
}

originStrategies

A link to a paged Collection of all Origin Strategy resources associated with your customer.

See Origin Strategy.

domainrangereadonlywriteonly
vocab:Customer🔗 hydra:Collection (of vocab:CustomerOriginStrategy)TrueFalse

HTTP operations

/customers/{customer}/originStrategies

MethodLabelExpectsReturnsStatus
GETList all your origin strategies-A paged hydra:Collection of vocab:CustomerOriginStrategy200 OK
POSTAdd a new parameterised vocab:CustomerOriginStrategy instance. The platform will assign the identifier (a GUID) to the new CustomerOriginStrategy if you do not supply an id property in the request body.-vocab:CustomerOriginStrategy201 Created
POST /customers/2/originStrategies
{
    "regex": "*",
    "strategy": "https://api.dlcs.io/originStrategies/basic-http-authentication",
    "credentials": "{ \"user\": \"uuu\", \"password\": \"ppp\" }",
    "optimised": false,
    "order": 1
}
field
regexREQUIRED
strategyREQUIRED
credentialsREQUIRED or OPTIONAL depending on strategy
optimisedOPTIONAL
orderOPTIONAL

See also the PUT and DELETE operations on CustomerOriginStrategy itself - you can use PUT to create without a GUID identifier.

deliveryChannelPolicies

A link to a paged Collection of further Collections of Delivery Channel Policies resources associated with your customer. Delivery Channel Policies control what the platform does with the asset you supply - e.g., make an image service (the iiif-img channel), make thumbnails at your desired sizes (the thumbnail delivery channel), transcode video (the iiif-av delivery channel) or simply serve up the file (the file delivery channel). Assets can have multiple channels, and different assets can have different policies for the same channel. See Delivery Channels.

When you add an asset to the platform, you specify the combination of delivery channel AND the policy it should use for that channel - or your asset inherits configured defaults from its space or customer (this collection).

This property on the Customer resource is a rare example of nested Collections - for organisational purposes.

domainrangereadonlywriteonly
vocab:Customer🔗 hydra:Collection (of hydra:Collection)TrueFalse

HTTP operations

/customers/{customer}/deliveryChannelPolicies

MethodLabelExpectsReturnsStatus
GETRetrieve the available collections of policies per channel-A hydra:Collection of hydra:Collection200 OK

You can't POST anything to the collection at /customers/{customer}/deliveryChannelPolicies - you can't make your own "folders" within it - the (currently) four collections are fixed. But you can post DeliveryChannelPolicy resources to these "folders" already there, for example:

/customers/{customer}/deliveryChannelPolicies/thumbnail

MethodLabelExpectsReturnsStatus
GETRetrieve your configured Delivery Channel Policies for the thumbnail channel-A hydra:Collection of vocab:DeliveryChannelPolicy200 OK
POSTAdd a Delivery Channel Policyvocab:DeliveryChannelPolicyvocab:DeliveryChannelPolicy201 Created

An example POST:

POST /customers/{customer}/deliveryChannelPolicies/thumbnail

{
    "id": "my-custom-thumbs",
    "displayName": "Standard set of thumbs for use on our website",
    "channel": "thumbnail",
    "policyData": "[ \"2048,\", \"1336,\", \"880,\", \"^!1024,1024\", \"^!400,400\", \"^,250\" ]"
}
field
idREQUIRED in POST; the patform will not mint an identifier/path element for a delivery channel policy
displayNameOPTIONAL
channelREQUIRED and must match the parent path (e.g., "thumbnail" for the above example)
policyDataREQUIRED or OPTIONAL depending on channel

You can also PUT new policies directly into these nested collections, as described in Delivery Channels.

defaultDeliveryChannels

A link to a paged Collection of default Delivery Channels. These are only used when you register an asset without supplying any delivery channels on the submitted asset resource. The platform uses the mediaType of the asset to match one of these. It looks in the defaultDeliveryChannels property of the asset's Space first, and continues looking at this customer level if none match from those in the space.

domainrangereadonlywriteonly
vocab:Customer🔗 hydra:Collection (of vocab:DeliveryChannel)TrueFalse

Unlike delivery channels on assets, any delivery channels listed here MUST have the mediaType property, which is used by the platform to match them to an asset. See Delivery Channels.

HTTP operations

/customers/{customer}/defaultDeliveryChannels

MethodLabelExpectsReturnsStatus
GETList all your default Delivery Channels-A paged hydra:Collection of vocab:DeliveryChannel200 OK
POSTAdd a new default Delivery Channel. The body must include the mediaType property. The platform will create a GUID for the last path element, which you can use on PUT and DELETE operations.-vocab:DeliveryChannel201 Created
POST /customers/2/defaultDeliveryChannels
{
    "channel": "iiif-img",
    "policy": "default",
    "mediaType": "image/*"
}

(You will already have this delivery channel).

field
channelREQUIRED
policyREQUIRED
mediaTypeREQUIRED

See also the PUT and DELETE operations on DeliveryChannel.

NB this is not a collection of collections like deliveryChannelPolicies.

namedQueries

Collection of all the Named Queries you have configured (plus those provided ‘out of the box’). See the Named Query topic for further information.

domainrangereadonlywriteonly
vocab:Customer🔗 hydra:Collection (of vocab:NamedQuery)TrueFalse

HTTP operations

/customers/{customer}/namedQueries

MethodLabelExpectsReturnsStatus
GETRetrieves all Named Queries-A paged hydra:Collection of vocab:NamedQuery200 OK
POSTCreates a new Named Query. The platform will create a GUID for the last path element, which you can use on PUT and DELETE operations.vocab:NamedQueryvocab:NamedQuery201 Created
POST /customers/2/namedQueries
{
    "name": "manifest",
    "template": "manifest=s1&sequence=0&canvas=n1&s1=p1"
}
field
nameREQUIRED
templateREQUIRED

The syntax for the named query template is covered in Named Query.

When your customer is created, a few sample named queries are included for you to use.

queue

The Customer’s view on the platform ingest queue. As well as allowing you to query the status of batches you have registered, you can POST new batches to the queue.

domainrangereadonlywriteonly
vocab:Customervocab:QueueTrueFalse

See Queues for details.

HTTP operations

/customers/{customer}/queue

MethodLabelExpectsReturnsStatus
GETReturns the queue resource-vocab:Queue200 OK
POSTSubmit a collection of assets and get a batch back.🔗 hydra:Collection (of vocab:NamedImageQuery)vocab:Batch201 Job has been accepted - Batch created and returned

portalUsers

Collection of user accounts that can log into the portal. Use this to grant access to others in your organisation.

domainrangereadonlywriteonly
vocab:Customer🔗 hydra:Collection (of vocab:PortalUser)TrueFalse

See Managing portal users for details.

HTTP operations

/customers/{customer}/portalUsers

MethodLabelExpectsReturnsStatus
GETRetrieves all portal users-🔗 hydra:Collection (of vocab:PortalUser)200 OK
POSTCreates a new portal uservocab:PortalUservocab:PortalUser201 Created

Clarify supply of id Clarify fields that may be POSTed (need to work out how portal users are authed)

authServices

Collection of IIIF Authorization Flow 2.0 (opens in a new tab) services available for use with your assets. If your assets have one or more roles, the platform will provide auth services endpoints to allow your end users to acquire the necessary role.

domainrangereadonlywriteonly
vocab:Customer🔗 hydra:Collection (of vocab:AuthService)TrueFalse

See Access Control for details.

HTTP operations

/customers/{customer}/authServices

MethodLabelExpectsReturnsStatus
GETRetrieves all Auth Services-🔗 hydra:Collection (of vocab:AuthService)200 OK
POSTCreates a new Auth Servicevocab:AuthServicevocab:AuthService201 Created

roleProviders

Collection of the available role providers. In order for a user to see an asset, the user must have at least one role associated with the asset. RoleProviders configure how the platform interacts with external systems to obtain the roles (or permissions, or claims) that your end users have.

domainrangereadonlywriteonly
vocab:Customer🔗 hydra:Collection (of vocab:RoleProvider)TrueFalse

See Access Control for details.

HTTP operations

/customers/{customer}/roleProviders

MethodLabelExpectsReturnsStatus
GETRetrieves all Role Providers-🔗 hydra:Collection (of vocab:RoleProvider)200 OK
POSTCreates a new Role Providervocab:RoleProvidervocab:RoleProvider201 Created

(POST not supported in Deliverator)

roles

Collection of the available roles you can assign to your assets. In order for an end-user to see an asset, the user must have the role associated with the asset, or at least one if the asset has multiple roles. Users interact with an AuthService to acquire a role or roles.

domainrangereadonlywriteonly
vocab:Customer🔗 hydra:Collection (of vocab:Role)TrueFalse

See Access Control for details.

HTTP operations

/customers/{customer}/roles

MethodLabelExpectsReturnsStatus
GETRetrieves all Roles-🔗 hydra:Collection (of vocab:Role)200 OK
POSTCreates a new Rolevocab:Rolevocab:Role201 Created

storage

Returns information about storage usage for the customer across all spaces. See the StoragePolicy topic for more information.

domainrangereadonlywriteonly
vocab:Customervocab:CustomerStorageTrueFalse

HTTP operations

/customers/{customer}/storage

MethodLabelExpectsReturnsStatus
GETReturns the customer storage resource-vocab:CustomerStorage200 OK

keys

⚠️

Use of permanent API keys will no longer be the default in the future. The Platform API will use OAuth2 with client id and refresh token. Existing customers can still use existing API keys and can disable their use when ready to switch.

Api keys allocated to this customer. The accompanying secret is only available at creation time. To obtain a key and a secret, make an empty POST to this collection with administrator privileges and the returned Key object will include the generated secret.

domainrangereadonlywriteonly
vocab:Customerhydra:CollectionTrueFalse

HTTP operations

/customers/{customer}/keys

MethodLabelExpectsReturnsStatus
GETReturns current set of API keys (secret omitted)-🔗 hydra:Collection (of vocab:Key)200 OK
POSTCreate a new key-vocab:Key (with secret, once)200 OK

The returned collection has vocab:key members like this:

   "member": [
        {
            "@id": "https://api.dlcs.io/customers/2/keys/9b060235-71d2-49a1-ac54-e4a1b36e79ff",
            "@type": "vocab:Key",
            "key": "9b060235-71d2-49a1-ac54-e4a1b36e79ff"
        },
        {
            "@id": "https://api.dlcs.io/customers/2/keys/93c93bf4-b7ea-4859-91e5-26a8f6e29c86",
            "@type": "vocab:Key",
            "key": "93c93bf4-b7ea-4859-91e5-26a8f6e29c86"
        }
   ]

The secret property is only returned once, when creating a new key with an empty POST to the collection:

{
    "@context": "https://dlcs.github.io/vocab/context/future.json",
    "@id": "https://api.dlcs.io/customers/2/keys/22d85624-31b4-4e00-bd97-8e7d126b1d9f",
    "@type": "vocab:Key",
    "key": "22d85624-31b4-4e00-bd97-8e7d126b1d9f",
    "secret": "................................................."
}

It's up to you to keep the secret safe!

An individual key can be deleted with an HTTP DELETE to its URI:

DELETE https://api.dlcs.io/customers/2/keys/93c93bf4-b7ea-4859-91e5-26a8f6e29c86

customHeaders

A collection of custom HTTP headers. Adding a Custom Header resource to this collection will cause it to be set on every HTTP response for info.json, image tiles and other asset delivery responses.

See Custom Headers.

domainrangereadonlywriteonly
vocab:Customerhydra:CollectionTrueFalse

HTTP operations

/customers/{customer}/customHeaders

MethodLabelExpectsReturnsStatus
GETReturns current set of custom headers-🔗 hydra:Collection (of vocab:CustomHeader)200 OK
POSTAdd a new custom header. The platform will assign the identifier (a GUID) to the custom header-vocab:CustomHeader201 Created

At the very least the request payload should provide a key and value. Without any further properties, ALL your public-facing responses will get this header. You can restrict to assets in a particular space, or assets with a particular role.

POST /customers/{customer}/customHeaders
{ "key": "Cache-Control", "public, s-maxage=2419200, max-age=2419200" }

The above is so common that you will already have this custom header when your Customer is created.

field
keyREQUIRED
valueREQUIRED
spaceOPTIONAL
roleOPTIONAL

See also the PUT and DELETE operations on Custom Header itself.

touched 2025-09-23T12:04:54