---
name: Certyo Enterprise Integration Skill
version: 1.0.0
description: Generate integration code between Certyo and enterprise platforms (Dynamics 365, SAP, NetSuite, Salesforce, Shopify, SQL Server, MuleSoft, Power Automate, Azure, AWS, Odoo)
api_base: https://www.certyos.com
auth: X-API-Key header
last_updated: 2026-04-14
---

# Certyo Enterprise Integration Skill

This skill enables AI agents to generate production-quality integration code between Certyo's blockchain-anchored records API and enterprise platforms. Use it to scaffold connectors, transforms, event handlers, and deployment configs for any supported platform.

---

## Certyo API Essentials

All `/api/v1/*` endpoints require an API key:

```
X-API-Key: your-api-key-here
```

### Ingest a Record

```
POST /api/v1/records
Content-Type: application/json
```

```json
{
  "tenantId": "acme-corp",
  "clientId": "erp-connector",
  "database": "source-system",
  "collection": "entity-name",
  "recordId": "unique-id",
  "recordVersion": "1",
  "operationType": "upsert",
  "recordPayload": { "...arbitrary JSON..." },
  "sourceTimestamp": "2026-04-14T10:00:00Z",
  "idempotencyKey": "unique-id-v1"
}
```

**Response: 202 Accepted**

```json
{
  "recordId": "unique-id",
  "recordHash": "sha256hex...",
  "tenantId": "acme-corp",
  "acceptedAt": "2026-04-14T10:00:05Z",
  "idempotencyReplayed": false
}
```

### Bulk Ingest (up to 1000 records)

```
POST /api/v1/records/bulk
```

### Verify a Record

```
POST /api/v1/verify/record
```

```json
{
  "tenantId": "acme-corp",
  "recordId": "unique-id",
  "recordVersion": "1"
}
```

### Pipeline

Records flow: Ingest → Kafka → Accumulate (1000 records or 60s) → Merkle tree → IPFS pin → Polygon anchor (~60-90s total).

---

## Supported Platforms

When generating integration code, follow these platform-specific patterns:

---

### Microsoft Dynamics 365

**Business Central (SMB):**
- Integration via OData v4 API Pages (`/api/v2.0/`)
- Auth: OAuth 2.0 client credentials with Microsoft Entra ID service principal
- Pattern: AL extension subscribes to `OnAfterPostSalesShipment` → publishes to Azure Service Bus → Azure Function calls Certyo
- Rate limit: 6,000 OData requests / 5-min sliding window per user
- Store certificate results in custom fields on the Item or Sales Shipment entity
- IMPORTANT: Build against API Pages, not legacy OData UI endpoints (deprecated 2027)

**Finance & Operations / Supply Chain:**
- Integration via Dataverse Web API (OData v4 REST) or Dual-Write
- Pattern: Dataverse row change trigger → Power Automate or Azure Function → Certyo
- Product serialization and lot traceability in SCM map directly to Certyo record payloads

**Field mapping:**
| D365 Field | Certyo Field |
|---|---|
| SalesShipmentHeader.No | recordId |
| Item.No | recordPayload.itemNumber |
| SalesLine.Quantity | recordPayload.quantity |
| PostingDate | sourceTimestamp |
| "dynamics365" | database |
| "sales-shipments" | collection |

---

### SAP S/4HANA & Business One

**S/4HANA:**
- Integration via SAP Integration Suite (iFlow) or direct OData API calls
- Auth: OAuth 2.0 / X.509 certificates via SAP BTP Destination service
- Pattern: Material document event (goods receipt/issue) → Integration Suite iFlow → HTTP adapter → Certyo POST /api/v1/records
- Transform with Groovy script or Message Mapping in Integration Suite
- SAP recommends OData/REST over legacy RFC/IDoc for all new integrations

**Business One:**
- Service Layer REST API (OData v4)
- Auth: Session-based login, wrap with API gateway for OAuth
- Pattern: B1if workflow triggered by Goods Receipt → call Certyo

**GS1 EPCIS alignment:**
| SAP Field | EPCIS / Certyo Mapping |
|---|---|
| Material Number (MATNR) | GTIN (in recordPayload) |
| Batch (CHARG) | lot identifier |
| Serial Number (SERNR) | SGTIN serial |
| Movement Type (BWART) | operationType (101=insert, 102=delete) |
| Posting Date (BUDAT) | sourceTimestamp |

---

### Oracle NetSuite

