Skip to main contentCertyo Developer Portal

SAP S/4HANA & Business One

Integra SAP S/4HANA (Cloud y On-Premise) y SAP Business One con Certyo para anclar documentos de material, recepciones de mercancía y datos de serie/lote en la blockchain.

Descripción general

Los entornos SAP varían ampliamente en modelo de despliegue y superficie de API. Esta guía cubre patrones listos para producción para los dos productos SAP más comunes:

  • SAP S/4HANA — Usa SAP Integration Suite (Cloud Integration) con iFlows para transformar eventos de documentos de material en registros Certyo. Funciona tanto con S/4HANA Cloud como on-premise vía Cloud Connector.
  • SAP Business One — Usa la API REST del Service Layer y B1if (Integration Framework) o llamadas HTTP directas para enviar recepciones de mercancía y eventos de inventario a Certyo.
SAP recomienda OData/REST para nuevas integraciones
SAP ha recomendado oficialmente las APIs OData y REST sobre las interfaces heredadas RFC e IDoc para todos los nuevos proyectos de integración. Todos los patrones en esta guía usan la superficie de API moderna. Si tienes integraciones existentes basadas en IDoc, considera migrarlas a suscripciones de eventos OData.

Requisitos previos

  • Cuenta de SAP BTP (Business Technology Platform) con derecho a Integration Suite
  • Sistema SAP S/4HANA (Cloud u on-premise con Cloud Connector) o SAP Business One 10.0+
  • Clave API de Certyo obtenida del backoffice (certyo_sk_live_...)
  • Communication Arrangement en S/4HANA para el escenario SAP_COM_0A08 (Material Document) o el escenario de Business Event relevante
  • Para Business One: acceso al Service Layer con un usuario de integración dedicado

Arquitectura

La arquitectura recomendada usa SAP Integration Suite como capa de middleware. S/4HANA publica eventos, el iFlow transforma el payload específico de SAP al formato de registro de Certyo, y el adaptador HTTP lo entrega:

SAP Integration Architecturebash
┌─────────────────────┐     ┌──────────────────────┐     ┌──────────────────┐     ┌──────────────┐
│  SAP S/4HANA        │     │  SAP Integration      │     │  HTTP Adapter    │     │  Certyo API  │
│                     │────>│  Suite                 │────>│  (outbound)      │────>│              │
│  Material Document  │     │                        │     │                  │     │  POST        │
│  posted (MIGO)      │     │  iFlow:                │     │  TLS 1.2+        │     │  /api/v1/    │
│  or Goods Receipt   │     │  SAP-to-Certyo         │     │  X-API-Key       │     │  records     │
│                     │     │  Transformation        │     │  header          │     │              │
└─────────────────────┘     └──────────────────────┘     └──────────────────┘     └──────────────┘
                                      │
    SAP Business One:                 │  For S/4HANA on-premise:
    Service Layer webhook  ──────────>│  SAP Cloud Connector
    or B1if scenario       ──────────>│  tunnels the connection
                                      │  to BTP securely

Integración con S/4HANA

SAP S/4HANA expone eventos de documentos de material a través de su framework Enterprise Event Enablement. Cuando se registra una recepción de mercancía (transacción MIGO) o una salida de mercancía, el sistema puede publicar un evento a SAP Integration Suite vía Event Mesh o webhook directo.

Paso 1: Configurar el Communication Arrangement

En S/4HANA, crea un Communication Arrangement usando el escenario SAP_COM_0A08 (Material Document - Created) o SAP_COM_0A09 (Material Document - Changed). Apunta la configuración de salida a tu tenant de Integration Suite.

Paso 2: Crear el iFlow

En SAP Integration Suite, crea un flujo de integración (iFlow) que reciba el evento de S/4HANA, extraiga los campos del documento de material, los transforme al esquema de registro de Certyo y los envíe vía adaptador HTTP.

Paso 3: Desplegar y monitorear

Despliega el iFlow y monitorea el procesamiento de mensajes en el panel de monitoreo de Integration Suite. Los mensajes fallidos se reintentan automáticamente con backoff exponencial.


Integración con Business One

SAP Business One proporciona el Service Layer (REST/OData) para acceso programático. El patrón recomendado usa el B1if Integration Framework para activarse en eventos de documentos, o una aplicación personalizada que consulta el Service Layer.

