Skip to main content

Content Configuration GraphQL API

Create, update, and delete content from CI pipelines, scripts, or your own tools, without opening the Admin Console. Reads and writes use the same GraphQL endpoint.

Your GraphQL endpoint is https://tenant-name.is.here.io/here/api/graphql

POST /here/api/graphql
x-openfin-cloud-api-key: <your API key>
Content-Type: application/json

mutation {
createContent(input: {
contentType: WEB
name: "Trading Portal"
contentId: "trading-portal"
active: true
featured: false
urls: ["https://trading.example.com"]
access: { subjects: ["jane.doe@example.com"], primitives: ["all-users"] }
}) { uuid id name active }
}

Six fields are required: contentType, name, contentId, active, featured, and access. Desktop content also requires nativeSettings. The server sets defaults for the rest. See Defaults.

Authentication​

Every request must carry one of these credentials:

CredentialHow to send itUse it for
API keyx-openfin-cloud-api-key headerUnattended systems, such as CI pipelines or backend services.
Bearer tokenAuthorization: Bearer <token> headerCallers that already hold a HERE access token.
Session cookiehere-session cookieScripts or tools run by a signed-in user.

For a pipeline or script that runs on its own, use an API key.

The credential must belong to an admin. What an admin can do depends on their admin type:

Admin typeReadCreate, update, and delete
ReadYesNo
Content ManagerYesYes
Full AccessYesYes

A signed-in user who isn't an admin can't read or write content through this API.

A missing, expired, or invalid credential fails with UNAUTHENTICATED. A valid credential without the right admin type fails with FORBIDDEN. Error codes appear in extensions.code on each GraphQL error.

caution

An API key has Full Access, so it can see and modify all items in the Admin Console. Store API keys in a secrets manager, give them only to the systems that need them, and rotate them regularly.

Identifiers​

Every content item has two identifiers:

IdentifierNotes
uuidServer-generated, stable, for example d48bf4cc-1b66-479e-a77d-59ab1e58557e.
contentIdThe human-readable ID you choose at creation, for example trading-portal. Unique within your organization.

updateContent and deleteContent accept either one. If the value parses as a UUID, the API uses it as a UUID. Otherwise, the API looks it up by contentId. In scripts, use content IDs so you don't have to store UUIDs.

The content query works differently. See Read content.

createContent​

createContent(input: CreateContentInput!): ContentBase!

Set contentType to WEB or DESKTOP. The type decides which other fields CreateContentInput accepts. For DESKTOP, nativeSettings is required, along with all three of its fields: desktopPath, desktopArgs, and withSnap. Every other field is optional.

Minimal web application​

mutation CreateContent($input: CreateContentInput!) {
createContent(input: $input) {
uuid
id
name
type
active
}
}
{
"input": {
"contentType": "WEB",
"name": "Trading Portal",
"contentId": "trading-portal",
"active": true,
"featured": false,
"urls": ["https://trading.example.com"],
"access": {
"subjects": ["jane.doe@example.com"],
"primitives": ["all-users"]
}
}
}

Web application, every field set​

{
"input": {
"contentType": "WEB",
"name": "Trading Portal",
"contentId": "trading-portal",
"active": true,
"featured": true,
"icon": "https://cdn.example.com/trading-icon.png",
"urls": ["https://trading.example.com", "https://trading-staging.example.com"],
"hereApiAccess": true,
"allowDuplication": false,
"allowOpenWithDefaultBrowser": false,
"useAIContext": true,
"enableSimpleWindow": false,
"environmentAvailability": {
"enableHereEB": true,
"enableHereZero": true,
"enableHereMobile": false
},
"viewSettings": {
"navigationControls": true,
"reloadControl": true
},
"dataLossPreventionSettings": {
"copyBehavior": "protect",
"pasteBehavior": "non-protected-content",
"screenCaptureBehavior": "block",
"printBehavior": "block"
},
"redirects": [],
"access": {
"subjects": ["jane.doe@example.com"],
"primitives": ["all-users"]
}
}
}

