{
    "openapi": "3.0.0",
    "info": {
        "title": "Cloketa API",
        "description": "API l\u00e9g\u00e8re pour le pointage et les int\u00e9grations. Les dates suivent ISO 8601 et les horodatages sont conserv\u00e9s en UTC.",
        "version": "1.0.0"
    },
    "servers": [
        {
            "url": "https://apps.cloketa.eu"
        }
    ],
    "paths": {
        "/api/v1/me": {
            "get": {
                "summary": "L\u2019utilisateur et l\u2019entreprise de la cl\u00e9",
                "description": "Une cl\u00e9 est cr\u00e9\u00e9e pour un utilisateur dans une entreprise. Cette route renvoie l\u2019utilisateur, la cl\u00e9 (nom, permissions, expiration) et l\u2019entreprise (identifiant, nom, num\u00e9ro BCE, r\u00f4le, adresse, langue, fuseau horaire, formule, options). L\u2019identifiant de l\u2019entreprise est la valeur de X-Cloketa-Organization, facultatif sur les autres routes.",
                "operationId": "get_api_v1_me",
                "responses": {
                    "200": {
                        "description": "Utilisateur, cl\u00e9 et entreprise"
                    },
                    "401": {
                        "description": "Cl\u00e9 API absente ou invalide"
                    }
                }
            }
        },
        "/api/v1/clock": {
            "post": {
                "summary": "Ajouter un \u00e9v\u00e9nement de pointage immuable",
                "operationId": "post_api_v1_clock",
                "parameters": [
                    {
                        "name": "X-Cloketa-Organization",
                        "in": "header",
                        "description": "Facultatif. UUID de l\u2019entreprise de la cl\u00e9 (organization.id de GET /api/v1/me) ; par d\u00e9faut, l\u2019entreprise \u00e0 laquelle la cl\u00e9 appartient.",
                        "required": false,
                        "schema": {
                            "type": "string",
                            "format": "uuid"
                        }
                    },
                    {
                        "name": "Idempotency-Key",
                        "in": "header",
                        "description": "Cl\u00e9 unique g\u00e9n\u00e9r\u00e9e par l\u2019appelant; rejouer la m\u00eame requ\u00eate ne cr\u00e9e pas un second \u00e9v\u00e9nement.",
                        "required": true,
                        "schema": {
                            "type": "string",
                            "maxLength": 64
                        }
                    }
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "required": [
                                    "action"
                                ],
                                "properties": {
                                    "action": {
                                        "type": "string",
                                        "enum": [
                                            "start",
                                            "pause_start",
                                            "pause_end",
                                            "stop"
                                        ]
                                    }
                                },
                                "type": "object"
                            }
                        }
                    }
                },
                "responses": {
                    "201": {
                        "description": "\u00c9v\u00e9nement cr\u00e9\u00e9"
                    },
                    "403": {
                        "description": "Scope clock ou emploi actif manquant"
                    },
                    "409": {
                        "description": "Transition invalide dans la machine \u00e0 \u00e9tats"
                    },
                    "422": {
                        "description": "Requ\u00eate incompl\u00e8te"
                    }
                }
            }
        },
        "/api/v1/employees": {
            "get": {
                "summary": "Lister les travailleurs de l\u2019entreprise",
                "description": "Liste pagin\u00e9e, du contrat le plus r\u00e9cent au plus ancien. La r\u00e9ponse contient data (les travailleurs de la page) et meta (page, per_page, total, pages) ; l\u2019en-t\u00eate X-Total-Count r\u00e9p\u00e8te le total.",
                "operationId": "get_api_v1_employees_list",
                "parameters": [
                    {
                        "name": "X-Cloketa-Organization",
                        "in": "header",
                        "description": "Facultatif. UUID de l\u2019entreprise de la cl\u00e9 (organization.id de GET /api/v1/me) ; par d\u00e9faut, l\u2019entreprise \u00e0 laquelle la cl\u00e9 appartient.",
                        "required": false,
                        "schema": {
                            "type": "string",
                            "format": "uuid"
                        }
                    },
                    {
                        "name": "page",
                        "in": "query",
                        "description": "Num\u00e9ro de page, \u00e0 partir de 1.",
                        "required": false,
                        "schema": {
                            "type": "integer",
                            "default": 1,
                            "minimum": 1
                        }
                    },
                    {
                        "name": "per_page",
                        "in": "query",
                        "description": "Travailleurs par page (100 par d\u00e9faut, 500 au plus).",
                        "required": false,
                        "schema": {
                            "type": "integer",
                            "default": 100,
                            "maximum": 500,
                            "minimum": 1
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Travailleurs actifs et archiv\u00e9s de la page demand\u00e9e, avec meta.page, meta.per_page, meta.total et meta.pages"
                    },
                    "403": {
                        "description": "Scope read et r\u00f4le administrateur requis"
                    }
                }
            },
            "post": {
                "summary": "Inviter un travailleur ou administrateur",
                "operationId": "post_api_v1_employees_invite",
                "parameters": [
                    {
                        "name": "X-Cloketa-Organization",
                        "in": "header",
                        "description": "Facultatif. UUID de l\u2019entreprise de la cl\u00e9 (organization.id de GET /api/v1/me) ; par d\u00e9faut, l\u2019entreprise \u00e0 laquelle la cl\u00e9 appartient.",
                        "required": false,
                        "schema": {
                            "type": "string",
                            "format": "uuid"
                        }
                    }
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "required": [
                                    "email"
                                ],
                                "properties": {
                                    "email": {
                                        "type": "string",
                                        "format": "email"
                                    },
                                    "role": {
                                        "type": "string",
                                        "enum": [
                                            "employee",
                                            "manager",
                                            "admin"
                                        ]
                                    },
                                    "can_track_time": {
                                        "type": "boolean",
                                        "default": true
                                    }
                                },
                                "type": "object"
                            }
                        }
                    }
                },
                "responses": {
                    "202": {
                        "description": "Invitation envoy\u00e9e de mani\u00e8re asynchrone"
                    },
                    "402": {
                        "description": "Abonnement inactif"
                    },
                    "409": {
                        "description": "Limite du plan atteinte"
                    }
                }
            }
        },
        "/api/v1/employees/{id}": {
            "delete": {
                "summary": "Archiver un travailleur sans supprimer son historique",
                "operationId": "delete_api_v1_employees_archive",
                "parameters": [
                    {
                        "name": "X-Cloketa-Organization",
                        "in": "header",
                        "description": "Facultatif. UUID de l\u2019entreprise de la cl\u00e9 (organization.id de GET /api/v1/me) ; par d\u00e9faut, l\u2019entreprise \u00e0 laquelle la cl\u00e9 appartient.",
                        "required": false,
                        "schema": {
                            "type": "string",
                            "format": "uuid"
                        }
                    },
                    {
                        "name": "id",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "string",
                            "format": "uuid"
                        }
                    }
                ],
                "responses": {
                    "204": {
                        "description": "Travailleur archiv\u00e9"
                    },
                    "409": {
                        "description": "Le propri\u00e9taire ne peut pas \u00eatre archiv\u00e9"
                    }
                }
            }
        },
        "/api/v1/inspection-export": {
            "post": {
                "summary": "T\u00e9l\u00e9charger le dossier d\u2019inspection sign\u00e9",
                "description": "P\u00e9riode de 12 mois au plus. Disponible quel que soit l\u2019\u00e9tat de l\u2019abonnement.",
                "operationId": "post_api_v1_inspection_export",
                "parameters": [
                    {
                        "name": "X-Cloketa-Organization",
                        "in": "header",
                        "description": "Facultatif. UUID de l\u2019entreprise de la cl\u00e9 (organization.id de GET /api/v1/me) ; par d\u00e9faut, l\u2019entreprise \u00e0 laquelle la cl\u00e9 appartient.",
                        "required": false,
                        "schema": {
                            "type": "string",
                            "format": "uuid"
                        }
                    }
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "required": [
                                    "from",
                                    "until"
                                ],
                                "properties": {
                                    "from": {
                                        "description": "Premier jour inclus",
                                        "type": "string",
                                        "format": "date"
                                    },
                                    "until": {
                                        "description": "Dernier jour inclus",
                                        "type": "string",
                                        "format": "date"
                                    }
                                },
                                "type": "object"
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Archive ZIP sign\u00e9e"
                    },
                    "503": {
                        "description": "Dossier momentan\u00e9ment impossible \u00e0 g\u00e9n\u00e9rer"
                    },
                    "403": {
                        "description": "Scope read et r\u00f4le administrateur requis"
                    },
                    "422": {
                        "description": "P\u00e9riode absente ou invalide"
                    }
                }
            }
        }
    },
    "components": {
        "parameters": {
            "organization": {
                "name": "X-Cloketa-Organization",
                "in": "header",
                "description": "Facultatif. UUID de l\u2019entreprise de la cl\u00e9 (organization.id de GET /api/v1/me) ; par d\u00e9faut, l\u2019entreprise \u00e0 laquelle la cl\u00e9 appartient.",
                "required": false,
                "schema": {
                    "type": "string",
                    "format": "uuid"
                }
            }
        },
        "securitySchemes": {
            "apiKey": {
                "type": "http",
                "bearerFormat": "ck_\u2026",
                "scheme": "bearer"
            }
        }
    },
    "security": [
        {
            "apiKey": []
        }
    ]
}