Patrón de eventos del Service Layer

Business One 10.0+ soporta alertas del Service Layer. Configura una alerta en la creación de GoodsReceiptDocument, que llama a una URL de webhook. Enruta el webhook a través de B1if o directamente a un servicio intermediario que llama a Certyo.

Patrón de polling

Si las alertas no están disponibles, consulta el endpoint PurchaseDeliveryNotes del Service Layer con un $filter en UpdateDate. Un cron job o función programada obtiene nuevos documentos cada 30 segundos y los reenvía a Certyo.


Ejemplos de código

Este script Groovy se ejecuta dentro de un iFlow de SAP Integration Suite. Recibe el payload del evento de documento de material de S/4HANA (OData JSON), extrae los campos relevantes y los transforma al formato de registro de Certyo.

SapToCertyoTransform.groovy (runs in SAP CPI iFlow)javascript
import com.sap.gateway.ip.core.customdev.util.Message
import groovy.json.JsonSlurper
import groovy.json.JsonOutput

def Message processData(Message message) {
    def body = message.getBody(String)
    def slurper = new JsonSlurper()
    def sapEvent = slurper.parseText(body)

    // Extract material document header fields
    def matDoc = sapEvent.d ?: sapEvent
    def materialDocument = matDoc.MaterialDocument ?: matDoc.MaterialDocumentNumber
    def materialDocumentYear = matDoc.MaterialDocumentYear ?: new Date().format("yyyy")
    def postingDate = matDoc.PostingDate ?: matDoc.DocumentDate
    def headerText = matDoc.MaterialDocumentHeaderText ?: ""

    // Extract line items
    def items = matDoc.to_MaterialDocumentItem?.results ?: matDoc.Items ?: []
    def recordLines = items.collect { item ->
        [
            itemNumber       : item.MaterialDocumentItem ?: item.LineNumber,
            material         : item.Material ?: item.ItemCode,
            plant            : item.Plant ?: item.Warehouse,
            storageLocation  : item.StorageLocation ?: "",
            batch            : item.Batch ?: "",
            serialNumber     : item.SerialNumber ?: "",
            quantity         : item.QuantityInEntryUnit ?: item.Quantity,
            entryUnit        : item.EntryUnit ?: item.UnitOfMeasure,
            movementType     : item.GoodsMovementType ?: item.MovementType,
            purchaseOrder    : item.PurchaseOrder ?: "",
            purchaseOrderItem: item.PurchaseOrderItem ?: ""
        ]
    }

    // Build Certyo record payload
    def tenantId = message.getProperty("CertyoTenantId")
    def certyoRecord = [
        tenantId       : tenantId,
        database       : "sap-s4hana",
        collection     : "MaterialDocuments",
        recordId       : "${materialDocument}-${materialDocumentYear}",
        recordVersion  : "1",
        operationType  : "insert",
        sourceTimestamp : postingDate,
        idempotencyKey : "${materialDocument}-${materialDocumentYear}-${postingDate?.take(10) ?: 'unknown'}",
        recordPayload  : [
            materialDocument     : materialDocument,
            materialDocumentYear : materialDocumentYear,
            postingDate          : postingDate,
            headerText           : headerText,
            documentType         : matDoc.MaterialDocumentType ?: "WE",
            referenceDocument    : matDoc.ReferenceDocument ?: "",
            items                : recordLines
        ]
    ]

    message.setBody(JsonOutput.toJson(certyoRecord))
    message.setHeader("Content-Type", "application/json")
    message.setHeader("X-API-Key", message.getProperty("CertyoApiKey"))

    return message
}

Configuración del iFlow de SAP Integration Suite

Al desplegar el script Groovy dentro de un iFlow, configura los siguientes artefactos:

Adaptador de envío (S/4HANA)

iFlow sender channel configurationjson
{
  "adapterType": "OData",
  "connectionType": "Internet",
  "address": "https://my-s4hana.example.com/sap/opu/odata/sap/API_MATERIAL_DOCUMENT_SRV",
  "authType": "OAuth2ClientCredentials",
  "credentialName": "S4HANA_OAUTH_CREDENTIALS",
  "entitySet": "A_MaterialDocumentHeader",
  "expand": "to_MaterialDocumentItem",
  "deltaToken": true,
  "pageSize": 100
}

