@wevion/cli 1.0.3489 → 1.0.3506

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 (2) hide show
  1. package/openapi.json +1313 -21
  2. package/package.json +1 -1
package/openapi.json CHANGED
@@ -46746,6 +46746,16 @@
46746
46746
  }
46747
46747
  ]
46748
46748
  },
46749
+ "copyAiGenerated": {
46750
+ "anyOf": [
46751
+ {
46752
+ "type": "boolean"
46753
+ },
46754
+ {
46755
+ "type": "null"
46756
+ }
46757
+ ]
46758
+ },
46749
46759
  "creativeFormat": {
46750
46760
  "anyOf": [
46751
46761
  {
@@ -51150,6 +51160,16 @@
51150
51160
  }
51151
51161
  ]
51152
51162
  },
51163
+ "copyAiGenerated": {
51164
+ "anyOf": [
51165
+ {
51166
+ "type": "boolean"
51167
+ },
51168
+ {
51169
+ "type": "null"
51170
+ }
51171
+ ]
51172
+ },
51153
51173
  "creativeFormat": {
51154
51174
  "anyOf": [
51155
51175
  {
@@ -55455,6 +55475,16 @@
55455
55475
  }
55456
55476
  ]
55457
55477
  },
55478
+ "copyAiGenerated": {
55479
+ "anyOf": [
55480
+ {
55481
+ "type": "boolean"
55482
+ },
55483
+ {
55484
+ "type": "null"
55485
+ }
55486
+ ]
55487
+ },
55458
55488
  "creativeFormat": {
55459
55489
  "anyOf": [
55460
55490
  {
@@ -63445,6 +63475,16 @@
63445
63475
  }
63446
63476
  ]
63447
63477
  },