Desktop application​

{
"input": {
"contentType": "DESKTOP",
"name": "Bloomberg Terminal",
"contentId": "bloomberg-terminal",
"active": true,
"featured": false,
"nativeSettings": {
"desktopPath": "C:\\Bloomberg\\blp.exe",
"desktopArgs": ["--workspace"],
"withSnap": true
},
"access": {
"subjects": [],
"primitives": ["all-users"]
}
}
}

Web application with FDC3 intents​

{
"input": {
"contentType": "WEB",
"name": "Chart Viewer",
"contentId": "chart-viewer",
"active": true,
"featured": false,
"urls": ["https://charts.example.com"],
"interop": {
"intents": {
"listensFor": {
"ViewChart": {
"displayName": "View Chart",
"contexts": ["fdc3.instrument"]
}
}
}
},
"access": {
"subjects": [],
"primitives": ["all-users"]
}
}
}

Field reference​

Common to both content types​

FieldTypeNotes
contentType *WEB | DESKTOPSelects which type-specific fields are valid.
name *StringDisplay name that users see.
contentId *StringYour stable identifier. 1–255 characters: letters, numbers, and hyphens only. Must be unique in your organization. A duplicate fails with CONFLICT.
active *BooleanWhether the content is available to users.
featured *BooleanPromotes the item in the storefront.
access *ContentAccessInputWho can launch it. See Access control.
iconStringAbsolute URL to an icon image.
customLabelStringOptional secondary label.

* required on create

Web content​

FieldTypeNotes
urls[String!]One or more launch URLs. The first is the primary url on read.
hereApiAccessBooleanGrants the page access to the HERE JavaScript API.
allowDuplicationBooleanLets users open more than one window of the app.
allowOpenWithDefaultBrowserBooleanAdds an "open in browser" action.
useAIContextBooleanMakes the app's content available to AI features.
enableSimpleWindowBooleanRenders in a chromeless window.
environmentAvailabilityobjectenableHereEB, enableHereZero, enableHereMobile.
viewSettingsobjectnavigationControls, reloadControl.
dataLossPreventionSettingsobjectcopyBehavior, pasteBehavior, screenCaptureBehavior, printBehavior.
redirects[ContentRedirectInput!]Domain redirect rules.
interopobjectFDC3 intents the app listens for.

Desktop content​

FieldTypeNotes
nativeSettings.desktopPath *StringPath to the executable on the user's machine. Escape backslashes in JSON.
nativeSettings.desktopArgs *[String!]Launch arguments.
nativeSettings.withSnap *BooleanParticipates in window snapping.

* required on create

Defaults​

When you omit an optional field, the server uses the same default as the Admin Console: permissive data loss prevention, availability in HERE Enterprise Browser only, and standard view settings. Defaults can change between releases, so set any field whose value matters to you.

Access control​

input ContentAccessInput {
subjects: [String!]! # individual users
primitives: [String!]! # groups
}

Both lists accept names or UUIDs, and one list can mix them. If a value parses as a UUID, the API uses it as a UUID. Otherwise, the API looks it up by username in subjects or by group name in primitives.

If a name doesn't resolve, the mutation fails with NOT_FOUND and the content doesn't change.

This controls which users and groups can launch a content item. To change which groups a user belongs to, use the User Group Management API.

"access": {
"subjects": ["jane.doe@example.com", "sam.patel@example.com"],
"primitives": ["traders-group"]
}

createContents​

createContents(inputs: [CreateContentInput!]!): BulkCreateContentResult!

Creates several items in one request, and returns them in created. If any item fails, the whole request fails.

mutation CreateContents($inputs: [CreateContentInput!]!) {
createContents(inputs: $inputs) {
created { uuid id name }
}
}
{
"inputs": [
{
"contentType": "WEB",
"name": "Trading Portal",
"contentId": "trading-portal",
"active": true,
"featured": false,
"urls": ["https://trading.example.com"],
"access": { "subjects": [], "primitives": ["all-users"] }
},
{
"contentType": "WEB",
"name": "Chart Viewer",
"contentId": "chart-viewer",
"active": true,
"featured": false,
"urls": ["https://charts.example.com"],
"access": { "subjects": [], "primitives": ["traders-group"] }
}
]
}

