Sap event mesh
23 SAP development skills for Claude Code — ABAP, RAP, CAP, Fiori, BTP, HANA, S/4HANA, Integration Suite and more. Agent Skills Specification compatible.
npx -y skills add efeumutaslan/SAP-SKILLS --skill sap-event-meshAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 4 stars4 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
What its author says it does
Copied from the file, not written here
SAP Event Mesh and Advanced Event Mesh skill for event-driven architecture on BTP. Use when publishing/consuming S/4HANA business events, configuring queues/topics, working with CloudEvents, or building event-driven microservices with CAP. If the user mentions Event Mesh, SAP business events, CloudEvents, message queue on BTP, or event-driven SAP integration, use this skill.
The file declares its own license as MIT. That is the author’s claim about this one file, and it is not the same thing as the license GitHub reports for the repository, which is listed with the other numbers below.
SKILL.md
10.5 KB, as published. Nobody here has run it
SAP Event Mesh & Event-Driven Architecture
Related Skills
sap-kyma-runtime— Event-driven Functions on Kyma consuming Event Meshsap-s4hana-extensibility— S/4HANA business events as event sourcessap-build-process-automation— Trigger workflows from events
Quick Start
Choose your event broker:
| Broker | Use Case | Protocol | Scale |
|---|---|---|---|
| SAP Event Mesh | BTP-native events, simple pub/sub | AMQP 1.0, REST, MQTT | Standard workloads |
| Advanced Event Mesh | Enterprise event mesh, multi-cloud | AMQP, MQTT, REST, SMF, JMS, WebSocket | High throughput, global |
Minimal CAP event producer:
// srv/order-service.js
const cds = require('@sap/cds');
module.exports = class OrderService extends cds.ApplicationService {
async init() {
this.after('CREATE', 'Orders', async (order) => {
const msg = await cds.connect.to('messaging');
await msg.emit('sap/sales/order/created/v1', {
orderId: order.ID,
customer: order.customer_ID,
total: order.total
});
});
await super.init();
}
};
Core Concepts
CloudEvents Specification
SAP Event Mesh uses CloudEvents 1.0 standard:
{
"specversion": "1.0",
"type": "sap.s4.beh.salesorder.v1.SalesOrder.Created.v1",
"source": "/default/sap.s4.beh/S4HANA_CLD",
"id": "a1b2c3d4-5678-90ab-cdef",
"time": "2026-03-24T10:00:00Z",
"datacontenttype": "application/json",
"data": {
"SalesOrder": "1000001",
"SalesOrganization": "1010",
"SoldToParty": "CUST001"
}
}
Topic Naming Convention
{namespace}/{business-object}/{event-type}/{version}
Examples:
sap.s4.beh/salesorder/created/v1
sap.s4.beh/businesspartner/changed/v1
custom/myapp/order/fulfilled/v1
Hierarchy rules:
- Use
/as level separator - Wildcards:
+(single level),*(multi-level) — for subscriptions only - Subscription example:
sap/s4/beh/+/created/v1matches all "created" events
Event Mesh Architecture
S/4HANA ──► Enterprise Messaging ──► Event Mesh ──► Consumers
│
BTP Apps ──► CAP Messaging ────────────┘ ┌── BTP App (webhook)
├── Kyma Function
External ──► REST/AMQP ───────────────────────├── Integration Flow
└── Queue → Worker
Queue vs. Topic
| Aspect | Topic | Queue |
|---|---|---|
| Delivery | Pub/sub (1-to-many) | Point-to-point (1-to-1) |
| Persistence | Not persistent | Messages persisted until consumed |
| Pattern | Events, notifications | Task processing, reliable delivery |
| Subscription | Topic filter with wildcards | Direct queue binding |
Common Patterns
Pattern 1: Event Mesh Service Instance (BTP)
// mta.yaml resource
{
"name": "event-mesh",
"type": "org.cloudfoundry.managed-service",
"parameters": {
"service": "enterprise-messaging",
"service-plan": "default",
"path": "./event-mesh.json"
}
}
// event-mesh.json
{
"emname": "my-app-events",
"namespace": "custom/myapp",
"version": "1.0.0",
"options": {
"management": true,
"messagingrest": true,
"messaging": true
},
"rules": {
"topicRules": {
"publishFilter": ["${namespace}/order/*"],
"subscribeFilter": ["${namespace}/order/*", "sap/s4/beh/+/created/v1"]
},
"queueRules": {
"publishFilter": ["${namespace}/*"],
"subscribeFilter": ["${namespace}/*"]
}
}
}
Pattern 2: CAP Event Consumer
// srv/event-handler.js
const cds = require('@sap/cds');
module.exports = async (srv) => {
const msg = await cds.connect.to('messaging');
// Subscribe to S/4HANA business partner events
msg.on('sap/s4/beh/businesspartner/changed/v1', async (event) => {
const { BusinessPartner } = event.data;
console.log(`BP changed: ${BusinessPartner}`);
// Sync to local replica
const { BusinessPartners } = srv.entities;
const bpData = await fetchBPFromS4(BusinessPartner);
await cds.run(UPSERT.into(BusinessPartners).entries(bpData));
});
// Subscribe with wildcard
msg.on('custom/myapp/order/+/v1', async (event) => {
console.log(`Order event: ${event.headers.type}`, event.data);
});
};
// package.json — messaging config
{
"cds": {
"requires": {
"messaging": {
"kind": "enterprise-messaging",
"format": "cloudevents",
"publishPrefix": "custom/myapp/",
"subscribePrefix": "custom/myapp/"
}
}
}
}
Pattern 3: REST API — Publish Event
import requests
import json
def publish_event(token_url, client_id, client_secret, em_url, topic, data):
"""Publish event via Event Mesh REST API."""
# Get OAuth token
token_resp = requests.post(
f"{token_url}/oauth/token?grant_type=client_credentials",
auth=(client_id, client_secret)
)
token = token_resp.json()["access_token"]
# Publish
encoded_topic = topic.replace("/", "%2F")
resp = requests.post(
f"{em_url}/messagingrest/v1/topics/{encoded_topic}/messages",
headers={
"Authorization": f"Bearer {token}",
"Content-Type": "application/cloudevents+json",
"x-qos": "1" # 0=at-most-once, 1=at-least-once
},
json={
"specversion": "1.0",
"type": topic,
"source": "/custom/myapp",
"id": str(__import__('uuid').uuid4()),
"data": data
}
)
resp.raise_for_status()
return resp.status_code
Pattern 4: Queue Subscription with Webhook
def create_queue_subscription(token, em_url, queue_name, topic_filter):
"""Create queue and bind topic subscription."""
headers = {"Authorization": f"Bearer {token}", "Content-Type": "application/json"}
# Create queue
requests.put(
f"{em_url}/messagingrest/v1/queues/{queue_name}",
headers=headers,
json={"messageTimeToLive": 86400, "maxQueueSizeInBytes": 10485760}
)
# Subscribe queue to topic
encoded_topic = topic_filter.replace("/", "%2F")
requests.put(
f"{em_url}/messagingrest/v1/queues/{queue_name}/subscriptions/{encoded_topic}",
headers=headers
)
Pattern 5: S/4HANA Business Event Configuration
Enable events in S/4HANA Cloud:
- App: "Enterprise Event Enablement" → Maintain channel binding
- Create channel: type = "SAP Event Mesh", connection = destination to Event Mesh
- Select event topics:
sap.s4.beh.salesorder.v1.SalesOrder.Created.v1 - Activate channel
S/4HANA On-Premise (via Integration Suite):
S/4HANA → AIF/IDoc → SAP Integration Suite → Event Mesh
Pattern 6: Dead Letter Queue Pattern
// Handle failed messages with retry
const msg = await cds.connect.to('messaging');
msg.on('custom/myapp/order/created/v1', async (event) => {
try {
await processOrder(event.data);
} catch (err) {
const retryCount = (event.headers['x-retry-count'] || 0) + 1;
if (retryCount <= 3) {
await msg.emit('custom/myapp/order/created/retry/v1', {
...event.data,
_retryCount: retryCount,
_originalError: err.message
});
} else {
await msg.emit('custom/myapp/dlq/order/v1', {
...event.data,
_error: err.message,
_failedAt: new Date().toISOString()
});
}
}
});
Error Catalog
| Error | Message | Root Cause | Fix |
|---|---|---|---|
403 | Publish not allowed | Topic not in publishFilter | Update event-mesh.json rules |
403 | Subscribe not allowed | Topic not in subscribeFilter | Update subscribe filter rules |
404 | Queue not found | Queue deleted or not created | Create queue before consuming |
409 | Queue already exists | Duplicate creation attempt | Use PUT (idempotent) instead of POST |
413 | Message too large | Exceeds max message size (1 MB default) | Reduce payload; use reference pattern (send URL) |
429 | Rate limit exceeded | Too many requests per second | Implement backoff; upgrade service plan |
500 | Broker unavailable | Event Mesh service issue | Check BTP system status; retry with backoff |
| Connection refused | AMQP connection failed | Wrong endpoint or credentials | Verify service key messaging array endpoints |
| No messages | Consumer gets nothing | Topic filter mismatch | Check wildcard syntax; verify namespace prefix |
| Duplicate events | Same event processed twice | At-least-once QoS | Implement idempotent consumer (check event ID) |
Performance Tips
- Use QoS 0 for non-critical events — At-most-once is faster; use QoS 1 only for business-critical events
- Batch publishing — Group multiple events per HTTP request where API supports it
- Partition queues — Use multiple queues for parallel consumption of high-volume topics
- Message TTL — Set appropriate
messageTimeToLiveto prevent queue overflow - Payload size — Keep events small (<10 KB); reference large data via URL/ID
- AMQP over REST — Use AMQP protocol for high-throughput; REST for low-volume/webhook
- Consumer acknowledgment — Acknowledge messages promptly; long processing delays redelivery
- Namespace isolation — Separate namespaces per application; avoid cross-app topic pollution
Gotchas
- Topic encoding: Forward slashes in topic names must be URL-encoded (
%2F) in REST API paths - Namespace prefix: All topics must match namespace defined in service instance; mismatches silently fail
- Event ordering: Event Mesh does NOT guarantee message ordering — design consumers to be order-independent
- Duplicate delivery: At-least-once means duplicates are possible — always implement idempotent processing
- Service plan limits:
defaultplan has message size and throughput limits; check plan quotas - S/4HANA events: Business events must be explicitly enabled per tenant; they're not on by default