
# Creare un'API

`POST /v1/apis` · permesso `apis:write`

Crea un'API nell'ambiente. `key`, `identifier` e `name` sono obbligatori; i campi opzionali omessi assumono i valori predefiniti. L'identificatore è univoco nell'ambiente (un'API eliminata mantiene l'identificatore riservato per 90 giorni). La risposta contiene un `ETag` con la versione attuale. Inviare un header `Idempotency-Key` per rendere i tentativi sicuri.

## Richiesta

Body `application/json`. I campi sconosciuti vengono rifiutati.

| Campo | Tipo | Obbligatorio | Descrizione |
|---|---|---|---|
| `key` | string | sì | Chiave di configurazione stabile, `^[a-z0-9_-]{1,64}$`. Immutabile. |
| `identifier` | string | sì | Audience del token: un URL https (senza query o frammento) oppure `urn:<nid>:<nss>`; archiviato in forma canonica. Immutabile. Lo spazio dei nomi `urn:idp:` è riservato. |
| `name` | string | sì | 1-128 caratteri. |
| `access_token_lifetime_s` | integer | no | 60-86400. Predefinito 3600 (600 con `mcp_profile`). |
| `token_format` | string | no | `jwt` (predefinito) o `opaque`. |
| `rbac_mode` | string | no | Modo in cui ruoli e permessi raggiungono il token: `claims` (predefinito) aggiunge `permissions` e `org_permissions`; `off` non aggiunge nessuno dei due (`org_roles` viene comunque aggiunto); `enforce` li aggiunge e limita inoltre gli scope concessi ai permessi effettivi dell'utente. |
| `allow_offline_access` | boolean | no | Predefinito `true`. |
| `require_resource_indicator` | boolean | no | Predefinito `false` (`true` con `mcp_profile`). |
| `dpop_required` | boolean | no | Predefinito `false`. |
| `mcp_profile` | boolean | no | Richiede un `identifier` https e `require_resource_indicator: true`. |
| `first_party_access` | string | no | `all` (predefinito) o `granted_only`. |
| `introspection_applications` | array | no | Applicazioni (`app_…`) che possono introspezionare i token di questa API, al massimo 50, senza duplicati. Solo applicazioni `web` e `m2m` dello stesso ambiente. Vuoto per impostazione predefinita. |

### Applicazioni di introspezione

L'endpoint di introspezione (`POST <issuer>/oauth2/introspect`, RFC 7662) risponde con `active: true` per un token di accesso solo a due chiamanti: l'applicazione a cui è stato emesso il token, oppure un'applicazione nell'elenco `introspection_applications` dell'API denominata nel `aud` del token. Tutti gli altri chiamanti ricevono `active: false`, quindi le API non possono leggere i token l'una dell'altra. Solo le applicazioni riservate (`web`, `m2m`) dello stesso ambiente possono essere elencate; l'elenco viene archiviato come un insieme e restituito in ordine ID. Un'applicazione sospesa rimane nell'elenco ma non può introspezionare. L'elenco dell'API di sistema non può essere scritto.

## Risposta

`201 Created` con un header `ETag` e l'API:

```json
{
  "id": "api_01h455vb4pex5vsknk084sn02q",
  "key": "orders",
  "identifier": "https://api.example.com/orders",
  "name": "Orders API",
  "is_system": false,
  "access_token_lifetime_s": 3600,
  "token_format": "jwt",
  "rbac_mode": "claims",
  "allow_offline_access": true,
  "require_resource_indicator": false,
  "dpop_required": false,
  "mcp_profile": false,
  "first_party_access": "all",
  "introspection_applications": ["app_01h455vb4pex5vsknk084sn02r"],
  "created_at": "2026-10-05T12:00:00Z",
  "updated_at": "2026-10-05T12:00:00Z"
}
```

## Errori

| HTTP | code | Quando |
|---|---|---|
| 400 | `unknown_field` | Il body contiene un campo non elencato sopra (ad esempio `id` o `is_system`). |
| 409 | `conflict` | Esiste già un'API con questa `key` o questo `identifier`. |
| 415 | `unsupported_media_type` | Il content type non è `application/json`. |
| 422 | `validation_failed` | Un campo è mancante o non valido (`errors[].pointer`, ad esempio `/identifier`). |
| 422 | `validation_failed` | Un elemento `introspection_applications` non esiste in questo ambiente (`unknown_application`), non è riservato (`not_confidential`), è un duplicato (`duplicate`) o non è un ID `app_…` (`invalid_value`); il puntatore denomina l'indice nella richiesta. |
| 403 | `quota_exceeded` | L'ambiente ha raggiunto il suo limite tecnico di API. |
| 403 | `insufficient_permissions` | La credenziale non ha `apis:write`. |

## Esempio

```bash
curl -X POST https://api.eu.keenauth.com/v1/apis \
  -H "Authorization: Bearer $KEENAUTH_SECRET_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{"key":"orders","identifier":"https://api.example.com/orders","name":"Orders API"}'
```
