@giveitsmaller/contracts 0.73.0 → 0.78.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (579) hide show
  1. package/README.md +2 -2
  2. package/accepted-options/accepted-options.json +1 -1
  3. package/accepted-options/image-output-routes.json +16 -2
  4. package/asyncapi/README.md +1 -1
  5. package/asyncapi/events.yaml +353 -90
  6. package/availability/availability.json +142 -45
  7. package/code-builder/code-builder-metadata.json +205 -45
  8. package/dist/asyncapi/AnonymousSchema_217.d.ts +6 -0
  9. package/dist/asyncapi/AnonymousSchema_217.js +7 -0
  10. package/dist/asyncapi/ErrorCode.d.ts +1 -0
  11. package/dist/asyncapi/ErrorCode.js +1 -0
  12. package/dist/asyncapi/Failure.d.ts +3 -0
  13. package/dist/asyncapi/LongFormJobMessage.d.ts +1 -0
  14. package/dist/asyncapi/MultiOutputCompletion.d.ts +3 -0
  15. package/dist/asyncapi/OperationMetrics.d.ts +2 -0
  16. package/dist/asyncapi/SingleOutputCompletion.d.ts +3 -0
  17. package/dist/asyncapi/UploadProbeMediaMetadata.d.ts +14 -0
  18. package/dist/asyncapi/index.d.ts +1 -0
  19. package/dist/asyncapi/index.js +1 -0
  20. package/dist/openapi/models/AccountLimitEntry.d.ts +2 -2
  21. package/dist/openapi/models/AccountLimitEntry.js +2 -2
  22. package/dist/openapi/models/AccountLimits.d.ts +2 -2
  23. package/dist/openapi/models/AccountLimits.js +2 -2
  24. package/dist/openapi/models/AccountLimitsLimits.d.ts +14 -2
  25. package/dist/openapi/models/AccountLimitsLimits.js +6 -2
  26. package/dist/openapi/models/AccountLimitsSuccessEnvelope.d.ts +2 -2
  27. package/dist/openapi/models/AccountLimitsSuccessEnvelope.js +2 -2
  28. package/dist/openapi/models/AnonymousOperationNotAllowedResponse.d.ts +145 -0
  29. package/dist/openapi/models/AnonymousOperationNotAllowedResponse.js +82 -0
  30. package/dist/openapi/models/AnonymousQuotaExhaustedResponse.d.ts +131 -0
  31. package/dist/openapi/models/AnonymousQuotaExhaustedResponse.js +77 -0
  32. package/dist/openapi/models/AudioWatermarkDecodeRequest.d.ts +2 -2
  33. package/dist/openapi/models/AudioWatermarkDecodeRequest.js +2 -2
  34. package/dist/openapi/models/AudioWatermarkDecodeResponse.d.ts +2 -2
  35. package/dist/openapi/models/AudioWatermarkDecodeResponse.js +2 -2
  36. package/dist/openapi/models/AuthErrorResponse.d.ts +14 -5
  37. package/dist/openapi/models/AuthErrorResponse.js +2 -2
  38. package/dist/openapi/models/AuthErrorType.d.ts +2 -2
  39. package/dist/openapi/models/AuthErrorType.js +2 -2
  40. package/dist/openapi/models/AuthRejectionEnvelope.d.ts +2 -2
  41. package/dist/openapi/models/AuthRejectionEnvelope.js +2 -2
  42. package/dist/openapi/models/AuthenticatedIdentity.d.ts +2 -2
  43. package/dist/openapi/models/AuthenticatedIdentity.js +2 -2
  44. package/dist/openapi/models/AvailabilityValue.d.ts +2 -2
  45. package/dist/openapi/models/AvailabilityValue.js +2 -2
  46. package/dist/openapi/models/BalanceExhaustedResponse.d.ts +14 -5
  47. package/dist/openapi/models/BalanceExhaustedResponse.js +2 -2
  48. package/dist/openapi/models/BalanceExhaustedResponseAllOfLinks.d.ts +2 -2
  49. package/dist/openapi/models/BalanceExhaustedResponseAllOfLinks.js +2 -2
  50. package/dist/openapi/models/BillingCheckoutRequest.d.ts +2 -2
  51. package/dist/openapi/models/BillingCheckoutRequest.js +2 -2
  52. package/dist/openapi/models/BillingCheckoutSession.d.ts +2 -2
  53. package/dist/openapi/models/BillingCheckoutSession.js +2 -2
  54. package/dist/openapi/models/BillingCheckoutSuccessEnvelope.d.ts +2 -2
  55. package/dist/openapi/models/BillingCheckoutSuccessEnvelope.js +2 -2
  56. package/dist/openapi/models/CallbackEventType.d.ts +2 -2
  57. package/dist/openapi/models/CallbackEventType.js +2 -2
  58. package/dist/openapi/models/CancelAccountDeletion200Response.d.ts +2 -2
  59. package/dist/openapi/models/CancelAccountDeletion200Response.js +2 -2
  60. package/dist/openapi/models/CancelAccountDeletion200ResponseData.d.ts +2 -2
  61. package/dist/openapi/models/CancelAccountDeletion200ResponseData.js +2 -2
  62. package/dist/openapi/models/CapabilityCondition.d.ts +2 -2
  63. package/dist/openapi/models/CapabilityCondition.js +2 -2
  64. package/dist/openapi/models/CapabilityConditionOneOf.d.ts +2 -2
  65. package/dist/openapi/models/CapabilityConditionOneOf.js +2 -2
  66. package/dist/openapi/models/CapabilityConditionOneOf1.d.ts +2 -2
  67. package/dist/openapi/models/CapabilityConditionOneOf1.js +2 -2
  68. package/dist/openapi/models/CapabilityConditionOneOf2.d.ts +2 -2
  69. package/dist/openapi/models/CapabilityConditionOneOf2.js +2 -2
  70. package/dist/openapi/models/CapabilityConditionOneOf3.d.ts +2 -2
  71. package/dist/openapi/models/CapabilityConditionOneOf3.js +2 -2
  72. package/dist/openapi/models/CapabilityConditionOneOf4.d.ts +2 -2
  73. package/dist/openapi/models/CapabilityConditionOneOf4.js +2 -2
  74. package/dist/openapi/models/CapabilityConditionOneOf5.d.ts +2 -2
  75. package/dist/openapi/models/CapabilityConditionOneOf5.js +2 -2
  76. package/dist/openapi/models/CapabilityConditionOneOf6.d.ts +2 -2
  77. package/dist/openapi/models/CapabilityConditionOneOf6.js +2 -2
  78. package/dist/openapi/models/CapabilityConstraint.d.ts +2 -2
  79. package/dist/openapi/models/CapabilityConstraint.js +2 -2
  80. package/dist/openapi/models/CapabilityInputSpec.d.ts +2 -2
  81. package/dist/openapi/models/CapabilityInputSpec.js +2 -2
  82. package/dist/openapi/models/CapabilityProduces.d.ts +2 -2
  83. package/dist/openapi/models/CapabilityProduces.js +2 -2
  84. package/dist/openapi/models/CapabilityProducesOneOf.d.ts +2 -2
  85. package/dist/openapi/models/CapabilityProducesOneOf.js +2 -2
  86. package/dist/openapi/models/CapabilityProducesOneOf1.d.ts +2 -2
  87. package/dist/openapi/models/CapabilityProducesOneOf1.js +2 -2
  88. package/dist/openapi/models/CapabilityProducesOneOf2.d.ts +2 -2
  89. package/dist/openapi/models/CapabilityProducesOneOf2.js +2 -2
  90. package/dist/openapi/models/ChangePasswordRequest.d.ts +2 -2
  91. package/dist/openapi/models/ChangePasswordRequest.js +2 -2
  92. package/dist/openapi/models/CheckoutSessionStatusResponse.d.ts +46 -0
  93. package/dist/openapi/models/CheckoutSessionStatusResponse.js +54 -0
  94. package/dist/openapi/models/CheckoutSessionStatusResponseData.d.ts +50 -0
  95. package/dist/openapi/models/CheckoutSessionStatusResponseData.js +55 -0
  96. package/dist/openapi/models/CodegenSource.d.ts +5 -4
  97. package/dist/openapi/models/CodegenSource.js +2 -2
  98. package/dist/openapi/models/CodegenSourceInput.d.ts +2 -2
  99. package/dist/openapi/models/CodegenSourceInput.js +2 -2
  100. package/dist/openapi/models/CodegenSourceJob.d.ts +2 -2
  101. package/dist/openapi/models/CodegenSourceJob.js +2 -2
  102. package/dist/openapi/models/CodegenSourceJobSource.d.ts +2 -2
  103. package/dist/openapi/models/CodegenSourceJobSource.js +2 -2
  104. package/dist/openapi/models/CodegenSourceOperation.d.ts +2 -2
  105. package/dist/openapi/models/CodegenSourceOperation.js +2 -2
  106. package/dist/openapi/models/CodegenUploadPlaceholder.d.ts +2 -2
  107. package/dist/openapi/models/CodegenUploadPlaceholder.js +2 -2
  108. package/dist/openapi/models/CompositionPlan.d.ts +2 -2
  109. package/dist/openapi/models/CompositionPlan.js +2 -2
  110. package/dist/openapi/models/CompositionPlanJob.d.ts +2 -2
  111. package/dist/openapi/models/CompositionPlanJob.js +2 -2
  112. package/dist/openapi/models/CompositionPlanOperation.d.ts +2 -2
  113. package/dist/openapi/models/CompositionPlanOperation.js +2 -2
  114. package/dist/openapi/models/ConfirmEmailChange200Response.d.ts +2 -2
  115. package/dist/openapi/models/ConfirmEmailChange200Response.js +2 -2
  116. package/dist/openapi/models/ConfirmEmailChange200ResponseData.d.ts +2 -2
  117. package/dist/openapi/models/ConfirmEmailChange200ResponseData.js +2 -2
  118. package/dist/openapi/models/ConfirmEmailChangeRequest.d.ts +2 -2
  119. package/dist/openapi/models/ConfirmEmailChangeRequest.js +2 -2
  120. package/dist/openapi/models/ConnectionSource.d.ts +2 -2
  121. package/dist/openapi/models/ConnectionSource.js +2 -2
  122. package/dist/openapi/models/ContactRequest.d.ts +2 -2
  123. package/dist/openapi/models/ContactRequest.js +2 -2
  124. package/dist/openapi/models/ContactSubject.d.ts +2 -2
  125. package/dist/openapi/models/ContactSubject.js +2 -2
  126. package/dist/openapi/models/ContactValidationErrorResponse.d.ts +2 -2
  127. package/dist/openapi/models/ContactValidationErrorResponse.js +2 -2
  128. package/dist/openapi/models/CreateApiKey201Response.d.ts +2 -2
  129. package/dist/openapi/models/CreateApiKey201Response.js +2 -2
  130. package/dist/openapi/models/CreateApiKey201ResponseData.d.ts +2 -2
  131. package/dist/openapi/models/CreateApiKey201ResponseData.js +2 -2
  132. package/dist/openapi/models/CreateApiKeyRequest.d.ts +2 -2
  133. package/dist/openapi/models/CreateApiKeyRequest.js +2 -2
  134. package/dist/openapi/models/CreateBillingCheckoutSession422Response.d.ts +2 -2
  135. package/dist/openapi/models/CreateBillingCheckoutSession422Response.js +2 -2
  136. package/dist/openapi/models/CreateExternalImport403Response.d.ts +2 -2
  137. package/dist/openapi/models/CreateExternalImport403Response.js +2 -2
  138. package/dist/openapi/models/CreateExternalImport422Response.d.ts +2 -2
  139. package/dist/openapi/models/CreateExternalImport422Response.js +2 -2
  140. package/dist/openapi/models/CreateWorkflow401Response.d.ts +14 -5
  141. package/dist/openapi/models/CreateWorkflow401Response.js +2 -2
  142. package/dist/openapi/models/CreateWorkflow403Response.d.ts +33 -0
  143. package/dist/openapi/models/CreateWorkflow403Response.js +57 -0
  144. package/dist/openapi/models/CreateWorkflow422Response.d.ts +2 -2
  145. package/dist/openapi/models/CreateWorkflow422Response.js +2 -2
  146. package/dist/openapi/models/CreditTransaction.d.ts +22 -12
  147. package/dist/openapi/models/CreditTransaction.js +2 -2
  148. package/dist/openapi/models/CreditTransactionSourceBucket.d.ts +2 -2
  149. package/dist/openapi/models/CreditTransactionSourceBucket.js +2 -2
  150. package/dist/openapi/models/CreditsBalanceResponse.d.ts +2 -2
  151. package/dist/openapi/models/CreditsBalanceResponse.js +2 -2
  152. package/dist/openapi/models/CreditsBalanceSuccessEnvelope.d.ts +2 -2
  153. package/dist/openapi/models/CreditsBalanceSuccessEnvelope.js +2 -2
  154. package/dist/openapi/models/CreditsUsageResponse.d.ts +2 -2
  155. package/dist/openapi/models/CreditsUsageResponse.js +2 -2
  156. package/dist/openapi/models/CreditsUsageSuccessEnvelope.d.ts +2 -2
  157. package/dist/openapi/models/CreditsUsageSuccessEnvelope.js +2 -2
  158. package/dist/openapi/models/Delivery.d.ts +2 -2
  159. package/dist/openapi/models/Delivery.js +2 -2
  160. package/dist/openapi/models/DeliveryOutputRef.d.ts +2 -2
  161. package/dist/openapi/models/DeliveryOutputRef.js +2 -2
  162. package/dist/openapi/models/DeliveryPlan.d.ts +2 -2
  163. package/dist/openapi/models/DeliveryPlan.js +2 -2
  164. package/dist/openapi/models/DeliveryPlanOutput.d.ts +2 -2
  165. package/dist/openapi/models/DeliveryPlanOutput.js +2 -2
  166. package/dist/openapi/models/DeliveryPlanReason.d.ts +2 -2
  167. package/dist/openapi/models/DeliveryPlanReason.js +2 -2
  168. package/dist/openapi/models/DeliverySelection.d.ts +2 -2
  169. package/dist/openapi/models/DeliverySelection.js +2 -2
  170. package/dist/openapi/models/DownloadBundle.d.ts +2 -2
  171. package/dist/openapi/models/DownloadBundle.js +2 -2
  172. package/dist/openapi/models/DroppedOption.d.ts +2 -2
  173. package/dist/openapi/models/DroppedOption.js +2 -2
  174. package/dist/openapi/models/EmailNotify.d.ts +2 -2
  175. package/dist/openapi/models/EmailNotify.js +2 -2
  176. package/dist/openapi/models/EmptySuccessEnvelope.d.ts +2 -2
  177. package/dist/openapi/models/EmptySuccessEnvelope.js +2 -2
  178. package/dist/openapi/models/EndpointProjection.d.ts +2 -2
  179. package/dist/openapi/models/EndpointProjection.js +2 -2
  180. package/dist/openapi/models/EndpointProjectionServersInner.d.ts +2 -2
  181. package/dist/openapi/models/EndpointProjectionServersInner.js +2 -2
  182. package/dist/openapi/models/ErrorEnvelope.d.ts +14 -5
  183. package/dist/openapi/models/ErrorEnvelope.js +2 -2
  184. package/dist/openapi/models/EstimateQuality.d.ts +2 -2
  185. package/dist/openapi/models/EstimateQuality.js +2 -2
  186. package/dist/openapi/models/EstimateRange.d.ts +2 -2
  187. package/dist/openapi/models/EstimateRange.js +2 -2
  188. package/dist/openapi/models/ExportAccountData200Response.d.ts +2 -2
  189. package/dist/openapi/models/ExportAccountData200Response.js +2 -2
  190. package/dist/openapi/models/ExportAccountData200ResponseData.d.ts +5 -4
  191. package/dist/openapi/models/ExportAccountData200ResponseData.js +5 -4
  192. package/dist/openapi/models/ExportAccountData200ResponseDataBilling.d.ts +36 -0
  193. package/dist/openapi/models/ExportAccountData200ResponseDataBilling.js +42 -0
  194. package/dist/openapi/models/ExportAccountData200ResponseDataBillingCheckoutSessionsInner.d.ts +58 -0
  195. package/dist/openapi/models/ExportAccountData200ResponseDataBillingCheckoutSessionsInner.js +62 -0
  196. package/dist/openapi/models/ExternalDestination.d.ts +2 -2
  197. package/dist/openapi/models/ExternalDestination.js +2 -2
  198. package/dist/openapi/models/ExternalImportCreatedResponse.d.ts +2 -2
  199. package/dist/openapi/models/ExternalImportCreatedResponse.js +2 -2
  200. package/dist/openapi/models/ExternalImportCreatedSuccessEnvelope.d.ts +2 -2
  201. package/dist/openapi/models/ExternalImportCreatedSuccessEnvelope.js +2 -2
  202. package/dist/openapi/models/ExternalImportRequest.d.ts +2 -2
  203. package/dist/openapi/models/ExternalImportRequest.js +2 -2
  204. package/dist/openapi/models/ExternalImportToken.d.ts +2 -2
  205. package/dist/openapi/models/ExternalImportToken.js +2 -2
  206. package/dist/openapi/models/ExternalSource.d.ts +2 -2
  207. package/dist/openapi/models/ExternalSource.js +2 -2
  208. package/dist/openapi/models/FeatureNotAvailableResponse.d.ts +14 -5
  209. package/dist/openapi/models/FeatureNotAvailableResponse.js +2 -2
  210. package/dist/openapi/models/FeatureTierRestrictedResponse.d.ts +14 -5
  211. package/dist/openapi/models/FeatureTierRestrictedResponse.js +2 -2
  212. package/dist/openapi/models/FeatureViolation.d.ts +2 -2
  213. package/dist/openapi/models/FeatureViolation.js +2 -2
  214. package/dist/openapi/models/GetProfile200Response.d.ts +2 -2
  215. package/dist/openapi/models/GetProfile200Response.js +2 -2
  216. package/dist/openapi/models/GetProfile200ResponseData.d.ts +2 -2
  217. package/dist/openapi/models/GetProfile200ResponseData.js +2 -2
  218. package/dist/openapi/models/ImageEncodeCapabilities.d.ts +2 -2
  219. package/dist/openapi/models/ImageEncodeCapabilities.js +2 -2
  220. package/dist/openapi/models/JobDefinition.d.ts +2 -2
  221. package/dist/openapi/models/JobDefinition.js +2 -2
  222. package/dist/openapi/models/JobDownload.d.ts +2 -2
  223. package/dist/openapi/models/JobDownload.js +2 -2
  224. package/dist/openapi/models/JobInputV2.d.ts +2 -2
  225. package/dist/openapi/models/JobInputV2.js +2 -2
  226. package/dist/openapi/models/JobMediaClass.d.ts +2 -2
  227. package/dist/openapi/models/JobMediaClass.js +2 -2
  228. package/dist/openapi/models/JobOutputSource.d.ts +2 -2
  229. package/dist/openapi/models/JobOutputSource.js +2 -2
  230. package/dist/openapi/models/JobResponse.d.ts +2 -2
  231. package/dist/openapi/models/JobResponse.js +2 -2
  232. package/dist/openapi/models/JobStatus.d.ts +2 -2
  233. package/dist/openapi/models/JobStatus.js +2 -2
  234. package/dist/openapi/models/JobType.d.ts +2 -2
  235. package/dist/openapi/models/JobType.js +2 -2
  236. package/dist/openapi/models/LivenessResponse.d.ts +2 -2
  237. package/dist/openapi/models/LivenessResponse.js +2 -2
  238. package/dist/openapi/models/LoginUser200Response.d.ts +2 -2
  239. package/dist/openapi/models/LoginUser200Response.js +2 -2
  240. package/dist/openapi/models/LoginUser200ResponseData.d.ts +2 -2
  241. package/dist/openapi/models/LoginUser200ResponseData.js +2 -2
  242. package/dist/openapi/models/LoginUser200ResponseDataUser.d.ts +2 -2
  243. package/dist/openapi/models/LoginUser200ResponseDataUser.js +2 -2
  244. package/dist/openapi/models/LoginUser401Response.d.ts +14 -5
  245. package/dist/openapi/models/LoginUser401Response.js +2 -2
  246. package/dist/openapi/models/LoginUserRequest.d.ts +2 -2
  247. package/dist/openapi/models/LoginUserRequest.js +2 -2
  248. package/dist/openapi/models/LongFormConcurrencyLimitResponse.d.ts +14 -5
  249. package/dist/openapi/models/LongFormConcurrencyLimitResponse.js +2 -2
  250. package/dist/openapi/models/LongFormConcurrencyLimitResponseAllOfLinks.d.ts +2 -2
  251. package/dist/openapi/models/LongFormConcurrencyLimitResponseAllOfLinks.js +2 -2
  252. package/dist/openapi/models/MetadataResponse.d.ts +2 -2
  253. package/dist/openapi/models/MetadataResponse.js +2 -2
  254. package/dist/openapi/models/MetadataResponseDimensions.d.ts +2 -2
  255. package/dist/openapi/models/MetadataResponseDimensions.js +2 -2
  256. package/dist/openapi/models/MetadataResponseExif.d.ts +2 -2
  257. package/dist/openapi/models/MetadataResponseExif.js +2 -2
  258. package/dist/openapi/models/MetadataResponseExifGps.d.ts +2 -2
  259. package/dist/openapi/models/MetadataResponseExifGps.js +2 -2
  260. package/dist/openapi/models/MetadataSuccessEnvelope.d.ts +2 -2
  261. package/dist/openapi/models/MetadataSuccessEnvelope.js +2 -2
  262. package/dist/openapi/models/MimeGroupSchema.d.ts +39 -3
  263. package/dist/openapi/models/MimeGroupSchema.js +12 -2
  264. package/dist/openapi/models/MultiInputSource.d.ts +2 -2
  265. package/dist/openapi/models/MultiInputSource.js +2 -2
  266. package/dist/openapi/models/MultipartCompleteRequest.d.ts +2 -2
  267. package/dist/openapi/models/MultipartCompleteRequest.js +2 -2
  268. package/dist/openapi/models/MultipartCompleteRequestPartsInner.d.ts +2 -2
  269. package/dist/openapi/models/MultipartCompleteRequestPartsInner.js +2 -2
  270. package/dist/openapi/models/MultipartCompleteResponse.d.ts +2 -2
  271. package/dist/openapi/models/MultipartCompleteResponse.js +2 -2
  272. package/dist/openapi/models/MultipartCompleteSuccessEnvelope.d.ts +2 -2
  273. package/dist/openapi/models/MultipartCompleteSuccessEnvelope.js +2 -2
  274. package/dist/openapi/models/MultipartInitiateRequestMetadataHint.d.ts +2 -2
  275. package/dist/openapi/models/MultipartInitiateRequestMetadataHint.js +2 -2
  276. package/dist/openapi/models/MultipartInitiateResponse.d.ts +2 -2
  277. package/dist/openapi/models/MultipartInitiateResponse.js +2 -2
  278. package/dist/openapi/models/MultipartInitiateSuccessEnvelope.d.ts +2 -2
  279. package/dist/openapi/models/MultipartInitiateSuccessEnvelope.js +2 -2
  280. package/dist/openapi/models/MultipartKeepaliveResponse.d.ts +2 -2
  281. package/dist/openapi/models/MultipartKeepaliveResponse.js +2 -2
  282. package/dist/openapi/models/MultipartKeepaliveSuccessEnvelope.d.ts +2 -2
  283. package/dist/openapi/models/MultipartKeepaliveSuccessEnvelope.js +2 -2
  284. package/dist/openapi/models/MultipartPartListing.d.ts +2 -2
  285. package/dist/openapi/models/MultipartPartListing.js +2 -2
  286. package/dist/openapi/models/MultipartPresignRequest.d.ts +2 -2
  287. package/dist/openapi/models/MultipartPresignRequest.js +2 -2
  288. package/dist/openapi/models/MultipartPresignResponse.d.ts +2 -2
  289. package/dist/openapi/models/MultipartPresignResponse.js +2 -2
  290. package/dist/openapi/models/MultipartPresignSuccessEnvelope.d.ts +2 -2
  291. package/dist/openapi/models/MultipartPresignSuccessEnvelope.js +2 -2
  292. package/dist/openapi/models/MultipartStatusResponse.d.ts +2 -2
  293. package/dist/openapi/models/MultipartStatusResponse.js +2 -2
  294. package/dist/openapi/models/MultipartStatusSuccessEnvelope.d.ts +2 -2
  295. package/dist/openapi/models/MultipartStatusSuccessEnvelope.js +2 -2
  296. package/dist/openapi/models/NotifyConfig.d.ts +9 -5
  297. package/dist/openapi/models/NotifyConfig.js +2 -2
  298. package/dist/openapi/models/OperationCapability.d.ts +2 -2
  299. package/dist/openapi/models/OperationCapability.js +2 -2
  300. package/dist/openapi/models/OperationDefinition.d.ts +2 -2
  301. package/dist/openapi/models/OperationDefinition.js +2 -2
  302. package/dist/openapi/models/OperationDownload.d.ts +6 -2
  303. package/dist/openapi/models/OperationDownload.js +2 -2
  304. package/dist/openapi/models/OperationInputModel.d.ts +2 -2
  305. package/dist/openapi/models/OperationInputModel.js +2 -2
  306. package/dist/openapi/models/OperationMessageParamsValue.d.ts +25 -0
  307. package/dist/openapi/models/OperationMessageParamsValue.js +31 -0
  308. package/dist/openapi/models/OperationResponse.d.ts +36 -2
  309. package/dist/openapi/models/OperationResponse.js +8 -2
  310. package/dist/openapi/models/OperationResult.d.ts +2 -2
  311. package/dist/openapi/models/OperationResult.js +2 -2
  312. package/dist/openapi/models/OperationResultMetadata.d.ts +29 -3
  313. package/dist/openapi/models/OperationResultMetadata.js +6 -2
  314. package/dist/openapi/models/OperationResultMetrics.d.ts +4 -4
  315. package/dist/openapi/models/OperationResultMetrics.js +2 -2
  316. package/dist/openapi/models/OperationSchemaDefinition.d.ts +5 -6
  317. package/dist/openapi/models/OperationSchemaDefinition.js +2 -2
  318. package/dist/openapi/models/OperationStatus.d.ts +2 -2
  319. package/dist/openapi/models/OperationStatus.js +2 -2
  320. package/dist/openapi/models/OperationType.d.ts +10 -4
  321. package/dist/openapi/models/OperationType.js +10 -4
  322. package/dist/openapi/models/OperationsSchemaResponse.d.ts +2 -2
  323. package/dist/openapi/models/OperationsSchemaResponse.js +2 -2
  324. package/dist/openapi/models/OperationsSchemaResponseWorkflowFeatures.d.ts +2 -2
  325. package/dist/openapi/models/OperationsSchemaResponseWorkflowFeatures.js +2 -2
  326. package/dist/openapi/models/OperationsSchemaResponseWorkflowFeaturesDelivery.d.ts +2 -2
  327. package/dist/openapi/models/OperationsSchemaResponseWorkflowFeaturesDelivery.js +2 -2
  328. package/dist/openapi/models/OperationsSchemaResponseWorkflowFeaturesDeliveryMode.d.ts +2 -2
  329. package/dist/openapi/models/OperationsSchemaResponseWorkflowFeaturesDeliveryMode.js +2 -2
  330. package/dist/openapi/models/OperationsSchemaResponseWorkflowFeaturesDeliverySelection.d.ts +2 -2
  331. package/dist/openapi/models/OperationsSchemaResponseWorkflowFeaturesDeliverySelection.js +2 -2
  332. package/dist/openapi/models/OperationsSchemaResponseWorkflowFeaturesProcessing.d.ts +2 -2
  333. package/dist/openapi/models/OperationsSchemaResponseWorkflowFeaturesProcessing.js +2 -2
  334. package/dist/openapi/models/OptionSchema.d.ts +40 -3
  335. package/dist/openapi/models/OptionSchema.js +10 -2
  336. package/dist/openapi/models/OutputProperties.d.ts +2 -2
  337. package/dist/openapi/models/OutputProperties.js +2 -2
  338. package/dist/openapi/models/OutputPropertiesIsAnimated.d.ts +2 -2
  339. package/dist/openapi/models/OutputPropertiesIsAnimated.js +2 -2
  340. package/dist/openapi/models/PerClassAvailabilityEntry.d.ts +2 -2
  341. package/dist/openapi/models/PerClassAvailabilityEntry.js +2 -2
  342. package/dist/openapi/models/PerRoleCardinalityEntry.d.ts +2 -2
  343. package/dist/openapi/models/PerRoleCardinalityEntry.js +2 -2
  344. package/dist/openapi/models/PerValueAvailabilityEntry.d.ts +2 -2
  345. package/dist/openapi/models/PerValueAvailabilityEntry.js +2 -2
  346. package/dist/openapi/models/PresignedUrlPart.d.ts +2 -2
  347. package/dist/openapi/models/PresignedUrlPart.js +2 -2
  348. package/dist/openapi/models/ProbePendingResponse.d.ts +14 -5
  349. package/dist/openapi/models/ProbePendingResponse.js +2 -2
  350. package/dist/openapi/models/ProcessingClass.d.ts +2 -2
  351. package/dist/openapi/models/ProcessingClass.js +2 -2
  352. package/dist/openapi/models/ProcessingClassBandViolation.d.ts +13 -2
  353. package/dist/openapi/models/ProcessingClassBandViolation.js +5 -2
  354. package/dist/openapi/models/ProcessingClassConstraints.d.ts +2 -2
  355. package/dist/openapi/models/ProcessingClassConstraints.js +2 -2
  356. package/dist/openapi/models/ProcessingClassEntry.d.ts +16 -2
  357. package/dist/openapi/models/ProcessingClassEntry.js +8 -2
  358. package/dist/openapi/models/ProcessingClassEntryInputUniformity.d.ts +65 -0
  359. package/dist/openapi/models/ProcessingClassEntryInputUniformity.js +57 -0
  360. package/dist/openapi/models/ProcessingClassEntryResolutionBands.d.ts +66 -0
  361. package/dist/openapi/models/ProcessingClassEntryResolutionBands.js +56 -0
  362. package/dist/openapi/models/ProcessingClassExceedsBandResponse.d.ts +14 -5
  363. package/dist/openapi/models/ProcessingClassExceedsBandResponse.js +2 -2
  364. package/dist/openapi/models/ProcessingClassHint.d.ts +2 -2
  365. package/dist/openapi/models/ProcessingClassHint.js +2 -2
  366. package/dist/openapi/models/ProcessingClassReason.d.ts +2 -2
  367. package/dist/openapi/models/ProcessingClassReason.js +2 -2
  368. package/dist/openapi/models/ProcessingClassRejectReason.d.ts +2 -2
  369. package/dist/openapi/models/ProcessingClassRejectReason.js +2 -2
  370. package/dist/openapi/models/ProcessingPlan.d.ts +2 -2
  371. package/dist/openapi/models/ProcessingPlan.js +2 -2
  372. package/dist/openapi/models/ProcessingPlanJob.d.ts +15 -2
  373. package/dist/openapi/models/ProcessingPlanJob.js +5 -2
  374. package/dist/openapi/models/ReEncodeDecision.d.ts +19 -8
  375. package/dist/openapi/models/ReEncodeDecision.js +19 -8
  376. package/dist/openapi/models/ReadinessResponse.d.ts +2 -2
  377. package/dist/openapi/models/ReadinessResponse.js +2 -2
  378. package/dist/openapi/models/RegisterUser422Response.d.ts +2 -2
  379. package/dist/openapi/models/RegisterUser422Response.js +2 -2
  380. package/dist/openapi/models/RegisterUserRequest.d.ts +2 -2
  381. package/dist/openapi/models/RegisterUserRequest.js +2 -2
  382. package/dist/openapi/models/RequestAccountDeletion200Response.d.ts +2 -2
  383. package/dist/openapi/models/RequestAccountDeletion200Response.js +2 -2
  384. package/dist/openapi/models/RequestAccountDeletion200ResponseData.d.ts +2 -2
  385. package/dist/openapi/models/RequestAccountDeletion200ResponseData.js +2 -2
  386. package/dist/openapi/models/RequestAccountDeletionRequest.d.ts +2 -2
  387. package/dist/openapi/models/RequestAccountDeletionRequest.js +2 -2
  388. package/dist/openapi/models/ResendVerificationEmailRequest.d.ts +2 -2
  389. package/dist/openapi/models/ResendVerificationEmailRequest.js +2 -2
  390. package/dist/openapi/models/ResetPasswordRequest.d.ts +2 -2
  391. package/dist/openapi/models/ResetPasswordRequest.js +2 -2
  392. package/dist/openapi/models/ResolutionBand.d.ts +44 -0
  393. package/dist/openapi/models/ResolutionBand.js +62 -0
  394. package/dist/openapi/models/ResolutionBandCeiling.d.ts +68 -0
  395. package/dist/openapi/models/ResolutionBandCeiling.js +57 -0
  396. package/dist/openapi/models/ResolutionBandCeilingConstraints.d.ts +32 -0
  397. package/dist/openapi/models/ResolutionBandCeilingConstraints.js +41 -0
  398. package/dist/openapi/models/ResolutionBandCeilingDerivation.d.ts +48 -0
  399. package/dist/openapi/models/ResolutionBandCeilingDerivation.js +51 -0
  400. package/dist/openapi/models/ResponseEnvelope.d.ts +2 -2
  401. package/dist/openapi/models/ResponseEnvelope.js +2 -2
  402. package/dist/openapi/models/RetryResponse.d.ts +2 -2
  403. package/dist/openapi/models/RetryResponse.js +2 -2
  404. package/dist/openapi/models/RetrySuccessEnvelope.d.ts +2 -2
  405. package/dist/openapi/models/RetrySuccessEnvelope.js +2 -2
  406. package/dist/openapi/models/SseCompletionBase.d.ts +2 -2
  407. package/dist/openapi/models/SseCompletionBase.js +2 -2
  408. package/dist/openapi/models/SseConnectionLimitResponse.d.ts +14 -5
  409. package/dist/openapi/models/SseConnectionLimitResponse.js +2 -2
  410. package/dist/openapi/models/SseEventType.d.ts +2 -2
  411. package/dist/openapi/models/SseEventType.js +2 -2
  412. package/dist/openapi/models/SseJobCompletedData.d.ts +2 -2
  413. package/dist/openapi/models/SseJobCompletedData.js +2 -2
  414. package/dist/openapi/models/SseJobFailedData.d.ts +2 -2
  415. package/dist/openapi/models/SseJobFailedData.js +2 -2
  416. package/dist/openapi/models/SseMultiOutputCompletion.d.ts +2 -2
  417. package/dist/openapi/models/SseMultiOutputCompletion.js +2 -2
  418. package/dist/openapi/models/SseMultiOutputCompletionMetrics.d.ts +2 -2
  419. package/dist/openapi/models/SseMultiOutputCompletionMetrics.js +2 -2
  420. package/dist/openapi/models/SseMultiOutputCompletionWithKind.d.ts +2 -2
  421. package/dist/openapi/models/SseMultiOutputCompletionWithKind.js +2 -2
  422. package/dist/openapi/models/SseMultiOutputResultEntry.d.ts +6 -2
  423. package/dist/openapi/models/SseMultiOutputResultEntry.js +2 -2
  424. package/dist/openapi/models/SseOperationCompletedData.d.ts +2 -2
  425. package/dist/openapi/models/SseOperationCompletedData.js +2 -2
  426. package/dist/openapi/models/SseOperationCompletionResult.d.ts +2 -2
  427. package/dist/openapi/models/SseOperationCompletionResult.js +2 -2
  428. package/dist/openapi/models/SseOperationFailedData.d.ts +33 -2
  429. package/dist/openapi/models/SseOperationFailedData.js +8 -2
  430. package/dist/openapi/models/SseOperationProgressData.d.ts +2 -2
  431. package/dist/openapi/models/SseOperationProgressData.js +2 -2
  432. package/dist/openapi/models/SseSingleOutputCompletion.d.ts +2 -2
  433. package/dist/openapi/models/SseSingleOutputCompletion.js +2 -2
  434. package/dist/openapi/models/SseWorkflowTerminalData.d.ts +2 -2
  435. package/dist/openapi/models/SseWorkflowTerminalData.js +2 -2
  436. package/dist/openapi/models/TierRestrictionKind.d.ts +2 -2
  437. package/dist/openapi/models/TierRestrictionKind.js +2 -2
  438. package/dist/openapi/models/TierRestrictionResponse.d.ts +14 -5
  439. package/dist/openapi/models/TierRestrictionResponse.js +2 -2
  440. package/dist/openapi/models/UpdateProfile200Response.d.ts +2 -2
  441. package/dist/openapi/models/UpdateProfile200Response.js +2 -2
  442. package/dist/openapi/models/UpdateProfile200ResponseData.d.ts +2 -2
  443. package/dist/openapi/models/UpdateProfile200ResponseData.js +2 -2
  444. package/dist/openapi/models/UpdateProfile422Response.d.ts +2 -2
  445. package/dist/openapi/models/UpdateProfile422Response.js +2 -2
  446. package/dist/openapi/models/UpdateProfileRequest.d.ts +2 -2
  447. package/dist/openapi/models/UpdateProfileRequest.js +2 -2
  448. package/dist/openapi/models/UploadConstraintsApplied.d.ts +2 -2
  449. package/dist/openapi/models/UploadConstraintsApplied.js +2 -2
  450. package/dist/openapi/models/UploadDurationExceedsTierResponse.d.ts +14 -5
  451. package/dist/openapi/models/UploadDurationExceedsTierResponse.js +2 -2
  452. package/dist/openapi/models/UploadFile403Response.d.ts +2 -2
  453. package/dist/openapi/models/UploadFile403Response.js +2 -2
  454. package/dist/openapi/models/UploadFile422Response.d.ts +2 -2
  455. package/dist/openapi/models/UploadFile422Response.js +2 -2
  456. package/dist/openapi/models/UploadProbeMediaMetadata.d.ts +107 -2
  457. package/dist/openapi/models/UploadProbeMediaMetadata.js +36 -2
  458. package/dist/openapi/models/UploadProbeProcessingClass.d.ts +4 -6
  459. package/dist/openapi/models/UploadProbeProcessingClass.js +4 -6
  460. package/dist/openapi/models/UploadProbeResponse.d.ts +2 -2
  461. package/dist/openapi/models/UploadProbeResponse.js +2 -2
  462. package/dist/openapi/models/UploadProbeStatus.d.ts +2 -2
  463. package/dist/openapi/models/UploadProbeStatus.js +2 -2
  464. package/dist/openapi/models/UploadProbeSuccessEnvelope.d.ts +2 -2
  465. package/dist/openapi/models/UploadProbeSuccessEnvelope.js +2 -2
  466. package/dist/openapi/models/UploadResponse.d.ts +2 -2
  467. package/dist/openapi/models/UploadResponse.js +2 -2
  468. package/dist/openapi/models/UploadSizeExceedsTierResponse.d.ts +14 -5
  469. package/dist/openapi/models/UploadSizeExceedsTierResponse.js +2 -2
  470. package/dist/openapi/models/UploadSource.d.ts +2 -2
  471. package/dist/openapi/models/UploadSource.js +2 -2
  472. package/dist/openapi/models/UploadSuccessEnvelope.d.ts +2 -2
  473. package/dist/openapi/models/UploadSuccessEnvelope.js +2 -2
  474. package/dist/openapi/models/UploadThresholds.d.ts +2 -2
  475. package/dist/openapi/models/UploadThresholds.js +2 -2
  476. package/dist/openapi/models/UserTier.d.ts +2 -2
  477. package/dist/openapi/models/UserTier.js +2 -2
  478. package/dist/openapi/models/ValidationErrorEnvelope.d.ts +19 -8
  479. package/dist/openapi/models/ValidationErrorEnvelope.js +2 -2
  480. package/dist/openapi/models/ValidationErrorEnvelopeDetailsInner.d.ts +2 -2
  481. package/dist/openapi/models/ValidationErrorEnvelopeDetailsInner.js +2 -2
  482. package/dist/openapi/models/VerifyEmailRequest.d.ts +2 -2
  483. package/dist/openapi/models/VerifyEmailRequest.js +2 -2
  484. package/dist/openapi/models/WarningType.d.ts +2 -2
  485. package/dist/openapi/models/WarningType.js +2 -2
  486. package/dist/openapi/models/WebhookOperationContext.d.ts +2 -2
  487. package/dist/openapi/models/WebhookOperationContext.js +2 -2
  488. package/dist/openapi/models/WebhookPayload.d.ts +2 -2
  489. package/dist/openapi/models/WebhookPayload.js +2 -2
  490. package/dist/openapi/models/WorkflowArchiveResponse.d.ts +2 -2
  491. package/dist/openapi/models/WorkflowArchiveResponse.js +2 -2
  492. package/dist/openapi/models/WorkflowArchiveSuccessEnvelope.d.ts +2 -2
  493. package/dist/openapi/models/WorkflowArchiveSuccessEnvelope.js +2 -2
  494. package/dist/openapi/models/WorkflowCancelBillingEffect.d.ts +7 -6
  495. package/dist/openapi/models/WorkflowCancelBillingEffect.js +7 -6
  496. package/dist/openapi/models/WorkflowCancelResponse.d.ts +2 -2
  497. package/dist/openapi/models/WorkflowCancelResponse.js +2 -2
  498. package/dist/openapi/models/WorkflowCancelSuccessEnvelope.d.ts +2 -2
  499. package/dist/openapi/models/WorkflowCancelSuccessEnvelope.js +2 -2
  500. package/dist/openapi/models/WorkflowCreateRequest.d.ts +11 -14
  501. package/dist/openapi/models/WorkflowCreateRequest.js +2 -2
  502. package/dist/openapi/models/WorkflowCreateResponse.d.ts +2 -2
  503. package/dist/openapi/models/WorkflowCreateResponse.js +2 -2
  504. package/dist/openapi/models/WorkflowCreateSuccessEnvelope.d.ts +2 -2
  505. package/dist/openapi/models/WorkflowCreateSuccessEnvelope.js +2 -2
  506. package/dist/openapi/models/WorkflowCreditSummary.d.ts +2 -2
  507. package/dist/openapi/models/WorkflowCreditSummary.js +2 -2
  508. package/dist/openapi/models/WorkflowDownloadResponse.d.ts +2 -2
  509. package/dist/openapi/models/WorkflowDownloadResponse.js +2 -2
  510. package/dist/openapi/models/WorkflowDownloadSuccessEnvelope.d.ts +2 -2
  511. package/dist/openapi/models/WorkflowDownloadSuccessEnvelope.js +2 -2
  512. package/dist/openapi/models/WorkflowEdge.d.ts +2 -2
  513. package/dist/openapi/models/WorkflowEdge.js +2 -2
  514. package/dist/openapi/models/WorkflowExpiredResponse.d.ts +14 -5
  515. package/dist/openapi/models/WorkflowExpiredResponse.js +2 -2
  516. package/dist/openapi/models/WorkflowListResponse.d.ts +2 -2
  517. package/dist/openapi/models/WorkflowListResponse.js +2 -2
  518. package/dist/openapi/models/WorkflowListSuccessEnvelope.d.ts +2 -2
  519. package/dist/openapi/models/WorkflowListSuccessEnvelope.js +2 -2
  520. package/dist/openapi/models/WorkflowPauseRequiredAction.d.ts +18 -6
  521. package/dist/openapi/models/WorkflowPauseRequiredAction.js +19 -7
  522. package/dist/openapi/models/WorkflowPausedDetail.d.ts +6 -5
  523. package/dist/openapi/models/WorkflowPausedDetail.js +2 -2
  524. package/dist/openapi/models/WorkflowPausedDetailLinks.d.ts +7 -5
  525. package/dist/openapi/models/WorkflowPausedDetailLinks.js +2 -2
  526. package/dist/openapi/models/WorkflowProcessing.d.ts +2 -2
  527. package/dist/openapi/models/WorkflowProcessing.js +2 -2
  528. package/dist/openapi/models/WorkflowRestoreResponse.d.ts +2 -2
  529. package/dist/openapi/models/WorkflowRestoreResponse.js +2 -2
  530. package/dist/openapi/models/WorkflowRestoreSuccessEnvelope.d.ts +2 -2
  531. package/dist/openapi/models/WorkflowRestoreSuccessEnvelope.js +2 -2
  532. package/dist/openapi/models/WorkflowResumeResponse.d.ts +2 -2
  533. package/dist/openapi/models/WorkflowResumeResponse.js +2 -2
  534. package/dist/openapi/models/WorkflowResumeSuccessEnvelope.d.ts +2 -2
  535. package/dist/openapi/models/WorkflowResumeSuccessEnvelope.js +2 -2
  536. package/dist/openapi/models/WorkflowSource.d.ts +2 -2
  537. package/dist/openapi/models/WorkflowSource.js +2 -2
  538. package/dist/openapi/models/WorkflowStatus.d.ts +10 -5
  539. package/dist/openapi/models/WorkflowStatus.js +10 -5
  540. package/dist/openapi/models/WorkflowStatusResponse.d.ts +5 -3
  541. package/dist/openapi/models/WorkflowStatusResponse.js +2 -2
  542. package/dist/openapi/models/WorkflowStatusSuccessEnvelope.d.ts +2 -2
  543. package/dist/openapi/models/WorkflowStatusSuccessEnvelope.js +2 -2
  544. package/dist/openapi/models/WorkflowSummary.d.ts +2 -2
  545. package/dist/openapi/models/WorkflowSummary.js +2 -2
  546. package/dist/openapi/models/WorkflowSummaryJob.d.ts +2 -2
  547. package/dist/openapi/models/WorkflowSummaryJob.js +2 -2
  548. package/dist/openapi/models/WorkflowWarning.d.ts +2 -2
  549. package/dist/openapi/models/WorkflowWarning.js +2 -2
  550. package/dist/openapi/models/WorkflowWarningSeverity.d.ts +2 -2
  551. package/dist/openapi/models/WorkflowWarningSeverity.js +2 -2
  552. package/dist/openapi/models/index.d.ts +14 -0
  553. package/dist/openapi/models/index.js +14 -0
  554. package/dist/openapi/runtime.d.ts +2 -2
  555. package/dist/openapi/runtime.js +2 -2
  556. package/dist/operations/archive.metadata.js +1 -0
  557. package/dist/operations/audio_overlay.metadata.js +1 -0
  558. package/dist/operations/audio_to_video.metadata.js +1 -0
  559. package/dist/operations/audio_watermark.metadata.js +4 -9
  560. package/dist/operations/custom_luma.metadata.js +1 -0
  561. package/dist/operations/image_watermark.metadata.js +1 -0
  562. package/dist/operations/merge.metadata.js +1 -0
  563. package/dist/operations/metadata-types.d.ts +2 -0
  564. package/dist/operations/split.metadata.js +12 -3
  565. package/dist/operations/text_watermark.metadata.js +1 -0
  566. package/dist/operations/video_text_watermark.metadata.js +2 -0
  567. package/dist/operations/video_watermark.metadata.js +1 -0
  568. package/openapi/README.md +1 -1
  569. package/openapi/api.yaml +1089 -172
  570. package/operation-capabilities/operation-capabilities.json +129 -1
  571. package/operations/schemas/audio_watermark.yaml +34 -33
  572. package/operations/schemas/compress.yaml +295 -177
  573. package/operations/schemas/convert.yaml +11 -0
  574. package/operations/schemas/merge.yaml +35 -1
  575. package/operations/schemas/split.yaml +144 -88
  576. package/operations/schemas/thumbnail.yaml +34 -26
  577. package/operations/schemas/video_text_watermark.yaml +112 -47
  578. package/operations/schemas/video_watermark.yaml +33 -28
  579. package/package.json +3 -3
