{
  "openapi": "3.1.1",
  "info": {
    "title": "API de transcription en français mp4tosrt.fr",
    "version": "1.0.0",
    "description": "Audio/vidéo vers sous-titres SRT français. Incluse dans tous les abonnements dès 6 €/mois pour 90 minutes, pas dans l’essai ; compteur de minutes commun avec le site. Deux clés actives maximum par abonnement. Création par le propriétaire : Mon abonnement → Accès API. Gardez la clé côté serveur. Les limites serveur configurables sont des valeurs par défaut du code, pas une garantie de configuration déployée. Les erreurs du proxy peuvent ne pas être JSON."
  },
  "servers": [
    {
      "url": "https://mp4tosrt.fr",
      "description": "Domaine public ; les chemins incluent /v1."
    }
  ],
  "externalDocs": {
    "url": "https://mp4tosrt.fr/api-documentation",
    "description": "Documentation développeur et exemples curl, Node, Python."
  },
  "security": [
    {
      "bearerAuth": []
    }
  ],
  "paths": {
    "/v1/transcriptions": {
      "post": {
        "operationId": "createTranscription",
        "summary": "Envoyer un fichier audio ou vidéo pour obtenir un SRT français",
        "description": "Un fichier multipart file ; aucun autre champ ne configure le traitement. Content-Length valide obligatoire, Transfer-Encoding refusé. 202 crée un job queued ; 200 renvoie le job existant pour même clé API, Idempotency-Key, taille et SHA-256. Les contrôles de débit et capacité précèdent la recherche d’idempotence, même en reprise. Conservez l’identifiant et consultez le statut. Limite publique du corps : 601 MB dans Caddy ; limite fichier backend configurable MAX_FILE_MB (2048 Mio par défaut), corps backend limité à ce plafond + 1 Mio. La plus petite limite s’applique. Formats : mp3, mp4, m4a, wav, aac, ogg, webm, mov, mkv, avi, flac, wma ; type MIME audio/* ou video/*. Durée maximale par défaut : 120 minutes, configurable ; son dépassement apparaît en échec asynchrone. Clé d’abonnement : 10 tentatives/minute, 2 jobs actifs et 2147483648 octets/heure UTC par clé (Content-Length réservé avant upload). Plafonds globaux configurables : 4 jobs actifs, 4 uploads, 100 en file, worker de concurrence 1 par défaut.",
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": true,
            "description": "Valeur distincte par fichier à traiter ; garder la même pour retenter le même envoi.",
            "schema": {
              "type": "string",
              "minLength": 8,
              "maxLength": 200
            },
            "example": "video-exemple-20261102-001"
          },
          {
            "name": "Content-Length",
            "in": "header",
            "required": true,
            "description": "Taille totale du multipart en octets, calculée par le client HTTP. Pas de Transfer-Encoding.",
            "schema": {
              "type": "integer",
              "minimum": 1
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "multipart/form-data": {
              "schema": {
                "type": "object",
                "required": [
                  "file"
                ],
                "properties": {
                  "file": {
                    "type": "string",
                    "format": "binary",
                    "description": "Un seul média local, avec nom de fichier autorisé et type MIME audio ou vidéo."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Job déjà existant (idempotence), dans son état actuel.",
            "headers": {
              "X-Request-Id": {
                "description": "Identifiant de requête renvoyé par le backend.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Job"
                },
                "example": {
                  "id": "11111111-1111-4111-8111-111111111111",
                  "status": "completed",
                  "created_at": {
                    "_seconds": 1793664000,
                    "_nanoseconds": 0
                  },
                  "updated_at": {
                    "_seconds": 1793664060,
                    "_nanoseconds": 0
                  },
                  "duration_seconds": 12.4,
                  "billable_seconds": 13,
                  "srt_url": "/v1/transcriptions/11111111-1111-4111-8111-111111111111/srt"
                }
              }
            }
          },
          "202": {
            "description": "Nouveau job accepté, encore en attente.",
            "headers": {
              "X-Request-Id": {
                "description": "Identifiant de requête renvoyé par le backend.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/JobQueued"
                },
                "example": {
                  "id": "11111111-1111-4111-8111-111111111111",
                  "status": "queued",
                  "created_at": {},
                  "updated_at": {}
                }
              }
            }
          },
          "400": {
            "description": "Idempotency-Key absente/hors longueur ou fichier manquant.",
            "headers": {
              "X-Request-Id": {
                "description": "Identifiant de requête renvoyé par le backend.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    },
                    {
                      "properties": {
                        "error": {
                          "properties": {
                            "code": {
                              "enum": [
                                "missing_idempotency_key",
                                "unsupported_media"
                              ]
                            }
                          }
                        }
                      }
                    }
                  ]
                }
              }
            }
          },
          "409": {
            "description": "Cette clé d’idempotence désigne un fichier différent.",
            "headers": {
              "X-Request-Id": {
                "description": "Identifiant de requête renvoyé par le backend.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    },
                    {
                      "properties": {
                        "error": {
                          "properties": {
                            "code": {
                              "enum": [
                                "idempotency_conflict"
                              ]
                            }
                          }
                        }
                      }
                    }
                  ]
                }
              }
            }
          },
          "411": {
            "description": "Longueur absente, invalide, nulle ou Transfer-Encoding présent.",
            "headers": {
              "X-Request-Id": {
                "description": "Identifiant de requête renvoyé par le backend.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    },
                    {
                      "properties": {
                        "error": {
                          "properties": {
                            "code": {
                              "enum": [
                                "missing_content_length"
                              ]
                            }
                          }
                        }
                      }
                    }
                  ]
                }
              }
            }
          },
          "413": {
            "description": "Limite du fichier ou du corps dépassée dans le backend. Le proxy peut aussi refuser en amont, sans JSON API.",
            "headers": {
              "X-Request-Id": {
                "description": "Identifiant de requête renvoyé par le backend.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    },
                    {
                      "properties": {
                        "error": {
                          "properties": {
                            "code": {
                              "enum": [
                                "file_too_large"
                              ]
                            }
                          }
                        }
                      }
                    }
                  ]
                }
              }
            }
          },
          "415": {
            "description": "Extension ou type MIME refusé.",
            "headers": {
              "X-Request-Id": {
                "description": "Identifiant de requête renvoyé par le backend.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    },
                    {
                      "properties": {
                        "error": {
                          "properties": {
                            "code": {
                              "enum": [
                                "unsupported_media"
                              ]
                            }
                          }
                        }
                      }
                    }
                  ]
                }
              }
            }
          },
          "429": {
            "description": "Débit minute/volume horaire dépassé ou trop de jobs actifs pour cette clé.",
            "headers": {
              "X-Request-Id": {
                "description": "Identifiant de requête renvoyé par le backend.",
                "schema": {
                  "type": "string"
                }
              },
              "Retry-After": {
                "description": "Délai en secondes avant une nouvelle tentative. Présent sur les refus de débit/capacité ; 300 sur le POST désactivé, absent si la configuration des clés manque.",
                "schema": {
                  "type": "string",
                  "pattern": "^[0-9]+$"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    },
                    {
                      "properties": {
                        "error": {
                          "properties": {
                            "code": {
                              "enum": [
                                "upload_rate_exceeded",
                                "service_overloaded"
                              ]
                            }
                          }
                        }
                      }
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "description": "Clé absente, invalide, inconnue ou révoquée.",
            "headers": {
              "X-Request-Id": {
                "description": "Identifiant de requête renvoyé par le backend.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    },
                    {
                      "properties": {
                        "error": {
                          "properties": {
                            "code": {
                              "enum": [
                                "invalid_api_key"
                              ]
                            }
                          }
                        }
                      }
                    }
                  ]
                }
              }
            }
          },
          "403": {
            "description": "Compte API inactif, abonnement non éligible ou organisation inactive.",
            "headers": {
              "X-Request-Id": {
                "description": "Identifiant de requête renvoyé par le backend.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    },
                    {
                      "properties": {
                        "error": {
                          "properties": {
                            "code": {
                              "enum": [
                                "account_inactive",
                                "organization_suspended"
                              ]
                            }
                          }
                        }
                      }
                    }
                  ]
                }
              }
            }
          },
          "500": {
            "description": "Erreur interne.",
            "headers": {
              "X-Request-Id": {
                "description": "Identifiant de requête renvoyé par le backend.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    },
                    {
                      "properties": {
                        "error": {
                          "properties": {
                            "code": {
                              "enum": [
                                "internal_error"
                              ]
                            }
                          }
                        }
                      }
                    }
                  ]
                }
              }
            }
          },
          "503": {
            "description": "API désactivée, file saturée ou capacité globale/stockage/uploads saturés.",
            "headers": {
              "X-Request-Id": {
                "description": "Identifiant de requête renvoyé par le backend.",
                "schema": {
                  "type": "string"
                }
              },
              "Retry-After": {
                "description": "Délai en secondes avant une nouvelle tentative. Présent sur les refus de débit/capacité ; 300 sur le POST désactivé, absent si la configuration des clés manque.",
                "schema": {
                  "type": "string",
                  "pattern": "^[0-9]+$"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    },
                    {
                      "properties": {
                        "error": {
                          "properties": {
                            "code": {
                              "enum": [
                                "api_disabled",
                                "queue_full",
                                "service_overloaded"
                              ]
                            }
                          }
                        }
                      }
                    }
                  ]
                }
              }
            }
          }
        }
      }
    },
    "/v1/transcriptions/{id}": {
      "get": {
        "operationId": "getTranscription",
        "summary": "Consulter le statut du job",
        "description": "Aucun corps ni Idempotency-Key. queued et processing : attendre ; completed : télécharger srt_url avec la même clé ; failed : lire error_code (toujours HTTP 200) ; expired : résultat expiré. SRT conservé 72 h après achèvement par défaut (configurable), purge toutes les 15 min. Le média source est supprimé au mieux à la fin du traitement. Pas de durée de conservation définie ici pour les métadonnées.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Identifiant reçu à la création ; seuls les jobs de cette clé sont accessibles.",
            "schema": {
              "type": "string"
            },
            "example": "11111111-1111-4111-8111-111111111111"
          }
        ],
        "responses": {
          "200": {
            "description": "État actuel du job.",
            "headers": {
              "X-Request-Id": {
                "description": "Identifiant de requête renvoyé par le backend.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Job"
                },
                "example": {
                  "id": "11111111-1111-4111-8111-111111111111",
                  "status": "completed",
                  "created_at": {
                    "_seconds": 1793664000,
                    "_nanoseconds": 0
                  },
                  "updated_at": {
                    "_seconds": 1793664060,
                    "_nanoseconds": 0
                  },
                  "duration_seconds": 12.4,
                  "billable_seconds": 13,
                  "srt_url": "/v1/transcriptions/11111111-1111-4111-8111-111111111111/srt"
                }
              }
            }
          },
          "404": {
            "description": "Job absent ou appartenant à une autre clé.",
            "headers": {
              "X-Request-Id": {
                "description": "Identifiant de requête renvoyé par le backend.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    },
                    {
                      "properties": {
                        "error": {
                          "properties": {
                            "code": {
                              "enum": [
                                "job_not_found"
                              ]
                            }
                          }
                        }
                      }
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "description": "Clé absente, invalide, inconnue ou révoquée.",
            "headers": {
              "X-Request-Id": {
                "description": "Identifiant de requête renvoyé par le backend.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    },
                    {
                      "properties": {
                        "error": {
                          "properties": {
                            "code": {
                              "enum": [
                                "invalid_api_key"
                              ]
                            }
                          }
                        }
                      }
                    }
                  ]
                }
              }
            }
          },
          "403": {
            "description": "Compte API inactif, abonnement non éligible ou organisation inactive.",
            "headers": {
              "X-Request-Id": {
                "description": "Identifiant de requête renvoyé par le backend.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    },
                    {
                      "properties": {
                        "error": {
                          "properties": {
                            "code": {
                              "enum": [
                                "account_inactive",
                                "organization_suspended"
                              ]
                            }
                          }
                        }
                      }
                    }
                  ]
                }
              }
            }
          },
          "500": {
            "description": "Erreur interne.",
            "headers": {
              "X-Request-Id": {
                "description": "Identifiant de requête renvoyé par le backend.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    },
                    {
                      "properties": {
                        "error": {
                          "properties": {
                            "code": {
                              "enum": [
                                "internal_error"
                              ]
                            }
                          }
                        }
                      }
                    }
                  ]
                }
              }
            }
          },
          "503": {
            "description": "Configuration des clés indisponible.",
            "headers": {
              "X-Request-Id": {
                "description": "Identifiant de requête renvoyé par le backend.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    },
                    {
                      "properties": {
                        "error": {
                          "properties": {
                            "code": {
                              "enum": [
                                "api_disabled"
                              ]
                            }
                          }
                        }
                      }
                    }
                  ]
                }
              }
            }
          }
        }
      }
    },
    "/v1/transcriptions/{id}/srt": {
      "get": {
        "operationId": "downloadTranscriptionSrt",
        "summary": "Télécharger le fichier SRT terminé",
        "description": "Aucun corps ni Idempotency-Key. Nécessite la même clé que la création, y compris pour srt_url. Un job failed donne 409 job_not_ready.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Identifiant reçu à la création ; seuls les jobs de cette clé sont accessibles.",
            "schema": {
              "type": "string"
            },
            "example": "11111111-1111-4111-8111-111111111111"
          }
        ],
        "responses": {
          "200": {
            "description": "Fichier SRT UTF-8 en pièce jointe, nom {id}.srt.",
            "headers": {
              "X-Request-Id": {
                "description": "Identifiant de requête renvoyé par le backend.",
                "schema": {
                  "type": "string"
                }
              },
              "Content-Disposition": {
                "description": "attachment ; nom de fichier {id}.srt",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/x-subrip": {
                "schema": {
                  "type": "string"
                },
                "example": "1\n00:00:01,000 --> 00:00:03,000\nBonjour.\n"
              }
            }
          },
          "404": {
            "description": "Job absent ou appartenant à une autre clé.",
            "headers": {
              "X-Request-Id": {
                "description": "Identifiant de requête renvoyé par le backend.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    },
                    {
                      "properties": {
                        "error": {
                          "properties": {
                            "code": {
                              "enum": [
                                "job_not_found"
                              ]
                            }
                          }
                        }
                      }
                    }
                  ]
                }
              }
            }
          },
          "409": {
            "description": "Job ni completed ni expired.",
            "headers": {
              "X-Request-Id": {
                "description": "Identifiant de requête renvoyé par le backend.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    },
                    {
                      "properties": {
                        "error": {
                          "properties": {
                            "code": {
                              "enum": [
                                "job_not_ready"
                              ]
                            }
                          }
                        }
                      }
                    }
                  ]
                }
              }
            }
          },
          "410": {
            "description": "Résultat expiré.",
            "headers": {
              "X-Request-Id": {
                "description": "Identifiant de requête renvoyé par le backend.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    },
                    {
                      "properties": {
                        "error": {
                          "properties": {
                            "code": {
                              "enum": [
                                "result_expired"
                              ]
                            }
                          }
                        }
                      }
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "description": "Clé absente, invalide, inconnue ou révoquée.",
            "headers": {
              "X-Request-Id": {
                "description": "Identifiant de requête renvoyé par le backend.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    },
                    {
                      "properties": {
                        "error": {
                          "properties": {
                            "code": {
                              "enum": [
                                "invalid_api_key"
                              ]
                            }
                          }
                        }
                      }
                    }
                  ]
                }
              }
            }
          },
          "403": {
            "description": "Compte API inactif, abonnement non éligible ou organisation inactive.",
            "headers": {
              "X-Request-Id": {
                "description": "Identifiant de requête renvoyé par le backend.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    },
                    {
                      "properties": {
                        "error": {
                          "properties": {
                            "code": {
                              "enum": [
                                "account_inactive",
                                "organization_suspended"
                              ]
                            }
                          }
                        }
                      }
                    }
                  ]
                }
              }
            }
          },
          "500": {
            "description": "Erreur interne.",
            "headers": {
              "X-Request-Id": {
                "description": "Identifiant de requête renvoyé par le backend.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    },
                    {
                      "properties": {
                        "error": {
                          "properties": {
                            "code": {
                              "enum": [
                                "internal_error"
                              ]
                            }
                          }
                        }
                      }
                    }
                  ]
                }
              }
            }
          },
          "503": {
            "description": "Configuration des clés indisponible.",
            "headers": {
              "X-Request-Id": {
                "description": "Identifiant de requête renvoyé par le backend.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    },
                    {
                      "properties": {
                        "error": {
                          "properties": {
                            "code": {
                              "enum": [
                                "api_disabled"
                              ]
                            }
                          }
                        }
                      }
                    }
                  ]
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "m4s_live_<clientId>.<secret>",
        "description": "Authorization: Bearer m4s_live_… ; clé fictive de forme valide : m4s_live_demo.AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA. clientId : 4 à 64 caractères alphanumériques, _ ou - ; secret : 43 caractères base64url."
      }
    },
    "schemas": {
      "Timestamp": {
        "description": "Valeur brute du stockage : objet horodatage persistant, ou objet vide du marqueur non résolu lors du nouveau POST. Pas de chaîne ISO.",
        "oneOf": [
          {
            "type": "object",
            "required": [
              "_seconds",
              "_nanoseconds"
            ],
            "properties": {
              "_seconds": {
                "type": "integer"
              },
              "_nanoseconds": {
                "type": "integer",
                "minimum": 0,
                "maximum": 999999999
              }
            },
            "additionalProperties": false
          },
          {
            "type": "object",
            "maxProperties": 0
          }
        ]
      },
      "JobQueued": {
        "type": "object",
        "required": [
          "id",
          "created_at",
          "updated_at",
          "status"
        ],
        "properties": {
          "id": {
            "type": "string"
          },
          "created_at": {
            "$ref": "#/components/schemas/Timestamp"
          },
          "updated_at": {
            "$ref": "#/components/schemas/Timestamp"
          },
          "status": {
            "const": "queued"
          }
        },
        "additionalProperties": false
      },
      "JobProcessing": {
        "type": "object",
        "required": [
          "id",
          "created_at",
          "updated_at",
          "status"
        ],
        "properties": {
          "id": {
            "type": "string"
          },
          "created_at": {
            "$ref": "#/components/schemas/Timestamp"
          },
          "updated_at": {
            "$ref": "#/components/schemas/Timestamp"
          },
          "status": {
            "const": "processing"
          }
        },
        "additionalProperties": false
      },
      "JobExpired": {
        "type": "object",
        "required": [
          "id",
          "created_at",
          "updated_at",
          "status"
        ],
        "properties": {
          "id": {
            "type": "string"
          },
          "created_at": {
            "$ref": "#/components/schemas/Timestamp"
          },
          "updated_at": {
            "$ref": "#/components/schemas/Timestamp"
          },
          "status": {
            "const": "expired"
          }
        },
        "additionalProperties": false
      },
      "JobCompleted": {
        "type": "object",
        "required": [
          "id",
          "created_at",
          "updated_at",
          "status",
          "duration_seconds",
          "billable_seconds",
          "srt_url"
        ],
        "properties": {
          "id": {
            "type": "string"
          },
          "created_at": {
            "$ref": "#/components/schemas/Timestamp"
          },
          "updated_at": {
            "$ref": "#/components/schemas/Timestamp"
          },
          "status": {
            "const": "completed"
          },
          "duration_seconds": {
            "type": "number"
          },
          "billable_seconds": {
            "type": "number",
            "description": "Secondes réservées pour l’usage."
          },
          "srt_url": {
            "type": "string",
            "pattern": "^/v1/transcriptions/[^/]+/srt$",
            "description": "Chemin relatif au domaine public ; téléchargement authentifié."
          }
        },
        "additionalProperties": false
      },
      "JobFailed": {
        "type": "object",
        "required": [
          "id",
          "created_at",
          "updated_at",
          "status",
          "error_code"
        ],
        "properties": {
          "id": {
            "type": "string"
          },
          "created_at": {
            "$ref": "#/components/schemas/Timestamp"
          },
          "updated_at": {
            "$ref": "#/components/schemas/Timestamp"
          },
          "status": {
            "const": "failed"
          },
          "error_code": {
            "type": "string",
            "enum": [
              "account_inactive",
              "organization_suspended",
              "billing_inactive",
              "insufficient_seconds",
              "operation_expired",
              "safety_limit_exceeded",
              "unsupported_media",
              "server_busy",
              "invalid_media_duration",
              "media_too_long",
              "alignment_too_large",
              "acoustic_out_of_media",
              "srt_out_of_media",
              "worker_interrupted",
              "internal_error"
            ]
          }
        },
        "additionalProperties": false
      },
      "Job": {
        "oneOf": [
          {
            "$ref": "#/components/schemas/JobQueued"
          },
          {
            "$ref": "#/components/schemas/JobProcessing"
          },
          {
            "$ref": "#/components/schemas/JobCompleted"
          },
          {
            "$ref": "#/components/schemas/JobFailed"
          },
          {
            "$ref": "#/components/schemas/JobExpired"
          }
        ]
      },
      "ApiError": {
        "type": "object",
        "required": [
          "error",
          "request_id"
        ],
        "properties": {
          "error": {
            "type": "object",
            "required": [
              "code",
              "message"
            ],
            "properties": {
              "code": {
                "type": "string"
              },
              "message": {
                "type": "string"
              }
            },
            "additionalProperties": false
          },
          "request_id": {
            "type": "string"
          }
        },
        "additionalProperties": false
      }
    }
  }
}