updateContent​

updateContent(identifier: ID!, input: UpdateContentInput!): ContentBase!

UpdateContentInput has the same fields as CreateContentInput, but they're all optional. Send only the fields you want to change. Everything else stays as it is. If you omit contentType, the item keeps its current type.

How access updates​

ValueEffect
omitted or nullLeave the current access list untouched.
{ subjects: [...], primitives: [...] }Replace the access list with exactly these entries.
{ subjects: [], primitives: [] }Remove all access. Users no longer launch the item.

To add or remove a single user or group, read the current access list, change it, and send the full list back.

Example​

mutation UpdateContent($identifier: ID!, $input: UpdateContentInput!) {
updateContent(identifier: $identifier, input: $input) {
uuid
name
active
... on WebContent { urls }
}
}
{
"identifier": "trading-portal",
"input": {
"name": "Trading Portal (v2)",
"featured": true,
"urls": ["https://trading.example.com", "https://trading-v2.example.com"],
"access": null
}
}

deleteContent​

deleteContent(identifier: ID!): Boolean!
mutation { deleteContent(identifier: "trading-portal") }
{ "data": { "deleteContent": true } }

Deletion is permanent. It also removes the item from users' saved docks, without notifying them. To hide an item but keep its record, set active to false.

Read content​

content reads one item. Pass a content ID as id, or a UUID as uuid:

query { content(id: "trading-portal") { uuid name } }
query { content(uuid: "d48bf4cc-1b66-479e-a77d-59ab1e58557e") { id name } }

Unlike updateContent and deleteContent, content doesn't detect UUIDs. content(id:) with a UUID doesn't find the item.

One item​

query {
content(id: "trading-portal") {
uuid
name
type
active
access { subjects primitives permissions }
... on WebContent {
urls
hereApiAccess
dataLossPreventionSettings {
copyBehavior pasteBehavior screenCaptureBehavior printBehavior
}
}
}
}

On read, access returns UUIDs, even if you wrote names.

Paginated list​

query ListContents {
contents(first: 50) {
totalCount
pageInfo { hasNextPage endCursor }
edges {
node {
uuid
id
name
type
active
... on WebContent { url urls }
... on DesktopContent { desktopPath desktopArgs withSnap }
}
}
}
}

Full snapshot with a fragment​

Use this fragment to export items, compare them, or read an item before you update it.

fragment ContentFields on ContentBase {
uuid
id
name
type
active
customLabel
featured
icon
createdAt
access { subjects primitives permissions }
... on WebContent {
url
urls
hereApiAccess
allowDuplication
allowOpenWithDefaultBrowser
useAIContext
enableSimpleWindow
environmentAvailability { enableHereEB enableHereZero enableHereMobile }
viewSettings { navigationControls reloadControl }
dataLossPreventionSettings {
copyBehavior pasteBehavior screenCaptureBehavior printBehavior
}
redirects { id name description redirectDetails { domains name icon } }
}
... on DesktopContent {
desktopPath
desktopArgs
withSnap
}
}

query {
contents(first: 50) {
totalCount
pageInfo { hasNextPage endCursor }
edges { node { ...ContentFields } }
}
}

Behavior to plan for​

  • The last write wins. If a script and an administrator edit the same item at the same time, one change silently overwrites the other. Avoid running automated and manual edits on the same content at once.
  • Every write is audited. Each create, update, and delete produces an audit event. A pipeline that creates hundreds of items in a tight loop produces a matching burst of audit events, so pace large migrations.
  • Deleting an item removes it from users' docks. See deleteContent.
  • Names cost a lookup. When you create many items, resolve names once and pass the UUIDs in access.
  • List fields replace the whole list. Sending urls, access, or redirects replaces the existing list. Other fields update individually.