Microsoft Power Automate Integration
Build low-code flows with a custom Certyo connector that triggers on Dynamics 365 changes, SharePoint uploads, and SQL events to anchor records on the blockchain.
Overview
Microsoft Power Automate enables citizen developers and integration teams to connect Certyo with 1,000+ Microsoft and third-party services using a visual flow builder. This guide covers creating a custom Certyo connector from an OpenAPI definition and building three production-ready flow templates.
The custom connector wraps Certyo's REST API as a first-class Power Platform resource, giving flow authors access to record ingestion, bulk operations, and verification without writing code.
Prerequisites
- Power Automate Premium ($15/user/month) — required for custom connectors and premium triggers
- Certyo API key (obtain from the Quickstart guide)
- Access to Power Platform admin center for connector registration
- Azure Active Directory tenant (for connector authentication setup)
- Source system access: Dynamics 365, SharePoint, or Azure SQL depending on your flow
Architecture
┌──────────────────────────────────────────────────────────────────┐
│ TRIGGER SOURCES │
│ ┌──────────────┐ ┌──────────────┐ ┌────────────────────────┐ │
│ │ Dynamics 365 │ │ SharePoint │ │ Azure SQL / SQL │ │
│ │ Dataverse │ │ Document │ │ Server Change │ │
│ │ Row Changed │ │ Uploaded │ │ Tracking │ │
│ └──────┬───────┘ └──────┬───────┘ └────────────┬───────────┘ │
│ └─────────────────┼───────────────────────┘ │
├───────────────────────────┼──────────────────────────────────────┤
│ POWER AUTOMATE FLOW │
│ ┌────────────────────────┴────────────────────────────────┐ │
│ │ 1. Trigger fires on source system event │ │
│ │ 2. Compose: build Certyo record JSON │ │
│ │ 3. Custom Connector: POST /api/v1/records │ │
│ │ 4. Condition: check 202 Accepted │ │
│ │ 5. Update source record with recordHash │ │
│ └────────────────────────┬────────────────────────────────┘ │
├───────────────────────────┼──────────────────────────────────────┤
│ CERTYO PIPELINE │
│ ┌────────────────────────┴────────────────────────────────┐ │
│ │ POST /api/v1/records ──► 202 Accepted + recordHash │ │
│ │ │ │ │
│ │ Kafka topic ──► Accumulate ──► Merkle tree │ │
│ │ ──► IPFS pin ──► Polygon anchor │ │
│ │ │ │
│ │ ~60-90 seconds to on-chain confirmation │ │
│ └──────────────────────────────────────────────────────────┘ │
└──────────────────────────────────────────────────────────────────┘Custom Connector Setup
Power Automate custom connectors are defined from an OpenAPI (Swagger) specification. Follow these steps to register the Certyo connector in your Power Platform environment.
Step 1: Create the connector
- Go to Power Automate > Data > Custom connectors > New custom connector > Import an OpenAPI from URL
- Enter a name:
Certyo Records API - Paste the URL to your hosted OpenAPI spec, or upload the JSON definition below
Step 2: Configure authentication
- On the Security tab, select API Key
- Parameter label:
API Key - Parameter name:
X-API-Key - Parameter location: Header
Step 3: Test the connector
- Create a new connection using your Certyo API key
- Select the IngestRecord operation
- Fill in test values and verify you receive a
202 Acceptedresponse
Code Samples
{
"openapi": "3.0.1",
"info": {
"title": "Certyo Records API",
"description": "Blockchain-backed record ingestion, verification, and query for the Certyo durable records platform.",
"version": "1.0.0",
"contact": {
"name": "Certyo Developer Support",
"url": "https://www.certyos.com/developers"
}
},
"servers": [
{
"url": "https://www.certyos.com"
}
],
"security": [
{
"ApiKeyAuth": []
}
],
"paths": {
"/api/v1/records": {
"post": {
"operationId": "IngestRecord",
"summary": "Ingest a single record for blockchain anchoring",
"description": "Accepts a record and returns 202 with a record hash. The record flows through the accumulation pipeline and is anchored on Polygon within ~60-90 seconds.",
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/IngestRecordRequest"
}
}
}
},
"responses": {
"202": {
"description": "Record accepted for processing",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/IngestRecordResponse"
}
}
}
}
}
},
"get": {
"operationId": "QueryRecords",
"summary": "Query records by tenant and record ID",
"parameters": [
{
"name": "tenantId",
"in": "query",
"required": true,
"schema": { "type": "string" }
},
{
"name": "recordId",
"in": "query",
"required": false,
"schema": { "type": "string" }
}
],
"responses": {
"200": {
"description": "Matching records"
}
}
}
},
"/api/v1/records/bulk": {
"post": {
"operationId": "BulkIngestRecords",
"summary": "Ingest up to 1000 records in a single request",
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/BulkIngestRequest"
}
}
}
},
"responses": {
"202": {
"description": "Bulk records accepted"
}
}
}
},
"/api/v1/verify/record": {
"post": {
"operationId": "VerifyRecord",
"summary": "Verify a record against its on-chain Merkle proof",
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/VerifyRecordRequest"
}
}
}
},
"responses": {
"200": {
"description": "Verification result"
}
}
}
}
},
"components": {
"securitySchemes": {
"ApiKeyAuth": {
"type": "apiKey",
"name": "X-API-Key",
"in": "header"
}
},
"schemas": {
"IngestRecordRequest": {
"type": "object",
"required": ["tenantId", "database", "collection", "recordId", "recordPayload"],
"properties": {
"tenantId": { "type": "string", "description": "Your tenant identifier" },
"database": { "type": "string", "description": "Logical source database or system" },
"collection": { "type": "string", "description": "Logical table or collection" },
"recordId": { "type": "string", "description": "Unique record identifier" },
"recordVersion": { "type": "string", "default": "1" },
"operationType": { "type": "string", "enum": ["insert", "update", "delete", "upsert"], "default": "upsert" },
"recordPayload": { "type": "object", "description": "The record data as arbitrary JSON" },
"sourceTimestamp": { "type": "string", "format": "date-time" },
"idempotencyKey": { "type": "string", "description": "Deduplication key (24h window)" }
}
},
"IngestRecordResponse": {
"type": "object",
"properties": {
"recordId": { "type": "string" },
"recordHash": { "type": "string" },
"tenantId": { "type": "string" },
"acceptedAt": { "type": "string", "format": "date-time" },
"idempotencyReplayed": { "type": "boolean" }
}
},
"BulkIngestRequest": {
"type": "object",
"required": ["tenantId", "records"],
"properties": {
"tenantId": { "type": "string" },
"records": {
"type": "array",
"maxItems": 1000,
"items": { "$ref": "#/components/schemas/IngestRecordRequest" }
}
}
},
"VerifyRecordRequest": {
"type": "object",
"required": ["tenantId", "database", "collection", "recordId", "payload"],
"properties": {
"tenantId": { "type": "string" },
"database": { "type": "string" },
"collection": { "type": "string" },
"recordId": { "type": "string" },
"payload": { "type": "object" }
}
}
}
}
}{
"definition": {
"$schema": "https://schema.management.azure.com/providers/Microsoft.Logic/schemas/2016-06-01/workflowdefinition.json#",
"contentVersion": "1.0.0.0",
"triggers": {
"When_a_row_is_added_or_modified": {
"type": "OpenApiConnectionWebhook",
"inputs": {
"host": {
"connectionName": "shared_commondataserviceforapps",
"operationId": "SubscribeWebhookTrigger",
"apiId": "/providers/Microsoft.PowerApps/apis/shared_commondataserviceforapps"
},
"parameters": {
"subscriptionRequest/message": 4,
"subscriptionRequest/entityname": "salesorder",
"subscriptionRequest/scope": 4,
"subscriptionRequest/filterexpression": "statecode eq 1"
}
}
}
},
"actions": {
"Compose_Certyo_Record": {
"type": "Compose",
"inputs": {
"tenantId": "@{parameters('CertyoTenantId')}",
"database": "dynamics-365",
"collection": "sales-orders",
"recordId": "@{triggerOutputs()?['body/salesorderid']}",
"recordVersion": "@{triggerOutputs()?['body/versionnumber']}",
"operationType": "upsert",
"recordPayload": {
"orderId": "@{triggerOutputs()?['body/salesorderid']}",
"orderNumber": "@{triggerOutputs()?['body/ordernumber']}",
"customerId": "@{triggerOutputs()?['body/_customerid_value']}",
"totalAmount": "@{triggerOutputs()?['body/totalamount']}",
"currency": "@{triggerOutputs()?['body/transactioncurrencyid']}",
"status": "@{triggerOutputs()?['body/statuscode']}",
"createdOn": "@{triggerOutputs()?['body/createdon']}",
"modifiedOn": "@{triggerOutputs()?['body/modifiedon']}"
},
"sourceTimestamp": "@{triggerOutputs()?['body/modifiedon']}",
"idempotencyKey": "@{triggerOutputs()?['body/salesorderid']}-@{triggerOutputs()?['body/versionnumber']}-@{utcNow('yyyy-MM-dd')}"
},
"runAfter": {}
},
"Ingest_Record_to_Certyo": {
"type": "OpenApiConnection",
"inputs": {
"host": {
"connectionName": "shared_certyo-records-api",
"operationId": "IngestRecord",
"apiId": "/providers/Microsoft.PowerApps/apis/shared_certyo-records-api"
},
"parameters": {
"body": "@outputs('Compose_Certyo_Record')"
}
},
"runAfter": {
"Compose_Certyo_Record": ["Succeeded"]
}
},
"Update_D365_with_Hash": {
"type": "OpenApiConnection",
"inputs": {
"host": {
"connectionName": "shared_commondataserviceforapps",
"operationId": "UpdateRecord",
"apiId": "/providers/Microsoft.PowerApps/apis/shared_commondataserviceforapps"
},
"parameters": {
"entityName": "salesorders",
"recordId": "@{triggerOutputs()?['body/salesorderid']}",
"item/cr_certyorecordhash": "@{body('Ingest_Record_to_Certyo')?['recordHash']}",
"item/cr_certyoacceptedat": "@{body('Ingest_Record_to_Certyo')?['acceptedAt']}"
}
},
"runAfter": {
"Ingest_Record_to_Certyo": ["Succeeded"]
}
},
"Handle_Failure": {
"type": "Compose",
"inputs": {
"error": "Certyo ingestion failed",
"orderId": "@{triggerOutputs()?['body/salesorderid']}",
"statusCode": "@{outputs('Ingest_Record_to_Certyo')['statusCode']}",
"timestamp": "@{utcNow()}"
},
"runAfter": {
"Ingest_Record_to_Certyo": ["Failed", "TimedOut"]
}
}
},
"parameters": {
"CertyoTenantId": {
"type": "string",
"defaultValue": "acme-corp"
}
}
}
}using System.Net;
using System.Net.Http.Json;
using System.Text.Json;
using System.Text.Json.Serialization;
using Microsoft.Azure.Functions.Worker;
using Microsoft.Azure.Functions.Worker.Http;
using Microsoft.Extensions.Logging;
namespace Certyo.PowerAutomate.Bridge;
/// <summary>
/// Azure Function that acts as a bridge between Power Automate and Certyo
/// for complex transformation scenarios that exceed Power Automate's
/// expression capabilities (nested loops, conditional mappings, etc.).
/// </summary>
public class CertyoBridge
{
private readonly HttpClient _http;
private readonly ILogger<CertyoBridge> _logger;
private readonly string _certyoApiKey;
private readonly string _certyoBaseUrl;
public CertyoBridge(
IHttpClientFactory httpFactory,
ILogger<CertyoBridge> logger)
{
_http = httpFactory.CreateClient("Certyo");
_logger = logger;
_certyoApiKey = Environment.GetEnvironmentVariable("CERTYO_API_KEY")
?? throw new InvalidOperationException("CERTYO_API_KEY not set");
_certyoBaseUrl = Environment.GetEnvironmentVariable("CERTYO_BASE_URL")
?? "https://www.certyos.com";
}
[Function("TransformAndIngest")]
public async Task<HttpResponseData> TransformAndIngest(
[HttpTrigger(AuthorizationLevel.Function, "post")] HttpRequestData req)
{
var input = await req.ReadFromJsonAsync<SourceRecord>();
if (input is null)
{
var bad = req.CreateResponse(HttpStatusCode.BadRequest);
await bad.WriteAsJsonAsync(new { error = "Invalid request body" });
return bad;
}
// Transform SharePoint document metadata to Certyo record
var certyoRecord = new CertyoRecord
{
TenantId = Environment.GetEnvironmentVariable("CERTYO_TENANT_ID")
?? "acme-corp",
Database = "sharepoint",
Collection = input.LibraryName ?? "documents",
RecordId = input.DocumentId,
RecordVersion = input.Version?.ToString() ?? "1",
OperationType = input.IsNew ? "insert" : "upsert",
RecordPayload = new Dictionary<string, object?>
{
["documentId"] = input.DocumentId,
["fileName"] = input.FileName,
["fileSize"] = input.FileSize,
["contentHash"] = input.ContentHash,
["libraryName"] = input.LibraryName,
["author"] = input.Author,
["modifiedBy"] = input.ModifiedBy,
["metadata"] = input.CustomMetadata
},
SourceTimestamp = input.ModifiedAt ?? DateTime.UtcNow,
IdempotencyKey = $"{input.DocumentId}-{input.Version}-"
+ $"{DateTime.UtcNow:yyyy-MM-dd}"
};
// Call Certyo API
using var request = new HttpRequestMessage(
HttpMethod.Post,
$"{_certyoBaseUrl}/api/v1/records");
request.Headers.Add("X-API-Key", _certyoApiKey);
request.Content = JsonContent.Create(certyoRecord);
var certyoResponse = await _http.SendAsync(request);
if (!certyoResponse.IsSuccessStatusCode)
{
_logger.LogError(
"Certyo ingestion failed: {Status} for doc {DocId}",
certyoResponse.StatusCode, input.DocumentId);
var errorResp = req.CreateResponse(certyoResponse.StatusCode);
await errorResp.WriteAsJsonAsync(new
{
error = "Certyo ingestion failed",
status = (int)certyoResponse.StatusCode,
documentId = input.DocumentId
});
return errorResp;
}
var result = await certyoResponse.Content
.ReadFromJsonAsync<IngestResponse>();
_logger.LogInformation(
"Record ingested: {Hash} for doc {DocId}",
result?.RecordHash, input.DocumentId);
var response = req.CreateResponse(HttpStatusCode.Accepted);
await response.WriteAsJsonAsync(result);
return response;
}
[Function("VerifyRecord")]
public async Task<HttpResponseData> VerifyRecord(
[HttpTrigger(AuthorizationLevel.Function, "post",
Route = "verify")] HttpRequestData req)
{
var input = await req.ReadFromJsonAsync<VerifyRequest>();
if (input is null)
{
var bad = req.CreateResponse(HttpStatusCode.BadRequest);
await bad.WriteAsJsonAsync(new { error = "Invalid request" });
return bad;
}
using var request = new HttpRequestMessage(
HttpMethod.Post,
$"{_certyoBaseUrl}/api/v1/verify/record");
request.Headers.Add("X-API-Key", _certyoApiKey);
request.Content = JsonContent.Create(input);
var certyoResponse = await _http.SendAsync(request);
var result = await certyoResponse.Content.ReadAsStringAsync();
var response = req.CreateResponse(certyoResponse.StatusCode);
response.Headers.Add("Content-Type", "application/json");
await response.WriteStringAsync(result);
return response;
}
}
public record SourceRecord
{
public string DocumentId { get; init; } = "";
public string? FileName { get; init; }
public long? FileSize { get; init; }
public string? ContentHash { get; init; }
public string? LibraryName { get; init; }
public string? Author { get; init; }
public string? ModifiedBy { get; init; }
public int? Version { get; init; }
public bool IsNew { get; init; }
public DateTime? ModifiedAt { get; init; }
public Dictionary<string, object?>? CustomMetadata { get; init; }
}
public record CertyoRecord
{
[JsonPropertyName("tenantId")] public string TenantId { get; init; } = "";
[JsonPropertyName("database")] public string Database { get; init; } = "";
[JsonPropertyName("collection")] public string Collection { get; init; } = "";
[JsonPropertyName("recordId")] public string RecordId { get; init; } = "";
[JsonPropertyName("recordVersion")] public string RecordVersion { get; init; } = "1";
[JsonPropertyName("operationType")] public string OperationType { get; init; } = "upsert";
[JsonPropertyName("recordPayload")] public Dictionary<string, object?> RecordPayload { get; init; } = new();
[JsonPropertyName("sourceTimestamp")] public DateTime SourceTimestamp { get; init; }
[JsonPropertyName("idempotencyKey")] public string IdempotencyKey { get; init; } = "";
}
public record IngestResponse
{
[JsonPropertyName("recordId")] public string RecordId { get; init; } = "";
[JsonPropertyName("recordHash")] public string RecordHash { get; init; } = "";
[JsonPropertyName("tenantId")] public string TenantId { get; init; } = "";
[JsonPropertyName("acceptedAt")] public DateTime AcceptedAt { get; init; }
[JsonPropertyName("idempotencyReplayed")] public bool IdempotencyReplayed { get; init; }
}
public record VerifyRequest
{
[JsonPropertyName("tenantId")] public string TenantId { get; init; } = "";
[JsonPropertyName("database")] public string Database { get; init; } = "";
[JsonPropertyName("collection")] public string Collection { get; init; } = "";
[JsonPropertyName("recordId")] public string RecordId { get; init; } = "";
[JsonPropertyName("payload")] public object? Payload { get; init; }
}#!/usr/bin/env pwsh
<#
.SYNOPSIS
Deploys the Certyo custom connector to a Power Platform environment.
.DESCRIPTION
Imports the OpenAPI definition, configures API Key authentication,
and creates a connection for the specified environment.
.PARAMETER EnvironmentId
Power Platform environment ID (GUID).
.PARAMETER OpenApiPath
Path to the certyo-connector-openapi.json file.
.PARAMETER CertyoApiKey
Certyo API key to configure on the connection.
#>
param(
[Parameter(Mandatory)]
[string]$EnvironmentId,
[Parameter(Mandatory)]
[string]$OpenApiPath,
[Parameter(Mandatory)]
[string]$CertyoApiKey
)
$ErrorActionPreference = "Stop"
# Ensure Power Apps admin module is installed
if (-not (Get-Module -ListAvailable -Name Microsoft.PowerApps.Administration.PowerShell)) {
Write-Host "Installing Power Apps admin module..."
Install-Module -Name Microsoft.PowerApps.Administration.PowerShell -Scope CurrentUser -Force
}
Import-Module Microsoft.PowerApps.Administration.PowerShell
# Authenticate to Power Platform
Write-Host "Authenticating to Power Platform..."
Add-PowerAppsAccount
# Read the OpenAPI definition
$openApiContent = Get-Content -Path $OpenApiPath -Raw
$openApiJson = $openApiContent | ConvertFrom-Json
Write-Host "Deploying Certyo connector to environment: $EnvironmentId"
# Create or update the custom connector
$connectorParams = @{
EnvironmentName = $EnvironmentId
ConnectorName = "certyo-records-api"
OpenApiDefinition = $openApiContent
}
try {
# Check if connector already exists
$existing = Get-AdminPowerAppConnector -EnvironmentName $EnvironmentId |
Where-Object { $_.ConnectorName -eq "certyo-records-api" }
if ($existing) {
Write-Host "Updating existing Certyo connector..."
Set-AdminPowerAppConnector @connectorParams
} else {
Write-Host "Creating new Certyo connector..."
New-AdminPowerAppConnector @connectorParams
}
Write-Host "Connector deployed successfully." -ForegroundColor Green
# Create a connection with the API key
Write-Host "Creating connection with API key..."
$connectionParams = @{
ConnectorName = "certyo-records-api"
EnvironmentName = $EnvironmentId
ConnectionParameters = @{
"api_key" = $CertyoApiKey
}
}
New-AdminPowerAppConnection @connectionParams
Write-Host "Connection created successfully." -ForegroundColor Green
Write-Host ""
Write-Host "Next steps:" -ForegroundColor Cyan
Write-Host " 1. Open Power Automate (https://make.powerautomate.com)"
Write-Host " 2. Create a new flow"
Write-Host " 3. Search for 'Certyo Records API' in the connector list"
Write-Host " 4. Use IngestRecord, BulkIngestRecords, or VerifyRecord actions"
} catch {
Write-Error "Deployment failed: $_"
exit 1
}Flow Templates
Below are three production-ready flow patterns. Each can be created in the Power Automate visual designer or imported as a JSON definition.
Flow 1: Dynamics 365 Record Change
Triggers when a sales order row is modified in Dataverse. The flow composes a Certyo record, ingests it, and writes the recordHash back to a custom column on the D365 entity for traceability.
- Trigger: When a row is added or modified (Dataverse connector)
- Filter:
statecode eq 1(only confirmed orders) - Action 1: Compose — build Certyo record JSON from trigger outputs
- Action 2: Certyo Custom Connector —
IngestRecord - Action 3: Update row — write
recordHashandacceptedAtback to D365 - Error path: On failure, compose error details for monitoring
Flow 2: SharePoint Document Upload
Triggers when a document is uploaded to a SharePoint library. The flow extracts document metadata and content hash, then ingests it into Certyo for document authenticity tracking.
- Trigger: When a file is created (SharePoint connector)
- Action 1: Get file properties — retrieve document metadata
- Action 2: Get file content — compute SHA-256 hash of the file
- Action 3: Certyo Custom Connector —
IngestRecordwith document metadata and content hash inrecordPayload - Action 4: Update file properties — store the Certyo
recordHashin a custom SharePoint column
Flow 3: Scheduled Verification
Runs on a schedule (e.g., daily) to verify that recently ingested records have been successfully anchored on the blockchain.
- Trigger: Recurrence — every 24 hours
- Action 1: Certyo Custom Connector —
QueryRecordswithtenantIdfilter - Action 2: Apply to each — iterate over records with status
Batched - Action 3: Certyo Custom Connector —
VerifyRecordfor each - Action 4: Condition — if verification fails, send an alert email via Outlook 365 connector
Authentication
The custom connector uses API Key authentication. When a user creates a connection to the Certyo connector in Power Automate, they enter their Certyo API key once. The platform securely stores it and attaches it as the X-API-Key header on every request.
- Per-user connections: Each flow author creates their own connection with their API key. This enables per-user audit trails in Certyo.
- Service account connection: For automated flows (scheduled, event-driven), use a dedicated Certyo service account API key. Share the connection with the flow owners.
- Key rotation: When rotating API keys, update the connection in Power Automate > Data > Connections. Active flows will pick up the new key automatically.
Connector Certification
To make the Certyo connector available in the public Power Platform connector gallery (visible to all Power Automate users worldwide), follow Microsoft's certification process:
- Submit for review: Use the
paconn submitCLI command from the Microsoft Power Platform Connectors SDK - Documentation: Provide a connector README, icon (160x160 PNG), and connection parameter descriptions
- Testing: Microsoft requires working test credentials and a demo flow for validation
- SLA: Connector must meet Microsoft's API reliability requirements (99.9% uptime, sub-3s response times)
- Timeline: Certification typically takes 2-4 weeks after submission
Throttling and Limits
Power Automate enforces execution limits that affect how you design Certyo integration flows:
- 600 actions per flow run — A flow run that processes 500 records in an "Apply to each" loop uses at minimum 500 actions (one per iteration) plus setup actions. Stay under the limit or split into sub-flows.
- 100,000 actions per 24 hours — Per-user daily limit across all flows. High-volume ingestion should use the
BulkIngestRecordsoperation to batch up to 1,000 records per action. - Connector concurrency: Custom connectors default to 1 concurrent request. Increase via the connector's General tab in the custom connector editor, up to a maximum of 50 concurrent connections.
- Retry policy: Power Automate retries failed HTTP actions up to 4 times with exponential backoff. Certyo's
idempotencyKeyensures safe retries.
AI Integration Skill
Download a skill file that enables AI agents to generate working Power Automate + Certyo integration code for any language or framework.
What's inside
- Authentication — Custom connector with API Key auth and Premium tier setup
- Architecture — D365/SharePoint/SQL trigger → Custom Certyo connector → records API
- Connector spec — OpenAPI 3.0 definition for importing into Power Platform
- Flow templates — D365 record change, SharePoint document upload, scheduled verification
- Certification — Path to Microsoft certified connector for public gallery
- Throttling — 600 actions/flow/run limits and efficient flow design patterns
How to use
Claude Code
Place the file in your project's .claude/commands/ directory, then use it as a slash command:
# Download the skill file
mkdir -p .claude/commands
curl -o .claude/commands/certyo-powerautomate.md \
https://www.certyos.com/developers/skills/certyo-powerautomate-skill.md
# Use it in Claude Code
/certyo-powerautomate "Generate a Power Automate flow that sends D365 record changes to Certyo"Cursor / Copilot / Any AI Agent
Add the file to your project root or attach it to a conversation. The AI agent will use the Power Automate-specific patterns, field mappings, and code examples to generate correct integration code.
# Add to your project
curl -o CERTYO_POWERAUTOMATE.md \
https://www.certyos.com/developers/skills/certyo-powerautomate-skill.md
# Then in your AI agent:
"Using the Certyo Power Automate spec in CERTYO_POWERAUTOMATE.md,
generate a power automate flow that sends d365 record changes to certyo"CLAUDE.md Context File
Append the skill file to your project's CLAUDE.md so every Claude conversation has Power Automate + Certyo context automatically.
# Append to your project's CLAUDE.md
echo "" >> CLAUDE.md
echo "## Certyo Power Automate Integration" >> CLAUDE.md
cat CERTYO_POWERAUTOMATE.md >> CLAUDE.md