Dynamics 365 CRM

v1.0.0

Create and update CRM records in Microsoft Dynamics 365 — Opportunities, Leads, Contacts, Accounts, and Tasks via Dataverse Web API with Azure AD OAuth 2.0.

0· 98·0 current·0 all-time
byDiego Vieira@vieiradiego

Install

OpenClaw Prompt Flow

Install with OpenClaw

Best for remote or guided setup. Copy the exact prompt, then paste it into OpenClaw for vieiradiego/openclaw-dynamics-365.

Previewing Install & Setup.
Prompt PreviewInstall & Setup
Install the skill "Dynamics 365 CRM" (vieiradiego/openclaw-dynamics-365) from ClawHub.
Skill page: https://clawhub.ai/vieiradiego/openclaw-dynamics-365
Keep the work scoped to this skill only.
After install, inspect the skill metadata and help me finish setup.
Required env vars: DYNAMICS365_CLIENT_ID, DYNAMICS365_CLIENT_SECRET, DYNAMICS365_TENANT_ID, DYNAMICS365_INSTANCE_URL
Use only the metadata you can verify from ClawHub; do not invent missing requirements.
Ask before making any broader environment changes.

Command Line

CLI Commands

Use the direct CLI path if you want to install manually and keep every step visible.

OpenClaw CLI

Bare skill slug

openclaw skills install openclaw-dynamics-365

ClawHub CLI

Package manager switcher

npx clawhub@latest install openclaw-dynamics-365
Security Scan
Capability signals
Requires OAuth token
These labels describe what authority the skill may exercise. They are separate from suspicious or malicious moderation verdicts.
VirusTotalVirusTotal
Benign
View report →
OpenClawOpenClaw
Benign
high confidence
Purpose & Capability
Name/description match the requested environment variables (Azure AD client ID/secret/tenant and instance URL). The client secret and instance URL are expected for a Dynamics 365 Dataverse integration. No unrelated credentials or system-level access are requested.
Instruction Scope
SKILL.md instructs the agent to perform OAuth authorization and to call the provided client methods that interact with the Dataverse Web API. It only references the declared env vars and the Dynamics instance and Microsoft's login endpoint; it does not instruct reading arbitrary files, other env vars, or sending data to unknown endpoints.
Install Mechanism
No install spec in the registry (instruction-only), and the package files included are a normal npm library layout. There are no downloads from arbitrary URLs or extract steps. package.json points to a GitHub repo and standard build/test steps.
Credentials
Required env vars (client id, client secret, tenant id, instance URL) are appropriate and minimal for OAuth + Dataverse calls. No extraneous secrets, unrelated service credentials, or unusual config-path access are requested.
Persistence & Privilege
always is false (not force-included). The skill does not request elevated persistent presence or modify other skills/config; it uses standard runtime OAuth flows and token refresh logic.
Assessment
This skill appears internally consistent and implements standard Azure AD OAuth + Dataverse API usage. Before installing: (1) verify the skill publisher/repository (registry metadata lists no homepage even though package.json points to a GitHub repo) so you trust where the code comes from; (2) create an Azure App Registration with minimal permissions (user_impersonation) and grant admin consent only if required; (3) store DYNAMICS365_CLIENT_SECRET securely (do not paste it into chat); (4) restrict the app registration's lifetime/permissions according to least privilege and rotate the secret periodically; (5) test in a non-production Dynamics environment first to confirm behavior and rate limits.

Like a lobster shell, security has layers — review code before you run it.

Runtime requirements

EnvDYNAMICS365_CLIENT_ID, DYNAMICS365_CLIENT_SECRET, DYNAMICS365_TENANT_ID, DYNAMICS365_INSTANCE_URL
Primary envDYNAMICS365_INSTANCE_URL
crmvk97bnfvbt50m7ek3qakeecm58x84r7w9dataversevk97bnfvbt50m7ek3qakeecm58x84r7w9dynamics365vk97bnfvbt50m7ek3qakeecm58x84r7w9latestvk97bnfvbt50m7ek3qakeecm58x84r7w9microsoftvk97bnfvbt50m7ek3qakeecm58x84r7w9
98downloads
0stars
1versions
Updated 2w ago
v1.0.0
MIT-0

Dynamics 365 CRM Skill

When to activate