- Integration via SuiteScript 2.x RESTlets or User Event Scripts
- Auth: Token-Based Authentication (consumer key/secret + token ID/secret) or OAuth 2.0
- Pattern: Item Fulfillment afterSubmit → N/https module calls Certyo
- Use N/record, N/search, N/log modules
- RESTlet concurrency limit: 10 — use Map/Reduce for bulk operations
- SuiteQL for complex queries: `SELECT * FROM transaction WHERE type = 'ItemShip'`

**Field mapping:**
| NetSuite Field | Certyo Field |
|---|---|
| fulfillment.tranid | recordId |
| fulfillment.trandate | sourceTimestamp |
| item.itemid | recordPayload.sku |
| inventorydetail.serialnumber | recordPayload.serialNumber |
| "netsuite" | database |
| "item-fulfillment" | collection |

---

### Salesforce

- Integration via Apex callouts, Platform Events, or Named Credentials
- Auth: Named Credential stores X-API-Key header; OAuth 2.0 client credentials for server-to-server
- Pattern: Order status → Apex Trigger → Platform Event → Async Apex → Certyo callout → update Certificate__c
- Use @future(callout=true) or Queueable for callouts from triggers
- Salesforce limits: 100 callouts per transaction — use Platform Events for async

**Custom Object: Certificate__c**
- RecordId__c (Text 255)
- SnapshotHash__c (Text 255)
- MerkleRoot__c (Text 255)
- AnchorStatus__c (Picklist: Pending, Anchored, Failed)
- PolygonTxHash__c (Text 255)
- VerifiedAt__c (DateTime)

**Apex pattern:**
```apex
public class CertyoService {
    private static final String NAMED_CRED = 'callout:Certyo_API';

    @future(callout=true)
    public static void ingestRecord(String recordId, String payload) {
        HttpRequest req = new HttpRequest();
        req.setEndpoint(NAMED_CRED + '/api/v1/records');
        req.setMethod('POST');
        req.setHeader('Content-Type', 'application/json');
        req.setBody(payload);
        HttpResponse res = new Http().send(req);
        // Process 202 response...
    }
}
```

---

### Shopify Plus

- Integration via GraphQL Admin API and webhooks
- Auth: Shopify Admin API access token, webhook HMAC-SHA256 verification
- Pattern: orders/fulfilled webhook → handler server → Certyo POST /api/v1/records → update product metafield via GraphQL
- GraphQL is mandatory for new public apps (REST Admin API deprecated Oct 2024)
- Rate limit: 500 GraphQL points/second on Plus (cost-based throttling)

**Webhook payload mapping:**
| Shopify Field | Certyo Field |
|---|---|
| order.line_items[].sku | recordId (per product) |
| order.id | recordPayload.orderId |
| fulfillment.tracking_number | recordPayload.trackingNumber |
| fulfillment.created_at | sourceTimestamp |
| "shopify" | database |
| "orders" | collection |

**Metafield storage:**
```graphql
mutation {
  productUpdate(input: {
    id: "gid://shopify/Product/123"
    metafields: [{
      namespace: "certyo"
      key: "certificate_hash"
      value: "sha256hex..."
      type: "single_line_text_field"
    }]
  }) { product { id } }
}
```

---

### Microsoft SQL Server

- Integration via Change Data Capture (CDC) polling
- Auth: SQL Server connection string (Windows Auth or SQL Auth), X-API-Key for Certyo
- Pattern: .NET 8 BackgroundService polls cdc.fn_cdc_get_net_changes → transforms rows → POST /api/v1/records
- Available on Azure SQL Database (Hyperscale and General Purpose), not just on-premises
- Track last processed LSN (Log Sequence Number) for incremental sync
- Batch optimization: accumulate changes, use POST /api/v1/records/bulk when batch > 10

**Enable CDC:**
```sql
EXEC sys.sp_cdc_enable_db;
EXEC sys.sp_cdc_enable_table
    @source_schema = N'dbo',
    @source_name = N'Products',
    @role_name = NULL,
    @supports_net_changes = 1;
```

---

### MuleSoft Anypoint

- Integration via API-led connectivity (System → Process → Experience layers)
- Auth: Anypoint Connected App for platform, X-API-Key in Mule Secure Properties for Certyo
- Pattern: Source system HTTP/OData trigger → DataWeave transformation → HTTP Requester to Certyo
- Use Mule 4 flows with error handling (on-error-propagate, on-error-continue)
- Batch Jobs for high-volume ingestion with bulk endpoint
- MuleSoft A2A Connector for future AI agent integration

**DataWeave transform:**
```dataweave
%dw 2.0
output application/json
---
{
  tenantId: vars.tenantId,
  database: payload.sourceSystem,
  collection: payload.entityType,
  recordId: payload.id,
  recordPayload: payload,
  sourceTimestamp: payload.modifiedDate,
  idempotencyKey: payload.id ++ "-" ++ payload.version
}
```

