Skip to main content

Quickstart

This guide takes you from zero to a successful API call. It covers account setup, obtaining a token, uploading a document via the Data Curation API, and running an enrichment action with the Context API.

Prefer a no-code approach?

If you'd rather send requests interactively without writing code, download the ready-made Bruno collections from Testing your integration.

Base URLs

Use the API base URL for Data Curation API and Context API requests, and the auth base URL for authentication:

EnvironmentAPI base URLAuth base URL
Production (US)https://knowledge-enrichment.ai.app.hyland.comhttps://auth.app.hyland.com
Production (EU)https://knowledge-enrichment.ai.app.hyland.euhttps://auth.app.hyland.eu

Replace {{api_base_url}} and {{auth_base_url}} in this guide's examples with the values for your environment.


1. Set up your account

Before making API calls you need a registered external client. Complete the following steps in the Content Innovation Cloud Administration Portal:

  1. Subscription — Confirm your environment has access to the Data Curation API and/or Context API.
  2. Service account — Obtain a service account from Hyland if you do not have one. See Metadata for SAML Identity Providers.
  3. User group — Create or use an existing user group with the Data Curation User or Context API User role. See Assigning User Groups to Roles.
  4. External client — Register your application as an external client and note the Client ID and Client Secret (shown only once). See Registering an External Application.
    • Required scope: environment_authorization
    • For DC API access, select cin-data-curation-api in the Application field.

→ Full details in Authentication guide


2. Obtain a token

To obtain the token, use the client_id and client_secret you generated when you set up your account.

curl -X POST {{auth_base_url}}/idp/connect/token \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "client_id=client_a1b2c3d4e5f6" \
-d "client_secret=secret_9x8y7z6w5v4u3t2s1r0q" \
-d "grant_type=client_credentials" \
-d "scope=environment_authorization"

Response:

{
"access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJjbGllbnRfYTFiMmMzZDRlNWY2IiwiaWF0IjoxNzE2MjM5MDIyfQ.example_signature",
"expires_in": 900,
"token_type": "Bearer",
"scope": "environment_authorization"
}

Save the access_token. Include it as Authorization: Bearer <access_token> on every subsequent request. Tokens expire after 15 minutes; request a new one when needed.


3. Curate a document (Data Curation API)

Processing is asynchronous: request presigned URLs, upload the file, poll for completion, and then download the results.

Step 3a — Request presigned URLs

All body fields are optional; omit any you don't need. For the full list of processing options, see Data Curation API Reference.

curl -X POST \
"{{api_base_url}}/latest/api/data-curation/presign" \
-H "Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJjbGllbnRfYTFiMmMzZDRlNWY2IiwiaWF0IjoxNzE2MjM5MDIyfQ.example_signature" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-d '{
"normalization": { "quotations": true, "dashes": true },
"chunking": true,
"chunk_size": 1000,
"embedding": true
}'

Response (200 OK):

{
"job_id": "6e1bb8a0-2bc3-43a2-b3a6-e87975799c8d",
"put_url": "https://<storage-endpoint>/ABCXYZ?<signature>",
"get_url": "https://<storage-endpoint>/ABCXYZ?<signature>",
"options": { "chunking": true, "embedding": true }
}

Save all three values: put_url for the upload, job_id for polling, and get_url for downloading results.

Step 3b — Upload the file

Send a PUT request directly to the put_url from the previous step.

curl -X PUT "<put_url>" \
-H "Content-Type: application/octet-stream" \
--data-binary @/path/to/your/file

Expected response: 200 OK.

Step 3c — Poll for completion

Use the job_id from Step 3a. Keep polling until status is "Done" or "Error".

curl "{{api_base_url}}/latest/api/data-curation/status/6e1bb8a0-2bc3-43a2-b3a6-e87975799c8d" \
-H "Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJjbGllbnRfYTFiMmMzZDRlNWY2IiwiaWF0IjoxNzE2MjM5MDIyfQ.example_signature" \
-H "Accept: application/json"

Response:

{
"jobId": "6e1bb8a0-2bc3-43a2-b3a6-e87975799c8d",
"status": "Done"
}

Initial status is "Wait For Upload". Terminal statuses are "Done" and "Error". If the job ends with "Error", downloading get_url returns an error payload instead of processed results.

Step 3d — Retrieve results

Send a GET request to the get_url from Step 3a.

curl "<get_url>"

Response:

{
"markdown": {
"output": "Extracted document text...",
"chunks_with_embeddings": [
{
"chunk": "Chunk text",
"embeddings": [-0.042955, 0.077558, 0.002666]
}
]
}
}

4. Enrich content (Context API)

The Context API applies enrichment actions to already-uploaded content. Processing is asynchronous: upload a file, submit a job, and then poll until results are ready.

Step 4a — Generate a presigned upload URL

note

Only .jpg and .png image files are supported for image actions. For text actions, PDF and 600+ other formats are supported.

Set the contentType query parameter to the MIME type of the file you want to upload.

curl "{{api_base_url}}/latest/api/context-enrichment/files/upload/presigned-url?contentType=image%2Fpng" \
-H "Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJjbGllbnRfYTFiMmMzZDRlNWY2IiwiaWF0IjoxNzE2MjM5MDIyfQ.example_signature" \
-H "Accept: application/json"

Response (200 OK):

{
"presignedUrl": "https://ke-storage-us.s3.amazonaws.com/contents/env-a1b2c3d4-e5f6-7890-abcd-ef1234567890/file-98765432-10ab-cdef-9876-543210fedcba/file-98765432-10ab-cdef-9876-543210fedcba?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIAIOSFODNN7EXAMPLE%2F20240601%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20240601T133000Z&X-Amz-Expires=3600&X-Amz-Signature=example9876543210fedcba",
"objectKey": "contents/env-a1b2c3d4-e5f6-7890-abcd-ef1234567890/file-98765432-10ab-cdef-9876-543210fedcba/file-98765432-10ab-cdef-9876-543210fedcba"
}

Save both values — presignedUrl is used in the next step, objectKey is used when submitting the processing request.

Object key structure

Both values are automatically generated by the API; you don't need to construct them manually.

Step 4b — Upload the file

Send a PUT request directly to the presignedUrl from the previous step.

curl -X PUT "<presignedUrl>" \
-H "Content-Type: image/png" \
--data-binary @/path/to/your/file.png

Expected response: 200 OK.

Step 4c — Submit a processing request

Use the objectKey from Step 4a. Specify which actions to run and provide example metadata for the model. For the full list of available actions and their parameters, see Actions Reference.

curl -X POST \
"{{api_base_url}}/latest/api/context-enrichment/content/process" \
-H "Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJjbGllbnRfYTFiMmMzZDRlNWY2IiwiaWF0IjoxNzE2MjM5MDIyfQ.example_signature" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-d '{
"version": "context.api/v2",
"objectKeys": [{ "path": "contents/env-a1b2c3d4-e5f6-7890-abcd-ef1234567890/file-98765432-10ab-cdef-9876-543210fedcba/file-98765432-10ab-cdef-9876-543210fedcba" }],
"actions": {
"imageMetadataGeneration": {
"kSimilarMetadata": [
{
"invoice_number": "INV-001",
"invoice_date": "2024-01-15"
}
],
"instructions": {
"invoice_date": "Convert dates to ISO format (YYYY-MM-DD)"
}
}
}
}'

Response (200 OK):

{
"processingId": "proc-abcdef12-3456-7890-abcd-ef1234567890"
}

Step 4d — Poll for results

Use the processingId from the previous step. Keep polling until inProgress is false.

curl "{{api_base_url}}/latest/api/context-enrichment/content/process/proc-abcdef12-3456-7890-abcd-ef1234567890/results" \
-H "Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJjbGllbnRfYTFiMmMzZDRlNWY2IiwiaWF0IjoxNzE2MjM5MDIyfQ.example_signature" \
-H "Accept: application/json"
StatusMeaning
202 AcceptedProcessing in progress — response body shows inProgress: true
200 OKComplete — response body shows inProgress: false
404 Not FoundProcessing ID does not exist

When the job is completed, status is SUCCESS, PARTIAL_FAILURE, or FAILURE. Stop polling when inProgress is false.

Example 200 OK response:

{
"id": "proc-abcdef12-3456-7890-abcd-ef1234567890",
"timestamp": "2025-04-04T08:01:56.000Z",
"status": "SUCCESS",
"inProgress": false,
"results": [
{
"objectKey": "contents/env-a1b2c3d4-e5f6-7890-abcd-ef1234567890/file-98765432-10ab-cdef-9876-543210fedcba/file-98765432-10ab-cdef-9876-543210fedcba",
"imageMetadata": {
"isSuccess": true,
"result": {
"invoice_number": "INV-001",
"invoice_date": "2024-01-15"
}
}
}
]
}

Next steps