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.
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:
| Environment | API base URL | Auth base URL |
|---|---|---|
| Production (US) | https://knowledge-enrichment.ai.app.hyland.com | https://auth.app.hyland.com |
| Production (EU) | https://knowledge-enrichment.ai.app.hyland.eu | https://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:
- Subscription — Confirm your environment has access to the Data Curation API and/or Context API.
- Service account — Obtain a service account from Hyland if you do not have one. See Metadata for SAML Identity Providers.
- 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.
- 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.
- Required scope:
→ 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
- HTTP
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"
POST {{auth_base_url}}/idp/connect/token HTTP/1.1
Content-Type: application/x-www-form-urlencoded
grant_type=client_credentials&client_id=client_a1b2c3d4e5f6&client_secret=secret_9x8y7z6w5v4u3t2s1r0q&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
- HTTP
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
}'
POST /latest/api/data-curation/presign HTTP/1.1
Host: {{api_base_url}}
Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJjbGllbnRfYTFiMmMzZDRlNWY2IiwiaWF0IjoxNzE2MjM5MDIyfQ.example_signature
Content-Type: application/json
Accept: application/json
{
"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
- HTTP
curl -X PUT "<put_url>" \
-H "Content-Type: application/octet-stream" \
--data-binary @/path/to/your/file
PUT <put_url> HTTP/1.1
Content-Type: application/octet-stream
<binary file data>
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
- HTTP
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"
GET /latest/api/data-curation/status/6e1bb8a0-2bc3-43a2-b3a6-e87975799c8d HTTP/1.1
Host: {{api_base_url}}
Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJjbGllbnRfYTFiMmMzZDRlNWY2IiwiaWF0IjoxNzE2MjM5MDIyfQ.example_signature
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
- HTTP
curl "<get_url>"
GET <get_url> HTTP/1.1
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
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
- HTTP
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"
GET /latest/api/context-enrichment/files/upload/presigned-url?contentType=image%2Fpng HTTP/1.1
Host: {{api_base_url}}
Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJjbGllbnRfYTFiMmMzZDRlNWY2IiwiaWF0IjoxNzE2MjM5MDIyfQ.example_signature
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.
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
- HTTP
curl -X PUT "<presignedUrl>" \
-H "Content-Type: image/png" \
--data-binary @/path/to/your/file.png
PUT <presignedUrl> HTTP/1.1
Content-Type: image/png
<binary file data>
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
- HTTP
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)"
}
}
}
}'
POST /latest/api/context-enrichment/content/process HTTP/1.1
Host: {{api_base_url}}
Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJjbGllbnRfYTFiMmMzZDRlNWY2IiwiaWF0IjoxNzE2MjM5MDIyfQ.example_signature
Content-Type: application/json
Accept: application/json
{
"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
- HTTP
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"
GET /latest/api/context-enrichment/content/process/proc-abcdef12-3456-7890-abcd-ef1234567890/results HTTP/1.1
Host: {{api_base_url}}
Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJjbGllbnRfYTFiMmMzZDRlNWY2IiwiaWF0IjoxNzE2MjM5MDIyfQ.example_signature
Accept: application/json
| Status | Meaning |
|---|---|
202 Accepted | Processing in progress — response body shows inProgress: true |
200 OK | Complete — response body shows inProgress: false |
404 Not Found | Processing 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
- Curating documents — full DC API workflow with all options
- Enriching content — full Context API workflow with all actions
- Context API actions reference — all available actions and their schemas
- Testing your integration — ready-made Bruno collections for both APIs if you prefer sending requests without writing code
- Error reference — what to do when something goes wrong