﻿---
name: webhook-entity-changed
description: >
  Instructs AI agents how to receive and handle Kyriba entity-changed webhook
  events. Kyriba POSTs a notification to your server whenever a platform entity
  (account, company, third party, user, etc.) is created, modified, or deleted.
version: 1.0.0
authors:
  - kyriba
tags:
  - kyriba
  - webhook
  - spi
  - api
---

> **Auth** — POST {AUTH_BASE_URL}/oauth/token · Basic base64(CLIENT_ID:CLIENT_SECRET) · no scope.
> Use token_type verbatim — do not hardcode `Bearer`. On 401: retry once with the other scheme (`token` vs `Bearer`). On 429: wait Kyriba-Customer-Rate-Limit-Reset.

# Kyriba API Skill: Webhook - Entity Changed

>  This is an **inbound webhook (SPI)** - Kyriba calls your server. You do not call Kyriba.

>  No OAuth scope needed. Authentication is via HMAC signature on the `kyriba-webhook-payload-signature` header.

---

## What is this webhook?

Kyriba fires this event whenever a platform entity is created, modified, or deleted. Use it to keep an external system in sync with Kyriba reference data.

---

## Your server must

1. Expose `POST` on any path you configure in Kyriba (e.g. `/webhook`)
2. Validate the `kyriba-webhook-payload-signature` HMAC-SHA256 header
3. Return `202 Accepted` - any other status causes Kyriba to retry

---

## Inbound Payload

```json
{
  "webhookApiVersion": "v1",
  "eventId": "d6703cc8-9e79-415d-ac03-a4dc7f6ab43c",
  "kyribaEntity": "entity",
  "eventType": "entity_changed",
  "eventTime": "2023-03-23T06:52:10.134Z",
  "kyribaPlatform": { "baseUrl": "https://www.demo.kyriba.com" },
  "kyribaCustomer": { "code": "ACMECORP" },
  "kyribaUser": { "code": "JOHNSMITH", "uuid": "123e4567-..." },
  "eventDetails": {
    "action": "CREATION",
    "entity": {
      "code": "NEW_THIRD_PARTY",
      "uuid": "ad487c41-34df-4eb1-8201-24764f009db1",
      "type": "THIRDPARTY",
      "version": 1
    }
  }
}
```

---

## Key Fields

| Field | Description |
|---|---|
| `eventId` | UUID - use for deduplication |
| `eventTime` | ISO-8601 timestamp of the change |
| `kyribaCustomer.code` | Kyriba customer code |
| `kyribaUser.code` | User who triggered the change |
| `eventDetails.action` | `CREATION`, `MODIFICATION`, or `DELETION` |
| `eventDetails.entity.type` | Entity type (see table below) |
| `eventDetails.entity.code` | Entity code |
| `eventDetails.entity.uuid` | Entity UUID |
| `eventDetails.entity.version` | New version number after the change |

### `eventDetails.entity.type` values

`ACCOUNT` · `ACCOUNT_GROUP` · `BANK` · `BANK_GROUP` · `BRANCH` · `BUDGET_CODE` · `CURRENCY` · `COMPANY` · `COMPANY_GROUP` · `SUPPLIER_SERVICE_ACCESS` · `SUPPLIER_USER` · `THIRDPARTY` · `THIRD_PARTY_CATEGORY` · `USER` · `USER_GROUP` · `WCF_INTEREST_TERM`

>  Treat `type` as an open set - new types may be added. Skip unknown types gracefully.

---

## Signature Validation

```python
import hmac, hashlib

def verify(payload_bytes: bytes, header_signature: str, secret: str) -> bool:
    expected = hmac.new(secret.encode(), payload_bytes, hashlib.sha256).hexdigest()
    return hmac.compare_digest(expected, header_signature)
```

---

## Critical Rules

1. Always return `202` - even if you skip processing an event
2. Use `eventId` to deduplicate (Kyriba may retry on timeout)
3. Skip unknown `type` or `action` values without raising an error
4. `kyriba-webhook-payload-signature` must be validated before processing
5. `kyribaPlatform.baseUrl` has no trailing slash

---

## OpenAPI Spec

- OpenAPI: `https://developer.kyriba.com/static/apis/webhook-entity-changed/entity_changed.yaml`