Activate this skill when the user mentions Microsoft Dynamics 365, D365, Dynamics CRM, or any of the following actions directed at a Dynamics 365 CRM:

  • Creating or updating an opportunity / deal / oportunidade
  • Creating or updating a lead
  • Creating or updating a contact / contacto
  • Creating or updating an account / empresa / conta
  • Creating a task / activity linked to a CRM record

Credentials required

VariableDescription
DYNAMICS365_CLIENT_IDAzure AD Application (client) ID
DYNAMICS365_CLIENT_SECRETAzure AD client secret
DYNAMICS365_TENANT_IDAzure AD Tenant ID — use common for multi-tenant
DYNAMICS365_INSTANCE_URLDynamics 365 instance URL, e.g. https://contoso.crm.dynamics.com

Step-by-step execution

1 — Identify intent and entity type

Determine from the user's message which entity to create or update:

User saysEntityAction
"create deal", "new opportunity", "deal com X"Opportunityupsert
"new lead", "criar lead", "prospect X"Leadupsert
"add contact", "criar contacto", "cliente X no CRM"Contactupsert
"new account", "empresa Y no CRM", "criar conta"Accountupsert
"create task", "follow-up", "lembrete para X"Taskcreate

2 — Extract fields from user input

Opportunity fields:

  • name — deal / opportunity name (required)
  • estimatedvalue — numeric value in local currency
  • stepname — pipeline stage: "Qualify" / "Develop" / "Propose" / "Close"
  • actualclosedate — expected close date (ISO: YYYY-MM-DD)

Lead fields:

  • fullname — full name (required)
  • emailaddress1 — email address
  • companyname — company name
  • telephone1 — phone number
  • jobtitle — job title

Contact fields:

  • fullname — full name (required)
  • emailaddress1 — email address
  • telephone1 — phone number
  • jobtitle — job title

Account fields:

  • name — company / account name (required)
  • emailaddress1 — email address
  • telephone1 — phone number
  • websiteurl — website

Task fields:

  • subject — task title (required)
  • description — details / notes
  • scheduledend — due date-time (ISO 8601)
  • prioritycode — 0 = Low, 1 = Normal, 2 = High

3 — Call the appropriate method

Use the Dynamics365Client from the openclaw-dynamics-365 npm package:

import { Dynamics365Client } from "openclaw-dynamics-365";

const client = new Dynamics365Client(
  process.env.DYNAMICS365_INSTANCE_URL,
  accessToken,  // obtained via OAuth flow
);

// Opportunity
const result = await client.upsertOpportunity({ name: "Deal Contoso", estimatedvalue: 50000 });

// Lead
const result = await client.upsertLead({ fullname: "João Silva", companyname: "TechNova" });

// Contact
const result = await client.upsertContact({ fullname: "Maria Santos", emailaddress1: "maria@techno.com" });

// Account
const result = await client.upsertAccount({ name: "TechNova Ltda" });

// Task
const taskId = await client.createTask({ subject: "Follow-up call", prioritycode: 2 });

4 — Format response to the user

On success:

✅ [Entity] "[name]" [created/updated] in Dynamics 365.
🔗 [record URL]

On error:

❌ Could not [create/update] [entity] in Dynamics 365: [error message]

OAuth setup

For initial authorization, use getAuthorizationUrl() to redirect the user to Microsoft's consent screen, then exchangeCodeForTokens() in the callback:

import { getAuthorizationUrl, exchangeCodeForTokens } from "openclaw-dynamics-365";

// 1. Redirect user
const url = getAuthorizationUrl(config, redirectUri, state);

// 2. In callback
const tokens = await exchangeCodeForTokens(config, code, redirectUri);

// 3. Refresh when expired (~1h)
if (isTokenExpired(tokens)) {
  tokens = await refreshAccessToken(config, tokens.refreshToken);
}

Notes

  • The Dataverse Web API uses OData v4 — all queries use $filter, $select, $top
  • Upsert operations search by name/email first to avoid duplicates
  • Lookup fields (e.g. linking a Contact to an Account) use OData binding syntax: "parentcustomerid_account@odata.bind": "/accounts({accountId})"
  • Rate limit: 6,000 requests / 5 minutes per user — well within typical usage
  • Access tokens expire after ~1 hour — implement refresh logic using refreshAccessToken()

Comments

Loading comments...