Adaptador de recepción (Certyo)

iFlow receiver HTTP adapterjson
{
  "adapterType": "HTTP",
  "address": "https://www.certyos.com/api/v1/records",
  "method": "POST",
  "authenticationType": "None",
  "requestHeaders": [
    { "name": "X-API-Key", "value": "${property.CertyoApiKey}" },
    { "name": "Content-Type", "value": "application/json" }
  ],
  "timeout": 15000,
  "retryPolicy": {
    "maxRetries": 3,
    "retryInterval": 5000,
    "exponentialBackoff": true
  }
}

Parámetros externalizados

Almacena las credenciales de forma segura usando los artefactos de Security Material de SAP Integration Suite. La clave API de Certyo debe almacenarse como un Secure Parameter y referenciarse en el iFlow:

# Externalized parameters in the iFlow
CertyoApiKey     = {{SecureParameter:CERTYO_API_KEY}}
CertyoTenantId   = your-tenant-id
SapOAuthTokenUrl = https://my-s4hana.example.com/sap/bc/sec/oauth2/token

Autenticación

Lado de SAP

SAP soporta múltiples métodos de autenticación según el despliegue:

  • S/4HANA Cloud: Credenciales de cliente OAuth 2.0 vía Communication Arrangements. Crea un Communication System y un Communication User, luego genera credenciales OAuth.
  • S/4HANA On-Premise: Autenticación básica o certificados de cliente X.509 a través de SAP Cloud Connector. El Cloud Connector establece un túnel seguro desde BTP a tu sistema on-premise.
  • Business One: Autenticación basada en sesión vía el endpoint POST /b1s/v1/Login del Service Layer. Usa un usuario de integración dedicado con autorizaciones mínimas.
SAP Business One Service Layer loginbash
# Authenticate to SAP Business One Service Layer
curl -X POST "https://b1-server:50000/b1s/v1/Login" \
  -H "Content-Type: application/json" \
  -d '{
    "CompanyDB": "SBODEMOUS",
    "UserName": "certyo_integration",
    "Password": "'"$SAP_B1_PASSWORD"'"
  }'

# Response includes a session cookie (B1SESSION) for subsequent requests
# Use this session to query GoodsReceiptDocuments:
curl "https://b1-server:50000/b1s/v1/PurchaseDeliveryNotes?\$filter=UpdateDate ge '2026-04-14'" \
  -H "Cookie: B1SESSION=<session-id>" \
  -H "Accept: application/json"

Lado de Certyo

Certyo usa el encabezado X-API-Key. En SAP Integration Suite, almacena la clave como un Secure Parameter. En aplicaciones personalizadas, usa variables de entorno o el Credential Store de SAP en BTP:

# Store Certyo API key in SAP BTP Credential Store
cf create-service credstore standard certyo-credentials
cf bind-service certyo-sap-integration certyo-credentials \
  -c '{"key": "certyo-api-key", "value": "certyo_sk_live_abc123..."}'

Alineación con GS1 EPCIS

Los números de material, números de lote y números de serie de SAP se mapean directamente a identificadores GS1 EPCIS, habilitando interoperabilidad en la cadena de suministro. Al construir el payload del registro Certyo, incluye estos mapeos:

EPCIS-aligned record payloadjson
{
  "tenantId": "pharma-corp",
  "database": "sap-s4hana",
  "collection": "MaterialDocuments",
  "recordId": "4900000123-2026",
  "recordPayload": {
    "materialDocument": "4900000123",
    "materialDocumentYear": "2026",
    "postingDate": "2026-04-14",
    "items": [
      {
        "material": "MAT-001234",
        "batch": "BATCH-2026-Q2-001",
        "serialNumber": "SN-00001",
        "quantity": 500,
        "entryUnit": "EA",
        "movementType": "101",
        "epcis": {
          "gtin": "01234567890128",
          "sgtin": "urn:epc:id:sgtin:0123456.078901.SN-00001",
          "lot": "BATCH-2026-Q2-001",
          "bizStep": "urn:epcglobal:cbv:bizstep:receiving",
          "disposition": "urn:epcglobal:cbv:disp:in_progress",
          "readPoint": "urn:epc:id:sgln:0123456.00001.0"
        }
      }
    ]
  }
}

