Start here: pick your path
New to this? Read this one section, pick a path, and follow only that path's steps. You do not need to understand the rest of the guide to get it working - the reference sections are there if you want them later.
First, two words you will see a lot
- API key - a long secret password (like
sk-ant-...) that lets the map talk to the AI service. You get it from the AI provider's website. - Studio - the map's admin screen. Open the Cordex Relationship Map app, then in the left menu choose Cordex Relationship Map Admin › Config. Scroll to the Cordex AI box. That is "Studio" everywhere below.
Which path should I choose?
| If this is you | Do this path | How hard |
|---|---|---|
| "I just want it working, fastest route" | Path A - Claude, with one shared org key | Easiest |
| "My company is all-in on Microsoft / Azure" | Path B - Azure OpenAI | Medium |
| "Our security policy blocks external AI, or the key must stay hidden from users" | Path C - In-tenant flow | Advanced |
| "I want each person to use their own AI account, not a company one" | Path A - Claude, then turn on Self-serve (leave the org key blank) | Easy |
The 5-minute version (Path A, recommended)
- Go to console.anthropic.com, make an account, and add a little credit in Billing.
- Open Settings › API Keys › Create Key. Copy the key (starts with
sk-ant-). Keep it safe - it is shown once. - In Studio: set Enable Cordex AI = On, Provider = Claude, paste the key in Org API key, press Save encrypted, then Save.
- Open any record, open the map, click the ✨ button, and ask a question.
Worked? You get an answer in the panel. If not, jump to Troubleshooting - the first row usually explains it. The full Path A steps (with the optional workspace and self-serve) are in section 4.
1. How Cordex AI works
Cordex AI is the sparkle (✨) panel on the map. It writes an account brief, answers questions about the record and the map, suggests a next best action, and (optionally) reads related tables to form a sentiment. It calls a provider only when a user asks; the white-space card is computed locally and never leaves the tenant.
You choose one of three providers. Claude and Azure OpenAI call the service directly from the user's browser. The in-tenant flow keeps the key server-side and proxies through your own Power Automate flow, for organisations whose policy blocks direct external AI calls.
| Provider | Where the key lives | Best for |
|---|---|---|
| Claude (Anthropic) | User browser or encrypted org row | Fastest setup, strongest analysis, the data-dive tool |
| Azure OpenAI | User browser or encrypted org row | Teams standardised on the Microsoft / Copilot stack |
| In-tenant flow | Server-side (Key Vault), never in the browser | Policy blocks direct external AI; key must stay hidden from users |
2. Where everything lives
All AI configuration is on one screen: open the app Cordex Relationship Map, go to Cordex Relationship Map Admin › Config (Studio), and scroll to the Cordex AI section. Only administrators can open Studio and read the key rows.
- Studio › Cordex AI - provider, org key, model, workspace, full system access, sentiment, self-serve.
- Studio › Actions - the Power Automate action flows behind the map's Flow button (separate from AI).
- The map › ✨ panel › 🔑 (key) button - where an individual user pastes their own key.
After you Save in Studio, open maps pick the change up on their next refresh.
3. Key resolution order
For Claude and Azure OpenAI, the runtime resolves a usable key in this exact order, using the first it finds:
- The user's own encrypted key row (they pasted it via the 🔑 button and it was saved to the AI Keys table, scoped to them).
- The organisation's encrypted key row (you saved one shared key in Studio).
- A key the user pasted this session into the panel, held in that browser only (never written to Dataverse).
So you can run one shared org key for everyone, let every user bring their own, or mix the two (a user's own key always wins over the org key). The in-tenant flow ignores this order entirely - it holds the key server-side.
4. Claude (Anthropic) Direct
Step 1 - Sign up and add credit
- Go to console.anthropic.com and create an account (or sign in).
- Open Settings › Billing (or Plans & Billing) and add a payment method / purchase credits. A new API key cannot call the model until the account has credit or an active plan.
Step 2 - Create a dedicated workspace (recommended)
- Open Settings › Workspaces and create a workspace, for example
CordexMap. - Set a monthly spend limit on that workspace so map usage is capped and billed separately from your other work.
anthropic-workspace-id header.Step 3 - Create the API key
- Open Settings › API Keys and choose Create Key.
- Scope it to the
CordexMapworkspace from Step 2, name it, and copy the key now (it is shown once). It looks likesk-ant-....
Step 4 - Configure in Studio
- Enable Cordex AI = On.
- Provider = Claude (Anthropic).
- Claude model - leave on Default to let the map pick the recommended model, or press Load available (after pasting/saving a key) to fetch the live model list from Anthropic and pick one, or choose Custom to type an exact model ID such as
claude-sonnet-4-5. - Claude workspace ID - leave blank for a single-workspace key. Fill it only if Anthropic replies "anthropic-workspace-id is required" (an identity-linked key).
- Org API key - to run one shared key for everyone, paste it and press Save encrypted. To let users bring their own instead, leave it blank (see Self-serve).
- Save.
Step 5 - Connect and test
Open a record's map, open the ✨ panel, and ask a question or press Brief. If you left the org
key blank, each user first presses the 🔑 button, pastes their own sk-ant-... key, and
presses Use key - it stays in their browser.
What the map sends
A direct POST to https://api.anthropic.com/v1/messages with these headers and body
(deterministic: temperature 0, so the same input gives the same reading):
POST https://api.anthropic.com/v1/messages
x-api-key: sk-ant-...
anthropic-version: 2023-06-01
anthropic-dangerous-direct-browser-access: true
anthropic-workspace-id: wrkspc_... (only when configured)
content-type: application/json
{
"model": "<configured model>",
"max_tokens": 1200,
"temperature": 0,
"system": "<Cordex system prompt (+ data-dive rules when full access is on)>",
"messages": [ ...last 8 turns, then the map snapshot + the question ],
"tools": [ <query tool> ] // only when Full system access is On
}
Return value. The answer is the joined content[] text blocks. When full system access is on,
the model may reply with stop_reason: "tool_use"; the map runs the requested read-only query and
loops (up to 8 rounds), then forces a prose answer.
5. Azure OpenAI Direct
Steps confirmed against Microsoft Learn. The Azure portal and Foundry UI move labels around from time to time; the three things you need out of it never change: an endpoint, a deployment name, and a key.
Step 1 - Create the Azure OpenAI resource
- Sign in to the Azure portal.
- Create a resource, search Azure OpenAI, choose Create.
- On Basics: pick a subscription, resource group, region and a name; pricing tier Standard.
- Configure network access, add any tags, then Review + submit › Create › Go to resource.
Step 2 - Deploy a model
- Open Microsoft Foundry and select your resource.
- Go to Deployments › + Deploy model › Deploy base model.
- Choose a chat model (for example
gpt-4o) and Confirm. - Give the deployment a name (for example
MyModel) and Deploy. Note this name - Azure calls use the deployment name, not the model name.
Step 3 - Get the endpoint and key
- Back in the Azure portal, open your resource › Keys and Endpoint (under Resource Management).
- Copy the Endpoint (for example
https://myresource.openai.azure.com/) and Key 1.
Step 4 - Configure in Studio
- Enable Cordex AI = On, Provider = Azure OpenAI.
- Azure endpoint = the resource endpoint from Step 3.
- Azure deployment = the deployment name from Step 2 (for example
MyModel). - Azure API version = default
2024-10-21(a current, stable value is2024-11-20; use the version your deployment supports). - Org API key = paste Key 1 and Save encrypted, or leave blank for self-serve.
- Save, then test from a map's ✨ panel.
gpt-4o.What the map sends
POST https://<endpoint>/openai/deployments/<deployment>/chat/completions?api-version=<version>
api-key: <Azure key>
content-type: application/json
{
"max_tokens": 1000,
"temperature": 0,
"messages": [ {"role":"system","content":"<Cordex system prompt>"}, ...turns ]
}
Return value. The answer is choices[0].message.content.
6. In-tenant flow Key-free
For organisations whose policy blocks direct external AI. The question and a small map snapshot POST to your Power Automate flow; the flow holds the provider key server-side (Key Vault) and returns the answer. No key ever reaches the browser.
Step 1 - Build the flow
- In Power Automate, create an instant cloud flow with the trigger When an HTTP request is received.
- Set the request body JSON schema to what the map sends (below). This trigger's URL is generated after you save.
- Add an HTTP action that calls your provider (Anthropic or Azure OpenAI), reading the API key from Azure Key Vault - never hard-code it in the flow.
- Add a Response action: status
200, and a headerAccess-Control-Allow-Origin: *(required, see the CORS note), returning the answer as JSON. - Save, then copy the trigger's HTTP POST URL.
Step 2 - What the map POSTs to your flow
POST <your flow trigger URL>
Content-Type: text/plain;charset=UTF-8 // a CORS "simple" request on purpose
{
"question": "who is the biggest stakeholder here?",
"system": "<Cordex system prompt>",
"context": { ...map snapshot: focal record, people, links... },
"history": [ ...last 8 turns... ],
"user": "<signed-in user's name>",
"source": "cordex-map v<version>"
}
text/plain so the browser treats it
as a simple request and does not send a preflight. Your Response action still must add
Access-Control-Allow-Origin: * or the browser blocks the map from reading the reply, and the panel
shows a network error even though the flow ran.Step 3 - What your flow returns
Return status 200. The map reads the answer in this order: JSON answer, then JSON
text, then the raw body as plain text. So either of these works:
// JSON (preferred)
{ "answer": "Jim Glynn is the strongest stakeholder - Champion, negative sentiment." }
// or plain text
Jim Glynn is the strongest stakeholder - Champion, negative sentiment.
Step 4 - Configure in Studio
- Enable Cordex AI = On, Provider = In-tenant flow.
- AI flow URL = the HTTP trigger URL from Step 1. It must start with
https://. Only administrators can read this row. - Save, then test from a map's ✨ panel.
Access-Control-Allow-Origin: * header - that one header is the usual culprit.7. Self-serve keys Claude / Azure
Instead of one org key, you can let approved users bring their own. This spreads cost across users' own provider accounts and keeps you out of key custody.
Admin
- Leave the Org API key blank.
- Self-serve credentials - leave Open to all, or switch to Restricted and add the specific users and teams allowed to add a key.
User
- Open the map's ✨ panel and press the 🔑 button.
- Paste the API key (Claude
sk-ant-...or the Azure key) and press Use key. - The key stays in that browser. If the button says self-serve is limited, ask an administrator to add you.
8. Grounding context
House terms, product names, sales stages, anything the model should always know. It is injected on every question automatically - the user never pastes it.
- Studio › Cordex AI › Grounding context.
- Press Generate starter, then edit the Global box (shared by every form) and, optionally, a per-form box.
- Applies - choose Global only, this form only, both (default), or off.
Each box holds up to about 4000 characters.
9. Full system access (data dive) Claude
Off by default, Cordex AI sees only the visible map snapshot. Turn on Allow full system access and it can run read-only Dataverse queries to answer questions about activities, pipeline, cases, owners and aggregates - executed as the signed-in user, so their own security roles are the ceiling and nothing is ever written.
- Studio › Cordex AI › Allow full system access = On.
The exact tool the model is given - its OData surface and limits - is in section 13.
10. Sentiment trend Claude
Cordex AI can read a record's related tables (cases, opportunities, leads, activities/emails) plus widely known public context to form a sentiment, and save it as a dated point so a trend builds over time (▲ improving / ▼ declining). The AI suggests; a person confirms it into the sentiment tag.
- Turn on Allow full system access first (section 9) - sentiment needs it.
- Add the Cordex Relationship Map Sentiment table and grant the Cordex security role Create/Read on it.
- Studio › Cordex AI › Sentiment trend = On.
- Optionally Assess automatically (first map open each day) or a Monthly refresh (admin approval; first run of the month).
11. Action flows (the Flow button)
Separate from Cordex AI: the map's inspector Flow button runs on-demand Power Automate flows against the record. This is where "flow triggers" beyond the AI proxy come in.
Build and map a flow
- Build the flow with the When an HTTP request is received trigger.
- The map POSTs a small JSON body identifying the record (below).
- Studio › Actions › enable Allow workflows & flows.
- Under Power Automate flows, press Load flows from this environment to list activated cloud flows, pick one by name, and paste its HTTPS trigger URL.
What the map POSTs to an action flow
POST <action flow trigger URL>
{ "table": "account", "id": "<record GUID>", "name": "A. Datum Corporation", "user": "<signed-in user>" }
12. Request / return reference
| Provider | Endpoint | Auth header | Answer field |
|---|---|---|---|
| Claude | api.anthropic.com/v1/messages | x-api-key | content[] text blocks |
| Azure OpenAI | <endpoint>/openai/deployments/<deployment>/chat/completions?api-version=<v> | api-key | choices[0].message.content |
| In-tenant flow | your HTTP trigger URL | none (server-side key) | answer, then text, then raw body |
| Setting (Studio) | Default | Notes |
|---|---|---|
| Claude model | Default (claude-sonnet-4-5) | Default, Load available, or Custom exact ID |
| Claude workspace ID | blank | Only for identity-linked, multi-workspace keys |
| Azure API version | 2024-10-21 | Use the version your deployment supports |
| max_tokens | Claude 1200 / Azure 1000 | temperature 0 on both (deterministic) |
| Tool loop rounds | up to 8 | Claude data dive only; final round forces prose |
| History carried | last 8 turns | Snapshot rides on the newest question only |
13. Read-only query tool schema Claude data dive
When full system access is on, Claude is given exactly one tool. It is a read-only Dataverse Web API GET, run in the browser as the signed-in user. Writes are impossible.
{
"name": "query",
"input_schema": {
"type": "object",
"properties": {
"path": { "type": "string",
"description": "OData path + query after /api/data/v9.2/ (or an @odata.nextLink to page)" }
},
"required": ["path"]
}
}
Supported OData surface: $select, $top (page cap 25; more via the
@odata.nextLink returned), $filter (eq ne gt ge lt le, and/or/not, grouping,
contains/startswith/endswith, the in operator, null tests, lookup _x_value GUID
filters, collection lambdas with any()), $expand (join a lookup's fields in one call),
$orderby (plain queries only), and $apply aggregates (sum, average, min, max, $count,
groupby).
Return value: the raw OData JSON, trimmed to about 7000 characters with the @odata.nextLink
kept visible so paging still works. Errors come back as ERROR: ... so the model can adjust.
Known limits the model is told about: $skip is not supported; $orderby is not
allowed on an $apply query (sort the result yourself); no countdistinct and no groupby on
datetime; aggregates over 50,000 rows fail with 8004E023 (narrow the filter); GET URLs cap near 32KB;
statecode 0 = active/open, 1 = inactive/closed.
14. Key storage & security
Saved keys (org and per-user) live in the Cordex Relationship Map AI Keys table
(mitaa_cordexmapaikeys), encrypted AES-256-GCM with a per-row random salt and IV. Clear text
never touches Dataverse, and rows are importable between environments.
- Provider is stored as a choice: Claude =
286640000, Azure =286640001. - Scope distinguishes an organisation key from a personal (self-serve) key.
15. Troubleshooting
| Symptom | Cause / fix |
|---|---|
| ✨ panel missing or greyed | License is below Tier 03, or Enable Cordex AI is Off. |
| "anthropic-workspace-id is required" | Identity-linked, multi-workspace key. Put the workspace ID in Studio (or the user's 🔑 override), or scope the key to a single workspace. |
| "Azure OpenAI endpoint and deployment are not configured" | Fill both Azure endpoint and deployment in Studio. Remember: deployment name, not model name. |
| Flow answer never arrives / network error, but the flow ran | The flow's Response action is missing Access-Control-Allow-Origin: *. Add it. |
| Flow returns 401 / 403 | The trigger URL is wrong or expired, or the server-side provider key is invalid. Re-copy the trigger URL and check Key Vault access. |
| "I can only see this map right now" | Full system access is Off. Turn on Allow full system access (Claude) to query live data. |
| Aggregate fails with 8004E023 | The filtered set exceeds 50,000 rows. Add a tighter filter inside the $apply. |
| Console shows "Result is not PredictAPI" or a Collector 401 | Platform / telemetry noise from the host form, not Cordex Relationship Map. Safe to ignore. |