package/openapi/api.yaml CHANGED
@@ -35,6 +35,20 @@ info:
35
35
  (parser obligation: absent = stable; per-enum-value granularity is the
36
36
  `per_value_availability` primitive landed via ticket I17).
37
37
 
38
+ **Free-text string fields: `x-string-vocabulary` (ticket
39
+ [`Q79yjcFF`](https://trello.com/c/Q79yjcFF)).** A `type: string` field
40
+ with no `enum` that names example values says, as data, what a client
41
+ may do with them (the same marker is used in the AsyncAPI document):
42
+ - `open` — a vocabulary that grows. Each published value keeps its
43
+ meaning, the SET is not closed: switch on the values you know and
44
+ handle an unknown one as the generic case (e.g. `ErrorEnvelope.error`).
45
+ - `advisory` — explanatory text. Display or log it; **never switch on
46
+ it** (e.g. `SseWorkflowTerminalData.reason`).
47
+ - `none` — not a vocabulary at all (an expression or an identifier,
48
+ e.g. `OptionSchema.pattern`).
49
+ A field whose description hedges with "common values" or "free-form"
50
+ must carry the marker; a test enforces it.
51
+
38
52
  **Localisation (per ticket [I26](https://trello.com/c/rcnqwgI4)).**
39
53
 
40
54
  Error responses + paused/blocked workflow statuses carry a localised
@@ -89,7 +103,7 @@ info:
89
103
  of truth instead of hardcoding magic numbers. A runtime
90
104
  `GET /api/uploads/limits` endpoint for dynamic discovery
91
105
  (per-tier / per-environment overrides) is a deferred follow-up.
92
- version: 2.208.0
106
+ version: 2.213.0
93
107
  contact:
94
108
  name: API Support
95
109
 
@@ -250,8 +264,16 @@ paths:
250
264
  tier_restriction, restriction_kind: file_size` instead.
251
265
  - **Pixel dimensions** (`error: IMAGE_DIMENSIONS_TOO_LARGE`) — a
252
266
  decodable raster image whose `width × height` exceeds the
253
- configured pixel ceiling (`UPLOAD_MAX_IMAGE_PIXELS`, default
254
- 16 MP). The server reads dimensions from the file **header** (no
267
+ SINGLE-SHOT pixel ceiling (`UPLOAD_MAX_IMAGE_PIXELS`, default
268
+ 16 MP), sized for the API's inline decode on this endpoint.
269
+ Multipart uploads have their own, higher ceiling
270
+ (`limits.max_multipart_upload_image_pixels`). It is an
271
+ environment setting, so an **authenticated**
272
+ client should read the effective value from
273
+ `limits.max_upload_image_pixels` on `GET /api/v2/account/limits`
274
+ (once the API emits it) rather than hard-code a number. ⚠️ That
275
+ endpoint requires authentication, so an **anonymous** uploader has
276
+ no discovery surface for it yet and learns it from this 413. The server reads dimensions from the file **header** (no
255
277
  full-bitmap decode) and rejects **before** decoding, so a
256
278
  within-byte-limit but huge-dimension image (e.g. a few-KB 26 MP
257
279
  PNG that would decode to ~100 MB) is rejected up front rather than
@@ -276,17 +298,21 @@ paths:
276
298
  '415':
277
299
  description: |
278
300
  Unsupported file type at the contract level (no tier permits
279
- this MIME). For tier-specific MIME restrictions where some
280
- tier does permit the MIME, the server returns 403 with
281
- `error_type: tier_restriction, restriction_kind: mime_type`
282
- instead.
301
+ this MIME): `error: UNSUPPORTED_FILE_TYPE`, flat envelope, never
302
+ retryable and never an upgrade prompt. For tier-specific MIME
303
+ restrictions where some tier does permit the MIME, the server
304
+ returns 403 with `error_type: tier_restriction, restriction_kind:
305
+ mime_type` instead. The file-type check runs before the size
306
+ check, so an unsupported file that is also too large gets this
307
+ 415.
283
308
  content:
284
309
  application/json:
285
310
  schema:
286
311
  $ref: '#/components/schemas/ErrorEnvelope'
287
312
  example:
288
313
  success: false
289
- error: "Unsupported MIME type: application/x-msdownload"
314
+ error: "UNSUPPORTED_FILE_TYPE"
315
+ message: "This file type is not supported."
290
316
  '422':
291
317
  description: |
292
318
  Tier-relative cap exceeded for this upload per ticket
@@ -461,11 +487,22 @@ paths:
461
487
  (across all tiers). For tier-specific size caps below this
462
488
  absolute limit, the server returns 403 with
463
489
  `error_type: tier_restriction, restriction_kind: file_size`.
464
- - **Pixel dimensions** (`error: IMAGE_DIMENSIONS_TOO_LARGE`) — as
465
- declared on `POST /api/uploads`: a decodable raster image whose
466
- `width x height` exceeds the configured pixel ceiling
467
- (`UPLOAD_MAX_IMAGE_PIXELS`, default 16 MP), read from the file
468
- **header** and rejected **before** decoding.
490
+ - **Pixel dimensions** (`error: IMAGE_DIMENSIONS_TOO_LARGE`) — a
491
+ decodable raster image whose `width x height` exceeds the
492
+ MULTIPART pixel ceiling, read from the file **header** and
493
+ rejected **before** decoding. It is a SEPARATE, HIGHER ceiling
494
+ than single-shot's 16 MP (owner ruling 2026-09-24, card
495
+ [`ae4Q1yCb`](https://trello.com/c/ae4Q1yCb)): single-shot's is
496
+ sized for the API's inline decode, which multipart never does,
497
+ and multipart carries ordinary camera photos — **a 24 MP photo
498
+ must pass**. API setting `UPLOAD_MAX_MULTIPART_IMAGE_PIXELS`,
499
+ enforced at multipart initiate. Default 50 MP (hub ruling 2026-09-24, on lambdas'
500
+ recommendation: the image workers declare a 100 MP source cap,
501
+ but none has run a job that large, so it stays at half that
502
+ until a staging proof). It is an API setting, so authenticated
503
+ clients read the effective value from
504
+ `limits.max_multipart_upload_image_pixels`
505
+ (`GET /api/v2/account/limits`) once the API emits it.
469
506
 
470
507
  🔴 **THIS CASE WAS UNDECLARED HERE UNTIL 2026-08-28, AND THIS IS
471
508
  THE PATH IT MATTERS MOST ON.** Multipart exists for LARGE uploads,
@@ -480,9 +517,11 @@ paths:
480
517
  $ref: '#/components/schemas/ErrorEnvelope'
481
518
  '415':
482
519
  description: |
483
- Unsupported file type at the contract level. For tier-specific
484
- MIME restrictions, the server returns 403 with
485
- `error_type: tier_restriction, restriction_kind: mime_type`.
520
+ Unsupported file type at the contract level (no tier permits
521
+ this MIME): `error: UNSUPPORTED_FILE_TYPE`, as on
522
+ `POST /api/uploads`. For tier-specific MIME restrictions, the
523
+ server returns 403 with `error_type: tier_restriction,
524
+ restriction_kind: mime_type`.
486
525
  content:
487
526
  application/json:
488
527
  schema:
@@ -1032,9 +1071,13 @@ paths:
1032
1071
  bad ones before submit.
1033
1072
 
1034
1073
  Per ticket [I28 `KbVAnGCm`](https://trello.com/c/KbVAnGCm).
1035
- `availability: planned` until the cross-repo Lambda support
1036
- ships; the runtime returns `feature_not_available` (422)
1037
- until then. Per Tension 1 (ADR-0001 §1.3).
1074
+ `availability: planned`. The upload-probe Lambda exists and runs
1075
+ asynchronously when an upload is finalised; this endpoint returns
1076
+ the cached result when one exists and `feature_not_available`
1077
+ (422) when none does yet. It does not invoke the probe itself.
1078
+ (A `planned` endpoint that answers 200 is inconsistent with the
1079
+ availability taxonomy; the flip decision is tracked separately,
1080
+ card `kAT0i5A6`.) Per Tension 1 (ADR-0001 §1.3).
1038
1081
 
1039
1082
  **SDK helper intent.** SDKs are expected to expose a
1040
1083
  `client.preflight_clips([file_ids])` helper that compiles to N
@@ -1045,11 +1088,10 @@ paths:
1045
1088
  **Tier scoping.** The probe respects the caller's tier — the
1046
1089
  `processing_class_pre_assignment` reflects the same logic
1047
1090
  F8.1 upload-side gating uses (per ticket I15-CONS), which
1048
- honours a class's `required_tier`. **Since 2026-09-23 no callable
1049
- video class carries one** (decision 26, `jLuZvlJe`; only the
1050
- `planned` `audio_watermark` keeps `enterprise`), so for every
1051
- callable class the pre-assignment depends on the file's duration
1052
- and size, not on the caller's tier.
1091
+ honours a class's `required_tier`. **Since 2026-09-23 no class
1092
+ carries one** (decision 26, `jLuZvlJe`, `UAQJcOi7`), so the
1093
+ pre-assignment depends on the file's duration and size, not on
1094
+ the caller's tier.
1053
1095
 
1054
1096
  **Idempotent.** Probing the same file_id twice returns the
1055
1097
  same `probed_at` timestamp + result (cached server-side per
@@ -1154,8 +1196,8 @@ paths:
1154
1196
  $ref: '#/components/schemas/ErrorEnvelope'
1155
1197
  '422':
1156
1198
  description: |
1157
- The endpoint is `availability: planned` and the runtime
1158
- Lambda has not yet shipped — returned as
1199
+ No probe result is cached for this upload yet (the probe runs
1200
+ asynchronously after the upload is finalised) — returned as
1159
1201
  `FeatureNotAvailableResponse` with `error_type:
1160
1202
  feature_not_available`. Per Tension 1 (ADR-0001 §1.3).
1161
1203
  content:
@@ -1740,17 +1782,32 @@ paths:
1740
1782
  more operations / mime_groups / options gated by a higher
1741
1783
  subscription tier than the caller has. Each violation is
1742
1784
  listed in `violations[]` with `required_tier` populated.
1785
+ - `anonymous_operation_not_allowed`: an ANONYMOUS caller (no
1786
+ credential) requested an operation outside the anonymous
1787
+ allow-list. `operation` names the first such operation.
1788
+ A register-wall: signing in is the remedy, not upgrading.
1789
+ - `anonymous_quota_exhausted`: an anonymous caller has used
1790
+ its per-IP workflow allowance for the rolling 24 hours.
1791
+ Also a register-wall.
1792
+
1793
+ Both anonymous walls are checked BEFORE the workflow is
1794
+ built, and neither consumes the caller's anonymous
1795
+ allowance. An authenticated caller never receives either.
1743
1796
  content:
1744
1797
  application/json:
1745
1798
  schema:
1746
1799
  oneOf:
1747
1800
  - $ref: '#/components/schemas/TierRestrictionResponse'
1748
1801
  - $ref: '#/components/schemas/FeatureTierRestrictedResponse'
1802
+ - $ref: '#/components/schemas/AnonymousOperationNotAllowedResponse'
1803
+ - $ref: '#/components/schemas/AnonymousQuotaExhaustedResponse'
1749
1804
  discriminator:
1750
1805
  propertyName: error_type
1751
1806
  mapping:
1752
1807
  tier_restriction: '#/components/schemas/TierRestrictionResponse'
1753
1808
  feature_tier_restricted: '#/components/schemas/FeatureTierRestrictedResponse'
1809
+ anonymous_operation_not_allowed: '#/components/schemas/AnonymousOperationNotAllowedResponse'
1810
+ anonymous_quota_exhausted: '#/components/schemas/AnonymousQuotaExhaustedResponse'
1754
1811
  examples:
1755
1812
  feature_tier_restricted:
1756
1813
  summary: Free tier referencing a Pro-tier operation
@@ -1763,6 +1820,25 @@ paths:
1763
1820
  availability: "stable"
1764
1821
  required_tier: "pro"
1765
1822
  documentation_url: "https://docs.giveitsmaller.com/operations/image_watermark"
1823
+ anonymous_operation_not_allowed:
1824
+ summary: Anonymous caller requesting an operation outside the allow-list
1825
+ value:
1826
+ success: false
1827
+ error: "ANONYMOUS_OPERATION_NOT_ALLOWED"
1828
+ error_type: "anonymous_operation_not_allowed"
1829
+ message: "Sign up to use the 'text_watermark' operation."
1830
+ message_key: "error.anonymous_operation_not_allowed"
1831
+ locale: "en-GB"
1832
+ operation: "text_watermark"
1833
+ anonymous_quota_exhausted:
1834
+ summary: Anonymous caller past its rolling-24h allowance
1835
+ value:
1836
+ success: false
1837
+ error: "ANONYMOUS_QUOTA_EXHAUSTED"
1838
+ error_type: "anonymous_quota_exhausted"
1839
+ message: "Sign up to keep compressing."
1840
+ message_key: "error.anonymous_quota_exhausted"
1841
+ locale: "en-GB"
1766
1842
  '402':
1767
1843
  description: |
1768
1844
  Credit reservation failed (per ticket
@@ -1897,6 +1973,37 @@ paths:
1897
1973
  Caller resolves by switching to `re_encode_mode: auto`
1898
1974
  or `always`. The compatibility-probe algorithm is
1899
1975
  server-side and deliberately opaque per plan v5 §F8.2.
1976
+ - Inputs not concat-uniform (ticket `MjzzPCWt`). Returned for a
1977
+ job that routes to a processing class declaring
1978
+ `input_uniformity` (today `merge.video.long_form_re_encode`)
1979
+ when its inputs differ in stream layout or in a listed
1980
+ attribute. `ValidationErrorEnvelope` with `error:
1981
+ "INPUTS_NOT_CONCAT_UNIFORM"`; `details[]` entries are shaped
1982
+ `{operation: "merge", field: "inputs[i].<attribute> vs
1983
+ inputs[j].<attribute>", message: "..."}`, one per difference.
1984
+ **Coverage rule:** the API refuses every difference its upload
1985
+ probe can see WITH THE WORKER GATE'S SEMANTICS (audio present
1986
+ on one input and not another; video codec, resolution; audio
1987
+ codec, layout, channels, sample rate). NOT frame rate: the
1988
+ probe's `fps` is the AVERAGE rate, which legitimately drifts
1989
+ between concat-uniform clips, while the worker compares
1990
+ `r_frame_rate`, so comparing `fps` would refuse valid merges.
1991
+ Differences the probe does not carry with the worker's
1992
+ semantics yet (frame rate as `r_frame_rate`, stream counts
1993
+ beyond one video / one audio, stream order, pix_fmt, SAR,
1994
+ timebase, codec_tag, profile, sample_fmt) are
1995
+ refused by the worker after acceptance until the upload prober
1996
+ emits them; the probe schema declares them
1997
+ (`UploadProbeMediaMetadata`, card `lGeDDi4V`), and once a probe
1998
+ carries one, the API refuses that difference at create too. **An input whose probe has not
1999
+ completed is ADMITTED**, and the worker gate is its only
2000
+ check, the same as **an input that is an upstream job's
2001
+ output** (which has no upload probe). It does NOT get the
2002
+ `probe_pending` branch: a probe that never lands cannot be
2003
+ told apart from one still running, so refusing until it
2004
+ lands could make a create that never succeeds (ruled
2005
+ 2026-09-24 on api's `nmYdwHAH`, matching api's disabled
2006
+ single-operation probe gate).
1900
2007
 
1901
2008
  **Branch dispatch via the `error_type` discriminator** (per
1902
2009
  [ADR-0018](../docs/decisions/0018-universal-422-error-type-discriminator.md)).
@@ -1905,7 +2012,9 @@ paths:
1905
2012
  (`propertyName: error_type`):
1906
2013
  - `validation_error` → `ValidationErrorEnvelope` (carries
1907
2014
  `details[]`; the specific failure is in the `error` machine
1908
- code — `INVALID_OPTIONS`, `REQUIRES_REENCODE`,
2015
+ code — `VALIDATION_FAILED` (an option or value failed
2016
+ validation: unknown key, out of range, wrong type, enum),
2017
+ `REQUIRES_REENCODE`,
1909
2018
  `CYCLIC_WORKFLOW_EDGES`, …). The `REQUIRES_REENCODE` flavour
1910
2019
  (per I16-CONS) reuses this same envelope/`error_type` and is
1911
2020
  distinguished only by its `error` code.
@@ -1958,18 +2067,16 @@ paths:
1958
2067
  probe_pending: '#/components/schemas/ProbePendingResponse'
1959
2068
  examples:
1960
2069
  validation_error:
1961
- summary: Generic validation error (legacy shape)
2070
+ summary: An option failed validation (as the API emits it — VALIDATION_FAILED, details[] of {field, message})
1962
2071
  value:
1963
2072
  success: false
1964
2073
  error_type: "validation_error"
1965
- error: "INVALID_OPTIONS"
2074
+ error: "VALIDATION_FAILED"
1966
2075
  details:
1967
- - operation: "compress"
1968
- option: "quality"
1969
- message: "Must be between 1 and 100"
1970
- - operation: "thumbnail"
1971
- option: "width"
1972
- message: "Required field"
2076
+ - field: "quality"
2077
+ message: "Option 'quality' must be at most 100."
2078
+ - field: "width"
2079
+ message: "Option 'width' is required."
1973
2080
  cyclic_workflow_edges:
1974
2081
  summary: Cyclic or self-referential explicit workflow_edges (g8PPkbNu)
1975
2082
  value:
@@ -2044,6 +2151,16 @@ paths:
2044
2151
  actual: 54000
2045
2152
  ceiling: 43200
2046
2153
  required_tier: "enterprise"
2154
+ inputs_not_concat_uniform:
2155
+ summary: merge.video long_form_re_encode with one input lacking audio (MjzzPCWt)
2156
+ value:
2157
+ success: false
2158
+ error_type: "validation_error"
2159
+ error: "INPUTS_NOT_CONCAT_UNIFORM"
2160
+ details:
2161
+ - operation: "merge"
2162
+ field: "inputs[0].audio vs inputs[1].audio"
2163
+ message: "Input 1 has no audio track and input 0 has one; long-form merge needs every input to share the same streams."
2047
2164
  requires_reencode:
2048
2165
  summary: merge.video re_encode_mode=never with incompatible inputs (I16-CONS)
2049
2166
  value:
@@ -3033,10 +3150,34 @@ paths:
3033
3150
  Its refusal behaviour, **as a SHAPE — the counts and intervals are
3034
3151
  configurable defaults in that repo and are deliberately not
3035
3152
  restated here, because a number copied across a repo boundary rots
3036
- silently**: a non-200 is raised as a *transport error*, retried a
3037
- bounded number of times on a delay, and then falls through to
3038
- `/status` polling with **adaptive backoff** — the interval GROWS
3039
- while the server reports no movement.
3153
+ silently.**
3154
+
3155
+ - **Since 2026-09-23 (`compression_frontend` #485, `17bd8b6`,
3156
+ ticket `nuipMybn` — built against this section's obligation):**
3157
+ a `429` / `503` **carrying `Retry-After` or the API's error
3158
+ envelope** is a deliberate refusal, not a transport error (`SseRefusedError`,
3159
+ carrying the status, the `Retry-After` delay and the `error`
3160
+ code). The reader keeps `/status` polling, reopens the stream
3161
+ only after `Retry-After` has elapsed — a wait that applies to
3162
+ **every** stream that browser tab opens, not only the refused
3163
+ one (it is held in the page, so another tab of the same caller
3164
+ does not share it) —
3165
+ and **never reopens** a refusal that carried no `Retry-After`.
3166
+ ⚠️ **Two edges it does not cover, stated so this is not read as
3167
+ blanket compliance:** an UNSTRUCTURED `503` (a load balancer's,
3168
+ with neither) still takes the transport path below; and a
3169
+ `Retry-After` too large for the browser's timer keeps THAT run on
3170
+ polling but does not set the caller-wide wait, so another stream
3171
+ in the same tab may open before it elapses. This contract sets
3172
+ no upper bound on `Retry-After`.
3173
+ - **Before that (measured 2026-08-25):** a non-200 was raised as a
3174
+ *transport error* and retried a bounded number of times on a
3175
+ fixed delay. Any other non-200 status, and the unstructured `503`
3176
+ above, still takes that transport path.
3177
+
3178
+ Either way the fallback is `/status` polling with **adaptive
3179
+ backoff** — the interval GROWS while the server reports no
3180
+ movement.
3040
3181
 
3041
3182
  ⚠️ **And the `/status` poll is NOT started by the fallback.** It
3042
3183
  runs **in parallel from the outset**, as resilience against a
@@ -3048,8 +3189,9 @@ paths:
3048
3189
  🔴 **SO REFUSAL TRADES CONTINUOUS WORKER OCCUPANCY FOR A HIGHER
3049
3190
  REQUEST RATE.** Both halves matter: a held stream pins one PHP-FPM
3050
3191
  worker for its whole life and refusal genuinely sheds that — a
3051
- short poll is not a held connection — while that client's
3052
- connection attempts and polls go **up**.
3192
+ short poll is not a held connection — while that client's polls go
3193
+ **up**. (Its stream re-attempts no longer do: since #485 they wait
3194
+ out `Retry-After`.)
3053
3195
  ⚠️ **Do not read either half alone.** "Refusal sheds load" invites
3054
3196
  a cap whose success metric moves the wrong way; "refusal increases
3055
3197
  load" argues against having a cap at all, and the occupancy it
@@ -3057,9 +3199,10 @@ paths:
3057
3199
 
3058
3200
  ⚠️ **THAT IS PER-CLIENT AND MEASURED. THE AGGREGATE IS NEITHER.**
3059
3201
  Whether refusing many clients at once produces a synchronised burst
3060
- is **UNMEASURED** — the retry delay is a fixed configured interval
3061
- with no jitter, so refusals issued together are retried together,
3062
- and nothing here has observed what that does in aggregate. **Do not
3202
+ is **UNMEASURED** — refusals issued together with the same
3203
+ `Retry-After` reopen together (the delay is the server's, with no
3204
+ client jitter), and nothing here has observed what that does in
3205
+ aggregate. **Do not
3063
3206
  read "not a storm" out of this section; it says the per-client cost
3064
3207
  is bounded and says nothing about the fleet.**
3065
3208
 
@@ -3070,10 +3213,11 @@ paths:
3070
3213
  before `Retry-After` elapses, never retried as a transport error,
3071
3214
  and `/status` polling permitted under that endpoint's own limits.
3072
3215
  ⚠️ **`Retry-After` governs the next STREAM request, not a poll
3073
- interval.** Falling back to polling is still load, merely cheaper,
3074
- and the measured behaviour above is what a client does TODAY; a
3075
- client that treats refusal as a transport error does not yet meet
3076
- the obligation.
3216
+ interval.** Falling back to polling is still load, merely cheaper.
3217
+ Our frontend meets the obligation since #485 for structured
3218
+ refusals with a timer-sized `Retry-After` (the two edges above are
3219
+ the exceptions); any reader that treats refusal as a transport
3220
+ error does not.
3077
3221
 
3078
3222
  📌 **THE POPULATIONS SPLIT BY READER KIND, NOT BY
3079
3223
  BROWSER-VERSUS-NOT.** The WHATWG rule covers **native
@@ -3081,7 +3225,9 @@ paths:
3081
3225
  safe only by its own code, inside a browser or outside one** — and
3082
3226
  a retry loop treating `429`/`503` as retryable on a fixed interval
3083
3227
  is where a storm is reachable. ⚠️ **Our own frontend is in that
3084
- population, not exempt from it.**
3228
+ population, not exempt from it** — it is safe today because #485
3229
+ made it so, and a regression in its code would not be visible
3230
+ here.
3085
3231
 
3086
3232
  ✅ **For OUR SDKs that is measured, not assumed** (sdks,
3087
3233
  2026-08-22, driven through the BUILT client with a stubbed
@@ -3148,8 +3294,11 @@ paths:
3148
3294
  - `unspent_reservation_released`: the workflow was in
3149
3295
  `pending` / `in_progress` / `paused_insufficient_credits`,
3150
3296
  and the unspent portion of the original reservation has
3151
- been refunded to the caller's balance. The refund appears
3152
- as a separate `CreditTransaction` with `type: refund`.
3297
+ been refunded to the caller's balance. The return appears
3298
+ as a separate `CreditTransaction` with `type:
3299
+ reservation_release` and `reference_type:
3300
+ workflow_reservation_release` — there is no `type: refund`
3301
+ (the API's ledger type is a closed set that has none).
3153
3302
  - `none`: no refund was issued (e.g. all reserved credits
3154
3303
  were already consumed by completed jobs at cancel time;
3155
3304
  or the workflow was already terminal in a previous cancel
@@ -3249,7 +3398,9 @@ paths:
3249
3398
  Per ticket [I24 `e50uXLcl`](https://trello.com/c/e50uXLcl).
3250
3399
 
3251
3400
  Resume succeeds only when the caller's `available_credits`
3252
- cover the next reservation the server would attempt. If the
3401
+ cover the reservation the server re-takes for the workflow's
3402
+ remaining work (the same estimate `WorkflowPausedDetail`'s
3403
+ `required_action: resume` is computed from). If the
3253
3404
  balance is still insufficient, the response is 402
3254
3405
  `BalanceExhaustedResponse` (mirroring the workflow-create
3255
3406
  flow per ticket I23) and the workflow remains
@@ -5053,6 +5204,33 @@ paths:
5053
5204
  type: object
5054
5205
  billing:
5055
5206
  type: object
5207
+ properties:
5208
+ checkout_sessions:
5209
+ type: array
5210
+ description: |
5211
+ Every checkout session the account started that
5212
+ the API recorded (ticket `JHrV4MUg`). Sessions
5213
+ created before that record existed are absent.
5214
+ items:
5215
+ type: object
5216
+ required: [session_id, mode, created_at, fulfilled_at]
5217
+ properties:
5218
+ session_id:
5219
+ type: string
5220
+ mode:
5221
+ type: string
5222
+ description: The checkout mode (`payment` for a credit pack, `subscription`).
5223
+ # OPEN: the provider's checkout mode, recorded as created; a
5224
+ # new mode is informational in an export, not a decision input.
5225
+ x-enum-openness: open
5226
+ enum: [payment, subscription]
5227
+ created_at:
5228
+ type: string
5229
+ format: date-time
5230
+ fulfilled_at:
5231
+ type: ['string', 'null']
5232
+ format: date-time
5233
+ description: When the purchase was applied; `null` while it has not been.
5056
5234
  '401':
5057
5235
  description: No authenticated principal.
5058
5236
  content:
@@ -5824,9 +6002,12 @@ paths:
5824
6002
  `schemas/operations/audio_watermark.yaml` — the operation
5825
6003
  embeds; this endpoint decodes.
5826
6004
 
5827
- **Tier-restricted.** This endpoint is `enterprise`-only. Free
5828
- and `pro` callers receive a 403 `feature_tier_restricted`.
5829
- Anonymous callers receive a 401.
6005
+ **No tier gate** (since 2026-09-23, decision 26 — the paired
6006
+ `audio_watermark` operation lost its `enterprise` gate the same
6007
+ day; `X8m2vbvS`), and no 403 is declared: decode reads an
6008
+ already-uploaded file, so no upload quota applies here. Any
6009
+ authenticated caller may call it once it ships. Anonymous
6010
+ callers receive a 401.
5830
6011
 
5831
6012
  **Scope: own watermarks only.** The decoder will refuse to
5832
6013
  extract from media the caller did not mark themselves
@@ -5847,7 +6028,7 @@ paths:
5847
6028
  `feature_not_available` (422) until the Lambda lands. Per
5848
6029
  Tension 1 (ADR-0001 §1.3).
5849
6030
  operationId: decodeAudioWatermark
5850
- security: [{bearerAuth: []}, {sessionAuth: []}] # required (explicit 401 in response set; tier-gated runtime call)
6031
+ security: [{bearerAuth: []}, {sessionAuth: []}] # required (explicit 401 in response set; authenticated runtime call, no tier gate)
5851
6032
  tags:
5852
6033
  - AudioWatermark
5853
6034
  x-availability: planned
@@ -5870,22 +6051,6 @@ paths:
5870
6051
  application/json:
5871
6052
  schema:
5872
6053
  $ref: '#/components/schemas/ErrorEnvelope'
5873
- '403':
5874
- description: |
5875
- Tier insufficient (free / pro caller) — returned as
5876
- `FeatureTierRestrictedResponse` with
5877
- `error_type: feature_tier_restricted`. Per ADR-0001 §1.3.
5878
- content:
5879
- application/json:
5880
- schema:
5881
- oneOf:
5882
- - $ref: '#/components/schemas/TierRestrictionResponse'
5883
- - $ref: '#/components/schemas/FeatureTierRestrictedResponse'
5884
- discriminator:
5885
- propertyName: error_type
5886
- mapping:
5887
- tier_restriction: '#/components/schemas/TierRestrictionResponse'
5888
- feature_tier_restricted: '#/components/schemas/FeatureTierRestrictedResponse'
5889
6054
  '404':
5890
6055
  description: |
5891
6056
  No watermark detected in the supplied asset, OR the
@@ -6047,9 +6212,11 @@ paths:
6047
6212
  Per ticket [I23 `DffjC3zm`](https://trello.com/c/DffjC3zm).
6048
6213
 
6049
6214
  Each transaction is immutable once written. Workflow-create
6050
- reservations appear here as a single row; refunds appear as
6051
- separate rows referencing the original via `reference_id`
6052
- (and `reference_type: workflow`).
6215
+ reservations appear here as a single row (`reference_type:
6216
+ workflow_reservation`); credits returned appear as separate
6217
+ rows carrying the workflow in `reference_id` and a
6218
+ `reference_type` naming how they came back (see
6219
+ `CreditTransaction.reference_type`).
6053
6220
 
6054
6221
  Default page is 20 transactions, ordered most-recent-first.
6055
6222
  operationId: getCreditsUsage
@@ -6119,7 +6286,7 @@ paths:
6119
6286
  purchased_amount: null
6120
6287
  pricing_version: "v3.2.0"
6121
6288
  description: "Workflow reservation: compress.video short_form"
6122
- reference_type: "workflow"
6289
+ reference_type: "workflow_reservation"
6123
6290
  reference_id: "019539ac-2222-7000-8000-000000000001"
6124
6291
  created_at: "2026-04-26T13:55:00Z"
6125
6292
  - id: "019539ad-3333-7000-8000-aaaaaaaaaa02"
@@ -6134,14 +6301,14 @@ paths:
6134
6301
  purchased_amount: -25
6135
6302
  pricing_version: "v3.2.0"
6136
6303
  description: "Workflow reservation: merge.video long_form_re_encode"
6137
- reference_type: "workflow"
6304
+ reference_type: "workflow_reservation"
6138
6305
  reference_id: "019539ac-2222-7000-8000-000000000002"
6139
6306
  created_at: "2026-04-26T13:54:00Z"
6140
6307
  total: 47
6141
6308
  limit: 20
6142
6309
  offset: 0
6143
- refund_followup:
6144
- summary: Refund row referencing the prior workflow_001 reservation
6310
+ reservation_release_followup:
6311
+ summary: Release row returning the prior workflow_001 reservation
6145
6312
  value:
6146
6313
  success: true
6147
6314
  data:
@@ -6151,7 +6318,7 @@ paths:
6151
6318
  # workflow_001.monthly_balance_after (955); after
6152
6319
  # adds back 45 → 1000.
6153
6320
  - id: "019539ad-3333-7000-8000-aaaaaaaaaa03"
6154
- type: "refund"
6321
+ type: "reservation_release"
6155
6322
  amount: 45
6156
6323
  monthly_balance_before: 955
6157
6324
  monthly_balance_after: 1000
@@ -6161,8 +6328,8 @@ paths:
6161
6328
  monthly_amount: 45
6162
6329
  purchased_amount: null
6163
6330
  pricing_version: "v3.2.0"
6164
- description: "Refund: terminal failure on operation-compression-video"
6165
- reference_type: "workflow"
6331
+ description: "Reservation released: terminal failure on operation-compression-video"
6332
+ reference_type: "workflow_reservation_release"
6166
6333
  reference_id: "019539ac-2222-7000-8000-000000000001"
6167
6334
  created_at: "2026-04-26T13:56:00Z"
6168
6335
  total: 47
@@ -6302,8 +6469,8 @@ paths:
6302
6469
  tier_default: 10485760
6303
6470
  overridden: false
6304
6471
  max_total_input_size_bytes:
6305
- effective: 1073741824
6306
- tier_default: 1073741824
6472
+ effective: 5000000000
6473
+ tier_default: 5000000000
6307
6474
  overridden: false
6308
6475
  enterprise_with_upload_override:
6309
6476
  summary: >-
@@ -6376,8 +6543,11 @@ paths:
6376
6543
  **How to observe the grant:** poll `GET /api/v2/credits/usage`
6377
6544
  for a transaction whose `reference_id` equals the `session_id`
6378
6545
  returned here, and whose `reference_type` is
6379
- `stripe_checkout_session`. That is the only client-observable
6380
- correlation between a checkout and its credits.
6546
+ `stripe_checkout_session`. **Today that is the only
6547
+ client-observable correlation** between a checkout and its credits.
6548
+ `GET /api/billing/checkout/{sessionId}/status` is declared as the
6549
+ second one, but it is `planned` (a `422 feature_not_available`)
6550
+ until the API implements it.
6381
6551
 
6382
6552
  🔴 **MATCH ON `reference_type` + `reference_id`, AND DO NOT
6383
6553
  FILTER ON `type`.** The pack grant is written as an
@@ -6535,7 +6705,7 @@ paths:
6535
6705
  value:
6536
6706
  success: false
6537
6707
  error_type: feature_not_available
6538
- error: FEATURE_NOT_AVAILABLE
6708
+ error: UNPROCESSABLE_ENTITY
6539
6709
  message: "Checkout is not yet available."
6540
6710
  violations:
6541
6711
  - feature: endpoint.billing.checkout
@@ -6561,20 +6731,24 @@ paths:
6561
6731
  headers.
6562
6732
  headers:
6563
6733
  X-RateLimit-Limit:
6564
- required: false
6734
+ required: true
6565
6735
  description: Requests permitted in the current window.
6566
6736
  schema:
6567
6737
  type: integer
6568
6738
  minimum: 0
6569
6739
  X-RateLimit-Remaining:
6570
- required: false
6740
+ required: true
6571
6741
  description: Requests remaining in the current window.
6572
6742
  schema:
6573
6743
  type: integer
6574
6744
  minimum: 0
6575
6745
  X-RateLimit-Reset:
6576
- required: false
6577
- description: Unix epoch seconds when the current window resets.
6746
+ required: true
6747
+ description: |
6748
+ SECONDS UNTIL the current window resets (a delay, not a
6749
+ timestamp). This said "Unix epoch seconds" until 2026-09-25;
6750
+ api has always sent the delay, and both SDKs parse it as one
6751
+ (card `KqPDtD9J`).
6578
6752
  schema:
6579
6753
  type: integer
6580
6754
  minimum: 0
@@ -6601,6 +6775,160 @@ paths:
6601
6775
  schema:
6602
6776
  $ref: '#/components/schemas/ErrorEnvelope'
6603
6777
 
6778
+ /api/billing/checkout/{sessionId}/status:
6779
+ get:
6780
+ summary: Status of a checkout session the caller created
6781
+ description: |
6782
+ Whether the credits for a checkout the caller started have been
6783
+ granted. Ticket [`7cSI8eIa`](https://trello.com/c/7cSI8eIa) — declared
6784
+ BEFORE the API builds it (hub ruling, Option A, 2026-08-29); the API
6785
+ half is [`JHrV4MUg`](https://trello.com/c/JHrV4MUg).
6786
+
6787
+ **Why it exists:** between "checkout created" and "the provider's
6788
+ callback lands" nothing used to record that the session existed or
6789
+ whose it was — so a post-checkout page, asked about the NORMAL
6790
+ page-load state, had nothing to ask. The fix records the session at
6791
+ creation; this endpoint reads that record and the credit ledger.
6792
+
6793
+ | `status` | meaning |
6794
+ |---|---|
6795
+ | `paid` | the purchase this session was for has been applied to the caller's account — for a credit **pack**, a credit transaction referencing this session exists; for a **subscription**, the subscription it started is still linked to the caller's billing account (see below) |
6796
+ | `pending` | the session is recorded as created BY THE CALLER and its purchase has not been applied yet — **not a failure** |
6797
+ | `unknown` | anything else, including a session created before this endpoint shipped (nothing recorded it) |
6798
+
6799
+ **Subscription `paid` means LINKED, not IN GOOD STANDING** (ruled
6800
+ 2026-09-25 on api's `JHrV4MUg`). It holds while the subscription the
6801
+ session started is still linked to the caller's billing account; a
6802
+ `past_due` or `incomplete` subscription that is still linked reads
6803
+ `paid`. It becomes `unknown` once the provider reports the
6804
+ subscription deleted. A stricter meaning needs the subscription's
6805
+ status recorded, which the API does not do today.
6806
+
6807
+ 🔴 **`unknown` DELIBERATELY COLLAPSES "not yours" WITH "never
6808
+ existed". This is a decision, not missing detail.** Telling them
6809
+ apart would make this endpoint an oracle for whether an arbitrary
6810
+ session id is real — a probe confirming a stranger's purchase exists.
6811
+ The requirement is *paid AND yours*; the honest refusal admits
6812
+ neither. ⛔ **Do not "improve" the answer by distinguishing the two**
6813
+ (a 403 or 404 for someone else's session is the same oracle).
6814
+
6815
+ ⛔ **No provider call on this read path.** It will be polled; a
6816
+ third-party call would turn provider latency and outages into page
6817
+ states and put the secret key on a read path.
6818
+
6819
+ ⛔ **No timing is stated here either** — the reason is the one given
6820
+ on `POST /api/billing/checkout` (the delay is the provider's callback
6821
+ latency, which this system does not measure). `pending` is a normal
6822
+ state to keep polling on, not an error.
6823
+ operationId: getCheckoutSessionStatus
6824
+ security: [{bearerAuth: []}, {sessionAuth: []}] # required; answers only about the caller's own sessions
6825
+ x-identity-scoped: true # a session belongs to the caller who created it
6826
+ x-availability: planned
6827
+ tags:
6828
+ - Billing
6829
+ parameters:
6830
+ - name: sessionId
6831
+ in: path
6832
+ required: true
6833
+ description: The `session_id` returned by `POST /api/billing/checkout`.
6834
+ schema:
6835
+ type: string
6836
+ minLength: 1
6837
+ responses:
6838
+ '200':
6839
+ description: |
6840
+ The session's status for this caller. **Once implemented, always
6841
+ 200 for an authenticated caller, for any session id the router
6842
+ accepts** — `unknown` is the answer for anything not provably the
6843
+ caller's (see the collapse rationale above). An id the router
6844
+ cannot route (for example invalid UTF-8 such as `cs_%FF`) is a
6845
+ `404` before this endpoint runs; that answer is the same for
6846
+ every caller and every session, so it reveals nothing. While the endpoint is `planned` it
6847
+ answers `422 feature_not_available` instead.
6848
+ content:
6849
+ application/json:
6850
+ schema:
6851
+ $ref: '#/components/schemas/CheckoutSessionStatusResponse'
6852
+ examples:
6853
+ paid:
6854
+ summary: Credits granted
6855
+ value:
6856
+ success: true
6857
+ data:
6858
+ session_id: cs_test_a1b2c3
6859
+ status: paid
6860
+ pending:
6861
+ summary: Recorded for this caller, grant not landed yet
6862
+ value:
6863
+ success: true
6864
+ data:
6865
+ session_id: cs_test_a1b2c3
6866
+ status: pending
6867
+ unknown:
6868
+ summary: Not provably this caller's — or never existed
6869
+ value:
6870
+ success: true
6871
+ data:
6872
+ session_id: cs_test_zzz
6873
+ status: unknown
6874
+ '401':
6875
+ description: Authentication required.
6876
+ content:
6877
+ application/json:
6878
+ schema:
6879
+ $ref: '#/components/schemas/ErrorEnvelope'
6880
+ '404':
6881
+ description: |
6882
+ The ROUTER could not route the path (for example a session id
6883
+ with invalid UTF-8). Returned before this endpoint runs, the same
6884
+ for every caller and every session id, so it says nothing about
6885
+ any session.
6886
+ content:
6887
+ application/json:
6888
+ schema:
6889
+ $ref: '#/components/schemas/ErrorEnvelope'
6890
+ '422':
6891
+ description: |
6892
+ `feature_not_available` while this endpoint is `planned`.
6893
+ content:
6894
+ application/json:
6895
+ schema:
6896
+ $ref: '#/components/schemas/FeatureNotAvailableResponse'
6897
+ '429':
6898
+ description: |
6899
+ Rate limit exceeded. This endpoint is limited as a STATUS POLL
6900
+ (the same family as the other polling reads), independently of
6901
+ `POST /api/billing/checkout`, so polling a pending session never
6902
+ spends the caller's checkout-creation budget. `error:
6903
+ TOO_MANY_REQUESTS`. No `Retry-After`; back off by
6904
+ `X-RateLimit-Reset`.
6905
+ headers:
6906
+ X-RateLimit-Limit:
6907
+ required: true
6908
+ description: Requests permitted in the most constrained window.
6909
+ schema:
6910
+ type: integer
6911
+ minimum: 0
6912
+ X-RateLimit-Remaining:
6913
+ required: true
6914
+ description: Requests remaining in that window.
6915
+ schema:
6916
+ type: integer
6917
+ minimum: 0
6918
+ X-RateLimit-Reset:
6919
+ required: true
6920
+ description: |
6921
+ SECONDS UNTIL that window resets (a delay, not a
6922
+ timestamp) — what api's limiter sends
6923
+ (`TieredRateLimiterService`: retry-after timestamp minus now).
6924
+ schema:
6925
+ type: integer
6926
+ minimum: 0
6927
+ content:
6928
+ application/json:
6929
+ schema:
6930
+ $ref: '#/components/schemas/ErrorEnvelope'
6931
+
6604
6932
  # ============================================
6605
6933
  # CONTACT ENDPOINT
6606
6934
  # ============================================
@@ -6828,12 +7156,22 @@ components:
6828
7156
  enum: [false]
6829
7157
  error:
6830
7158
  type: string
7159
+ x-string-vocabulary: open
6831
7160
  description: |
6832
- Stable, machine-readable error code (e.g.
6833
- `INVALID_OPTIONS`, `BALANCE_EXHAUSTED`,
7161
+ Machine-readable error code. **Each published code is stable; the
7162
+ SET is open** (`x-string-vocabulary: open`): handle an unknown code
7163
+ as a generic error. E.g.
7164
+ `VALIDATION_FAILED`, `BALANCE_EXHAUSTED`,
6834
7165
  `REQUIRES_REENCODE`). Canonical English; never localised.
6835
7166
  SDKs duck-type on this field for typed error-branch
6836
- helpers.
7167
+ helpers — **except where an HTTP-status-shaped code
7168
+ (`UNPROCESSABLE_ENTITY`, `BAD_REQUEST`, …) covers several
7169
+ branches: there `error_type` is the discriminator.**
7170
+ Example: `POST /api/billing/checkout` answers
7171
+ `UNPROCESSABLE_ENTITY` both when checkout is switched off
7172
+ (`error_type: feature_not_available`) and when a pack or
7173
+ plan is not provisioned (no `error_type`); only
7174
+ `error_type` tells them apart.
6837
7175
 
6838
7176
  Multipart-session resume codes (per ticket
6839
7177
  [`HxUmVr3Y`](https://trello.com/c/HxUmVr3Y), V2.10.0):
@@ -6954,21 +7292,33 @@ components:
6954
7292
  dispatch on `error_type` instead of structural `instanceOf`
6955
7293
  guards (which mis-fire on camelCase-vs-snake_case property
6956
7294
  names). Distinct from the `error` machine code below: `error`
6957
- carries the specific failure code (`INVALID_OPTIONS`,
7295
+ carries the specific failure code (`VALIDATION_FAILED`,
6958
7296
  `REQUIRES_REENCODE`, `CYCLIC_WORKFLOW_EDGES`, …) while
6959
7297
  `error_type` only names the envelope shape.
6960
7298
  error:
6961
7299
  type: string
6962
- description: |
6963
- Stable error code. Common values: `INVALID_OPTIONS`
6964
- (generic option/value validation failure), `REQUIRES_REENCODE`
7300
+ x-string-vocabulary: open
7301
+ description: |
7302
+ Error code. **Each published code is stable; the SET is open**
7303
+ (`x-string-vocabulary: open`): handle an unknown code as a generic
7304
+ validation error. Codes emitted today: `VALIDATION_FAILED`
7305
+ (request, query-param **and workflow-create option/value**
7306
+ validation failure — the API emits it for every create-time
7307
+ option error: unknown key, out of range, wrong type, bad enum
7308
+ value; `details[]` items carry `field` = the option key and
7309
+ `message`), `REQUIRES_REENCODE`
6965
7310
  (per ticket I16-CONS — `merge.video` with
6966
7311
  `re_encode_mode: never` and incompatible inputs; caller
6967
7312
  resolves by switching to `re_encode_mode: auto` or `always`),
6968
7313
  `CYCLIC_WORKFLOW_EDGES` (cyclic/self explicit `workflow_edges`,
6969
- per `g8PPkbNu`), `VALIDATION_FAILED` (request/query-param
6970
- validation failure per the project-wide convention — e.g.
6971
- `GET /api/v2/credits/usage` invalid `limit`/`offset`).
7314
+ per `g8PPkbNu`).
7315
+ ⚠️ **`INVALID_OPTIONS` is NOT a create-time wire code**, though
7316
+ earlier text here said it was and the example showed it: the
7317
+ API has always sent `VALIDATION_FAILED` for option failures
7318
+ (measured on prod by `compression_e2e`, 2026-09-23;
7319
+ `WorkflowController` maps every `validation_error` to it).
7320
+ `invalid_options` lives on the worker's
7321
+ `OperationResult.error_code` (asyncapi), not on this envelope.
6972
7322
  SDKs duck-type on this field for typed error-branch helpers.
6973
7323
  message:
6974
7324
  type: string
@@ -7075,6 +7425,7 @@ components:
7075
7425
  enum: [false]
7076
7426
  error:
7077
7427
  type: string
7428
+ x-string-vocabulary: open
7078
7429
  description: |
7079
7430
  Stable machine-readable failure code. `UNPROCESSABLE_ENTITY`
7080
7431
  for the generic auth domain rejections (register /
@@ -7118,12 +7469,23 @@ components:
7118
7469
  ReEncodeDecision:
7119
7470
  type: string
7120
7471
  description: |
7121
- Path chosen for `merge.video` when `re_encode_mode=auto`.
7122
- Server reports the actual path so callers can see why
7123
- `auto` took the slow path. Absent for non-`merge.video`
7124
- operations and for `merge.video` when `re_encode_mode` is
7125
- `always` or `never` (path was caller-fixed). Per ticket
7126
- I16-CONS (Trello 7nCZXEru).
7472
+ Path the worker actually took for a SUCCESSFUL `merge.video`,
7473
+ reported in EVERY `re_encode_mode`: `always` reports `re_encode`;
7474
+ `never` reports `stream_copy`; `auto` reports whichever path it
7475
+ chose. Absent for non-`merge.video` operations and on any failed
7476
+ operation, even one that carries other metrics such as sizes or
7477
+ cost figures (for example a `never`
7478
+ request whose inputs need a re-encode, or a long-form merge the
7479
+ uniformity gate refuses before the path is decided). Per ticket I16-CONS (Trello
7480
+ 7nCZXEru).
7481
+
7482
+ ⚠️ An earlier revision said the field was ABSENT under `always` /
7483
+ `never`. The worker never behaved that way (it reports the path
7484
+ in every mode), and the same contract listed an `always`-mode
7485
+ reason as an example, so the text contradicted itself. The
7486
+ worker's behaviour is the canonical one (ruled 2026-09-24 on
7487
+ compression_e2e's report); a consumer MUST NOT assert absence
7488
+ on a successful merge under a caller-fixed mode.
7127
7489
 
7128
7490
  Mirrors the AsyncAPI `ReEncodeDecision` (and
7129
7491
  `OperationMetrics.re_encode_decision`); exposed on the REST
@@ -7987,6 +8349,32 @@ components:
7987
8349
  data:
7988
8350
  $ref: '#/components/schemas/AccountLimits'
7989
8351
 
8352
+ CheckoutSessionStatusResponse:
8353
+ type: object
8354
+ # Envelope CLOSED, payload OPEN — the repo's success-envelope convention:
8355
+ # top-level drift is detected, and new `data` fields stay additive.
8356
+ additionalProperties: false
8357
+ required: [success, data]
8358
+ properties:
8359
+ success:
8360
+ type: boolean
8361
+ enum: [true]
8362
+ data:
8363
+ type: object
8364
+ required: [session_id, status]
8365
+ properties:
8366
+ session_id:
8367
+ type: string
8368
+ description: Echo of the path parameter.
8369
+ status:
8370
+ type: string
8371
+ enum: [paid, pending, unknown]
8372
+ x-enum-openness: closed
8373
+ description: |
8374
+ `paid` / `pending` / `unknown` — see
8375
+ `GET /api/billing/checkout/{sessionId}/status`. `unknown`
8376
+ collapses "not yours" and "never existed" on purpose.
8377
+
7990
8378
  AccountLimits:
7991
8379
  type: object
7992
8380
  # Open payload (response data target stays open for additive evolution —
@@ -8047,6 +8435,29 @@ components:
8047
8435
  # api emits it. Unit is SECONDS — carried by the key name, per
8048
8436
  # AccountLimitEntry.
8049
8437
  $ref: '#/components/schemas/AccountLimitEntry'
8438
+ max_upload_image_pixels:
8439
+ # OPTIONAL in this expand step (ONxpaAlk); NOT required until api
8440
+ # emits it. The upload gate's pixel ceiling for decodable rasters
8441
+ # (width x height from the header) — the 413
8442
+ # IMAGE_DIMENSIONS_TOO_LARGE threshold. It is an ENV KNOB on the
8443
+ # API (UPLOAD_MAX_IMAGE_PIXELS), so the contract carries the
8444
+ # SHAPE and the server serves the NUMBER; a number written here
8445
+ # could drift from the running value by a task-definition edit.
8446
+ # Not tier-varying today: `tier_default` equals `effective`.
8447
+ # SINGLE-SHOT only (POST /api/uploads): sized for the API's inline
8448
+ # decode. Multipart has its own key below (ae4Q1yCb).
8449
+ $ref: '#/components/schemas/AccountLimitEntry'
8450
+ max_multipart_upload_image_pixels:
8451
+ # OPTIONAL in this expand step (ae4Q1yCb, owner ruling 2026-09-24);
8452
+ # NOT required until api emits it. The MULTIPART upload pixel
8453
+ # ceiling (width x height from the header) — the 413
8454
+ # IMAGE_DIMENSIONS_TOO_LARGE threshold on the multipart path. A
8455
+ # SEPARATE, HIGHER API setting than max_upload_image_pixels:
8456
+ # default 50 MP (hub, 2026-09-24), about half the workers'
8457
+ # declared 100 MP source cap, which is unproven end to end; it
8458
+ # rises only after a 100 MP staging proof. It MUST admit a 24 MP
8459
+ # photo. The server serves the number. Not tier-varying today.
8460
+ $ref: '#/components/schemas/AccountLimitEntry'
8050
8461
 
8051
8462
  AccountLimitEntry:
8052
8463
  type: object
@@ -8101,9 +8512,10 @@ components:
8101
8512
  description: |
8102
8513
  Single ledger entry. Immutable once written. A workflow-create
8103
8514
  reservation appears here as a single row with `source_bucket`
8104
- indicating which pool(s) were debited; refunds appear as
8105
- separate rows referencing the original via `reference_id` and
8106
- `reference_type: workflow`.
8515
+ indicating which pool(s) were debited; a returned reservation
8516
+ appears as a separate `reservation_release` row referencing the
8517
+ workflow via `reference_id` (see `reference_type` for the
8518
+ values that distinguish a release from a settle refund).
8107
8519
 
8108
8520
  `type`, `pricing_version`, and `reference_type` are
8109
8521
  deliberately free-form strings — their value sets evolve with
@@ -8132,11 +8544,16 @@ components:
8132
8544
  $ref: '#/components/schemas/UuidV7'
8133
8545
  type:
8134
8546
  type: string
8135
- description: |
8136
- Ledger entry type — free-form string. Common values:
8137
- `reservation`, `refund`, `top_up`, `monthly_grant`,
8138
- `adjustment`. Not enumerated to avoid contract churn as
8139
- billing event taxonomy evolves.
8547
+ x-string-vocabulary: open
8548
+ description: |
8549
+ Ledger entry type — free-form string. Values the API emits
8550
+ today (its `CreditTransactionType`, a closed set): `grant`,
8551
+ `deduction`, `adjustment`, `overdraft_repayment`,
8552
+ `reservation`, `reservation_release`. **There is no
8553
+ `refund`, `top_up` or `monthly_grant`** — earlier text listed
8554
+ them, and a consumer filtering on one matched nothing. Not
8555
+ enumerated in the schema to avoid contract churn as billing
8556
+ event taxonomy evolves; SDKs duck-type.
8140
8557
  amount:
8141
8558
  type: integer
8142
8559
  description: |
@@ -8200,6 +8617,7 @@ components:
8200
8617
  applies symmetrically.
8201
8618
  pricing_version:
8202
8619
  type: string
8620
+ x-string-vocabulary: none
8203
8621
  description: |
8204
8622
  Pricing-table version applied to this transaction.
8205
8623
  Free-form string (server emits a semver-shaped or
@@ -8213,10 +8631,16 @@ components:
8213
8631
  description: Human-readable description of the ledger entry.
8214
8632
  reference_type:
8215
8633
  type: string
8216
- description: |
8217
- What the transaction references. Common values:
8218
- `workflow`, `top_up`, `cycle_grant`, `adjustment`.
8219
- Free-form string.
8634
+ x-string-vocabulary: open
8635
+ description: |
8636
+ What the transaction references. Free-form string. Values
8637
+ the API emits for workflow credits: `workflow_reservation`
8638
+ (the debit), `workflow_reservation_release`,
8639
+ `workflow_pause_release`, `workflow_expiry_release` and
8640
+ `workflow_settle_refund` (credits returned);
8641
+ `stripe_checkout_session` for a credit-pack purchase. Match
8642
+ on this field, not on `type`, to tell a release from a
8643
+ settle refund.
8220
8644
  reference_id:
8221
8645
  type: string
8222
8646
  description: |
@@ -8274,6 +8698,7 @@ components:
8274
8698
  # additively from the API ahead of this contract.
8275
8699
  state:
8276
8700
  type: [string, "null"]
8701
+ x-string-vocabulary: open
8277
8702
  description: |
8278
8703
  Reservation lifecycle state — free-form string (kept opaque like
8279
8704
  `type`/`reference_type` for churn-resistance; SDKs duck-type).
@@ -8585,10 +9010,11 @@ components:
8585
9010
  Effect of a workflow cancel on outstanding credit
8586
9011
  reservations.
8587
9012
  - `unspent_reservation_released`: caller refunded for the
8588
- unspent portion of the original reservation; refund
8589
- appears as a separate `CreditTransaction` (`type: refund`,
8590
- `reference_type: workflow`, `reference_id` matching the
8591
- cancelled workflow).
9013
+ unspent portion of the original reservation; the return
9014
+ appears as a separate `CreditTransaction` (`type:
9015
+ reservation_release`, `reference_type:
9016
+ workflow_reservation_release`, `reference_id` matching the
9017
+ cancelled workflow). There is no `type: refund`.
8592
9018
  - `none`: no refund issued (all reserved credits already
8593
9019
  consumed by completed jobs at cancel time, OR the
8594
9020
  workflow was already terminal in a previous cancel — the
@@ -8791,15 +9217,28 @@ components:
8791
9217
 
8792
9218
  WorkflowPauseRequiredAction:
8793
9219
  type: string
9220
+ x-enum-openness: open
8794
9221
  description: |
8795
- Action the caller must take to resume a paused workflow.
8796
- Same enum as `BalanceExhaustedResponse.required_action` —
8797
- the pause cause is always insufficient credits, so the
8798
- resolution affordances align.
9222
+ Action the caller must take to resume a paused workflow. The
9223
+ first three match `BalanceExhaustedResponse.required_action`.
9224
+ `resume` (ticket `xNatWWpO`, api #747): the account can afford
9225
+ the resume NOW, so the only action is to resume: call the
9226
+ `resumeWorkflow` operation (`POST /api/workflows/{id}/resume`).
9227
+ `links.resume`, when present, is a UI deep link, not the API
9228
+ call. The
9229
+ API emits it when the balance, plus this month's pending grant
9230
+ for the base tier, covers the same cost estimate the resume
9231
+ handler reserves — so `/status` and resume agree. A UI must not
9232
+ offer a top-up, upgrade or pack for it.
9233
+ **Open enum:** handle an unknown value as the generic case.
9234
+ ⚠️ Rollout order, because a strict SDK deserialiser throws on an
9235
+ unknown value: SDKs tolerate unknown values and are published
9236
+ first, and only then does the API emit `resume`.
8799
9237
  enum:
8800
9238
  - add_credits
8801
9239
  - upgrade_plan
8802
9240
  - wait_for_renewal
9241
+ - resume
8803
9242
 
8804
9243
  # ============================================
8805
9244
  # WORKFLOW ADVISORY WARNINGS (per ticket I25)
@@ -8950,9 +9389,10 @@ components:
8950
9389
 
8951
9390
  SDK + frontend gate UI on `required_action` to render the
8952
9391
  appropriate "Top up to resume" / "Upgrade plan to resume" /
8953
- "Wait for renewal" affordance, with `links.resume` enabling
8954
- a one-click POST to `/api/workflows/{id}/resume` once the
8955
- balance is sufficient.
9392
+ "Wait for renewal" affordance — or, for `resume`, only the
9393
+ resume action. The resume itself is the `resumeWorkflow`
9394
+ operation (`POST /api/workflows/{id}/resume`); `links.resume` is
9395
+ the frontend page where a user can do it, not that API call.
8956
9396
  required:
8957
9397
  - paused_at
8958
9398
  - expires_at
@@ -9000,9 +9440,11 @@ components:
9000
9440
  type: string
9001
9441
  format: uri
9002
9442
  description: |
9003
- Deep link to the resume action — typically
9004
- `POST /api/workflows/{id}/resume` exposed via the
9005
- frontend's "resume" UI.
9443
+ URL of the frontend page for this workflow (e.g.
9444
+ `{frontend}/{locale}/profile/workflows/{id}`), where the
9445
+ user can resume it. **NOT the API call:** a client resumes
9446
+ with the `resumeWorkflow` operation
9447
+ (`POST /api/workflows/{id}/resume`).
9006
9448
  top_up:
9007
9449
  type: string
9008
9450
  format: uri
@@ -9263,6 +9705,67 @@ components:
9263
9705
  # FEATURE AVAILABILITY ENVELOPES
9264
9706
  # ============================================
9265
9707
 
9708
+ AnonymousOperationNotAllowedResponse:
9709
+ description: |
9710
+ 403 from `POST /api/workflows` when an ANONYMOUS caller (no
9711
+ credential) requests an operation outside the anonymous
9712
+ allow-list. A register-wall: the frontend renders a sign-up
9713
+ prompt, since no tier upgrade applies to a caller without an
9714
+ account.
9715
+
9716
+ Mirrors `compression_api`'s `WorkflowController` register-wall
9717
+ (`JobsErrorCode::AnonymousOperationNotAllowed`), which checks
9718
+ every operation in the body and names the FIRST disallowed one.
9719
+
9720
+ ⚠️ **The allow-list itself is NOT yet declared in this contract**
9721
+ (ticket [`UQ7zROTr`](https://trello.com/c/UQ7zROTr)), so a client
9722
+ can parse this refusal but cannot yet predict it. Do not hard-code
9723
+ the list from this description: it deliberately names none.
9724
+ allOf:
9725
+ - $ref: '#/components/schemas/ErrorEnvelope'
9726
+ - type: object
9727
+ required:
9728
+ - error_type
9729
+ - operation
9730
+ properties:
9731
+ error:
9732
+ enum:
9733
+ - ANONYMOUS_OPERATION_NOT_ALLOWED
9734
+ error_type:
9735
+ description: Discriminator for the 403 oneOf. Always `anonymous_operation_not_allowed` for this envelope.
9736
+ type: string
9737
+ enum:
9738
+ - anonymous_operation_not_allowed
9739
+ operation:
9740
+ description: |
9741
+ The first operation in the request body that an anonymous
9742
+ caller may not run.
9743
+ $ref: '#/components/schemas/OperationType'
9744
+ AnonymousQuotaExhaustedResponse:
9745
+ description: |
9746
+ 403 from `POST /api/workflows` when an ANONYMOUS caller (no
9747
+ credential) has used its per-IP workflow allowance for the
9748
+ rolling 24 hours. A register-wall, distinct from the generic
9749
+ `429`: the remedy is signing in, not waiting.
9750
+
9751
+ Mirrors `compression_api`'s `WorkflowController` register-wall
9752
+ (`JobsErrorCode::AnonymousQuotaExhausted`). The allowance is only
9753
+ consumed by a workflow that is actually created, so a refused
9754
+ request does not use it up.
9755
+ allOf:
9756
+ - $ref: '#/components/schemas/ErrorEnvelope'
9757
+ - type: object
9758
+ required:
9759
+ - error_type
9760
+ properties:
9761
+ error:
9762
+ enum:
9763
+ - ANONYMOUS_QUOTA_EXHAUSTED
9764
+ error_type:
9765
+ description: Discriminator for the 403 oneOf. Always `anonymous_quota_exhausted` for this envelope.
9766
+ type: string
9767
+ enum:
9768
+ - anonymous_quota_exhausted
9266
9769
  FeatureViolation:
9267
9770
  type: object
9268
9771
  description: |
@@ -9506,6 +10009,13 @@ components:
9506
10009
  description: |
9507
10010
  The class whose ceiling was exceeded — typically `long_form`
9508
10011
  or `long_form_re_encode`.
10012
+ resolution_band:
10013
+ $ref: '#/components/schemas/ResolutionBand'
10014
+ description: |
10015
+ The band whose ceiling `ceiling` is, when the class declares
10016
+ `resolution_bands`; omitted otherwise. `unknown` means the
10017
+ resolution could not be determined — a different customer
10018
+ action from a known-resolution overflow.
9509
10019
  actual:
9510
10020
  type: integer
9511
10021
  minimum: 0
@@ -9759,9 +10269,14 @@ components:
9759
10269
  - `failed`: All jobs finished, at least one failed, none succeeded.
9760
10270
  - `partially_failed`: Some jobs succeeded, some failed.
9761
10271
  - `paused_insufficient_credits`: Workflow paused at a job/
9762
- stage boundary because the next reservation exceeded the
9763
- caller's available credits. Pause occurs at boundaries
9764
- only — never mid-stream within a running operation.
10272
+ stage boundary because it no longer holds a credit
10273
+ reservation. The API reserves the FULL estimated cost at
10274
+ create (a 402 there if the balance is short), so a normal run
10275
+ never pauses; this is a defence for a workflow whose
10276
+ reservation was released mid-flight (e.g. by an orphan
10277
+ clean-up). There is no per-stage reservation (ticket
10278
+ `mNA2uv3y`). Pause occurs at boundaries only — never
10279
+ mid-stream within a running operation.
9765
10280
  Resumable via `POST /api/workflows/{id}/resume` once the
9766
10281
  caller tops up; expires after a 7-day TTL by default.
9767
10282
  - `cancelled`: Caller-initiated termination via
@@ -9837,6 +10352,12 @@ components:
9837
10352
  OperationType:
9838
10353
  type: string
9839
10354
  description: |
10355
+ ⚠️ **HOMONYM:** `asyncapi/events.yaml` also declares an `OperationType` —
10356
+ the narrower event PAYLOAD vocabulary. This one is the CREATE surface.
10357
+ Same name, different membership; generated SDKs emit both, and the
10358
+ import path is the only distinguisher (not renamed — breaking;
10359
+ `bFy3zo5Y`). Relation asserted in `schemas/cross-document-enums.yaml`.
10360
+
9840
10361
  Available operation types:
9841
10362
  - compress: Reduce file size (images, audio, video, documents)
9842
10363
  - thumbnail: Legacy thumbnail value. Generates a preview image
@@ -9862,11 +10383,11 @@ components:
9862
10383
  - convert: Change file format (all types)
9863
10384
  - custom_luma: Apply a caller-uploaded luma matte to a base video for a custom luma-matte transition effect. Multi-input (`role: base` + `role: transition_mask`). `availability: planned` (no tier gate); dispatch returns `feature_not_available` (422) until Lambda ships. Distinct from FFmpeg `xfade=custom` (which is an expression, not an operation). Per ticket I29 (Trello EPUE5Vs1).
9864
10385
  - audio_overlay: Mix a secondary audio asset over a primary audio or video base (DJ tags, podcast intros/outros, station IDs, jingles). Multi-input (`role: base` + `role: overlay`). `availability: planned`; dispatch returns `feature_not_available` (422) until Lambda ships. **NOT** the same as `audio_watermark` — that operation is steganographic (imperceptible identifier embedded for ownership tracking), tracked separately by I20. Per ticket I19 (Trello Xr3Z4GBF).
9865
- - audio_watermark: Embed a steganographic forensic watermark into an audio asset (or a video's audio track) — Cinavia / Resemble PerTh territory. Single-input. `availability: planned` + `required_tier: enterprise`; dispatch returns `feature_not_available` (422) until Lambda ships. Pairs with `POST /api/audio-watermark/decode` for own-watermarks-only extraction. Per ticket I20 (Trello omiCq7Vn).
10386
+ - audio_watermark: Embed a steganographic forensic watermark into an audio asset (or a video's audio track) — Cinavia / Resemble PerTh territory. Single-input. `availability: planned` (no tier gate since 2026-09-23); dispatch returns `feature_not_available` (422) until Lambda ships. Pairs with `POST /api/audio-watermark/decode` for own-watermarks-only extraction. Per ticket I20 (Trello omiCq7Vn).
9866
10387
  - audio_to_video: Produce a video from an audio input plus an OPTIONAL still image overlay. Multi-input role-based with the first OPTIONAL role on the contract (`role: base` audio required, `role: overlay` image 0..1 — see `per_role_cardinality`). When overlay is omitted, the video uses a solid background colour. `availability: planned` — WITHDRAWN 2026-09-15: measured 0.300 s of encode per second of output PLUS A 7 s FIXED COST, so the advertised PT2H needs 2167 s against a 900 s platform maximum (0.300 x 7200 alone is 2160 — the intercept is what makes the figure 2167, and a consumer dividing 600 by 0.300 gets a 2000 s in-flight boundary where the real one is 1976 s). Returns `feature_not_available` (422) at workflow-create. An already-accepted workflow is not cancelled (availability is checked at create) and fails only when its output duration exceeds ~1976 s ON THE INPUT THE RATE WAS MEASURED WITH (a real photographic 1080p still plus looped real audio), where 0.300 s per second plus a 7 s fixed cost reaches the worker's 600 s cap — the 60 s and 120 s measured cells both COMPLETED. The driver is the STILL'S RESOLUTION, not duration alone: a 4K still is roughly 4x the rate (unmeasured), which would put the boundary near a quarter of that, and this schema places no constraint on the overlay's resolution. Per ticket [`SlluxMBN`](https://trello.com/c/SlluxMBN) + ADR-0015 (introduces `per_role_cardinality` vocab).
9867
10388
  - video_watermark: Apply an image overlay onto a base video via FFmpeg's `overlay` filter. Multi-input role-based (`role: base` video + `role: overlay` image, exactly one of each per `per_role_cardinality`). Re-encode required; audio stream-copy passthrough. Distinct from `image_watermark` (pure-Rust/image-only). `availability: planned` — WITHDRAWN 2026-09-15, operation AND `short_form`: a real 1080p source at the advertised PT5M / 500 MB was killed at 606 s by the worker's 600 s encode cap, no output. Returns `feature_not_available` (422) at workflow-create; an already-accepted workflow is not cancelled and fails only if it exceeds that cap; the 606 s kill is ONE measured point and nothing measured says where the boundary is. `long_form` and `multi_overlay_stack` were already `planned`. Per ticket [`4NrRPCgh`](https://trello.com/c/4NrRPCgh) + ADR-0013.
9868
10389
  - video_text_watermark: Render a text overlay onto a base video via FFmpeg's `drawtext` filter. Single-input — text and styling in options. Same `watermark_mode` (single/tiled), anchor + margin vocab as `text_watermark`. Re-encode required; audio stream-copy passthrough. `availability: planned` — WITHDRAWN 2026-09-15, operation AND `short_form`: a real 1080p source at the advertised PT5M was killed at 604 s by the worker's 600 s encode cap. Returns `feature_not_available` (422) at workflow-create. ⚠️ This entry previously read "until Lambda ships", which was wrong in a way that mattered: the worker SHIPPED and runs — it is the CEILING that cannot be served. Per ticket [`4NrRPCgh`](https://trello.com/c/4NrRPCgh) + ADR-0013.
9869
- - split: Fan one input file into N outputs across GIF / PDF / audio / video MIME families. Single-input per-mime-group catalog (mirrors merge/convert): GIF uses `frame_range` (REQUIRED) + `output_format`; PDF uses `page_range` OR `page_groups` (mutually exclusive); audio + video use a `mode` discriminator (interval/count/cut_points) + numeric-seconds wire format + `precision` flag (fast/exact). 200-output hard cap per ADR-0009 §D5 with per-mode preflight math; output naming `output-001..output-200`. Long-form video routes to a separate `split-video-fargate` worker via `processing_class`. `availability: beta` for the `audio` and `video` mime_groups (workers live on staging — shape-stable + opt-in, MUST NOT 422); video activates BOTH classes (`video.processing_class.short_form: beta` AND `long_form: beta` — `split-video-fargate` deployed + wired on staging but NOT yet proven end-to-end per [`rcwvUKhI`](https://trello.com/c/rcwvUKhI); the first customer-path soak has not completed, the 4GB+ speed-up is unmeasured, and the long-form fan-out is flag-gated dark). The `image_gif` and `document_pdf` mime_groups stay `availability: planned` and dispatch returns `feature_not_available` (422) until their workers ship. Per ticket [`vKI0CFDu`](https://trello.com/c/vKI0CFDu) + ADR-0014.
10390
+ - split: Fan one input file into N outputs across GIF / PDF / audio / video MIME families. Single-input per-mime-group catalog (mirrors merge/convert): GIF uses `frame_range` (REQUIRED) + `output_format`; PDF uses `page_range` OR `page_groups` (mutually exclusive); audio + video use a `mode` discriminator (interval/count/cut_points) + numeric-seconds wire format + `precision` flag (fast/exact). 200-output hard cap per ADR-0009 §D5 with per-mode preflight math; output naming `output-001..output-200`. Long-form video routes to a separate `split-video-fargate` worker via `processing_class`. `availability: beta` for the `audio` and `video` mime_groups (workers live on staging — shape-stable + opt-in, MUST NOT 422); video activates BOTH classes (`video.processing_class.short_form: beta` AND `long_form: beta` — `split-video-fargate` deployed + wired on staging; it stays `beta` until a PRODUCTION `customer_path` run is recorded in `availability/prod-verification-log.yaml` per [`rcwvUKhI`](https://trello.com/c/rcwvUKhI)). The `image_gif` and `document_pdf` mime_groups stay `availability: planned` and dispatch returns `feature_not_available` (422) until their workers ship. Per ticket [`vKI0CFDu`](https://trello.com/c/vKI0CFDu) + ADR-0014.
9870
10391
  - passthrough: Inert lossless source operation. A single-input source job whose SOLE operation is `passthrough` emits its source bytes UNCHANGED — no compression, no Lambda. The API self-completes the job at publish (terminal output = the upload `{bucket, key}` unchanged). Its purpose is to feed an uploaded file into a multi-input operation LOSSLESSLY: because `JobInputV2.source` is narrowed to exclude upload-direct, an upload that must enter a `merge` / `archive` / `image_watermark` op enters via a `passthrough` source job referenced downstream by `{type: job_output, from: <id>}` — preserving billing / DAG / lineage. Distinct from `operations: []` (which keeps its implicit-compress meaning on a single-input upload job); `passthrough` is the EXPLICIT lossless path via the "non-empty `operations[]` without `compress` = compression opt-out" rule. Media-agnostic; no options. `availability: beta` — activated (the inputs[]-narrowing + passthrough self-complete mechanism is deployed API-side); workflow-create accepts `passthrough` source jobs and MUST NOT return `feature_not_available`. **Never published to SNS** — deliberately absent from the AsyncAPI routing enums (API self-completes; no `ops-passthrough` queue). Per ticket [`4som89Uh`](https://trello.com/c/4som89Uh) + ADR-0004 (planned→beta flip).
9871
10392
 
9872
10393
  - transform: Geometric/orientation transform — v1 = rotate (0/90/180/270) + flip (none/horizontal/vertical/both), ADR-0026. Single-input; `produces: same_as_input` (geometry preserves format/container). Chainable (NOT sole_op); canonical single-job chain order is `transform → convert → compress → thumbnail` (geometry before encode/derive so downstream width/height/fit refer to the final frame). Media groups: image (still jpeg/png/webp + animated `image_gif`), video (mp4/webm), document (PDF page-rotate only — no flip); audio not supported. ALL groups `availability: planned` (epic `fhiWebI0`) — workflow-create returns `feature_not_available` (422) until per-media Lambdas ship. A no-op transform (`rotate: 0` + `flip: none`) is rejected as `invalid_options`. The public operation type is `transform`; the API resolves an internal per-media SNS routing sub-type (`transform_image` / `transform_video` / `transform_document`) — those sub-types are routing-only and are NOT part of this public enum. Per ADR-0026.
@@ -10754,13 +11275,9 @@ components:
10754
11275
  The two forms are mutually exclusive (a request supplies exactly
10755
11276
  one — enforced by the `oneOf` below); they are NOT combined.
10756
11277
 
10757
- 🔴 **THE FLAT FORM IS `planned`, AND THE SERVER DOES NOT ACCEPT IT
10758
- YET.** Send `jobs[]`. A flat request is rejected today, and the
10759
- rejection is currently a generic *"At least one job is required"*
10760
- rather than the `feature_not_available` (422) envelope this contract
10761
- requires for a `planned` shape — tracked against `compression_api`,
10762
- so do not read that generic message as a validation error in your
10763
- own payload.
11278
+ 🔴 **THE FLAT FORM IS `planned`.** Send `jobs[]`. A flat request is
11279
+ rejected with the `feature_not_available` (422) envelope (feature
11280
+ `workflow.request.flat_form`) until the API accepts the flat form.
10764
11281
 
10765
11282
  ⚠️ **The equivalence stated above is the DESIGN, not observed
10766
11283
  behaviour.** It describes what the server will do once the lowering
@@ -10916,11 +11433,12 @@ components:
10916
11433
  $ref: '#/components/schemas/NotifyConfig'
10917
11434
  description: |
10918
11435
  Optional per-job completion-notification config
10919
- (channel-agnostic). Currently exposes the `email` channel: the
10920
- API emails the configured recipients when the selected workflow
10921
- events occur, with a **server-composed** presigned `/downloads`
10922
- link to the results — the request carries recipients + event
10923
- selection only.
11436
+ (channel-agnostic). Declares the `email` channel: once the
11437
+ dispatch engine ships, the API emails the configured recipients
11438
+ when the selected workflow events occur, with a
11439
+ **server-composed** presigned `/downloads` link to the results —
11440
+ the request carries recipients + event selection only. Nothing is
11441
+ sent today (see `NotifyConfig`).
10924
11442
 
10925
11443
  **Advertised-ahead (contract-first, ticket
10926
11444
  [`IQtEwVET`](https://trello.com/c/IQtEwVET)):** the completion-
@@ -11462,6 +11980,7 @@ components:
11462
11980
  job that consumes this output.
11463
11981
  node_id:
11464
11982
  type: string
11983
+ x-string-vocabulary: open
11465
11984
  description: |
11466
11985
  Symbolic composition `node_id` correlating this delivered output
11467
11986
  to its canonical node in `composition_plan` (e.g. `encode`,
@@ -11753,6 +12272,7 @@ components:
11753
12272
  $ref: '#/components/schemas/ProcessingClass'
11754
12273
  execution_pool:
11755
12274
  type: string
12275
+ x-string-vocabulary: advisory
11756
12276
  description: |
11757
12277
  Logical pool name. **Opaque string** — not an enum — so
11758
12278
  future pool naming evolves without contract churn. Known
@@ -11769,6 +12289,15 @@ components:
11769
12289
  $ref: '#/components/schemas/EstimateQuality'
11770
12290
  reason:
11771
12291
  $ref: '#/components/schemas/ProcessingClassReason'
12292
+ resolution_band:
12293
+ $ref: '#/components/schemas/ResolutionBand'
12294
+ description: |
12295
+ The resolution band whose ceiling the class decision was taken
12296
+ against, when the operation's classes declare
12297
+ `resolution_bands`; omitted otherwise. `unknown` says the
12298
+ resolution could not be determined, so `reason` (which names the
12299
+ AXIS, e.g. `input_duration_exceeds_short_form`) was judged against
12300
+ the `unknown` band's ceiling.
11772
12301
  dropped_options:
11773
12302
  type: array
11774
12303
  description: |
@@ -12016,6 +12545,7 @@ components:
12016
12545
  properties:
12017
12546
  node_id:
12018
12547
  type: string
12548
+ x-string-vocabulary: open
12019
12549
  description: |
12020
12550
  Stable **symbolic** canonical node id (e.g. `original`,
12021
12551
  `processed_base`, `encode`, `thumbnail`). The correlation key
@@ -12038,6 +12568,7 @@ components:
12038
12568
  nodes `type` is the operation as submitted.
12039
12569
  chain_group:
12040
12570
  type: string
12571
+ x-string-vocabulary: open
12041
12572
  description: |
12042
12573
  Which canonical stage this operation belongs to. **Open string,
12043
12574
  NOT a fixed enum** (mirrors `ProcessingPlanJob.execution_pool`) —
@@ -12166,10 +12697,8 @@ components:
12166
12697
  `blocked` is emitted when no tier-permitted pool exists for
12167
12698
  the file — any caller probing a `corrupt` /
12168
12699
  `unsupported_codec` file, or a caller below a class's
12169
- `required_tier`. Since 2026-09-23 (decision 26) the only
12170
- video classes still carrying one are `audio_watermark`'s
12171
- (`enterprise`, both `planned`), so the tier branch is
12172
- unreachable for every callable video class.
12700
+ `required_tier`. Since 2026-09-23 (decision 26) no class
12701
+ carries one, so the tier branch is currently unreachable.
12173
12702
  # CLOSED. It GATES AN AFFORDANCE: `blocked` is a hard stop and the others
12174
12703
  # predict routing. An unrecognised class cannot be safely treated as routable —
12175
12704
  # a consumer guessing would offer an upload the server will refuse. A new
@@ -12307,6 +12836,84 @@ components:
12307
12836
  contract on the OpenAPI side; the prober reports the
12308
12837
  page-1 horizontal DPI when the document declares it,
12309
12838
  otherwise omits the field.
12839
+ # STREAM TOPOLOGY + CONCAT ATTRIBUTES (lGeDDi4V, for MjzzPCWt): what the
12840
+ # API needs to refuse a non-concat-uniform long-form merge at create.
12841
+ # Defined with the SAME semantics as compression_lambdas' merge gate
12842
+ # (re_encode.rs TopologyCounts / classify_non_uniform), or the
12843
+ # create-time refusal and the worker gate would disagree. All OPTIONAL:
12844
+ # a prober that has not emitted them yet simply omits them.
12845
+ video_stream_count:
12846
+ type: integer
12847
+ minimum: 0
12848
+ description: Streams whose ffprobe `codec_type` is `video`.
12849
+ audio_stream_count:
12850
+ type: integer
12851
+ minimum: 0
12852
+ description: Streams whose ffprobe `codec_type` is `audio`.
12853
+ other_stream_count:
12854
+ type: integer
12855
+ minimum: 0
12856
+ description: |
12857
+ Every other stream: `codec_type` subtitle, data, attachment,
12858
+ or unknown — the worker gate's `other` bucket.
12859
+ stream_order:
12860
+ type: array
12861
+ items:
12862
+ type: string
12863
+ enum: [video, audio, other]
12864
+ description: |
12865
+ Per stream index, in container order, its kind (`other` as
12866
+ above). Two inputs are order-compatible iff these are equal.
12867
+ r_frame_rate:
12868
+ type: string
12869
+ pattern: '^[0-9]+/[0-9]+$'
12870
+ description: |
12871
+ ffprobe `r_frame_rate` of the video stream, raw (`30000/1001`;
12872
+ ffprobe's `0/0` is carried as-is and means UNUSABLE). NOT the
12873
+ average rate in `fps`, which drifts between concat-uniform
12874
+ clips. **The worker's frame-rate rule, which a create-time
12875
+ comparison must reproduce exactly:** (1) `r_frame_rate` and
12876
+ `avg_frame_rate` must each be present on all inputs or absent
12877
+ on all (else `input_metadata_inconsistent`); (2) if every
12878
+ input has a usable `r_frame_rate`, compare those as parsed
12879
+ rationals; (3) otherwise compare `avg_frame_rate` as parsed
12880
+ rationals. Both comparisons are by VALUE (`60/2` equals `30/1`),
12881
+ never by string.
12882
+ avg_frame_rate:
12883
+ type: string
12884
+ pattern: '^[0-9]+/[0-9]+$'
12885
+ description: |
12886
+ ffprobe `avg_frame_rate` of the video stream, raw rational.
12887
+ Presence-checked always; compared only as the fallback in the
12888
+ `r_frame_rate` rule. `fps` is its lossy numeric form.
12889
+ pix_fmt:
12890
+ type: string
12891
+ x-string-vocabulary: none
12892
+ description: ffprobe `pix_fmt` of the video stream (e.g. `yuv420p`).
12893
+ sar:
12894
+ type: string
12895
+ pattern: '^[0-9]+:[0-9]+$'
12896
+ description: Sample aspect ratio of the video stream (`1:1`).
12897
+ video_time_base:
12898
+ type: string
12899
+ pattern: '^[0-9]+/[0-9]+$'
12900
+ description: ffprobe `time_base` of the video stream (`1/30000`).
12901
+ audio_time_base:
12902
+ type: string
12903
+ pattern: '^[0-9]+/[0-9]+$'
12904
+ description: ffprobe `time_base` of the audio stream (`1/48000`).
12905
+ codec_tag:
12906
+ type: string
12907
+ x-string-vocabulary: none
12908
+ description: ffprobe `codec_tag_string` of the video stream (e.g. `avc1`).
12909
+ profile:
12910
+ type: string
12911
+ x-string-vocabulary: none
12912
+ description: ffprobe `profile` of the video stream (e.g. `High`).
12913
+ sample_fmt:
12914
+ type: string
12915
+ x-string-vocabulary: none
12916
+ description: ffprobe `sample_fmt` of the audio stream (e.g. `fltp`).
12310
12917
  probed_at:
12311
12918
  type: string
12312
12919
  format: date-time
@@ -12750,7 +13357,9 @@ components:
12750
13357
  description: |
12751
13358
  OPTIONAL, drill-in-only "code for this run" / replay projection — the
12752
13359
  allowlisted, re-submittable shape of the original request (for an SDK
12753
- snippet / "run it again"). Absent until the API populates it. NOT a
13360
+ snippet / "run it again"). Emitted on every workflow status
13361
+ response by an API that implements the projector; OPTIONAL so a
13362
+ consumer of an older API build tolerates its absence. NOT a
12754
13363
  dump of the persisted option bag; see `CodegenSource`. Per ticket
12755
13364
  `LO0R5gzk`.
12756
13365
 
@@ -12985,8 +13594,9 @@ components:
12985
13594
  EXCLUDES all of that plus runtime results.
12986
13595
 
12987
13596
  **Detail-only** — `WorkflowStatusResponse` only, NEVER `WorkflowSummary`
12988
- (payload + the list view doesn't need it). OPTIONAL: the projector ships
12989
- incrementally; the field is absent until the API populates it.
13597
+ (payload + the list view doesn't need it). OPTIONAL in the schema so a
13598
+ consumer of an older API build tolerates its absence; an API that
13599
+ implements the projector emits it on every status response.
12990
13600
 
12991
13601
  **Scope: the reproducible JOB graph only.** Workflow-level request
12992
13602
  fields (`delivery` / `export` / `processing`) are deliberately NOT part
@@ -13397,6 +14007,9 @@ components:
13397
14007
  `never_started` (the operation was terminated without ever running
13398
14008
  because its job reached a terminal state first — an upstream failure
13399
14009
  OR a cancellation; API-derived, never worker-emitted),
14010
+ `processing_limit_exceeded` (a processing tool was killed at a
14011
+ budget set from this input — deterministic, non-retryable; a
14012
+ transient deadline is `timeout`),
13400
14013
  `unknown` (unclassified),
13401
14014
  `out_of_memory` (retryable), `timeout` (retryable),
13402
14015
  `s3_download_failed` (retryable), `s3_upload_failed` (retryable).
@@ -13407,6 +14020,39 @@ components:
13407
14020
  Human-readable failure detail. Present when `status` is `failed`;
13408
14021
  absent otherwise. Mirrors `SseOperationFailedData.error_message`.
13409
14022
  example: "output_too_large: Output (12156489 bytes) is not smaller than input (6187609 bytes)"
14023
+ message_key:
14024
+ $ref: '#/components/schemas/OperationMessageKey'
14025
+ message_params:
14026
+ $ref: '#/components/schemas/OperationMessageParams'
14027
+
14028
+ OperationMessageKey:
14029
+ type: string
14030
+ x-string-vocabulary: open
14031
+ pattern: '^[a-z][a-z0-9_]*(\.[a-z][a-z0-9_]*)+$'
14032
+ description: |
14033
+ Stable, never-localised key REFINING `error_code` on a failed
14034
+ operation, so a client can show specific, localised copy (e.g.
14035
+ `thumbnail.epub.no_cover`). OPTIONAL, failed only. Every value is
14036
+ declared, with the codes it may accompany and its parameters, in
14037
+ `schemas/operation-message-keys.yaml` (the one registry). Passed
14038
+ through unchanged from the worker's OperationResult. A client
14039
+ that does not know a key, or receives one whose registry
14040
+ `error_codes` do not include this `error_code`, ignores the key and
14041
+ falls back to the `error_code` headline;
14042
+ retry is still decided from the code. Ticket U7GQhjhX.
14043
+ example: "thumbnail.epub.no_cover"
14044
+
14045
+ OperationMessageParams:
14046
+ type: object
14047
+ additionalProperties:
14048
+ type: [string, integer, number, boolean]
14049
+ description: |
14050
+ Interpolation values for `message_key`, named and typed in
14051
+ `schemas/operation-message-keys.yaml`. JSON scalars only (string,
14052
+ integer, number, boolean) — no nested objects. Absent when the key
14053
+ declares no parameters (`params: {}`), and carries exactly the
14054
+ registry's parameters otherwise. Never carries free-text
14055
+ diagnostics; those stay in `error_message`.
13410
14056
 
13411
14057
  OperationResultMetadata:
13412
14058
  type: object
@@ -13418,9 +14064,15 @@ components:
13418
14064
  diagnostics never leak. New keys are **additive named cuts** (the
13419
14065
  `additionalProperties: false` closure is the point — an unmodelled
13420
14066
  key is a coordinated contract change, not a silent rollout). Twin of
13421
- the AsyncAPI `OperationResultMetadata` (wire ↔ read parity). Distinct
14067
+ the AsyncAPI `OperationResultMetadata` (wire ↔ read parity), except
14068
+ `already_optimal` / `estimated_saving_pct`, which the API projects
14069
+ from the wire `OperationMetrics` where the worker emits them. Distinct
13422
14070
  from `OperationResult` (the deliverable output file): this carries
13423
14071
  small per-operation metadata, not the output. Per `EurbZLMH` (B1).
14072
+ # The estimated_saving_pct => already_optimal:true relation is ENFORCED on
14073
+ # the wire OperationMetrics this is projected from, not here: this schema
14074
+ # also types the workflowCallback webhook payload, where oasdiff reads an
14075
+ # added if/then as a breaking REQUEST change.
13424
14076
  properties:
13425
14077
  watermark_id:
13426
14078
  type: string
@@ -13433,6 +14085,28 @@ components:
13433
14085
  whitelist ship now (additive) so the result_metadata pipeline +
13434
14086
  read projection land without a later contract bump; absent in
13435
14087
  practice until B3 is live.
14088
+ already_optimal:
14089
+ type: boolean
14090
+ description: |
14091
+ `true` when the operation completed by returning the ORIGINAL file
14092
+ unchanged, because compressing it would not have made it smaller
14093
+ (or the source was already efficiently encoded). The operation is
14094
+ a success, not a failure: `result` is the original. Show it as
14095
+ "already optimised", not as "same size". On an ordinary result it
14096
+ is absent or `false`; treat the two the same. Projected by the API from the wire
14097
+ `OperationMetrics.already_optimal` (ticket `roNRMilt`).
14098
+ example: true
14099
+ estimated_saving_pct:
14100
+ type: number
14101
+ minimum: 0
14102
+ maximum: 100
14103
+ description: |
14104
+ OPTIONAL, only with `already_optimal: true`: the worker's ESTIMATE
14105
+ of how much smaller, as a percentage of the input size, a re-encode
14106
+ would have made the file, when it declined before encoding. Absent
14107
+ when no estimate was made. An estimate, not a guarantee. Projected
14108
+ from the wire `OperationMetrics.estimated_saving_pct`.
14109
+ example: 3.5
13436
14110
 
13437
14111
  OperationResult:
13438
14112
  type: object
@@ -13527,6 +14201,7 @@ components:
13527
14201
  `OperationMetrics.measured_quality`.
13528
14202
  quality_metric:
13529
14203
  type: string
14204
+ x-string-vocabulary: advisory
13530
14205
  description: |
13531
14206
  The perceptual metric that produced `measured_quality` — a free-form
13532
14207
  string (not an enum) so it can evolve without contract churn. Present
@@ -13543,10 +14218,11 @@ components:
13543
14218
  $ref: '#/components/schemas/ReEncodeDecision'
13544
14219
  re_encode_reason:
13545
14220
  type: string
14221
+ x-string-vocabulary: advisory
13546
14222
  description: |
13547
14223
  Advisory explanation for `re_encode_decision` (e.g.
13548
- `all_inputs_compatible`, `explicit_always_mode`,
13549
- `input_codec_mismatch`, `input_framerate_mismatch`).
14224
+ `compatible_inputs`, `always_mode_forces_re_encode`,
14225
+ `input_video_codec_mismatch`, `long_form_stream_copy`).
13550
14226
  Free-form string — not an enum — so the Lambda can emit
13551
14227
  human-readable diagnostics that evolve without contract
13552
14228
  changes. Mirrors `OperationMetrics.re_encode_reason`.
@@ -13837,6 +14513,7 @@ components:
13837
14513
  Mirrors `OperationMetrics.measured_quality`.
13838
14514
  quality_metric:
13839
14515
  type: string
14516
+ x-string-vocabulary: advisory
13840
14517
  description: |
13841
14518
  For an `auto_quality` encode: the perceptual metric that produced
13842
14519
  `measured_quality` — a free-form string (not an enum) so it can evolve
@@ -13857,6 +14534,10 @@ components:
13857
14534
  is gapless ONLY for a full conversion, not for a sparse selection.
13858
14535
  NOT the download `filename` suffix (that is a 0-based array
13859
14536
  position — see `OperationDownload.filename`). Mutually exclusive with `position`.
14537
+ For a `split` of a PDF with `mode: page_groups`, each output holds
14538
+ a GROUP of pages and `page_index` is the group's FIRST source
14539
+ page; the group covers `page_index` .. `page_index + page_groups
14540
+ - 1`, and the last group ends at the document's last page.
13860
14541
  Normative semantics: ADR-0009 §D2.
13861
14542
  Absent on non-indexed (single-output) downloads. Mirrors
13862
14543
  `OperationResultOutputEntry.page_index`. Per ADR-0009 §D2.
@@ -13885,6 +14566,7 @@ components:
13885
14566
  example: "thumb-2x"
13886
14567
  node_id:
13887
14568
  type: string
14569
+ x-string-vocabulary: open
13888
14570
  description: |
13889
14571
  Symbolic composition `node_id` correlating this download to its
13890
14572
  canonical node in `WorkflowCreateResponse.composition_plan` (e.g.
@@ -14268,9 +14950,10 @@ components:
14268
14950
  not: { required: [page_index] }
14269
14951
  - title: Unindexed
14270
14952
  description: |
14271
- Output without an explicit indexing field. Reserved for future
14272
- operations that index by something other than page/position.
14273
- Schema-valid but not currently emitted by any operation.
14953
+ Output without a page/position indexing field. Covers legacy
14954
+ single-output entries AND `render_variants` variant outputs (still
14955
+ `planned`, so not reachable through the API until that operation
14956
+ is). Mirrors the AsyncAPI `OperationResultOutputEntry` branch.
14274
14957
  not:
14275
14958
  anyOf:
14276
14959
  - required: [page_index]
@@ -14300,6 +14983,10 @@ components:
14300
14983
  is gapless ONLY for a full conversion, not for a sparse selection.
14301
14984
  NOT the download `filename` suffix (that is a 0-based array
14302
14985
  position — see `OperationDownload.filename`). Mutually exclusive with `position`.
14986
+ For a `split` of a PDF with `mode: page_groups`, each output holds
14987
+ a GROUP of pages and `page_index` is the group's FIRST source
14988
+ page; the group covers `page_index` .. `page_index + page_groups
14989
+ - 1`, and the last group ends at the document's last page.
14303
14990
  Normative semantics: ADR-0009 §D2.
14304
14991
  Absent on non-indexed outputs. Mirrors
14305
14992
  `OperationResultOutputEntry.page_index`. Per ADR-0009 §D2.
@@ -14346,6 +15033,10 @@ components:
14346
15033
  generic reason.
14347
15034
  error_message:
14348
15035
  type: string
15036
+ message_key:
15037
+ $ref: '#/components/schemas/OperationMessageKey'
15038
+ message_params:
15039
+ $ref: '#/components/schemas/OperationMessageParams'
14349
15040
 
14350
15041
  SseJobCompletedData:
14351
15042
  type: object
@@ -14406,6 +15097,7 @@ components:
14406
15097
  - partially_failed
14407
15098
  reason:
14408
15099
  type: string
15100
+ x-string-vocabulary: advisory
14409
15101
  description: |
14410
15102
  Optional advisory reason for the terminal state. Free-form
14411
15103
  string; not an enum. Examples: "all jobs completed
@@ -15244,10 +15936,9 @@ components:
15244
15936
  description: |
15245
15937
  Operation-level availability tag. Optional — when absent, the
15246
15938
  operation is treated as `stable` (parser obligation per
15247
- ADR-0001 §1.4 / FORMAT.md §Availability Taxonomy). Runtime
15248
- emission lands with [I3 `eCWIpug8`](https://trello.com/c/eCWIpug8);
15249
- until then the contract declares the shape but the endpoint
15250
- does not yet surface the field.
15939
+ ADR-0001 §1.4 / FORMAT.md §Availability Taxonomy). Echoed by
15940
+ `GET /api/operations/schema` whenever the operation schema
15941
+ declares it ([I3 `eCWIpug8`](https://trello.com/c/eCWIpug8)).
15251
15942
  required_tier:
15252
15943
  $ref: '#/components/schemas/UserTier'
15253
15944
  description: |
@@ -15410,7 +16101,7 @@ components:
15410
16101
  description: |
15411
16102
  Optional mime-group-level INPUT-file size ceiling in BYTES
15412
16103
  (ticket [`uKsFzORi`](https://trello.com/c/uKsFzORi)). Sibling of
15413
- `max_output_pixels`. **Applies to the enclosing operation's input**, and
16104
+ `max_output_pixels` (declared below). **Applies to the enclosing operation's input**, and
15414
16105
  a consumer MUST scope it to the operation whose schema carries it —
15415
16106
  **the same MIME can carry different ceilings under different
15416
16107
  operations, because different workers process it.** ⚠️ This line
@@ -15433,6 +16124,33 @@ components:
15433
16124
  `processing_class.<class>.constraints.max_input_size_bytes` instead —
15434
16125
  never both, so the input ceiling lives in exactly one place per group.
15435
16126
  CI-enforced by `scripts/check-per-tier-constraints.py`.
16127
+ max_output_pixels:
16128
+ type: integer
16129
+ format: int64
16130
+ minimum: 1
16131
+ description: |
16132
+ Optional mime-group-level OUTPUT area cap: a request is valid on
16133
+ this axis iff `width × height <= max_output_pixels`, read from the
16134
+ two option values. Declared here since 2026-09-23 (`gACSVjiK`): it
16135
+ was named as a "sibling" of `max_input_size_bytes` while existing
16136
+ only in the operation schemas and the availability sidecar, and a
16137
+ consumer diffing the served schema reported it as a missing key.
16138
+ ⚠️ **Optional, and not yet round-tripped by `GET
16139
+ /api/operations/schema`** — the operation schemas under `schemas/`
16140
+ and `availability/availability.json` carry it today. See
16141
+ `schemas/FORMAT.md` §`max_output_pixels`.
16142
+ input_size_bound:
16143
+ type: string
16144
+ enum: [processing_time]
16145
+ x-enum-openness: closed
16146
+ description: |
16147
+ Declares that the group has **no byte ceiling on purpose**: the
16148
+ worker is bounded by processing time instead. XOR with
16149
+ `max_input_size_bytes` — exactly one is present when either is, so
16150
+ an absent pair means "nothing declared", never "unlimited".
16151
+ Declared here since 2026-09-23 (`gACSVjiK`) for the same reason as
16152
+ `max_output_pixels`, with the same round-trip caveat. See
16153
+ `schemas/FORMAT.md` §`input_size_bound`.
15436
16154
  max_input_duration:
15437
16155
  type: string
15438
16156
  description: |
@@ -15609,6 +16327,7 @@ components:
15609
16327
  description: Maximum value (for integer/float types)
15610
16328
  pattern:
15611
16329
  type: string
16330
+ x-string-vocabulary: none
15612
16331
  description: |
15613
16332
  ECMA-262 regular expression a `type: string` value MUST match
15614
16333
  (the string analogue of `min`/`max`). Consumers pre-validate
@@ -15619,6 +16338,29 @@ components:
15619
16338
  `#RRGGBB`; a CSS named colour was silently dropped to white). Only
15620
16339
  meaningful for `type: string`. See `schemas/FORMAT.md`.
15621
16340
  example: "^#[0-9a-fA-F]{6}$"
16341
+ items:
16342
+ type: object
16343
+ additionalProperties: true
16344
+ description: |
16345
+ `type: array` only. A JSON Schema 2020-12 OBJECT subschema every
16346
+ element must satisfy (boolean schemas are not used in this DSL;
16347
+ e.g. `{type: number, exclusiveMinimum: 0}` for
16348
+ `split.cut_points`, or an object shape for
16349
+ `image_watermark.overlays`). Named in JSON Schema's own camelCase,
16350
+ like `pattern`, because these ARE JSON Schema keywords and the
16351
+ published operation schemas already use them (fzrEO6GN).
16352
+ minItems:
16353
+ type: integer
16354
+ minimum: 0
16355
+ description: "`type: array` only. Fewest elements allowed."
16356
+ maxItems:
16357
+ type: integer
16358
+ minimum: 0
16359
+ description: "`type: array` only. Most elements allowed."
16360
+ uniqueItems:
16361
+ type: boolean
16362
+ description: |
16363
+ `type: array` only. `true`: elements must be pairwise distinct.
15622
16364
  depends_on:
15623
16365
  type: object
15624
16366
  description: |
@@ -15641,7 +16383,10 @@ components:
15641
16383
  on the optimiser path (e.g. JPEG `progressive`); `[format_change]`
15642
16384
  only on the transcoder path (e.g. `background` alpha-flatten to JPEG).
15643
16385
  ABSENT ≡ honored on every route the option's `depends_on` already
15644
- admits (back-compat — existing options need no tag). Orthogonal to
16386
+ admits (back-compat — existing options need no tag). An EMPTY
16387
+ list `[]` ≡ ACCEPTED BUT INERT: the option is still accepted on
16388
+ the wire but no route honours it, so it is never visible and
16389
+ never in `honored_options` (card `Nqd3TdC6`). Orthogonal to
15645
16390
  `availability`: a `planned` option still declares the route it WILL
15646
16391
  be honoured on. Consumers derive option visibility from
15647
16392
  `honored_on` ∩ active-route ∩ (availability != planned) ∩ depends_on.
@@ -15735,6 +16480,69 @@ components:
15735
16480
  Baseline caps for the lowest tier this class's
15736
16481
  `required_tier` permits. Overlaid per-caller by
15737
16482
  `per_tier_constraints` (see below).
16483
+ input_uniformity:
16484
+ type: object
16485
+ additionalProperties: false
16486
+ description: |
16487
+ Present on a class that CONCATENATES inputs without normalising
16488
+ them (today `merge.video.long_form_re_encode`, ticket `MjzzPCWt`):
16489
+ every input must share its stream layout (`structural`, a
16490
+ permanent requirement) and its stream attributes (`attributes`,
16491
+ until the heterogeneous re-encode ships). The names are the
16492
+ worker gate's reason vocabulary. A request that breaks it is
16493
+ refused at create with the `refusal` code where the API's upload
16494
+ probe can see the difference; the worker gate refuses the rest.
16495
+ required: [refusal, structural, attributes]
16496
+ properties:
16497
+ refusal:
16498
+ type: string
16499
+ enum: [INPUTS_NOT_CONCAT_UNIFORM]
16500
+ description: The `ErrorEnvelope.error` code of the create-time refusal.
16501
+ structural:
16502
+ type: array
16503
+ items: {type: string}
16504
+ description: Permanent stream-layout requirements (worker gate reason names).
16505
+ attributes:
16506
+ type: object
16507
+ additionalProperties:
16508
+ type: array
16509
+ items: {type: string}
16510
+ description: |
16511
+ Per stream kind (`video`, `audio`), the attributes every input
16512
+ must share until the heterogeneous re-encode ships; plus
16513
+ `field_presence`: a video/audio stream field present on one
16514
+ input and absent on another.
16515
+ resolution_bands:
16516
+ type: object
16517
+ description: |
16518
+ Optional per-resolution ceilings for this class (ticket
16519
+ [`GxQPL4IY`](https://trello.com/c/GxQPL4IY)). Keys are EVERY
16520
+ `ResolutionBand` value — each band in
16521
+ `schemas/resolution-bands.yaml` plus `unknown` — so when the
16522
+ block is present a consumer never has to invent a ceiling.
16523
+ An input is placed in a band by its probe's frame pixels
16524
+ (width x height); `unknown` applies when the probe has no
16525
+ width or height. A band only TIGHTENS `constraints` (after
16526
+ the `per_tier_constraints` overlay): the effective ceiling on
16527
+ an axis is the smaller of the two, and an axis the band omits
16528
+ falls through to the class. An input over its band's ceiling
16529
+ exceeds this class, exactly as one over `constraints` does.
16530
+ Absent = no resolution axis; `constraints` binds at every
16531
+ resolution. CI-checked by `scripts/check-resolution-bands.py`.
16532
+ See `schemas/FORMAT.md` §`resolution_bands`.
16533
+ # Every band is REQUIRED: a consumer must never invent a ceiling. The
16534
+ # property names are the `ResolutionBand` enum, held equal by a test.
16535
+ additionalProperties: false
16536
+ required: [le_720p, p1080, gt_1080p, unknown]
16537
+ properties:
16538
+ le_720p:
16539
+ $ref: '#/components/schemas/ResolutionBandCeiling'
16540
+ p1080:
16541
+ $ref: '#/components/schemas/ResolutionBandCeiling'
16542
+ gt_1080p:
16543
+ $ref: '#/components/schemas/ResolutionBandCeiling'
16544
+ unknown:
16545
+ $ref: '#/components/schemas/ResolutionBandCeiling'
15738
16546
  per_tier_constraints:
15739
16547
  type: object
15740
16548
  description: |
@@ -15753,6 +16561,108 @@ components:
15753
16561
  additionalProperties:
15754
16562
  $ref: '#/components/schemas/ProcessingClassConstraints'
15755
16563
 
16564
+ ResolutionBand:
16565
+ type: string
16566
+ description: |
16567
+ A resolution band (ticket [`GxQPL4IY`](https://trello.com/c/GxQPL4IY)).
16568
+ The band names and their frame-pixel bounds are declared ONCE in
16569
+ `schemas/resolution-bands.yaml`; this enum is those names plus the
16570
+ `unknown` band, held equal by a test.
16571
+
16572
+ - `le_720p`, `p1080`, `gt_1080p`: ascending frame-pixel bands
16573
+ (width x height). Their bounds are `max_frame_pixels` in
16574
+ `schemas/resolution-bands.yaml` and are deliberately not
16575
+ restated here.
16576
+ - `unknown`: the upload probe reported no width or no height, so the
16577
+ resolution could not be determined. A refusal or escalation under
16578
+ this band means "we could not tell this file's resolution", which
16579
+ calls for a different action (re-upload, wait for the probe,
16580
+ contact us) than "your file is too long".
16581
+
16582
+ Pixels, not height: a portrait clip lands in the same band as its
16583
+ landscape twin.
16584
+ # CLOSED. The band a consumer computes decides which ceiling it enforces;
16585
+ # an unrecognised band cannot be mapped to a ceiling safely in either
16586
+ # direction, so a new band is a contract event consumers must learn.
16587
+ x-enum-openness: closed
16588
+ enum:
16589
+ - le_720p
16590
+ - p1080
16591
+ - gt_1080p
16592
+ - unknown
16593
+
16594
+ ResolutionBandCeiling:
16595
+ type: object
16596
+ additionalProperties: false
16597
+ description: |
16598
+ One band's ceiling within `ProcessingClassEntry.resolution_bands`.
16599
+ `basis` is REQUIRED so no consumer inherits a default for a band
16600
+ nobody measured. `not_served` carries neither `constraints` nor
16601
+ `derivation`; `measured` carries both; `ruled` carries
16602
+ `constraints` only.
16603
+ required:
16604
+ - basis
16605
+ allOf:
16606
+ - if:
16607
+ properties: {basis: {const: not_served}}
16608
+ then:
16609
+ not:
16610
+ anyOf:
16611
+ - required: [constraints]
16612
+ - required: [derivation]
16613
+ else:
16614
+ required: [constraints]
16615
+ - if:
16616
+ properties: {basis: {const: measured}}
16617
+ then:
16618
+ required: [derivation]
16619
+ else:
16620
+ not:
16621
+ required: [derivation]
16622
+ properties:
16623
+ basis:
16624
+ type: string
16625
+ description: |
16626
+ - `measured`: the ceiling is derived from measured encode time;
16627
+ `derivation` carries the line it was solved from.
16628
+ - `ruled`: a policy value, not a measurement (today: the
16629
+ `unknown` band, which takes the `le_720p` ceiling).
16630
+ - `not_served`: this class does not serve inputs in this band.
16631
+ No `constraints`; an input in this band exceeds the class
16632
+ (for `short_form`: it escalates to `long_form`, or is refused
16633
+ where `long_form` is not available).
16634
+ # CLOSED: each value changes what a consumer enforces.
16635
+ x-enum-openness: closed
16636
+ enum: [measured, ruled, not_served]
16637
+ constraints:
16638
+ type: object
16639
+ additionalProperties: false
16640
+ description: Present unless `basis` is `not_served`.
16641
+ minProperties: 1
16642
+ properties:
16643
+ max_input_duration:
16644
+ type: string
16645
+ description: ISO-8601 duration; the band's input duration ceiling.
16646
+ example: "PT4M35S"
16647
+ derivation:
16648
+ type: object
16649
+ additionalProperties: false
16650
+ description: |
16651
+ Present only when `basis` is `measured`. Encode time was measured
16652
+ as a line, `slope_s_per_s x duration + intercept_s`; the ceiling is
16653
+ that line solved for `cap_s` and FLOORED, so it never promises a
16654
+ duration that crosses the cap. CI recomputes the ceiling from these.
16655
+ required: [slope_s_per_s, intercept_s, cap_s]
16656
+ properties:
16657
+ slope_s_per_s:
16658
+ type: number
16659
+ exclusiveMinimum: 0
16660
+ intercept_s:
16661
+ type: number
16662
+ cap_s:
16663
+ type: number
16664
+ exclusiveMinimum: 0
16665
+
15756
16666
  # ============================================
15757
16667
  # RETRY SCHEMAS
15758
16668
  # ============================================
@@ -15810,15 +16720,22 @@ components:
15810
16720
  NotifyConfig:
15811
16721
  type: object
15812
16722
  x-availability: planned
16723
+ # CLOSED to the declared channels: the API refuses an undeclared channel
16724
+ # key as validation_error, so the schema says so too (codex, #568).
16725
+ additionalProperties: false
15813
16726
  description: |
15814
16727
  Channel-agnostic per-job completion-notification config (ticket
15815
16728
  [`IQtEwVET`](https://trello.com/c/IQtEwVET)). Currently the `email`
15816
16729
  channel only; `webhook` folds onto the same dispatch engine later
15817
16730
  (today webhook is configured via the top-level `callback_url` /
15818
16731
  `callback_events`). **Advertised-ahead** — the API returns
15819
- `feature_not_available` (422) for any `notify` use until the
15820
- dispatch engine ships. `x-availability` is decorative per
15821
- ADR-0001 §1.5; the API is the authority on the 422 gate.
16732
+ `feature_not_available` (422) for any use of a declared channel
16733
+ until the dispatch engine ships, with feature path
16734
+ `workflow.notify.<channel>` (today `workflow.notify.email`), the
16735
+ same dotted grammar as `workflow.request.flat_form`. An undeclared
16736
+ channel key is a `validation_error` (422). `x-availability` is
16737
+ decorative per ADR-0001 §1.5; the API is the authority on the 422
16738
+ gate.
15822
16739
 
15823
16740
  An **empty `notify`** (object present but no channel set) is a
15824
16741
  no-op — the workflow runs normally with no notifications; it is