Este mapeo permite que los consumidores posteriores de tus certificados Certyo los correlacionen con eventos GS1 EPCIS, lo cual es crítico para la serialización farmacéutica (DSCSA), seguridad alimentaria (FSMA 204) y trazabilidad de bienes de lujo.


Verificación y escritura de vuelta a SAP

Después de que Certyo ancla el registro (60-90 segundos), verifica y actualiza el registro de Quality Inspection de SAP o una tabla Z personalizada con los detalles del certificado. Este ejemplo usa la API OData de S/4HANA para actualizar un campo personalizado en el documento de material:

verify_and_writeback.pypython
"""
Verify Certyo records and write certificate data back to SAP S/4HANA.
Runs as a scheduled job (e.g., every 2 minutes via cron or SAP BTP Job Scheduler).
"""

import os
import time
import requests
from requests.auth import HTTPBasicAuth

CERTYO_BASE_URL = os.environ.get("CERTYO_BASE_URL", "https://www.certyos.com")
CERTYO_API_KEY = os.environ["CERTYO_API_KEY"]
CERTYO_TENANT_ID = os.environ["CERTYO_TENANT_ID"]
SAP_BASE_URL = os.environ["SAP_BASE_URL"]
SAP_USERNAME = os.environ["SAP_USERNAME"]
SAP_PASSWORD = os.environ["SAP_PASSWORD"]


def get_csrf_token() -> tuple[str, requests.Session]:
    """Fetch CSRF token from SAP for write operations."""
    session = requests.Session()
    session.auth = HTTPBasicAuth(SAP_USERNAME, SAP_PASSWORD)
    response = session.head(
        f"{SAP_BASE_URL}/sap/opu/odata/sap/API_MATERIAL_DOCUMENT_SRV",
        headers={"X-CSRF-Token": "Fetch"},
        timeout=10,
    )
    csrf_token = response.headers.get("X-CSRF-Token", "")
    return csrf_token, session


def verify_and_write_back():
    """Query Certyo for anchored records and write verification back to SAP."""
    # 1. Query Certyo for recently anchored records
    query_response = requests.get(
        f"{CERTYO_BASE_URL}/api/v1/records",
        params={
            "tenantId": CERTYO_TENANT_ID,
            "database": "sap-s4hana",
            "status": "Anchored",
            "limit": 50,
        },
        headers={"X-API-Key": CERTYO_API_KEY},
        timeout=15,
    )
    query_response.raise_for_status()
    records = query_response.json().get("items", [])

    if not records:
        print("No anchored records to verify")
        return

    csrf_token, sap_session = get_csrf_token()

    for record in records:
        record_id = record["recordId"]
        payload_data = record.get("recordPayload", {})

        # 2. Verify the record on-chain
        verify_response = requests.post(
            f"{CERTYO_BASE_URL}/api/v1/verify/record",
            headers={
                "X-API-Key": CERTYO_API_KEY,
                "Content-Type": "application/json",
            },
            json={
                "tenantId": CERTYO_TENANT_ID,
                "database": "sap-s4hana",
                "collection": "MaterialDocuments",
                "recordId": record_id,
                "payload": payload_data,
            },
            timeout=15,
        )
        verification = verify_response.json()

        if not verification.get("verified"):
            print(f"Verification failed for {record_id}: {verification.get('reasonCategory')}")
            continue

        # 3. Write certificate data back to SAP Quality Inspection
        mat_doc = payload_data.get("materialDocument", "")
        mat_doc_year = payload_data.get("materialDocumentYear", "")

        # Update custom Z-fields via SAP OData PATCH
        sap_session.patch(
            f"{SAP_BASE_URL}/sap/opu/odata/sap/ZCERTYO_CERTIFICATE_SRV/CertificateSet(MaterialDocument='{mat_doc}',MaterialDocumentYear='{mat_doc_year}')",
            json={
                "CertyoVerified": True,
                "CertyoRecordHash": verification.get("snapshotHash", ""),
                "CertyoMerkleRoot": verification.get("merkleRoot", ""),
                "CertyoPolygonTx": verification.get("onChainProof", {}).get("polygonScanEventUrl", ""),
                "CertyoIpfsCid": verification.get("ipfsEvidence", {}).get("ipfsCid", ""),
                "CertyoVerifiedAt": time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime()),
            },
            headers={
                "X-CSRF-Token": csrf_token,
                "Content-Type": "application/json",
                "If-Match": "*",
            },
            timeout=10,
        )
        print(
            f"Wrote certificate to SAP for {mat_doc}/{mat_doc_year}: "
            f"{verification['onChainProof']['polygonScanEventUrl']}"
        )