---

### Microsoft Power Automate

- Integration via custom connector built from OpenAPI spec
- Auth: Custom connector uses API Key auth (X-API-Key header)
- Pattern: Dynamics 365/SharePoint/SQL trigger → custom Certyo connector → POST /api/v1/records
- Premium tier required ($15/user/month)
- Flow limit: 600 actions per flow run — design efficient flows
- Path to Microsoft certified connector for public gallery

---

### Microsoft Azure

- Reference architecture: Event Grid → Service Bus → Azure Function → Certyo API
- Auth: Managed Identity for Azure services, X-API-Key in Key Vault
- Services: API Management (gateway + developer portal), Service Bus (durable buffer), Event Grid (event routing), Logic Apps (no-code orchestration)
- Azure Functions: ServiceBusTrigger for ingestion, TimerTrigger for verification polling

**C# Azure Function pattern:**
```csharp
[Function("IngestRecord")]
public async Task Run(
    [ServiceBusTrigger("certyo-records")] ServiceBusReceivedMessage message)
{
    var payload = message.Body.ToString();
    var response = await _httpClient.PostAsync(
        $"{_certyoUrl}/api/v1/records",
        new StringContent(payload, Encoding.UTF8, "application/json"));
    response.EnsureSuccessStatusCode();
}
```

---

### Amazon Web Services

- Reference architecture: EventBridge → API Destination (direct) or Lambda (transform) → Certyo
- Auth: EventBridge Connection with API Key auth, Lambda uses Secrets Manager
- Services: EventBridge (event routing), Lambda (transform), Step Functions (orchestration), API Gateway (internal gateway)
- Use API Destinations for simple forwarding (no Lambda needed), Lambda for complex transforms
- Step Functions ASL for verification workflows with Wait states and Choice branching

---

### Odoo

- Integration via XML-RPC, JSON-RPC, or REST API (Odoo 17+)
- Auth: Odoo API Keys (Settings → Users → API Keys), X-API-Key for Certyo
- Pattern: Automated Action on stock.picking state=done → Python server action or external cron → Certyo
- Store credentials as ir.config_parameter (System Parameters)
- Models: stock.picking (delivery), mrp.production (manufacturing), quality.check (quality)

**Python XML-RPC pattern:**
```python
import xmlrpc.client
import requests

common = xmlrpc.client.ServerProxy(f"{ODOO_URL}/xmlrpc/2/common")
uid = common.authenticate(db, user, api_key, {})
models = xmlrpc.client.ServerProxy(f"{ODOO_URL}/xmlrpc/2/object")

pickings = models.execute_kw(db, uid, api_key,
    "stock.picking", "search_read",
    [[("state", "=", "done"), ("x_certyo_record_hash", "=", False)]],
    {"fields": ["name", "partner_id", "date_done"]})
```

**Field mapping:**
| Odoo Field | Certyo Field |
|---|---|
| stock.picking.name | recordId ("WH/OUT/00042") |
| stock.picking.date_done | sourceTimestamp |
| "odoo" | database |
| "stock.picking" | collection |
| (computed JSON) | recordPayload |

---

## Code Generation Rules

When generating integration code for any platform:

1. **Always include idempotencyKey** — Compose from recordId + version to make retries safe
2. **Handle 202 Accepted** — Certyo ingestion is async; don't wait for anchoring
3. **Store recordHash** — Write the hash back to the source system for future verification
4. **Use bulk endpoint** — When ingesting > 10 records, use POST /api/v1/records/bulk (max 1000)
5. **Poll or subscribe** — Check anchoring status via POST /api/v1/verify/record periodically
6. **Respect rate limits** — Certyo returns X-RateLimit-Remaining headers; implement backoff on 429
7. **Use realistic field names** — Map actual platform fields (not generic placeholders) to Certyo fields
8. **Include error handling** — Wrap API calls with try/catch, log failures, implement retry with exponential backoff
9. **Store API keys securely** — Use Key Vault (Azure), Secrets Manager (AWS), Named Credentials (Salesforce), System Parameters (Odoo)
10. **Include verification** — Always show how to verify anchored records, not just ingest

---

## Quick Start Template

For any platform, the integration follows this skeleton:

```
1. TRIGGER: Detect event in source system (webhook, CDC, cron poll)
2. EXTRACT: Read the record data from the source system API
3. TRANSFORM: Map source fields to Certyo record payload format
4. INGEST: POST /api/v1/records with X-API-Key header
5. STORE: Write recordHash back to source system
6. VERIFY: Periodically call POST /api/v1/verify/record
7. UPDATE: Write anchor status + Polygon tx hash back to source system
```
