﻿---
name: mapping-tables
description: >
  Instructs AI agents how to create, read, update, and delete mapping tables
  in Kyriba. Mapping tables translate external system codes (ERP, bank) to
  internal Kyriba codes, used primarily in ERP and bank connectivity integrations.
version: 1.0.0
scopes:
  - mapping-tables-scope
authors:
  - kyriba
tags:
  - kyriba
  - platform
  - mapping-tables
  - erp
  - 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: Mapping Tables

---

## Required Kyriba Permission

```
mapping-tables-scope
```

This is a Kyriba access permission — not an OAuth scope parameter. Do NOT add `scope=` to the token request.

---

## Base Path

```
/v1/mapping-tables/{entityType}
```

>  Pagination uses `limit`/`offset` - NOT `page.limit`/`page.offset`.

---

## `entityType` Values

Mapping tables are scoped to a Kyriba entity type. Pass `entityType` as a path parameter:

```
COMPANY, BANK_ACCOUNT, BANK, BANK_BRANCH, THIRD_PARTY,
CASH_FLOW_CODE, BUDGET_CODE, CURRENCY, COUNTRY, FREE
```

`FREE` - no internal code validation (free-form string mapping).

---

## Endpoints

`{ref}` accepts either `uuid` or `code` of the mapping table.

| Method | Path | Description |
|--------|------|-------------|
| `GET` | `/v1/mapping-tables/{entityType}` | List mapping tables |
| `POST` | `/v1/mapping-tables/{entityType}` | Create a new mapping table |
| `GET` | `/v1/mapping-tables/{entityType}/{ref}` | Get a specific mapping table |
| `PUT` | `/v1/mapping-tables/{entityType}/{ref}` | Update a mapping table (requires ETag) |
| `DELETE` | `/v1/mapping-tables/{entityType}/{ref}` | Delete a mapping table (requires ETag) |
| `GET` | `/v1/mapping-tables/searchable-fields` | List filterable fields |
| `POST` | `/v1/mapping-tables/mapping-values/search` | Search mapping values by external code |

---

## ETag - Required for PUT and DELETE

Kyriba uses **optimistic locking** on mapping tables. `PUT` and `DELETE` require an `If-Match` header with the current ETag:

1. Fetch the resource with `GET /mapping-tables/{entityType}/{ref}`
2. Copy the `ETag` from the response header
3. Include it in `PUT`/`DELETE`: `If-Match: "abc123etag"`

| Status | Meaning |
|---|---|
| `412 Precondition Failed` | ETag provided but doesn't match (resource changed) |
| `428 Precondition Required` | `If-Match` header is missing entirely |

---

## Two Types of Mapping

**Entity mapping** (entityType = COMPANY, BANK_ACCOUNT, etc.) - `internalCode` is an object:
```json
{
  "externalCode": "SAP_COMP_001",
  "internalCode": { "code": "MY_COMPANY", "uuid": "..." }
}
```

**Free mapping** (entityType = FREE) - `internalCode` is a plain string:
```json
{
  "externalCode": "SAP_CODE_001",
  "internalCode": "KYRIBA_CODE_001"
}
```

---

## Example Requests

**List all COMPANY mapping tables:**
```
GET /mapping-tables/COMPANY?limit=100&offset=0
```

**GET list response:**
```json
{
  "metadata": {
    "pageLimit": 100,
    "pageOffset": 0,
    "pageResults": 2,
    "numberOfTotalResults": 2
  },
  "results": [ ... ]
}
```
> Response key is always `results`. Stop paginating when `len(results) < pageLimit`.

**Create a COMPANY mapping table:**
```http
POST /mapping-tables/COMPANY
Content-Type: application/json

{
  "code": "COMP_MAP",
  "description": "SAP company code mapping",
  "ownershipCompany": { "code": "MY_COMPANY" },
  "mappings": [
    { "externalCode": "1000", "internalCode": { "code": "COMP_FR" } },
    { "externalCode": "2000", "internalCode": { "code": "COMP_DE" } }
  ]
}
```

**Create response:** `{ "uuid": "...", "code": "COMP_MAP", ... }`

**Get a specific mapping table (captures ETag):**
```
GET /mapping-tables/COMPANY/COMP_MAP
-> Response header: ETag: "abc123etag"
```

**Update (requires ETag):**
```http
PUT /mapping-tables/COMPANY/COMP_MAP
If-Match: "abc123etag"
Content-Type: application/json

{
  "description": "Updated SAP mapping",
  "mappings": [
    { "externalCode": "1000", "internalCode": { "code": "COMP_FR" } },
    { "externalCode": "3000", "internalCode": { "code": "COMP_ES" } }
  ]
}
```

**Search by external code:**
```http
POST /mapping-tables/mapping-values/search
Content-Type: application/json

{
  "entityType": "COMPANY",
  "externalCode": "1000"
}
```

---

## List Response Schema

```json
{
  "metadata": { "total": 5, "count": 5, "limit": 100, "offset": 0 },
  "results": [
    {
      "code": "COMP_MAP",
      "uuid": "...",
      "description": "SAP company code mapping",
      "ownershipCompany": { "code": "MY_COMPANY" },
      "mappings": [
        { "externalCode": "1000", "internalCode": { "code": "COMP_FR" } }
      ]
    }
  ]
}
```

---

## Critical Rules

1. Pagination: `limit`/`offset` - NOT `page.limit`/`page.offset`
2. `uuid` is auto-generated - do not include in `POST` body
3. `PUT` and `DELETE` require `If-Match` header with current ETag - always `GET` first
4. `428` = missing `If-Match` header; `412` = ETag mismatch (resource updated by someone else)
5. Entity-type mappings: `internalCode` is an object; FREE mappings: `internalCode` is a string
6. **No PATCH endpoint** - adding one mapping entry requires: `GET` (capture ETag + full `mappings` array) -> append new entry locally -> `PUT` the full updated array back

---

## Error Reference

| Status | Meaning |
|---|---|
| `201` | Mapping table created |
| `204` | Mapping table deleted |
| `400` | Invalid request body |
| `403` | Required Kyriba permission not configured on your API client |
| `404` | Mapping table not found |
| `409` | Conflict - code already exists |
| `412` | ETag mismatch - resource modified since last fetch |
| `428` | Missing `If-Match` header |

---

## OpenAPI Spec & Postman Collection

- OpenAPI: `https://developer.kyriba.com/static/apis/mapping-tables/mapping-tables.yaml`
- Postman: `https://developer.kyriba.com/static/apis/mapping-tables/mapping-tables-postman-collection.json`