63478
+ "copyAiGenerated": {
63479
+ "anyOf": [
63480
+ {
63481
+ "type": "boolean"
63482
+ },
63483
+ {
63484
+ "type": "null"
63485
+ }
63486
+ ]
63487
+ },
63448
63488
  "creativeFormat": {
63449
63489
  "anyOf": [
63450
63490
  {
@@ -103274,7 +103314,7 @@
103274
103314
  "creative-hub",
103275
103315
  "ai-register"
103276
103316
  ],
103277
- "description": "Lists the workspace AI-creatives register required by EU AI Act art. 50(2) traceability: Creative Hub library assets (generated, uploaded, imported) with their AI classification and provenance evidence, plus the caller's own completed AI generation jobs, from the chat and the legacy hub endpoints (media transforms — resize, background removal — and Creatomate composite renders of user footage are not generations and are excluded). `is_ai_generated` is tri-state — NULL means unknown, never human-made. Use the /export sibling for the CSV attachment.",
103317
+ "description": "Lists the workspace AI-creatives register required by EU AI Act art. 50(2) traceability: Creative Hub library assets (generated, uploaded, imported) with their AI classification and provenance evidence, the caller's own completed AI generation jobs from the chat and the legacy hub endpoints (media transforms — resize, background removal — and Creatomate composite renders of user footage are not generations and are excluded), and campaign drafts whose ad text was written by a model. `is_ai_generated` is tri-state — NULL means unknown, never human-made. `marking_evidence` says whether the file was actually read or the pipeline merely declared it. Use the /export sibling for the CSV attachment.",
103278
103318
  "parameters": [
103279
103319
  {
103280
103320
  "schema": {
@@ -103370,6 +103410,7 @@
103370
103410
  "source",
103371
103411
  "is_ai_generated",
103372
103412
  "ai_provenance",
103413
+ "marking_evidence",
103373
103414
  "generation_id",
103374
103415
  "created_at"
103375
103416
  ],
@@ -103379,7 +103420,7 @@
103379
103420
  "type": "string"
103380
103421
  },
103381
103422
  "entry_type": {
103382
- "description": "Origin table: `asset` = Creative Hub library asset, `generation_job` = completed AI generation job (chat or legacy hub).",
103423
+ "description": "Origin table: `asset` = Creative Hub library asset, `generation_job` = completed AI generation job (chat or legacy hub), `campaign_copy` = campaign draft whose ad text was written by a model.",
103383
103424
  "anyOf": [
103384
103425
  {
103385
103426
  "type": "string",
@@ -103387,6 +103428,12 @@
103387
103428
  "asset"
103388
103429
  ]
103389
103430
  },
103431
+ {
103432
+ "type": "string",
103433
+ "enum": [
103434
+ "campaign_copy"
103435
+ ]
103436
+ },
103390
103437
  {
103391
103438
  "type": "string",
103392
103439
  "enum": [
@@ -103480,6 +103527,35 @@
103480
103527
  "description": "Arbitrary JSON value with nested arrays and objects."
103481
103528
  }
103482
103529
  },
103530
+ "marking_evidence": {
103531
+ "description": "Where the classification comes from. `file_bytes` = the stored file was read (marking pipeline, upload detection or backfill) and `ai_provenance` reports what it carried. `pipeline_declaration` = a generation job our pipeline asserts it produced; the delivered file was never re-read, so it is NOT proof the bytes carry the marker. `human_declaration` = manually reclassified by a user. `none` = no evidence recorded.",
103532
+ "anyOf": [
103533
+ {
103534
+ "type": "string",
103535
+ "enum": [
103536
+ "file_bytes"
103537
+ ]
103538
+ },
103539
+ {
103540
+ "type": "string",
103541
+ "enum": [
103542
+ "pipeline_declaration"
103543
+ ]
103544
+ },
103545
+ {
103546
+ "type": "string",
103547
+ "enum": [
103548
+ "human_declaration"
103549
+ ]
103550
+ },
103551
+ {
103552
+ "type": "string",
103553
+ "enum": [
103554
+ "none"
103555
+ ]
103556
+ }
103557
+ ]
103558
+ },
103483
103559
  "generation_id": {
103484
103560
  "description": "Wevion generation this asset came from. Non-null rows are immutable AI facts.",
103485
103561
  "anyOf": [
@@ -160864,9 +160940,10 @@
160864
160940
  ]
160865
160941
  },
160866
160942
  "country_code": {
160867
- "description": "Paese ISO-3166-1 alpha-2.",
160943
+ "description": "Paese ISO-3166-1 alpha-2 (due lettere).",
160868
160944
  "maxLength": 2,
160869
160945
  "minLength": 2,
160946
+ "pattern": "^[A-Za-z]{2}$",
160870
160947
  "type": "string"
160871
160948
  },
160872
160949
  "email": {
@@ -161883,12 +161960,26 @@
161883
161960
  "description": "L’offerta di passaggio al Binario B che aspetta chi chiama. ⚠️ Non porta il token della pratica: quello è la chiave di lettura del fascicolo e non ha ragione di uscire da qui.",
161884
161961
  "type": "object",
161885
161962
  "required": [
161963
+ "country_code",
161886
161964
  "offered_at",
161887
161965
  "reason",
161888
161966
  "tc_document_id",
161889
161967
  "tc_version"
161890
161968
  ],
161891
161969
  "properties": {
161970
+ "country_code": {
161971
+ "description": "Il paese già dichiarato sulla pratica, o `null` se va ancora chiesto. ★ Oggi è sempre `null`: l’offerta la genera un cron del Binario A e nessuno ha compilato niente. Esce comunque perché è ciò che dice al modulo che quel campo è **da chiedere** — il giorno in cui un percorso saprà il paese in anticipo, lo stesso campo lo pre-compila senza toccare né la pagina né il contratto.",
161972
+ "anyOf": [
161973
+ {
161974
+ "maxLength": 2,
161975
+ "minLength": 2,
161976
+ "type": "string"
161977
+ },
161978
+ {
161979
+ "type": "null"
161980
+ }
161981
+ ]
161982
+ },
161892
161983
  "offered_at": {
161893
161984
  "description": "Quando l’offerta è nata. È l’unica data che esiste finché non la si accetta.",
161894
161985
  "format": "date-time",
@@ -162001,7 +162092,7 @@
162001
162092
  "tags": [
162002
162093
  "partner"
162003
162094
  ],
162004
- "description": "Accetta i termini dell’offerta di passaggio al Binario B. ★ È l’ATTO che il ponte non aveva: registra `tc_accepted_at`, l’IP, lo user-agent, l’impronta del testo e la versione — gli stessi cinque campi che la candidatura pubblica raccoglie, perché una prova di consenso non può avere due forme a seconda di dove entra — e porta la pratica in `received`, cioè nella coda normale. Finché questo atto non avviene l’approvazione risponde `409 tc_not_accepted` e il vincolo `ck_papp_approved_needs_consent` rifiuta comunque la transizione: nessuno può essere approvato senza aver accettato. `404` quando non c’è nulla da accettare (nessuna offerta, o già accettata: i due casi rispondono identico). `409 stale_version` quando la versione inviata non è quella corrente. `403` quando il programma è chiuso: accettare a porta chiusa scriverebbe un consenso write-once su un percorso che non può proseguire.",
162095
+ "description": "Completa e accetta l’offerta di passaggio al Binario B. ★ È l’ATTO che il ponte non aveva: porta il **paese** dichiarato (`country_code`, obbligatorio — l’offerta nasce senza, perché a generarla è un cron) e la prova di consenso. registra `tc_accepted_at`, l’IP, lo user-agent, l’impronta del testo e la versione — gli stessi cinque campi che la candidatura pubblica raccoglie, perché una prova di consenso non può avere due forme a seconda di dove entra — e porta la pratica in `received`, cioè nella coda normale. Finché questo atto non avviene l’approvazione risponde `409 tc_not_accepted` e il vincolo `ck_papp_approved_needs_consent` rifiuta comunque la transizione: nessuno può essere approvato senza aver accettato. `404` quando non c’è nulla da accettare (nessuna offerta, o già accettata: i due casi rispondono identico). `409 stale_version` quando la versione inviata non è quella corrente; `409 open_application_exists` quando per la stessa email esiste già una candidatura aperta — l’offerta non può portarne una seconda, e dirlo non è un oracolo perché quella pratica è di chi chiede. `400 invalid_country` quando `country_code` non è due lettere: è l’unico rifiuto non anti-oracolo di questa rotta, deciso prima di cercare l’offerta — un `404` al suo posto direbbe «non c’è niente per te» mentre manca solo un campo. `403` quando il programma è chiuso: accettare a porta chiusa scriverebbe un consenso write-once su un percorso che non può proseguire.",
162005
162096
  "requestBody": {
162006
162097
  "required": true,
162007
162098
  "content": {
@@ -162010,9 +162101,17 @@
162010
162101
  "additionalProperties": false,
162011
162102
  "type": "object",
162012
162103
  "required": [
162104
+ "country_code",
162013
162105
  "tos_version"
162014
162106
  ],
162015
162107
  "properties": {
162108
+ "country_code": {
162109
+ "description": "Il paese ISO-3166-1 alpha-2 in cui il partner è stabilito. ★ **Obbligatorio, e senza ripiego**: l’offerta di ponte nasce con `country_code` vuoto perché a generarla è un cron, e questa è l’unica porta da cui può arrivarne uno dichiarato. Non è un’etichetta: all’approvazione viene copiato in `partner.country_code`, e da lì `requiredChecksForLevel` decide se VIES è un controllo KYC dovuto o va sostituito da `company_registry`. Un valore indovinato sceglierebbe una verifica antiriciclaggio al posto di chi la deve subire.",
162110
+ "maxLength": 2,
162111
+ "minLength": 2,
162112
+ "pattern": "^[A-Za-z]{2}$",
162113
+ "type": "string"
162114
+ },
162016
162115
  "tos_version": {
162017
162116
  "description": "La versione dei T&C partner che si sta accettando. Deve essere quella CORRENTE: accettare una versione vecchia scriverebbe una prova di consenso su un testo diverso da quello mostrato.",
162018
162117
  "maxLength": 20,
@@ -162053,6 +162152,41 @@
162053
162152
  }
162054
162153
  }
162055
162154
  },
162155
+ "400": {
162156
+ "description": "Errore standard del backend.",
162157
+ "content": {
162158
+ "application/json": {
162159
+ "schema": {
162160
+ "additionalProperties": false,
162161
+ "description": "Errore standard del backend.",
162162
+ "type": "object",
162163
+ "required": [
162164
+ "error",
162165
+ "message",
162166
+ "statusCode"
162167
+ ],
162168
+ "properties": {
162169
+ "code": {
162170
+ "description": "Codice macchina dell’errore, quando disponibile.",
162171
+ "type": "string"
162172
+ },
162173
+ "error": {
162174
+ "description": "Etichetta breve dell’errore.",
162175
+ "type": "string"
162176
+ },
162177
+ "message": {
162178
+ "description": "Messaggio leggibile.",
162179
+ "type": "string"
162180
+ },
162181
+ "statusCode": {
162182
+ "description": "Codice di stato HTTP ripetuto nel corpo.",
162183
+ "type": "integer"
162184
+ }
162185
+ }
162186
+ }
162187
+ }
162188
+ }
162189
+ },
162056
162190
  "401": {
162057
162191
  "description": "Errore standard del backend.",
162058
162192
  "content": {
@@ -163965,6 +164099,892 @@
163965
164099
  }
163966
164100
  }
163967
164101
  },
164102
+ "/api/v1/partner/invoices": {
164103
+ "get": {
164104
+ "operationId": "listPartnerInvoices",
164105
+ "summary": "Le mie fatture",
164106
+ "tags": [
164107
+ "partner"
164108
+ ],
164109
+ "description": "Le fatture caricate dal partner, dalla più recente. Ogni riga porta un link firmato a 15 minuti, rigenerato a ogni chiamata: non esiste un URL permanente verso un documento fiscale. Chi è compensato in credito di fatturazione (Binario A) riceve 403: non fattura, quindi non carica.",
164110
+ "security": [
164111
+ {
164112
+ "bearerAuth": []
164113
+ }
164114
+ ],
164115
+ "responses": {
164116
+ "200": {
164117
+ "description": "Le fatture caricate dal partner, dalla più recente.",
164118
+ "content": {
164119
+ "application/json": {
164120
+ "schema": {
164121
+ "additionalProperties": false,
164122
+ "description": "Le fatture caricate dal partner, dalla più recente.",
164123
+ "type": "object",
164124
+ "required": [
164125
+ "rows"
164126
+ ],
164127
+ "properties": {
164128
+ "rows": {
164129
+ "type": "array",
164130
+ "items": {
164131
+ "additionalProperties": false,
164132
+ "description": "Una fattura del partner.",
164133
+ "type": "object",
164134
+ "required": [
164135
+ "applied_on",
164136
+ "currency",
164137
+ "download_url",
164138
+ "expires_at",
164139
+ "gross_amount_minor",
164140
+ "id",
164141
+ "invoice_date",
164142
+ "invoice_number",
164143
+ "reject_reason",
164144
+ "retain_until",
164145
+ "sha256",
164146
+ "size_bytes",
164147
+ "status",
164148
+ "uploaded_at"
164149
+ ],
164150
+ "properties": {
164151
+ "applied_on": {
164152
+ "description": "`null` finché il bonifico non è uscito.",
164153
+ "anyOf": [
164154
+ {
164155
+ "description": "Giorno in cui la fattura è stata scalata su un bonifico.",
164156
+ "format": "date",
164157
+ "pattern": "^[0-9]{4}-[0-9]{2}-[0-9]{2}$",
164158
+ "type": "string"
164159
+ },
164160
+ {
164161
+ "type": "null"
164162
+ }
164163
+ ]
164164
+ },
164165
+ "currency": {
164166
+ "description": "Valuta del documento. Sempre `EUR` nel programma di oggi.",
164167
+ "type": "string"
164168
+ },
164169
+ "download_url": {
164170
+ "description": "Link firmato a 15 minuti, rigenerato a ogni chiamata. `null` quando la firma non è configurata: una lista non deve rispondere 500 per un link in meno.",
164171
+ "anyOf": [
164172
+ {
164173
+ "type": "string"
164174
+ },
164175
+ {
164176
+ "type": "null"
164177
+ }
164178
+ ]
164179
+ },
164180
+ "expires_at": {
164181
+ "description": "Scadenza del link. `null` quando il link non è stato firmato.",
164182
+ "anyOf": [
164183
+ {
164184
+ "format": "date-time",
164185
+ "type": "string"
164186
+ },
164187
+ {
164188
+ "type": "null"
164189
+ }
164190
+ ]
164191
+ },
164192
+ "gross_amount_minor": {
164193
+ "description": "Totale della fattura, IVA inclusa: è la cifra che si bonifica per intero. Minor units (centesimi) come stringa decimale.",
164194
+ "pattern": "^-?[0-9]+$",
164195
+ "type": "string"
164196
+ },
164197
+ "id": {
164198
+ "description": "Id del documento.",
164199
+ "format": "uuid",
164200
+ "type": "string"
164201
+ },
164202
+ "invoice_date": {
164203
+ "description": "Data della fattura.",
164204
+ "format": "date",
164205
+ "pattern": "^[0-9]{4}-[0-9]{2}-[0-9]{2}$",
164206
+ "type": "string"
164207
+ },
164208
+ "invoice_number": {
164209
+ "description": "Numero della fattura, come lo ha scritto il partner.",
164210
+ "type": "string"
164211
+ },
164212
+ "reject_reason": {
164213
+ "description": "Perché è stata rifiutata. `null` in ogni altro stato.",
164214
+ "anyOf": [
164215
+ {
164216
+ "type": "string"
164217
+ },
164218
+ {
164219
+ "type": "null"
164220
+ }
164221
+ ]
164222
+ },
164223
+ "retain_until": {
164224
+ "description": "Fino a quando il documento resta conservato: caricamento + 10 anni (art. 2220 c.c.).",
164225
+ "format": "date-time",
164226
+ "type": "string"
164227
+ },
164228
+ "sha256": {
164229
+ "description": "Impronta dei byte, calcolata dal backend. È la stessa che il download ri-verifica.",
164230
+ "pattern": "^[0-9a-f]{64}$",
164231
+ "type": "string"
164232
+ },
164233
+ "size_bytes": {
164234
+ "description": "Dimensione del PDF archiviato.",
164235
+ "type": "integer"
164236
+ },
164237
+ "status": {
164238
+ "description": "`uploaded` caricata · `verified` importo confrontato col bonifico · `applied` scalata su un bonifico uscito · `rejected` rifiutata, con motivo. `applied` e `rejected` sono terminali.",
164239
+ "anyOf": [
164240
+ {
164241
+ "type": "string",
164242
+ "enum": [
164243
+ "uploaded"
164244
+ ]
164245
+ },
164246
+ {
164247
+ "type": "string",
164248
+ "enum": [
164249
+ "verified"
164250
+ ]
164251
+ },
164252
+ {
164253
+ "type": "string",
164254
+ "enum": [
164255
+ "applied"
164256
+ ]
164257
+ },
164258
+ {
164259
+ "type": "string",
164260
+ "enum": [
164261
+ "rejected"
164262
+ ]
164263
+ }
164264
+ ]
164265
+ },
164266
+ "uploaded_at": {
164267
+ "description": "Quando è stata caricata.",
164268
+ "format": "date-time",
164269
+ "type": "string"
164270
+ }
164271
+ }
164272
+ }
164273
+ }
164274
+ }
164275
+ }
164276
+ }
164277
+ }
164278
+ },
164279
+ "401": {
164280
+ "description": "Errore standard del backend.",
164281
+ "content": {
164282
+ "application/json": {
164283
+ "schema": {
164284
+ "additionalProperties": false,
164285
+ "description": "Errore standard del backend.",
164286
+ "type": "object",
164287
+ "required": [
164288
+ "error",
164289
+ "message",
164290
+ "statusCode"
164291
+ ],
164292
+ "properties": {
164293
+ "code": {
164294
+ "description": "Codice macchina dell’errore, quando disponibile.",
164295
+ "type": "string"
164296
+ },
164297
+ "error": {
164298
+ "description": "Etichetta breve dell’errore.",
164299
+ "type": "string"
164300
+ },
164301
+ "message": {
164302
+ "description": "Messaggio leggibile.",
164303
+ "type": "string"
164304
+ },
164305
+ "statusCode": {
164306
+ "description": "Codice di stato HTTP ripetuto nel corpo.",
164307
+ "type": "integer"
164308
+ }
164309
+ }
164310
+ }
164311
+ }
164312
+ }
164313
+ },
164314
+ "403": {
164315
+ "description": "Errore standard del backend.",
164316
+ "content": {
164317
+ "application/json": {
164318
+ "schema": {
164319
+ "additionalProperties": false,
164320
+ "description": "Errore standard del backend.",
164321
+ "type": "object",
164322
+ "required": [
164323
+ "error",
164324
+ "message",
164325
+ "statusCode"
164326
+ ],
164327
+ "properties": {
164328
+ "code": {
164329
+ "description": "Codice macchina dell’errore, quando disponibile.",
164330
+ "type": "string"
164331
+ },
164332
+ "error": {
164333
+ "description": "Etichetta breve dell’errore.",
164334
+ "type": "string"
164335
+ },
164336
+ "message": {
164337
+ "description": "Messaggio leggibile.",
164338
+ "type": "string"
164339
+ },
164340
+ "statusCode": {
164341
+ "description": "Codice di stato HTTP ripetuto nel corpo.",
164342
+ "type": "integer"
164343
+ }
164344
+ }
164345
+ }
164346
+ }
164347
+ }
164348
+ }
164349
+ }
164350
+ },
164351
+ "post": {
164352
+ "operationId": "uploadPartnerInvoice",
164353
+ "summary": "Carica una fattura",
164354
+ "tags": [
164355
+ "partner"
164356
+ ],
164357
+ "description": "Carica la fattura del partner: **una** parte file `application/pdf` di al massimo 10 MB, più i campi `invoice_number`, `invoice_date` (`YYYY-MM-DD`) e `gross_amount_minor` (minor units EUR come stringa). Il totale è il LORDO IVA inclusa — la cifra che si bonifica per intero — e al momento della verifica dovrà coincidere al centesimo con quella del bonifico. L’impronta `sha256` la calcola il **backend** sui byte ricevuti: un valore dichiarato dal client non viene letto. Lo stesso PDF caricato due volte risponde 409. Il documento è archiviato con conservazione decennale e non è cancellabile: il ripensamento è farsela rifiutare e ricaricarne una.",
164358
+ "security": [
164359
+ {
164360
+ "bearerAuth": []
164361
+ }
164362
+ ],
164363
+ "responses": {
164364
+ "201": {
164365
+ "description": "Una fattura del partner.",
164366
+ "content": {
164367
+ "application/json": {
164368
+ "schema": {
164369
+ "additionalProperties": false,
164370
+ "description": "Una fattura del partner.",
164371
+ "type": "object",
164372
+ "required": [
164373
+ "applied_on",
164374
+ "currency",
164375
+ "download_url",
164376
+ "expires_at",
164377
+ "gross_amount_minor",
164378
+ "id",
164379
+ "invoice_date",
164380
+ "invoice_number",
164381
+ "reject_reason",
164382
+ "retain_until",
164383
+ "sha256",
164384
+ "size_bytes",
164385
+ "status",
164386
+ "uploaded_at"
164387
+ ],
164388
+ "properties": {
164389
+ "applied_on": {
164390
+ "description": "`null` finché il bonifico non è uscito.",
164391
+ "anyOf": [
164392
+ {
164393
+ "description": "Giorno in cui la fattura è stata scalata su un bonifico.",
164394
+ "format": "date",
164395
+ "pattern": "^[0-9]{4}-[0-9]{2}-[0-9]{2}$",
164396
+ "type": "string"
164397
+ },
164398
+ {
164399
+ "type": "null"
164400
+ }
164401
+ ]
164402
+ },
164403
+ "currency": {
164404
+ "description": "Valuta del documento. Sempre `EUR` nel programma di oggi.",
164405
+ "type": "string"
164406
+ },
164407
+ "download_url": {
164408
+ "description": "Link firmato a 15 minuti, rigenerato a ogni chiamata. `null` quando la firma non è configurata: una lista non deve rispondere 500 per un link in meno.",
164409
+ "anyOf": [
164410
+ {
164411
+ "type": "string"
164412
+ },
164413
+ {
164414
+ "type": "null"
164415
+ }
164416
+ ]
164417
+ },
164418
+ "expires_at": {
164419
+ "description": "Scadenza del link. `null` quando il link non è stato firmato.",
164420
+ "anyOf": [
164421
+ {
164422
+ "format": "date-time",
164423
+ "type": "string"
164424
+ },
164425
+ {
164426
+ "type": "null"
164427
+ }
164428
+ ]
164429
+ },
164430
+ "gross_amount_minor": {
164431
+ "description": "Totale della fattura, IVA inclusa: è la cifra che si bonifica per intero. Minor units (centesimi) come stringa decimale.",
164432
+ "pattern": "^-?[0-9]+$",
164433
+ "type": "string"
164434
+ },
164435
+ "id": {
164436
+ "description": "Id del documento.",
164437
+ "format": "uuid",
164438
+ "type": "string"
164439
+ },
164440
+ "invoice_date": {
164441
+ "description": "Data della fattura.",
164442
+ "format": "date",
164443
+ "pattern": "^[0-9]{4}-[0-9]{2}-[0-9]{2}$",
164444
+ "type": "string"
164445
+ },
164446
+ "invoice_number": {
164447
+ "description": "Numero della fattura, come lo ha scritto il partner.",
164448
+ "type": "string"
164449
+ },
164450
+ "reject_reason": {
164451
+ "description": "Perché è stata rifiutata. `null` in ogni altro stato.",
164452
+ "anyOf": [
164453
+ {
164454
+ "type": "string"
164455
+ },
164456
+ {
164457
+ "type": "null"
164458
+ }
164459
+ ]
164460
+ },
164461
+ "retain_until": {
164462
+ "description": "Fino a quando il documento resta conservato: caricamento + 10 anni (art. 2220 c.c.).",
164463
+ "format": "date-time",
164464
+ "type": "string"
164465
+ },
164466
+ "sha256": {
164467
+ "description": "Impronta dei byte, calcolata dal backend. È la stessa che il download ri-verifica.",
164468
+ "pattern": "^[0-9a-f]{64}$",
164469
+ "type": "string"
164470
+ },
164471
+ "size_bytes": {
164472
+ "description": "Dimensione del PDF archiviato.",
164473
+ "type": "integer"
164474
+ },
164475
+ "status": {
164476
+ "description": "`uploaded` caricata · `verified` importo confrontato col bonifico · `applied` scalata su un bonifico uscito · `rejected` rifiutata, con motivo. `applied` e `rejected` sono terminali.",
164477
+ "anyOf": [
164478
+ {
164479
+ "type": "string",
164480
+ "enum": [
164481
+ "uploaded"
164482
+ ]
164483
+ },
164484
+ {
164485
+ "type": "string",
164486
+ "enum": [
164487
+ "verified"
164488
+ ]
164489
+ },
164490
+ {
164491
+ "type": "string",
164492
+ "enum": [
164493
+ "applied"
164494
+ ]
164495
+ },
164496
+ {
164497
+ "type": "string",
164498
+ "enum": [
164499
+ "rejected"
164500
+ ]
164501
+ }
164502
+ ]
164503
+ },
164504
+ "uploaded_at": {
164505
+ "description": "Quando è stata caricata.",
164506
+ "format": "date-time",
164507
+ "type": "string"
164508
+ }
164509
+ }
164510
+ }
164511
+ }
164512
+ }
164513
+ },
164514
+ "400": {
164515
+ "description": "Errore standard del backend.",
164516
+ "content": {
164517
+ "application/json": {
164518
+ "schema": {
164519
+ "additionalProperties": false,
164520
+ "description": "Errore standard del backend.",
164521
+ "type": "object",
164522
+ "required": [
164523
+ "error",
164524
+ "message",
164525
+ "statusCode"
164526
+ ],
164527
+ "properties": {
164528
+ "code": {
164529
+ "description": "Codice macchina dell’errore, quando disponibile.",
164530
+ "type": "string"
164531
+ },
164532
+ "error": {
164533
+ "description": "Etichetta breve dell’errore.",
164534
+ "type": "string"
164535
+ },
164536
+ "message": {
164537
+ "description": "Messaggio leggibile.",
164538
+ "type": "string"
164539
+ },
164540
+ "statusCode": {
164541
+ "description": "Codice di stato HTTP ripetuto nel corpo.",
164542
+ "type": "integer"
164543
+ }
164544
+ }
164545
+ }
164546
+ }
164547
+ }
164548
+ },
164549
+ "401": {
164550
+ "description": "Errore standard del backend.",
164551
+ "content": {
164552
+ "application/json": {
164553
+ "schema": {
164554
+ "additionalProperties": false,
164555
+ "description": "Errore standard del backend.",
164556
+ "type": "object",
164557
+ "required": [
164558
+ "error",
164559
+ "message",
164560
+ "statusCode"
164561
+ ],
164562
+ "properties": {
164563
+ "code": {
164564
+ "description": "Codice macchina dell’errore, quando disponibile.",
164565
+ "type": "string"
164566
+ },
164567
+ "error": {
164568
+ "description": "Etichetta breve dell’errore.",
164569
+ "type": "string"
164570
+ },
164571
+ "message": {
164572
+ "description": "Messaggio leggibile.",
164573
+ "type": "string"
164574
+ },
164575
+ "statusCode": {
164576
+ "description": "Codice di stato HTTP ripetuto nel corpo.",
164577
+ "type": "integer"
164578
+ }
164579
+ }
164580
+ }
164581
+ }
164582
+ }
164583
+ },
164584
+ "403": {
164585
+ "description": "Errore standard del backend.",
164586
+ "content": {
164587
+ "application/json": {
164588
+ "schema": {
164589
+ "additionalProperties": false,
164590
+ "description": "Errore standard del backend.",
164591
+ "type": "object",
164592
+ "required": [
164593
+ "error",
164594
+ "message",
164595
+ "statusCode"
164596
+ ],
164597
+ "properties": {
164598
+ "code": {
164599
+ "description": "Codice macchina dell’errore, quando disponibile.",
164600
+ "type": "string"
164601
+ },
164602
+ "error": {
164603
+ "description": "Etichetta breve dell’errore.",
164604
+ "type": "string"
164605
+ },
164606
+ "message": {
164607
+ "description": "Messaggio leggibile.",
164608
+ "type": "string"
164609
+ },
164610
+ "statusCode": {
164611
+ "description": "Codice di stato HTTP ripetuto nel corpo.",
164612
+ "type": "integer"
164613
+ }
164614
+ }
164615
+ }
164616
+ }
164617
+ }
164618
+ },
164619
+ "409": {
164620
+ "description": "Errore standard del backend.",
164621
+ "content": {
164622
+ "application/json": {
164623
+ "schema": {
164624
+ "additionalProperties": false,
164625
+ "description": "Errore standard del backend.",
164626
+ "type": "object",
164627
+ "required": [
164628
+ "error",
164629
+ "message",
164630
+ "statusCode"
164631
+ ],
164632
+ "properties": {
164633
+ "code": {
164634
+ "description": "Codice macchina dell’errore, quando disponibile.",
164635
+ "type": "string"
164636
+ },
164637
+ "error": {
164638
+ "description": "Etichetta breve dell’errore.",
164639
+ "type": "string"
164640
+ },
164641
+ "message": {
164642
+ "description": "Messaggio leggibile.",
164643
+ "type": "string"
164644
+ },
164645
+ "statusCode": {
164646
+ "description": "Codice di stato HTTP ripetuto nel corpo.",
164647
+ "type": "integer"
164648
+ }
164649
+ }
164650
+ }
164651
+ }
164652
+ }
164653
+ },
164654
+ "413": {
164655
+ "description": "Errore standard del backend.",
164656
+ "content": {
164657
+ "application/json": {
164658
+ "schema": {
164659
+ "additionalProperties": false,
164660
+ "description": "Errore standard del backend.",
164661
+ "type": "object",
164662
+ "required": [
164663
+ "error",
164664
+ "message",
164665
+ "statusCode"
164666
+ ],
164667
+ "properties": {
164668
+ "code": {
164669
+ "description": "Codice macchina dell’errore, quando disponibile.",
164670
+ "type": "string"
164671
+ },
164672
+ "error": {
164673
+ "description": "Etichetta breve dell’errore.",
164674
+ "type": "string"
164675
+ },
164676
+ "message": {
164677
+ "description": "Messaggio leggibile.",
164678
+ "type": "string"
164679
+ },
164680
+ "statusCode": {
164681
+ "description": "Codice di stato HTTP ripetuto nel corpo.",
164682
+ "type": "integer"
164683
+ }
164684
+ }
164685
+ }
164686
+ }
164687
+ }
164688
+ },
164689
+ "415": {
164690
+ "description": "Errore standard del backend.",
164691
+ "content": {
164692
+ "application/json": {
164693
+ "schema": {
164694
+ "additionalProperties": false,
164695
+ "description": "Errore standard del backend.",
164696
+ "type": "object",
164697
+ "required": [
164698
+ "error",
164699
+ "message",
164700
+ "statusCode"
164701
+ ],
164702
+ "properties": {
164703
+ "code": {
164704
+ "description": "Codice macchina dell’errore, quando disponibile.",
164705
+ "type": "string"
164706
+ },
164707
+ "error": {
164708
+ "description": "Etichetta breve dell’errore.",
164709
+ "type": "string"
164710
+ },
164711
+ "message": {
164712
+ "description": "Messaggio leggibile.",
164713
+ "type": "string"
164714
+ },
164715
+ "statusCode": {
164716
+ "description": "Codice di stato HTTP ripetuto nel corpo.",
164717
+ "type": "integer"
164718
+ }
164719
+ }
164720
+ }
164721
+ }
164722
+ }
164723
+ },
164724
+ "429": {
164725
+ "description": "Errore standard del backend.",
164726
+ "content": {
164727
+ "application/json": {
164728
+ "schema": {
164729
+ "additionalProperties": false,
164730
+ "description": "Errore standard del backend.",
164731
+ "type": "object",
164732
+ "required": [
164733
+ "error",
164734
+ "message",
164735
+ "statusCode"
164736
+ ],
164737
+ "properties": {
164738
+ "code": {
164739
+ "description": "Codice macchina dell’errore, quando disponibile.",
164740
+ "type": "string"
164741
+ },
164742
+ "error": {
164743
+ "description": "Etichetta breve dell’errore.",
164744
+ "type": "string"
164745
+ },
164746
+ "message": {
164747
+ "description": "Messaggio leggibile.",
164748
+ "type": "string"
164749
+ },
164750
+ "statusCode": {
164751
+ "description": "Codice di stato HTTP ripetuto nel corpo.",
164752
+ "type": "integer"
164753
+ }
164754
+ }
164755
+ }
164756
+ }
164757
+ }
164758
+ },
164759
+ "503": {
164760
+ "description": "Errore standard del backend.",
164761
+ "content": {
164762
+ "application/json": {
164763
+ "schema": {
164764
+ "additionalProperties": false,
164765
+ "description": "Errore standard del backend.",
164766
+ "type": "object",
164767
+ "required": [
164768
+ "error",
164769
+ "message",
164770
+ "statusCode"
164771
+ ],
164772
+ "properties": {
164773
+ "code": {
164774
+ "description": "Codice macchina dell’errore, quando disponibile.",
164775
+ "type": "string"
164776
+ },
164777
+ "error": {
164778
+ "description": "Etichetta breve dell’errore.",
164779
+ "type": "string"
164780
+ },
164781
+ "message": {
164782
+ "description": "Messaggio leggibile.",
164783
+ "type": "string"
164784
+ },
164785
+ "statusCode": {
164786
+ "description": "Codice di stato HTTP ripetuto nel corpo.",
164787
+ "type": "integer"
164788
+ }
164789
+ }
164790
+ }
164791
+ }
164792
+ }
164793
+ }
164794
+ }
164795
+ }
164796
+ },
164797
+ "/api/v1/partner/invoices/{id}/download": {
164798
+ "get": {
164799
+ "operationId": "downloadPartnerInvoice",
164800
+ "summary": "Scarica una mia fattura",
164801
+ "tags": [
164802
+ "partner"
164803
+ ],
164804
+ "description": "Consegna i byte della fattura. Il token viaggia in QUERY e non in path — un parametro di path è limitato a 100 caratteri da Fastify — ed è **firmato**, mai presigned: un URL presigned sopravvivrebbe alla revoca del ruolo di chi l’ha generato. Il backend rilegge i byte e **ricalcola** l’impronta: se non coincide con quella registrata al caricamento risponde 409 invece di consegnare un documento che è cambiato. Token scaduto, manomesso o di un altro partner: 403 con lo stesso corpo, i tre casi sono indistinguibili di proposito.",
164805
+ "parameters": [
164806
+ {
164807
+ "schema": {
164808
+ "maxLength": 512,
164809
+ "minLength": 1,
164810
+ "type": "string"
164811
+ },
164812
+ "in": "query",
164813
+ "name": "token",
164814
+ "required": true,
164815
+ "description": "Token firmato."
164816
+ },
164817
+ {
164818
+ "schema": {
164819
+ "format": "uuid",
164820
+ "type": "string"
164821
+ },
164822
+ "in": "path",
164823
+ "name": "id",
164824
+ "required": true,
164825
+ "description": "Id del documento."
164826
+ }
164827
+ ],
164828
+ "security": [
164829
+ {
164830
+ "bearerAuth": []
164831
+ }
164832
+ ],
164833
+ "responses": {
164834
+ "200": {
164835
+ "description": "Il PDF della fattura, letto dallo storage e verificato per impronta.",
164836
+ "content": {
164837
+ "application/pdf": {
164838
+ "schema": {
164839
+ "description": "Byte del PDF.",
164840
+ "type": "string"
164841
+ }
164842
+ }
164843
+ }
164844
+ },
164845
+ "401": {
164846
+ "description": "Sessione assente o scaduta.",
164847
+ "content": {
164848
+ "application/json": {
164849
+ "schema": {
164850
+ "additionalProperties": false,
164851
+ "description": "Errore standard del backend.",
164852
+ "type": "object",
164853
+ "required": [
164854
+ "error",
164855
+ "message",
164856
+ "statusCode"
164857
+ ],
164858
+ "properties": {
164859
+ "code": {
164860
+ "description": "Codice macchina dell’errore, quando disponibile.",
164861
+ "type": "string"
164862
+ },
164863
+ "error": {
164864
+ "description": "Etichetta breve dell’errore.",
164865
+ "type": "string"
164866
+ },
164867
+ "message": {
164868
+ "description": "Messaggio leggibile.",
164869
+ "type": "string"
164870
+ },
164871
+ "statusCode": {
164872
+ "description": "Codice di stato HTTP ripetuto nel corpo.",
164873
+ "type": "integer"
164874
+ }
164875
+ }
164876
+ }
164877
+ }
164878
+ }
164879
+ },
164880
+ "403": {
164881
+ "description": "Token scaduto, manomesso o di un altro partner: stesso corpo in tutti i casi.",
164882
+ "content": {
164883
+ "application/json": {
164884
+ "schema": {
164885
+ "additionalProperties": false,
164886
+ "description": "Errore standard del backend.",
164887
+ "type": "object",
164888
+ "required": [
164889
+ "error",
164890
+ "message",
164891
+ "statusCode"
164892
+ ],
164893
+ "properties": {
164894
+ "code": {
164895
+ "description": "Codice macchina dell’errore, quando disponibile.",
164896
+ "type": "string"
164897
+ },
164898
+ "error": {
164899
+ "description": "Etichetta breve dell’errore.",
164900
+ "type": "string"
164901
+ },
164902
+ "message": {
164903
+ "description": "Messaggio leggibile.",
164904
+ "type": "string"
164905
+ },
164906
+ "statusCode": {
164907
+ "description": "Codice di stato HTTP ripetuto nel corpo.",
164908
+ "type": "integer"
164909
+ }
164910
+ }
164911
+ }
164912
+ }
164913
+ }
164914
+ },
164915
+ "404": {
164916
+ "description": "Il documento non è più nello storage.",
164917
+ "content": {
164918
+ "application/json": {
164919
+ "schema": {
164920
+ "additionalProperties": false,
164921
+ "description": "Errore standard del backend.",
164922
+ "type": "object",
164923
+ "required": [
164924
+ "error",
164925
+ "message",
164926
+ "statusCode"
164927
+ ],
164928
+ "properties": {
164929
+ "code": {
164930
+ "description": "Codice macchina dell’errore, quando disponibile.",
164931
+ "type": "string"
164932
+ },
164933
+ "error": {
164934
+ "description": "Etichetta breve dell’errore.",
164935
+ "type": "string"
164936
+ },
164937
+ "message": {
164938
+ "description": "Messaggio leggibile.",
164939
+ "type": "string"
164940
+ },
164941
+ "statusCode": {
164942
+ "description": "Codice di stato HTTP ripetuto nel corpo.",
164943
+ "type": "integer"
164944
+ }
164945
+ }
164946
+ }
164947
+ }
164948
+ }
164949
+ },
164950
+ "409": {
164951
+ "description": "I byte riletti non corrispondono all’impronta registrata al caricamento.",
164952
+ "content": {
164953
+ "application/json": {
164954
+ "schema": {
164955
+ "additionalProperties": false,
164956
+ "description": "Errore standard del backend.",
164957
+ "type": "object",
164958
+ "required": [
164959
+ "error",
164960
+ "message",
164961
+ "statusCode"
164962
+ ],
164963
+ "properties": {
164964
+ "code": {
164965
+ "description": "Codice macchina dell’errore, quando disponibile.",
164966
+ "type": "string"
164967
+ },
164968
+ "error": {
164969
+ "description": "Etichetta breve dell’errore.",
164970
+ "type": "string"
164971
+ },
164972
+ "message": {
164973
+ "description": "Messaggio leggibile.",
164974
+ "type": "string"
164975
+ },
164976
+ "statusCode": {
164977
+ "description": "Codice di stato HTTP ripetuto nel corpo.",
164978
+ "type": "integer"
164979
+ }
164980
+ }
164981
+ }
164982
+ }
164983
+ }
164984
+ }
164985
+ }
164986
+ }
164987
+ },
163968
164988
  "/api/v1/partner/me": {
163969
164989
  "get": {
163970
164990
  "operationId": "getPartnerMe",
@@ -164119,6 +165139,7 @@
164119
165139
  "type": "object",
164120
165140
  "required": [
164121
165141
  "applied_invoices",
165142
+ "apply_max_bp",
164122
165143
  "available_minor",
164123
165144
  "currency",
164124
165145
  "locked_minor",
@@ -164132,6 +165153,12 @@
164132
165153
  "minimum": 0,
164133
165154
  "type": "integer"
164134
165155
  },
165156
+ "apply_max_bp": {
165157
+ "description": "Quota massima di CIASCUNA fattura che il credito può coprire, in basis point interi (`partner_track_a_apply_max_bp`, modificabile a caldo dal registro). ★ Esiste perché il pannello scriveva «fino al 50%» come testo tradotto in ogni lingua: il giorno in cui il registro fosse stato stretto a 2500, la frase sarebbe rimasta a 50% e nessun test se ne sarebbe accorto. Il numero è del server, non della copy.",
165158
+ "maximum": 10000,
165159
+ "minimum": 0,
165160
+ "type": "integer"
165161
+ },
164135
165162
  "available_minor": {
164136
165163
  "description": "Spendibile ORA sulla prossima fattura. Minor units (centesimi) come stringa decimale.",
164137
165164
  "pattern": "^-?[0-9]+$",
@@ -164517,15 +165544,14 @@
164517
165544
  },
164518
165545
  "reconsent": {
164519
165546
  "additionalProperties": false,
164520
- "description": "Stato del ri-consenso ai termini di programma: cosa manca e se è esigibile.",
165547
+ "description": "Stato del ri-consenso ai termini di programma: cosa risulta non allineato. È MISURA, non esigenza — il campo booleano `required` è stato tolto il 25/08/2026 perché nessun percorso poteva più alzarlo.",
164521
165548
  "type": "object",
164522
165549
  "required": [
164523
165550
  "accepted_documents",
164524
165551
  "accepted_program_version",
164525
165552
  "current_program_version",
164526
165553
  "outstanding_documents",
164527
- "reasons",
164528
- "required"
165554
+ "reasons"
164529
165555
  ],
164530
165556
  "properties": {
164531
165557
  "accepted_documents": {
@@ -164614,16 +165640,12 @@
164614
165640
  }
164615
165641
  },
164616
165642
  "reasons": {
164617
- "description": "Perché il ri-consenso è dovuto. Vuoto quando `required` è false.",
165643
+ "description": "Cosa è stato rilevato. Vuoto quando non c’è nulla da segnalare. ⚠️ NON è un gate: al partner non viene chiesto di riaccettare nulla, perché l’art. 7 dell’accordo ricava l’accettazione dal preavviso di 30 giorni più la partecipazione continuata. Serve alla dashboard e a chi decide se mandare quel preavviso.",
164618
165644
  "type": "array",
164619
165645
  "items": {
164620
165646
  "description": "never_enrolled | program_version_superseded | documents_outdated.",
164621
165647
  "type": "string"
164622
165648
  }
164623
- },
164624
- "required": {
164625
- "description": "true solo quando esiste qualcosa che il partner può DAVVERO riaccettare (vedi `reasons`).",
164626
- "type": "boolean"
164627
165649
  }
164628
165650
  }
164629
165651
  },
@@ -165360,7 +166382,7 @@
165360
166382
  "tags": [
165361
166383
  "partner"
165362
166384
  ],
165363
- "description": "Registra l’accettazione dei documenti di programma da parte del partner autenticato: una riga `legal_consent` per documento e, quando esiste una versione di programma pubblicata per il suo binario, una riga `partner_program_enrollment`. L’adesione è APPEND-ONLY (`trg_ppe_append_only`) e unica per versione (`uq_ppe_partner_version`): riaccettare la stessa versione è idempotente e restituisce `enrolled: false`. Una versione di documento diversa da quella corrente è `409`: un client fermo su un testo vecchio si dichiarerebbe in pari senza aver mai visto quello nuovo.",
166385
+ "description": "⚠️ NON è un gate, e dal 25/08/2026 nessuna schermata la chiama: il pannello non chiede più al partner di riaccettare nulla, perché l’art. 7 dell’accordo ricava l’accettazione dal preavviso di 30 giorni più la partecipazione continuata, e l’adesione al programma nasce ormai nell’approvazione (`application.service.ts`). Resta esposta perché un’accettazione DELIBERATA possa essere registrata quando qualcuno sceglie di darla. Registra l’accettazione dei documenti di programma da parte del partner autenticato: una riga `legal_consent` per documento e, quando esiste una versione di programma pubblicata per il suo binario, una riga `partner_program_enrollment`. L’adesione è APPEND-ONLY (`trg_ppe_append_only`) e unica per versione (`uq_ppe_partner_version`): riaccettare la stessa versione è idempotente e restituisce `enrolled: false`. Una versione di documento diversa da quella corrente è `409`: un client fermo su un testo vecchio si dichiarerebbe in pari senza aver mai visto quello nuovo.",
165364
166386
  "requestBody": {
165365
166387
  "required": true,
165366
166388
  "content": {
@@ -165438,15 +166460,14 @@
165438
166460
  },
165439
166461
  "reconsent": {
165440
166462
  "additionalProperties": false,
165441
- "description": "Stato del ri-consenso ai termini di programma: cosa manca e se è esigibile.",
166463
+ "description": "Stato del ri-consenso ai termini di programma: cosa risulta non allineato. È MISURA, non esigenza — il campo booleano `required` è stato tolto il 25/08/2026 perché nessun percorso poteva più alzarlo.",
165442
166464
  "type": "object",
165443
166465
  "required": [
165444
166466
  "accepted_documents",
165445
166467
  "accepted_program_version",
165446
166468
  "current_program_version",
165447
166469
  "outstanding_documents",
165448
- "reasons",
165449
- "required"
166470
+ "reasons"
165450
166471
  ],
165451
166472
  "properties": {
165452
166473
  "accepted_documents": {
@@ -165535,16 +166556,12 @@
165535
166556
  }
165536
166557
  },
165537
166558
  "reasons": {
165538
- "description": "Perché il ri-consenso è dovuto. Vuoto quando `required` è false.",
166559
+ "description": "Cosa è stato rilevato. Vuoto quando non c’è nulla da segnalare. ⚠️ NON è un gate: al partner non viene chiesto di riaccettare nulla, perché l’art. 7 dell’accordo ricava l’accettazione dal preavviso di 30 giorni più la partecipazione continuata. Serve alla dashboard e a chi decide se mandare quel preavviso.",
165539
166560
  "type": "array",
165540
166561
  "items": {
165541
166562
  "description": "never_enrolled | program_version_superseded | documents_outdated.",
165542
166563
  "type": "string"
165543
166564
  }
165544
- },
165545
- "required": {
165546
- "description": "true solo quando esiste qualcosa che il partner può DAVVERO riaccettare (vedi `reasons`).",
165547
- "type": "boolean"
165548
166565
  }
165549
166566
  }
165550
166567
  }
@@ -165944,6 +166961,281 @@
165944
166961
  }
165945
166962
  }
165946
166963
  },
166964
+ "/api/v1/partner/payout-profile": {
166965
+ "post": {
166966
+ "operationId": "savePartnerPayoutProfile",
166967
+ "summary": "Salva il profilo di incasso (società di fatturazione e conto)",
166968
+ "tags": [
166969
+ "partner"
166970
+ ],
166971
+ "description": "Salva l’identità fiscale e le coordinate di incasso del partner autenticato, poi tenta di renderlo pagabile da solo (verifica europea della partita IVA). ⚠️ **L’IBAN non viene conservato**: se ne verifica la cifra di controllo e se ne scrive la sola impronta `sha256(pepper || IBAN)` (§6.7). Ogni salvataggio apre un raffreddamento di 72 ore sul pagamento — è la finestra in cui il titolare vero si accorge di un cambio di conto che non ha fatto. `403` = questo profilo non appartiene a chi è compensato in credito di fatturazione. `409` = quella partita IVA o quel conto sono già di un altro partner (lo dice il vincolo del database, non una SELECT che due schede supererebbero entrambe). `422` = IBAN con cifra di controllo sbagliata, o partita IVA implausibile.",
166972
+ "requestBody": {
166973
+ "required": true,
166974
+ "content": {
166975
+ "application/json": {
166976
+ "schema": {
166977
+ "additionalProperties": false,
166978
+ "type": "object",
166979
+ "required": [
166980
+ "account_holder",
166981
+ "country_code",
166982
+ "iban",
166983
+ "legal_name",
166984
+ "vat_number"
166985
+ ],
166986
+ "properties": {
166987
+ "account_holder": {
166988
+ "description": "Intestatario del conto, come appare in banca. Può differire dalla ragione sociale (il consulente che si fa accreditare sul conto personale è un caso legittimo e comune): la differenza si registra, non si rifiuta.",
166989
+ "maxLength": 200,
166990
+ "minLength": 2,
166991
+ "type": "string"
166992
+ },
166993
+ "country_code": {
166994
+ "description": "Paese fiscale, ISO 3166-1 alpha-2 (due lettere). Decide se la partita IVA passa dal controllo europeo. ⚠️ **`pattern`, non solo la lunghezza**: questo valore finisce direttamente in `partner.country_code` — questa rotta si auto-esegue, nessun approvatore in mezzo — e da lì `requiredChecksForLevel` decide se il controllo dovuto sia `vies` o `company_registry`. Con la sola lunghezza, `12` e `z!` entravano e sceglievano una verifica antiriciclaggio al posto di chi la deve subire. `422 PARTNER_COUNTRY_INVALID` è la rete sotto, nel servizio.",
166995
+ "maxLength": 2,
166996
+ "minLength": 2,
166997
+ "pattern": "^[A-Za-z]{2}$",
166998
+ "type": "string"
166999
+ },
167000
+ "iban": {
167001
+ "description": "⚠️ NON viene conservato. Se ne verifica la cifra di controllo (ISO 13616) e se ne scrive l’impronta. Spazi e punti sono ammessi: si normalizza prima di calcolarla, o lo stesso conto scritto in due modi sembrerebbe un cambio di coordinate.",
167002
+ "maxLength": 42,
167003
+ "minLength": 15,
167004
+ "type": "string"
167005
+ },
167006
+ "legal_name": {
167007
+ "description": "La società con cui il partner ci fattura. Diventa l’intestazione del rendiconto — che è il documento da cui il partner copia i dati per emettere la fattura.",
167008
+ "maxLength": 255,
167009
+ "minLength": 2,
167010
+ "type": "string"
167011
+ },
167012
+ "vat_number": {
167013
+ "description": "Partita IVA. Qui se ne controlla solo la forma: che esista lo dice il controllo europeo.",
167014
+ "maxLength": 20,
167015
+ "minLength": 4,
167016
+ "type": "string"
167017
+ }
167018
+ }
167019
+ }
167020
+ }
167021
+ }
167022
+ },
167023
+ "security": [
167024
+ {
167025
+ "bearerAuth": []
167026
+ }
167027
+ ],
167028
+ "responses": {
167029
+ "200": {
167030
+ "description": "Il profilo salvato, con l’esito del tentativo automatico di sbloccare il pagamento.",
167031
+ "content": {
167032
+ "application/json": {
167033
+ "schema": {
167034
+ "additionalProperties": false,
167035
+ "description": "Il profilo salvato, con l’esito del tentativo automatico di sbloccare il pagamento.",
167036
+ "type": "object",
167037
+ "required": [
167038
+ "cooling_off_until",
167039
+ "payable",
167040
+ "readiness"
167041
+ ],
167042
+ "properties": {
167043
+ "cooling_off_until": {
167044
+ "description": "Fine del raffreddamento di 72 ore aperto dal cambio di coordinate. Fino a quel momento il ciclo mette in attesa il pagamento — è la finestra in cui il titolare vero si accorge di un cambio che non ha fatto. Sul ciclo mensile è invisibile.",
167045
+ "format": "date-time",
167046
+ "type": "string"
167047
+ },
167048
+ "payable": {
167049
+ "description": "true se la verifica automatica ha reso il partner pagabile senza che nessuno intervenga. false NON è un errore: il profilo è salvato comunque, e `readiness` dice cosa manca.",
167050
+ "type": "boolean"
167051
+ },
167052
+ "readiness": {
167053
+ "description": "`docs_missing` | `awaiting_program_activation` | `ready`, riletto dopo il tentativo.",
167054
+ "type": "string"
167055
+ }
167056
+ }
167057
+ }
167058
+ }
167059
+ }
167060
+ },
167061
+ "401": {
167062
+ "description": "Errore standard del backend.",
167063
+ "content": {
167064
+ "application/json": {
167065
+ "schema": {
167066
+ "additionalProperties": false,
167067
+ "description": "Errore standard del backend.",
167068
+ "type": "object",
167069
+ "required": [
167070
+ "error",
167071
+ "message",
167072
+ "statusCode"
167073
+ ],
167074
+ "properties": {
167075
+ "code": {
167076
+ "description": "Codice macchina dell’errore, quando disponibile.",
167077
+ "type": "string"
167078
+ },
167079
+ "error": {
167080
+ "description": "Etichetta breve dell’errore.",
167081
+ "type": "string"
167082
+ },
167083
+ "message": {
167084
+ "description": "Messaggio leggibile.",
167085
+ "type": "string"
167086
+ },
167087
+ "statusCode": {
167088
+ "description": "Codice di stato HTTP ripetuto nel corpo.",
167089
+ "type": "integer"
167090
+ }
167091
+ }
167092
+ }
167093
+ }
167094
+ }
167095
+ },
167096
+ "403": {
167097
+ "description": "Errore standard del backend.",
167098
+ "content": {
167099
+ "application/json": {
167100
+ "schema": {
167101
+ "additionalProperties": false,
167102
+ "description": "Errore standard del backend.",
167103
+ "type": "object",
167104
+ "required": [
167105
+ "error",
167106
+ "message",
167107
+ "statusCode"
167108
+ ],
167109
+ "properties": {
167110
+ "code": {
167111
+ "description": "Codice macchina dell’errore, quando disponibile.",
167112
+ "type": "string"
167113
+ },
167114
+ "error": {
167115
+ "description": "Etichetta breve dell’errore.",
167116
+ "type": "string"
167117
+ },
167118
+ "message": {
167119
+ "description": "Messaggio leggibile.",
167120
+ "type": "string"
167121
+ },
167122
+ "statusCode": {
167123
+ "description": "Codice di stato HTTP ripetuto nel corpo.",
167124
+ "type": "integer"
167125
+ }
167126
+ }
167127
+ }
167128
+ }
167129
+ }
167130
+ },
167131
+ "409": {
167132
+ "description": "Errore standard del backend.",
167133
+ "content": {
167134
+ "application/json": {
167135
+ "schema": {
167136
+ "additionalProperties": false,
167137
+ "description": "Errore standard del backend.",
167138
+ "type": "object",
167139
+ "required": [
167140
+ "error",
167141
+ "message",
167142
+ "statusCode"
167143
+ ],
167144
+ "properties": {
167145
+ "code": {
167146
+ "description": "Codice macchina dell’errore, quando disponibile.",
167147
+ "type": "string"
167148
+ },
167149
+ "error": {
167150
+ "description": "Etichetta breve dell’errore.",
167151
+ "type": "string"
167152
+ },
167153
+ "message": {
167154
+ "description": "Messaggio leggibile.",
167155
+ "type": "string"
167156
+ },
167157
+ "statusCode": {
167158
+ "description": "Codice di stato HTTP ripetuto nel corpo.",
167159
+ "type": "integer"
167160
+ }
167161
+ }
167162
+ }
167163
+ }
167164
+ }
167165
+ },
167166
+ "422": {
167167
+ "description": "Errore standard del backend.",
167168
+ "content": {
167169
+ "application/json": {
167170
+ "schema": {
167171
+ "additionalProperties": false,
167172
+ "description": "Errore standard del backend.",
167173
+ "type": "object",
167174
+ "required": [
167175
+ "error",
167176
+ "message",
167177
+ "statusCode"
167178
+ ],
167179
+ "properties": {
167180
+ "code": {
167181
+ "description": "Codice macchina dell’errore, quando disponibile.",
167182
+ "type": "string"
167183
+ },
167184
+ "error": {
167185
+ "description": "Etichetta breve dell’errore.",
167186
+ "type": "string"
167187
+ },
167188
+ "message": {
167189
+ "description": "Messaggio leggibile.",
167190
+ "type": "string"
167191
+ },
167192
+ "statusCode": {
167193
+ "description": "Codice di stato HTTP ripetuto nel corpo.",
167194
+ "type": "integer"
167195
+ }
167196
+ }
167197
+ }
167198
+ }
167199
+ }
167200
+ },
167201
+ "429": {
167202
+ "description": "Errore standard del backend.",
167203
+ "content": {
167204
+ "application/json": {
167205
+ "schema": {
167206
+ "additionalProperties": false,
167207
+ "description": "Errore standard del backend.",
167208
+ "type": "object",
167209
+ "required": [
167210
+ "error",
167211
+ "message",
167212
+ "statusCode"
167213
+ ],
167214
+ "properties": {
167215
+ "code": {
167216
+ "description": "Codice macchina dell’errore, quando disponibile.",
167217
+ "type": "string"
167218
+ },
167219
+ "error": {
167220
+ "description": "Etichetta breve dell’errore.",
167221
+ "type": "string"
167222
+ },
167223
+ "message": {
167224
+ "description": "Messaggio leggibile.",
167225
+ "type": "string"
167226
+ },
167227
+ "statusCode": {
167228
+ "description": "Codice di stato HTTP ripetuto nel corpo.",
167229
+ "type": "integer"
167230
+ }
167231
+ }
167232
+ }
167233
+ }
167234
+ }
167235
+ }
167236
+ }
167237
+ }
167238
+ },
165947
167239
  "/api/v1/partner/payout-request": {
165948
167240
  "post": {
165949
167241
  "operationId": "createPartnerPayoutRequest",