# Implementazione di un proxy

## Requisiti funzionali

Sono requisiti che dipendono da nostre scelte implementative, possono cambiare man mano che evolviamo la piattaforma, per supportare nuovi casi d'uso (pagamento dei dovuti) oppure perché ci accorgiamo che abbiamo commesso qualche errore nella progettazione.

1. Gestione di pagamenti spontanei
2. Gestione di pagamenti con bilancio
3. Gestione della notifica dello stato del pagamento da parte dell'IdP - se disponibile - o del polling se non è disponibile la notifica
4. Se è implementato il polling, questo deve avvenire con un [back-off](https://cloud.google.com/memorystore/docs/redis/exponential-backoff?hl=it) esponenziale che assicuri alcuni check nel giro di pochi minuti e poi si diradi fino a un massimo di un check al giorno fino alla scadenza del pagamento o 1 anno se la scadenza è inferiore.
5. Gestione delle configurazioni a livello di Tenant e di Servizio

## Requisiti normativi

* Avere una specifica in formato OpenAPI v3
* Rispettare la [Linee Guida di interoperabilità](https://docs.italia.it/italia/piano-triennale-ict/lg-modellointeroperabilita-docs): in particolare per quanto riguarda&#x20;
  * [il formato dei dati](https://docs.italia.it/italia/piano-triennale-ict/lg-modellointeroperabilita-docs/it/bozza/doc/04_Raccomandazioni%20di%20implementazione/04_raccomandazioni-tecniche-generali/02_formato-dei-dati.html) (4.2)
  * [raccomandazioni sul naming](https://docs.italia.it/italia/piano-triennale-ict/lg-modellointeroperabilita-docs/it/bozza/doc/04_Raccomandazioni%20di%20implementazione/04_raccomandazioni-tecniche-generali/03_progettazione-e-naming.html) (4.3) optando per la scelta di `snake_case` per i nomi degli attributi
  * logging (4.4)
  * risultare valido nel [validatore ufficiale OA3](https://github.com/italia/api-oas-checker)

## Requisiti per l'ambiente di produzione

* Sappiamo che in molti topic ci sono diversi eventi mal formati, per vari errori e assenza di uno schema registry, quindi è necessario validare gli eventi in input e opzionalmente in output (lo fanno le nostre prime implementazioni in python, ma è un requisito?)
* Ci aspettiamo che se di dovesse aggiornare il formato dell'evento nel topic `payments` gestiremo eventi anche in parallelo con versioni distinte, quindi ogni proxy deve Interpretare solo gli eventi che riportano il formato più recente dell'evento nel topic payments: `event_version: 2.0`
* Integrarsi con [sentry](https://sentry.io/) per la gestione degli errori
* Esporre metriche di monitoraggio in [formato prometheus](https://prometheus.io/docs/concepts/data_model/), in particolare:

  * counter sul numero di pagamenti creati
  * counter sul numero di errori durante il processamento di pagamenti, differenziando gli errori interni (errori di formato dati in ingresso o validazione) da errori esterni (errori di dialogo con l'IdP)
  * latenza delle chiamate fatte all'IdP

  Di seguito la tabella contenente le specifiche di ogni metrica

<table><thead><tr><th width="258">Metrica</th><th>Labels</th><th>Descrizione</th></tr></thead><tbody><tr><td><code>oc_payment_validation_errors_total</code></td><td>cluster, env, app_name</td><td>la metrica deve misurare gli errori di validazione sull'evento letto (es. l'importo è una stringa invece che un float)</td></tr><tr><td><code>oc_api_requests_total</code></td><td>cluster, env, method, app_name, status_code</td><td>la metrica deve monitorare le chiamate http indicandone lo status code</td></tr><tr><td><code>oc_payment_success_events_total</code></td><td>cluster, env, app_name</td><td>la metrica deve misurare solo gli eventi per cui il proxy ha una configurazione e che stati processati con successo</td></tr><tr><td><code>oc_payment_failed_events_total</code></td><td>cluster, env, app_name</td><td>la metrica deve misurare gli eventi di pagamento validi di cui però è fallito il processing per qualsiasi motivo (escluso il caso in cui non esiste una configurazione per esso)</td></tr><tr><td><code>oc_payment_provider_errors_total</code></td><td>cluster, env, app_name</td><td>la metrica deve misurare gli eventi di pagamento validi di cui però è fallito il processing a causa di un errore sul provider</td></tr><tr><td><code>oc_payment_internal_errors_total</code></td><td>cluster, env, app_name</td><td>la metrica deve misurare gli eventi di pagamento validi di cui però è fallito il processing per errori interni al codice</td></tr><tr><td><code>oc_payment_provider_latency_bucket</code></td><td>cluster, env, app_name</td><td>istogramma che mostra la distribuzione di latenza delle risposte del provider</td></tr></tbody></table>

Inoltre il servizio deve rispettare gli [standard della piattaforma](https://docs.opencityitalia.it/sviluppatori-e-partner-tecnologici/standard-e-convenzioni/standard-della-piattaforma) in particolare per quanto riguarda la gestione dello storage: non possiamo avere vendor-lockin sulle tecnologie, quindi dobbiamo essere compatibili con file-system posix tradizionale, NFS share e almeno i due cloud-storage più diffusi  S3 e Azure Blob.

## Documentazione API di Esempio - Swagger&#x20;

## Get Status

> Get Service Status

```json
{"openapi":"3.1.0","info":{"title":"MyPay Proxy","version":"3.1.10"},"tags":[{"name":"Status"}],"servers":[{"url":"https://api.qa.stanzadelcittadino.it/payment-proxy/mypay-trentino/v2","description":"mypay-payment-proxy"}],"paths":{"/status":{"get":{"tags":["Status"],"summary":"Get Status","description":"Get Service Status","operationId":"get_status_status_get","responses":{"200":{"description":"Successful Response","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Status"}}}},"422":{"description":"Validation Error","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorMessage"}}}},"503":{"description":"Service Unavailable","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorMessage"}}}}}}}},"components":{"schemas":{"Status":{"properties":{"status":{"type":"string","title":"Status"}},"type":"object","required":["status"],"title":"Status"},"ErrorMessage":{"properties":{"type":{"type":"string","title":"Type"},"title":{"type":"string","title":"Title"},"status":{"type":"integer","format":"int32","title":"Status"},"detail":{"anyOf":[{"type":"string"},{"type":"object"}],"title":"Detail"},"instance":{"type":"string","title":"Instance"}},"type":"object","required":["type","title","status","detail"],"title":"ErrorMessage"}}}}
```

## GET /online-payment/{payment\_id}

> Get Online Url

```json
{"openapi":"3.1.0","info":{"title":"MyPay Proxy","version":"3.1.10"},"tags":[{"name":"Payments"}],"servers":[{"url":"https://api.qa.stanzadelcittadino.it/payment-proxy/mypay-trentino/v2","description":"mypay-payment-proxy"}],"paths":{"/online-payment/{payment_id}":{"get":{"tags":["Payments"],"summary":"Get Online Url","operationId":"get_online_url_online_payment__payment_id__get","parameters":[{"required":true,"schema":{"type":"string","title":"Payment Id"},"name":"payment_id","in":"path"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorMessage"}}}}}}}},"components":{"schemas":{"ErrorMessage":{"properties":{"type":{"type":"string","title":"Type"},"title":{"type":"string","title":"Title"},"status":{"type":"integer","format":"int32","title":"Status"},"detail":{"anyOf":[{"type":"string"},{"type":"object"}],"title":"Detail"},"instance":{"type":"string","title":"Instance"}},"type":"object","required":["type","title","status","detail"],"title":"ErrorMessage"}}}}
```

## GET /notice/{payment\_id}

> Get Notice Url

```json
{"openapi":"3.1.0","info":{"title":"MyPay Proxy","version":"3.1.10"},"tags":[{"name":"Payments"}],"servers":[{"url":"https://api.qa.stanzadelcittadino.it/payment-proxy/mypay-trentino/v2","description":"mypay-payment-proxy"}],"paths":{"/notice/{payment_id}":{"get":{"tags":["Payments"],"summary":"Get Notice Url","operationId":"get_notice_url_notice__payment_id__get","parameters":[{"required":true,"schema":{"type":"string","title":"Payment Id"},"name":"payment_id","in":"path"},{"required":true,"schema":{"type":"string","title":"Offline Url"},"name":"offline_url","in":"query"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorMessage"}}}}}}}},"components":{"schemas":{"ErrorMessage":{"properties":{"type":{"type":"string","title":"Type"},"title":{"type":"string","title":"Title"},"status":{"type":"integer","format":"int32","title":"Status"},"detail":{"anyOf":[{"type":"string"},{"type":"object"}],"title":"Detail"},"instance":{"type":"string","title":"Instance"}},"type":"object","required":["type","title","status","detail"],"title":"ErrorMessage"}}}}
```

## GET /receipt/{payment\_id}

> Get Receipt Url

```json
{"openapi":"3.1.0","info":{"title":"MyPay Proxy","version":"3.1.10"},"tags":[{"name":"Payments"}],"servers":[{"url":"https://api.qa.stanzadelcittadino.it/payment-proxy/mypay-trentino/v2","description":"mypay-payment-proxy"}],"paths":{"/receipt/{payment_id}":{"get":{"tags":["Payments"],"summary":"Get Receipt Url","operationId":"get_receipt_url_receipt__payment_id__get","parameters":[{"required":true,"schema":{"type":"string","title":"Payment Id"},"name":"payment_id","in":"path"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorMessage"}}}}}}}},"components":{"schemas":{"ErrorMessage":{"properties":{"type":{"type":"string","title":"Type"},"title":{"type":"string","title":"Title"},"status":{"type":"integer","format":"int32","title":"Status"},"detail":{"anyOf":[{"type":"string"},{"type":"object"}],"title":"Detail"},"instance":{"type":"string","title":"Instance"}},"type":"object","required":["type","title","status","detail"],"title":"ErrorMessage"}}}}
```

## GET /update/{payment\_id}

> Check For Updates

```json
{"openapi":"3.1.0","info":{"title":"MyPay Proxy","version":"3.1.10"},"tags":[{"name":"Payments"}],"servers":[{"url":"https://api.qa.stanzadelcittadino.it/payment-proxy/mypay-trentino/v2","description":"mypay-payment-proxy"}],"paths":{"/update/{payment_id}":{"get":{"tags":["Payments"],"summary":"Check For Updates","operationId":"check_for_updates_update__payment_id__get","parameters":[{"required":true,"schema":{"type":"string","title":"Payment Id"},"name":"payment_id","in":"path"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorMessage"}}}}}}}},"components":{"schemas":{"ErrorMessage":{"properties":{"type":{"type":"string","title":"Type"},"title":{"type":"string","title":"Title"},"status":{"type":"integer","format":"int32","title":"Status"},"detail":{"anyOf":[{"type":"string"},{"type":"object"}],"title":"Detail"},"instance":{"type":"string","title":"Instance"}},"type":"object","required":["type","title","status","detail"],"title":"ErrorMessage"}}}}
```

## GET /landing/{payment\_id}

> Get Landing Url

```json
{"openapi":"3.1.0","info":{"title":"MyPay Proxy","version":"3.1.10"},"tags":[{"name":"Payments"}],"servers":[{"url":"https://api.qa.stanzadelcittadino.it/payment-proxy/mypay-trentino/v2","description":"mypay-payment-proxy"}],"paths":{"/landing/{payment_id}":{"get":{"tags":["Payments"],"summary":"Get Landing Url","operationId":"get_landing_url_landing__payment_id__get","parameters":[{"required":true,"schema":{"title":"Payment Id"},"name":"payment_id","in":"path"},{"required":false,"schema":{"type":"string","title":"Idsession"},"name":"idSession","in":"query"},{"required":false,"schema":{"type":"string","title":"Esito","default":"OK"},"name":"esito","in":"query"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorMessage"}}}}}}}},"components":{"schemas":{"ErrorMessage":{"properties":{"type":{"type":"string","title":"Type"},"title":{"type":"string","title":"Title"},"status":{"type":"integer","format":"int32","title":"Status"},"detail":{"anyOf":[{"type":"string"},{"type":"object"}],"title":"Detail"},"instance":{"type":"string","title":"Instance"}},"type":"object","required":["type","title","status","detail"],"title":"ErrorMessage"}}}}
```

## PATCH /payments/{payment\_id}

> Register Payment

```json
{"openapi":"3.1.0","info":{"title":"MyPay Proxy","version":"3.1.10"},"tags":[{"name":"Payments"}],"servers":[{"url":"https://api.qa.stanzadelcittadino.it/payment-proxy/mypay-trentino/v2","description":"mypay-payment-proxy"}],"paths":{"/payments/{payment_id}":{"patch":{"tags":["Payments"],"summary":"Register Payment","operationId":"register_payment_payments__payment_id__patch","parameters":[{"required":true,"schema":{"title":"Payment Id"},"name":"payment_id","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaymentPatch"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorMessage"}}}}}}}},"components":{"schemas":{"PaymentPatch":{"properties":{"status":{"$ref":"#/components/schemas/PaymentStatus"}},"type":"object","required":["status"],"title":"PaymentPatch"},"PaymentStatus":{"enum":["CANCELED"],"title":"PaymentStatus","description":"An enumeration."},"ErrorMessage":{"properties":{"type":{"type":"string","title":"Type"},"title":{"type":"string","title":"Title"},"status":{"type":"integer","format":"int32","title":"Status"},"detail":{"anyOf":[{"type":"string"},{"type":"object"}],"title":"Detail"},"instance":{"type":"string","title":"Instance"}},"type":"object","required":["type","title","status","detail"],"title":"ErrorMessage"}}}}
```

## GET /tenants/schema

> Get Tenant Form Schema

```json
{"openapi":"3.1.0","info":{"title":"MyPay Proxy","version":"3.1.10"},"tags":[{"name":"Tenants"}],"servers":[{"url":"https://api.qa.stanzadelcittadino.it/payment-proxy/mypay-trentino/v2","description":"mypay-payment-proxy"}],"paths":{"/tenants/schema":{"get":{"tags":["Tenants"],"summary":"Get Tenant Form Schema","operationId":"get_tenant_form_schema_tenants_schema_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorMessage"}}}}}}}},"components":{"schemas":{"ErrorMessage":{"properties":{"type":{"type":"string","title":"Type"},"title":{"type":"string","title":"Title"},"status":{"type":"integer","format":"int32","title":"Status"},"detail":{"anyOf":[{"type":"string"},{"type":"object"}],"title":"Detail"},"instance":{"type":"string","title":"Instance"}},"type":"object","required":["type","title","status","detail"],"title":"ErrorMessage"}}}}
```

## GET /tenants/{tenant\_id}

> Get Tenant Configuration

```json
{"openapi":"3.1.0","info":{"title":"MyPay Proxy","version":"3.1.10"},"tags":[{"name":"Tenants"}],"servers":[{"url":"https://api.qa.stanzadelcittadino.it/payment-proxy/mypay-trentino/v2","description":"mypay-payment-proxy"}],"paths":{"/tenants/{tenant_id}":{"get":{"tags":["Tenants"],"summary":"Get Tenant Configuration","operationId":"get_tenant_configuration_tenants__tenant_id__get","parameters":[{"required":true,"schema":{"type":"string","format":"uuid","title":"Tenant Id"},"name":"tenant_id","in":"path"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Tenant"}}}},"422":{"description":"Validation Error","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorMessage"}}}}}}}},"components":{"schemas":{"Tenant":{"properties":{"name":{"type":"string","title":"Name"},"IPA_code":{"type":"string","title":"Ipa Code"},"tax_identification_number":{"type":"string","title":"Tax Identification Number"},"password":{"type":"string","title":"Password"},"cart_password":{"type":"string","title":"Cart Password","default":""},"application_code":{"type":"string","title":"Application Code","default":""},"active":{"type":"boolean","title":"Active"},"enable_checkout":{"type":"boolean","title":"Enable Checkout","default":false},"id":{"type":"string","format":"uuid","title":"Id"}},"type":"object","required":["name","IPA_code","password","active","id"],"title":"Tenant"},"ErrorMessage":{"properties":{"type":{"type":"string","title":"Type"},"title":{"type":"string","title":"Title"},"status":{"type":"integer","format":"int32","title":"Status"},"detail":{"anyOf":[{"type":"string"},{"type":"object"}],"title":"Detail"},"instance":{"type":"string","title":"Instance"}},"type":"object","required":["type","title","status","detail"],"title":"ErrorMessage"}}}}
```

## PUT /tenants/{tenant\_id}

> Update Tenant Configuration

```json
{"openapi":"3.1.0","info":{"title":"MyPay Proxy","version":"3.1.10"},"tags":[{"name":"Tenants"}],"servers":[{"url":"https://api.qa.stanzadelcittadino.it/payment-proxy/mypay-trentino/v2","description":"mypay-payment-proxy"}],"paths":{"/tenants/{tenant_id}":{"put":{"tags":["Tenants"],"summary":"Update Tenant Configuration","operationId":"update_tenant_configuration_tenants__tenant_id__put","parameters":[{"required":true,"schema":{"type":"string","format":"uuid","title":"Tenant Id"},"name":"tenant_id","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TenantUpdate"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorMessage"}}}}}}}},"components":{"schemas":{"TenantUpdate":{"properties":{"name":{"type":"string","title":"Name"},"IPA_code":{"type":"string","title":"Ipa Code"},"tax_identification_number":{"type":"string","title":"Tax Identification Number"},"password":{"type":"string","title":"Password"},"cart_password":{"type":"string","title":"Cart Password","default":""},"application_code":{"type":"string","title":"Application Code","default":""},"active":{"type":"boolean","title":"Active"},"enable_checkout":{"type":"boolean","title":"Enable Checkout","default":false}},"type":"object","required":["name","IPA_code","password","active"],"title":"TenantUpdate"},"ErrorMessage":{"properties":{"type":{"type":"string","title":"Type"},"title":{"type":"string","title":"Title"},"status":{"type":"integer","format":"int32","title":"Status"},"detail":{"anyOf":[{"type":"string"},{"type":"object"}],"title":"Detail"},"instance":{"type":"string","title":"Instance"}},"type":"object","required":["type","title","status","detail"],"title":"ErrorMessage"}}}}
```

## PATCH /tenants/{tenant\_id}

> Update Existing Tenant Configuration

```json
{"openapi":"3.1.0","info":{"title":"MyPay Proxy","version":"3.1.10"},"tags":[{"name":"Tenants"}],"servers":[{"url":"https://api.qa.stanzadelcittadino.it/payment-proxy/mypay-trentino/v2","description":"mypay-payment-proxy"}],"paths":{"/tenants/{tenant_id}":{"patch":{"tags":["Tenants"],"summary":"Update Existing Tenant Configuration","operationId":"update_existing_tenant_configuration_tenants__tenant_id__patch","parameters":[{"required":true,"schema":{"type":"string","format":"uuid","title":"Tenant Id"},"name":"tenant_id","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","title":"New Configuration"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorMessage"}}}}}}}},"components":{"schemas":{"ErrorMessage":{"properties":{"type":{"type":"string","title":"Type"},"title":{"type":"string","title":"Title"},"status":{"type":"integer","format":"int32","title":"Status"},"detail":{"anyOf":[{"type":"string"},{"type":"object"}],"title":"Detail"},"instance":{"type":"string","title":"Instance"}},"type":"object","required":["type","title","status","detail"],"title":"ErrorMessage"}}}}
```

## DELETE /tenants/{tenant\_id}

> Delete Tenant

```json
{"openapi":"3.1.0","info":{"title":"MyPay Proxy","version":"3.1.10"},"tags":[{"name":"Tenants"}],"servers":[{"url":"https://api.qa.stanzadelcittadino.it/payment-proxy/mypay-trentino/v2","description":"mypay-payment-proxy"}],"paths":{"/tenants/{tenant_id}":{"delete":{"tags":["Tenants"],"summary":"Delete Tenant","operationId":"delete_tenant_tenants__tenant_id__delete","parameters":[{"required":true,"schema":{"type":"string","format":"uuid","title":"Tenant Id"},"name":"tenant_id","in":"path"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorMessage"}}}}}}}},"components":{"schemas":{"ErrorMessage":{"properties":{"type":{"type":"string","title":"Type"},"title":{"type":"string","title":"Title"},"status":{"type":"integer","format":"int32","title":"Status"},"detail":{"anyOf":[{"type":"string"},{"type":"object"}],"title":"Detail"},"instance":{"type":"string","title":"Instance"}},"type":"object","required":["type","title","status","detail"],"title":"ErrorMessage"}}}}
```

## POST /tenants

> Save Tenant Configuration

```json
{"openapi":"3.1.0","info":{"title":"MyPay Proxy","version":"3.1.10"},"tags":[{"name":"Tenants"}],"servers":[{"url":"https://api.qa.stanzadelcittadino.it/payment-proxy/mypay-trentino/v2","description":"mypay-payment-proxy"}],"paths":{"/tenants":{"post":{"tags":["Tenants"],"summary":"Save Tenant Configuration","operationId":"save_tenant_configuration_tenants_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Tenant"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorMessage"}}}}}}}},"components":{"schemas":{"Tenant":{"properties":{"name":{"type":"string","title":"Name"},"IPA_code":{"type":"string","title":"Ipa Code"},"tax_identification_number":{"type":"string","title":"Tax Identification Number"},"password":{"type":"string","title":"Password"},"cart_password":{"type":"string","title":"Cart Password","default":""},"application_code":{"type":"string","title":"Application Code","default":""},"active":{"type":"boolean","title":"Active"},"enable_checkout":{"type":"boolean","title":"Enable Checkout","default":false},"id":{"type":"string","format":"uuid","title":"Id"}},"type":"object","required":["name","IPA_code","password","active","id"],"title":"Tenant"},"ErrorMessage":{"properties":{"type":{"type":"string","title":"Type"},"title":{"type":"string","title":"Title"},"status":{"type":"integer","format":"int32","title":"Status"},"detail":{"anyOf":[{"type":"string"},{"type":"object"}],"title":"Detail"},"instance":{"type":"string","title":"Instance"}},"type":"object","required":["type","title","status","detail"],"title":"ErrorMessage"}}}}
```

## GET /configs/schema

> Get Service Form Schema

```json
{"openapi":"3.1.0","info":{"title":"MyPay Proxy","version":"3.1.10"},"tags":[{"name":"Configurations"}],"servers":[{"url":"https://api.qa.stanzadelcittadino.it/payment-proxy/mypay-trentino/v2","description":"mypay-payment-proxy"}],"paths":{"/configs/schema":{"get":{"tags":["Configurations"],"summary":"Get Service Form Schema","operationId":"get_service_form_schema_configs_schema_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorMessage"}}}}}}}},"components":{"schemas":{"ErrorMessage":{"properties":{"type":{"type":"string","title":"Type"},"title":{"type":"string","title":"Title"},"status":{"type":"integer","format":"int32","title":"Status"},"detail":{"anyOf":[{"type":"string"},{"type":"object"}],"title":"Detail"},"instance":{"type":"string","title":"Instance"}},"type":"object","required":["type","title","status","detail"],"title":"ErrorMessage"}}}}
```

## GET /configs

> Get Payment Configurations List

```json
{"openapi":"3.1.0","info":{"title":"MyPay Proxy","version":"3.1.10"},"tags":[{"name":"Configurations"}],"servers":[{"url":"https://api.qa.stanzadelcittadino.it/payment-proxy/mypay-trentino/v2","description":"mypay-payment-proxy"}],"paths":{"/configs":{"get":{"tags":["Configurations"],"summary":"Get Payment Configurations List","operationId":"get_payment_configurations_list_configs_get","parameters":[{"description":"Lista id delle configurazioni di pagamento","required":false,"schema":{"items":{"type":"string","format":"uuid"},"type":"array","title":"Config Ids","description":"Lista id delle configurazioni di pagamento"},"name":"config_ids","in":"query"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/Configuration"},"type":"array","title":"Response Get Payment Configurations List Configs Get"}}}},"422":{"description":"Validation Error","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorMessage"}}}}}}}},"components":{"schemas":{"Configuration":{"properties":{"tenant_id":{"type":"string","format":"uuid","title":"Tenant Id"},"remote_collection":{"$ref":"#/components/schemas/RemoteCollection"},"items":{"items":{"$ref":"#/components/schemas/Item"},"type":"array","maxItems":1,"minItems":1,"title":"Items"},"active":{"type":"boolean","title":"Active"},"id":{"type":"string","format":"uuid","title":"Id"}},"type":"object","required":["tenant_id","remote_collection","items","active"],"title":"Configuration"},"RemoteCollection":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"type":{"type":"string","title":"Type","default":"service"}},"type":"object","required":["id"],"title":"RemoteCollection"},"Item":{"properties":{"payment_type":{"allOf":[{"$ref":"#/components/schemas/PaymentType"}],"default":"pagopa"},"management_id":{"type":"string","title":"Management Id"},"amount":{"type":"number","minimum":0,"title":"Amount"},"reason":{"type":"string","title":"Reason"},"expire_at":{"type":"integer","title":"Expire At"},"collection_data":{"type":"string","title":"Collection Data"},"pagopa_category":{"type":"string","title":"Pagopa Category"},"split":{"items":{"$ref":"#/components/schemas/PaymentSplit"},"type":"array","title":"Split","default":[]},"fixed_expiration_date":{"type":"string","format":"date-time","title":"Fixed Expiration Date"},"receiver":{"$ref":"#/components/schemas/Receiver"}},"type":"object","required":["amount","reason","expire_at","collection_data","pagopa_category"],"title":"Item"},"PaymentType":{"type":"string","enum":["pagopa","stamp"],"title":"PaymentType","description":"An enumeration."},"PaymentSplit":{"properties":{"id":{"type":"string","title":"Id"},"budget_chapter":{"type":"string","title":"Budget Chapter"},"office_code":{"type":"string","title":"Office Code"},"assessment":{"type":"string","title":"Assessment"},"amount":{"type":"number","minimum":0,"title":"Amount"}},"type":"object","required":["id","amount"],"title":"PaymentSplit"},"Receiver":{"properties":{"tax_identification_number":{"type":"string","title":"Tax Identification Number"},"name":{"type":"string","title":"Name"},"iban":{"type":"string","title":"Iban"},"address":{"type":"string","title":"Address"},"building_number":{"type":"string","title":"Building Number"},"postal_code":{"type":"string","title":"Postal Code"},"town_name":{"type":"string","title":"Town Name"},"country_subdivision":{"type":"string","title":"Country Subdivision"},"country":{"type":"string","title":"Country"}},"type":"object","required":["tax_identification_number","name","iban"],"title":"Receiver"},"ErrorMessage":{"properties":{"type":{"type":"string","title":"Type"},"title":{"type":"string","title":"Title"},"status":{"type":"integer","format":"int32","title":"Status"},"detail":{"anyOf":[{"type":"string"},{"type":"object"}],"title":"Detail"},"instance":{"type":"string","title":"Instance"}},"type":"object","required":["type","title","status","detail"],"title":"ErrorMessage"}}}}
```

## POST /configs

> Save Payment Configuration

```json
{"openapi":"3.1.0","info":{"title":"MyPay Proxy","version":"3.1.10"},"tags":[{"name":"Configurations"}],"servers":[{"url":"https://api.qa.stanzadelcittadino.it/payment-proxy/mypay-trentino/v2","description":"mypay-payment-proxy"}],"paths":{"/configs":{"post":{"tags":["Configurations"],"summary":"Save Payment Configuration","operationId":"save_payment_configuration_configs_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Configuration"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorMessage"}}}}}}}},"components":{"schemas":{"Configuration":{"properties":{"tenant_id":{"type":"string","format":"uuid","title":"Tenant Id"},"remote_collection":{"$ref":"#/components/schemas/RemoteCollection"},"items":{"items":{"$ref":"#/components/schemas/Item"},"type":"array","maxItems":1,"minItems":1,"title":"Items"},"active":{"type":"boolean","title":"Active"},"id":{"type":"string","format":"uuid","title":"Id"}},"type":"object","required":["tenant_id","remote_collection","items","active"],"title":"Configuration"},"RemoteCollection":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"type":{"type":"string","title":"Type","default":"service"}},"type":"object","required":["id"],"title":"RemoteCollection"},"Item":{"properties":{"payment_type":{"allOf":[{"$ref":"#/components/schemas/PaymentType"}],"default":"pagopa"},"management_id":{"type":"string","title":"Management Id"},"amount":{"type":"number","minimum":0,"title":"Amount"},"reason":{"type":"string","title":"Reason"},"expire_at":{"type":"integer","title":"Expire At"},"collection_data":{"type":"string","title":"Collection Data"},"pagopa_category":{"type":"string","title":"Pagopa Category"},"split":{"items":{"$ref":"#/components/schemas/PaymentSplit"},"type":"array","title":"Split","default":[]},"fixed_expiration_date":{"type":"string","format":"date-time","title":"Fixed Expiration Date"},"receiver":{"$ref":"#/components/schemas/Receiver"}},"type":"object","required":["amount","reason","expire_at","collection_data","pagopa_category"],"title":"Item"},"PaymentType":{"type":"string","enum":["pagopa","stamp"],"title":"PaymentType","description":"An enumeration."},"PaymentSplit":{"properties":{"id":{"type":"string","title":"Id"},"budget_chapter":{"type":"string","title":"Budget Chapter"},"office_code":{"type":"string","title":"Office Code"},"assessment":{"type":"string","title":"Assessment"},"amount":{"type":"number","minimum":0,"title":"Amount"}},"type":"object","required":["id","amount"],"title":"PaymentSplit"},"Receiver":{"properties":{"tax_identification_number":{"type":"string","title":"Tax Identification Number"},"name":{"type":"string","title":"Name"},"iban":{"type":"string","title":"Iban"},"address":{"type":"string","title":"Address"},"building_number":{"type":"string","title":"Building Number"},"postal_code":{"type":"string","title":"Postal Code"},"town_name":{"type":"string","title":"Town Name"},"country_subdivision":{"type":"string","title":"Country Subdivision"},"country":{"type":"string","title":"Country"}},"type":"object","required":["tax_identification_number","name","iban"],"title":"Receiver"},"ErrorMessage":{"properties":{"type":{"type":"string","title":"Type"},"title":{"type":"string","title":"Title"},"status":{"type":"integer","format":"int32","title":"Status"},"detail":{"anyOf":[{"type":"string"},{"type":"object"}],"title":"Detail"},"instance":{"type":"string","title":"Instance"}},"type":"object","required":["type","title","status","detail"],"title":"ErrorMessage"}}}}
```

## GET /configs/{config\_id}

> Get Payment Configuration

```json
{"openapi":"3.1.0","info":{"title":"MyPay Proxy","version":"3.1.10"},"tags":[{"name":"Configurations"}],"servers":[{"url":"https://api.qa.stanzadelcittadino.it/payment-proxy/mypay-trentino/v2","description":"mypay-payment-proxy"}],"paths":{"/configs/{config_id}":{"get":{"tags":["Configurations"],"summary":"Get Payment Configuration","operationId":"get_payment_configuration_configs__config_id__get","parameters":[{"required":true,"schema":{"type":"string","format":"uuid","title":"Config Id"},"name":"config_id","in":"path"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Configuration"}}}},"422":{"description":"Validation Error","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorMessage"}}}}}}}},"components":{"schemas":{"Configuration":{"properties":{"tenant_id":{"type":"string","format":"uuid","title":"Tenant Id"},"remote_collection":{"$ref":"#/components/schemas/RemoteCollection"},"items":{"items":{"$ref":"#/components/schemas/Item"},"type":"array","maxItems":1,"minItems":1,"title":"Items"},"active":{"type":"boolean","title":"Active"},"id":{"type":"string","format":"uuid","title":"Id"}},"type":"object","required":["tenant_id","remote_collection","items","active"],"title":"Configuration"},"RemoteCollection":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"type":{"type":"string","title":"Type","default":"service"}},"type":"object","required":["id"],"title":"RemoteCollection"},"Item":{"properties":{"payment_type":{"allOf":[{"$ref":"#/components/schemas/PaymentType"}],"default":"pagopa"},"management_id":{"type":"string","title":"Management Id"},"amount":{"type":"number","minimum":0,"title":"Amount"},"reason":{"type":"string","title":"Reason"},"expire_at":{"type":"integer","title":"Expire At"},"collection_data":{"type":"string","title":"Collection Data"},"pagopa_category":{"type":"string","title":"Pagopa Category"},"split":{"items":{"$ref":"#/components/schemas/PaymentSplit"},"type":"array","title":"Split","default":[]},"fixed_expiration_date":{"type":"string","format":"date-time","title":"Fixed Expiration Date"},"receiver":{"$ref":"#/components/schemas/Receiver"}},"type":"object","required":["amount","reason","expire_at","collection_data","pagopa_category"],"title":"Item"},"PaymentType":{"type":"string","enum":["pagopa","stamp"],"title":"PaymentType","description":"An enumeration."},"PaymentSplit":{"properties":{"id":{"type":"string","title":"Id"},"budget_chapter":{"type":"string","title":"Budget Chapter"},"office_code":{"type":"string","title":"Office Code"},"assessment":{"type":"string","title":"Assessment"},"amount":{"type":"number","minimum":0,"title":"Amount"}},"type":"object","required":["id","amount"],"title":"PaymentSplit"},"Receiver":{"properties":{"tax_identification_number":{"type":"string","title":"Tax Identification Number"},"name":{"type":"string","title":"Name"},"iban":{"type":"string","title":"Iban"},"address":{"type":"string","title":"Address"},"building_number":{"type":"string","title":"Building Number"},"postal_code":{"type":"string","title":"Postal Code"},"town_name":{"type":"string","title":"Town Name"},"country_subdivision":{"type":"string","title":"Country Subdivision"},"country":{"type":"string","title":"Country"}},"type":"object","required":["tax_identification_number","name","iban"],"title":"Receiver"},"ErrorMessage":{"properties":{"type":{"type":"string","title":"Type"},"title":{"type":"string","title":"Title"},"status":{"type":"integer","format":"int32","title":"Status"},"detail":{"anyOf":[{"type":"string"},{"type":"object"}],"title":"Detail"},"instance":{"type":"string","title":"Instance"}},"type":"object","required":["type","title","status","detail"],"title":"ErrorMessage"}}}}
```

## PUT /configs/{config\_id}

> Update Payment Configuration

```json
{"openapi":"3.1.0","info":{"title":"MyPay Proxy","version":"3.1.10"},"tags":[{"name":"Configurations"}],"servers":[{"url":"https://api.qa.stanzadelcittadino.it/payment-proxy/mypay-trentino/v2","description":"mypay-payment-proxy"}],"paths":{"/configs/{config_id}":{"put":{"tags":["Configurations"],"summary":"Update Payment Configuration","operationId":"update_payment_configuration_configs__config_id__put","parameters":[{"required":true,"schema":{"type":"string","format":"uuid","title":"Config Id"},"name":"config_id","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConfigurationUpdate"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorMessage"}}}}}}}},"components":{"schemas":{"ConfigurationUpdate":{"properties":{"tenant_id":{"type":"string","format":"uuid","title":"Tenant Id"},"remote_collection":{"$ref":"#/components/schemas/RemoteCollection"},"items":{"items":{"$ref":"#/components/schemas/Item"},"type":"array","maxItems":1,"minItems":1,"title":"Items"},"active":{"type":"boolean","title":"Active"}},"type":"object","required":["tenant_id","remote_collection","items","active"],"title":"ConfigurationUpdate"},"RemoteCollection":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"type":{"type":"string","title":"Type","default":"service"}},"type":"object","required":["id"],"title":"RemoteCollection"},"Item":{"properties":{"payment_type":{"allOf":[{"$ref":"#/components/schemas/PaymentType"}],"default":"pagopa"},"management_id":{"type":"string","title":"Management Id"},"amount":{"type":"number","minimum":0,"title":"Amount"},"reason":{"type":"string","title":"Reason"},"expire_at":{"type":"integer","title":"Expire At"},"collection_data":{"type":"string","title":"Collection Data"},"pagopa_category":{"type":"string","title":"Pagopa Category"},"split":{"items":{"$ref":"#/components/schemas/PaymentSplit"},"type":"array","title":"Split","default":[]},"fixed_expiration_date":{"type":"string","format":"date-time","title":"Fixed Expiration Date"},"receiver":{"$ref":"#/components/schemas/Receiver"}},"type":"object","required":["amount","reason","expire_at","collection_data","pagopa_category"],"title":"Item"},"PaymentType":{"type":"string","enum":["pagopa","stamp"],"title":"PaymentType","description":"An enumeration."},"PaymentSplit":{"properties":{"id":{"type":"string","title":"Id"},"budget_chapter":{"type":"string","title":"Budget Chapter"},"office_code":{"type":"string","title":"Office Code"},"assessment":{"type":"string","title":"Assessment"},"amount":{"type":"number","minimum":0,"title":"Amount"}},"type":"object","required":["id","amount"],"title":"PaymentSplit"},"Receiver":{"properties":{"tax_identification_number":{"type":"string","title":"Tax Identification Number"},"name":{"type":"string","title":"Name"},"iban":{"type":"string","title":"Iban"},"address":{"type":"string","title":"Address"},"building_number":{"type":"string","title":"Building Number"},"postal_code":{"type":"string","title":"Postal Code"},"town_name":{"type":"string","title":"Town Name"},"country_subdivision":{"type":"string","title":"Country Subdivision"},"country":{"type":"string","title":"Country"}},"type":"object","required":["tax_identification_number","name","iban"],"title":"Receiver"},"ErrorMessage":{"properties":{"type":{"type":"string","title":"Type"},"title":{"type":"string","title":"Title"},"status":{"type":"integer","format":"int32","title":"Status"},"detail":{"anyOf":[{"type":"string"},{"type":"object"}],"title":"Detail"},"instance":{"type":"string","title":"Instance"}},"type":"object","required":["type","title","status","detail"],"title":"ErrorMessage"}}}}
```

## DELETE /configs/{config\_id}

> Delete Service

```json
{"openapi":"3.1.0","info":{"title":"MyPay Proxy","version":"3.1.10"},"tags":[{"name":"Configurations"}],"servers":[{"url":"https://api.qa.stanzadelcittadino.it/payment-proxy/mypay-trentino/v2","description":"mypay-payment-proxy"}],"paths":{"/configs/{config_id}":{"delete":{"tags":["Configurations"],"summary":"Delete Service","operationId":"delete_service_configs__config_id__delete","parameters":[{"required":true,"schema":{"type":"string","format":"uuid","title":"Config Id"},"name":"config_id","in":"path"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorMessage"}}}}}}}},"components":{"schemas":{"ErrorMessage":{"properties":{"type":{"type":"string","title":"Type"},"title":{"type":"string","title":"Title"},"status":{"type":"integer","format":"int32","title":"Status"},"detail":{"anyOf":[{"type":"string"},{"type":"object"}],"title":"Detail"},"instance":{"type":"string","title":"Instance"}},"type":"object","required":["type","title","status","detail"],"title":"ErrorMessage"}}}}
```

## PATCH /configs/{config\_id}

> Update Existing Payment Configuration

```json
{"openapi":"3.1.0","info":{"title":"MyPay Proxy","version":"3.1.10"},"tags":[{"name":"Configurations"}],"servers":[{"url":"https://api.qa.stanzadelcittadino.it/payment-proxy/mypay-trentino/v2","description":"mypay-payment-proxy"}],"paths":{"/configs/{config_id}":{"patch":{"tags":["Configurations"],"summary":"Update Existing Payment Configuration","operationId":"update_existing_payment_configuration_configs__config_id__patch","parameters":[{"required":true,"schema":{"type":"string","format":"uuid","title":"Config Id"},"name":"config_id","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","title":"New Configuration"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorMessage"}}}}}}}},"components":{"schemas":{"ErrorMessage":{"properties":{"type":{"type":"string","title":"Type"},"title":{"type":"string","title":"Title"},"status":{"type":"integer","format":"int32","title":"Status"},"detail":{"anyOf":[{"type":"string"},{"type":"object"}],"title":"Detail"},"instance":{"type":"string","title":"Instance"}},"type":"object","required":["type","title","status","detail"],"title":"ErrorMessage"}}}}
```

## POST /update-user-dues

> Update User Dues

```json
{"openapi":"3.1.0","info":{"title":"MyPay Proxy","version":"3.1.10"},"tags":[{"name":"Payments"}],"servers":[{"url":"https://api.qa.stanzadelcittadino.it/payment-proxy/mypay-trentino/v2","description":"mypay-payment-proxy"}],"paths":{"/update-user-dues":{"post":{"tags":["Payments"],"summary":"Update User Dues","operationId":"update_user_dues_update_user_dues_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdatePaymentsReuqest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorMessage"}}}}}}}},"components":{"schemas":{"UpdatePaymentsReuqest":{"properties":{"tax_identification_number":{"type":"string","title":"Tax Identification Number"},"user_id":{"type":"string","title":"User Id"},"tenant_id":{"type":"string","title":"Tenant Id"},"job_id":{"type":"string","title":"Job Id"}},"type":"object","required":["tax_identification_number","user_id","tenant_id","job_id"],"title":"UpdatePaymentsReuqest"},"ErrorMessage":{"properties":{"type":{"type":"string","title":"Type"},"title":{"type":"string","title":"Title"},"status":{"type":"integer","format":"int32","title":"Status"},"detail":{"anyOf":[{"type":"string"},{"type":"object"}],"title":"Detail"},"instance":{"type":"string","title":"Instance"}},"type":"object","required":["type","title","status","detail"],"title":"ErrorMessage"}}}}
```

## Esempi di proxy da cui si può prendere spunto

EFIL: <http://gitlab.com/opencontent/stanza-del-cittadino/efil-payment-proxy>

IRIS: [http://gitlab.com/opencontent/stanza-del-cittadino/iris-payment-proxy](http://gitlab.com/opencontent/stanza-del-cittadino/efil-payment-proxy)

MYPAY: [http://gitlab.com/opencontent/stanza-del-cittadino/mypay-payment-proxy](http://gitlab.com/opencontent/stanza-del-cittadino/efil-payment-proxy)

PMPAY: [http://gitlab.com/opencontent/stanza-del-cittadino/pmpay-payment-proxy](http://gitlab.com/opencontent/stanza-del-cittadino/efil-payment-proxy)

Questi proxy condividono alcune scelte implementative grazie a un apposito python-sdk sviluppato in parallelo ai proxy stessi:

* le configurazioni sono salvate su disco locale o s3 secondo un albero ben definito tenant->servizio
* i singoli pagamenti vengono salvati su storage fino a che il pagamento è pendente, così da poter fare il polling in autonomia.

## Altri riferimenti utili

* [Presentazione API Interoperability a EuroPython 2018](https://docs.italia.it/italia/piano-triennale-ict/lg-modellointeroperabilita-docs/it/bozza/doc/04_Raccomandazioni%20di%20implementazione/04_raccomandazioni-tecniche-generali/03_progettazione-e-naming.html)
* [Presentazione API Interoperability a EuroPython 2019](https://docs.google.com/presentation/d/1blql0E_zcbq7r-wzmslgJPiW7ELkYlIn9_fqIVEXr4A/edit#slide=id.p4)
* [API Starter Kit](https://github.com/teamdigitale/api-starter-kit)