if __name__ == "__main__":
    verify_and_write_back()
Servicio OData personalizado de SAP requerido
El ejemplo de escritura de vuelta usa un servicio OData personalizado (ZCERTYO_CERTIFICATE_SRV). Necesitas crearlo como una vista CDS personalizada o proyecto SEGW en S/4HANA, exponiendo los campos Z para datos del certificado. Para Business One, usa User-Defined Fields (UDFs) en el tipo de documento relevante.

Pruebas

  1. Configura el iFlow de SAP Integration Suite con tu clave sandbox de Certyo y despliégalo en un tenant de prueba. (certyo_sk_test_...)
  2. Registra una recepción de mercancía en S/4HANA (transacción MIGO, tipo de movimiento 101) o crea una nota de entrega de compra en Business One.
  3. Monitorea la ejecución del iFlow en SAP Integration Suite > Monitor > Message Processing. Confirma que la llamada a Certyo retornó 202 Accepted y un recordHash.
  4. Espera 60-90 segundos para el anclaje, luego llama a POST /api/v1/verify/record con los datos del documento de material para confirmar el anclaje on-chain.
  5. Ejecuta el script de verificación y escritura de vuelta y confirma que los datos del certificado aparecen en los campos personalizados o tabla Z de SAP.

Solución de problemas

  • 401 from S/4HANA OData — Verifica que el Communication Arrangement esté activo y que las credenciales OAuth no hayan expirado. Para on-premise, verifica que el túnel de Cloud Connector esté activo.
  • Empty items array in Certyo — Asegúrate de que el parámetro $expand de OData incluya to_MaterialDocumentItem. Sin él, las líneas del documento no se obtienen.
  • Duplicate records in Certyo — El patrón de idempotencyKey usa materialDocument-year-postingDate. Si vuelves a registrar el mismo documento el mismo día, Certyo retorna la respuesta original con idempotencyReplayed: true.
  • CSRF token errors on SAP write-back — Siempre obtén un token CSRF fresco antes de operaciones PATCH/POST. Los tokens expiran después del tiempo de espera de sesión de SAP (30 minutos por defecto).

AI Integration · v1.0.0

AI Integration Skill

Download a skill file that enables AI agents to generate working SAP + Certyo integration code for any language or framework.

v1.0.0
What is this?
A markdown file containing SAP-specific field mappings, authentication setup, code examples, and integration patterns for Certyo. Drop it into your AI agent's context and ask it to generate integration code.

What's inside

  • Authentication — OAuth 2.0 / X.509 vía SAP BTP y credenciales de Integration Suite
  • Architecture — Documento de material → iFlow de SAP Integration Suite → adaptador HTTP → Certyo
  • Field mapping — MATNR, CHARG, SERNR, BWART a campos de Certyo con alineación GS1 EPCIS
  • Code examples — Transformación Groovy en iFlow, handler JavaScript CAP, poller Python OData
  • Verification — PATCH OData con manejo de token CSRF para escritura de vuelta a SAP
  • Integration patterns — S/4HANA Cloud vía Integration Suite, on-premise vía Cloud Connector

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-sap.md \
  https://www.certyos.com/developers/skills/certyo-sap-skill.md

# Use it in Claude Code
/certyo-sap "Genera un iFlow de SAP Integration Suite que envíe documentos de material a 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 SAP-specific patterns, field mappings, and code examples to generate correct integration code.

# Add to your project
curl -o CERTYO_SAP.md \
  https://www.certyos.com/developers/skills/certyo-sap-skill.md

# Then in your AI agent:
"Using the Certyo SAP spec in CERTYO_SAP.md,
 genera un iflow de sap integration suite que envíe documentos de material a certyo"

CLAUDE.md Context File

Append the skill file to your project's CLAUDE.md so every Claude conversation has SAP + Certyo context automatically.

# Append to your project's CLAUDE.md
echo "" >> CLAUDE.md
echo "## Certyo SAP Integration" >> CLAUDE.md
cat CERTYO_SAP.md >> CLAUDE.md