{
  "components" : {
    "schemas" : {
      "AccountingDraftResponse" : {
        "properties" : {
          "disclaimer" : {
            "type" : "string"
          },
          "entries" : {
            "items" : {
              "$ref" : "#/components/schemas/AccountingEntryResponse"
            },
            "type" : "array"
          },
          "from" : {
            "type" : "string"
          },
          "to" : {
            "type" : "string"
          }
        },
        "type" : "object"
      },
      "AccountingEntryResponse" : {
        "properties" : {
          "day" : {
            "type" : "string"
          },
          "firstSaleId" : {
            "format" : "int64",
            "type" : "integer"
          },
          "lastSaleId" : {
            "format" : "int64",
            "type" : "integer"
          },
          "taxExemption" : {
            "type" : "string"
          },
          "taxRate" : {
            "format" : "int32",
            "type" : "integer"
          },
          "tickets" : {
            "format" : "int32",
            "type" : "integer"
          },
          "total" : {
            "type" : "string"
          }
        },
        "type" : "object"
      },
      "Availability" : {
        "properties" : {
          "bookableUntil" : {
            "format" : "date",
            "type" : "string"
          },
          "day" : {
            "format" : "date",
            "type" : "string"
          },
          "serviceId" : {
            "format" : "int32",
            "type" : "integer"
          },
          "slots" : {
            "items" : {
              "$ref" : "#/components/schemas/Slot"
            },
            "type" : "array"
          }
        },
        "type" : "object"
      },
      "Booking" : {
        "properties" : {
          "appointmentId" : {
            "format" : "int64",
            "type" : "integer"
          },
          "customerId" : {
            "format" : "int64",
            "type" : "integer"
          },
          "day" : {
            "format" : "date",
            "type" : "string"
          },
          "end" : {
            "format" : "time-local",
            "type" : "string"
          },
          "reference" : {
            "type" : "string"
          },
          "serviceId" : {
            "format" : "int32",
            "type" : "integer"
          },
          "start" : {
            "format" : "time-local",
            "type" : "string"
          }
        },
        "type" : "object"
      },
      "BookingCustomer" : {
        "properties" : {
          "email" : {
            "format" : "email",
            "maxLength" : 100,
            "minLength" : 0,
            "type" : "string"
          },
          "name" : {
            "maxLength" : 60,
            "minLength" : 0,
            "type" : "string"
          },
          "phone" : {
            "maxLength" : 15,
            "minLength" : 0,
            "type" : "string"
          },
          "surname" : {
            "maxLength" : 100,
            "minLength" : 0,
            "type" : "string"
          }
        },
        "required" : [ "name" ],
        "type" : "object"
      },
      "CustomerExistsResponse" : {
        "properties" : {
          "exists" : {
            "type" : "boolean"
          }
        },
        "type" : "object"
      },
      "CustomerResponse" : {
        "properties" : {
          "address" : {
            "type" : "string"
          },
          "city" : {
            "type" : "string"
          },
          "email" : {
            "type" : "string"
          },
          "id" : {
            "format" : "int64",
            "type" : "integer"
          },
          "mobile" : {
            "type" : "string"
          },
          "name" : {
            "type" : "string"
          },
          "phone" : {
            "type" : "string"
          },
          "postalCode" : {
            "type" : "string"
          },
          "province" : {
            "type" : "string"
          },
          "surname" : {
            "type" : "string"
          },
          "taxId" : {
            "type" : "string"
          },
          "updatedOn" : {
            "type" : "string"
          }
        },
        "type" : "object"
      },
      "IntegrationBookingRequest" : {
        "properties" : {
          "customer" : {
            "$ref" : "#/components/schemas/BookingCustomer"
          },
          "day" : {
            "format" : "date",
            "type" : "string"
          },
          "reference" : {
            "maxLength" : 100,
            "minLength" : 0,
            "type" : "string"
          },
          "serviceId" : {
            "format" : "int32",
            "type" : "integer"
          },
          "start" : {
            "format" : "time-local",
            "type" : "string"
          }
        },
        "required" : [ "customer", "day", "reference", "serviceId", "start" ],
        "type" : "object"
      },
      "IntegrationPageCustomerResponse" : {
        "properties" : {
          "items" : {
            "items" : {
              "$ref" : "#/components/schemas/CustomerResponse"
            },
            "type" : "array"
          },
          "nextCursor" : {
            "type" : "string"
          }
        },
        "type" : "object"
      },
      "IntegrationPageProductResponse" : {
        "properties" : {
          "items" : {
            "items" : {
              "$ref" : "#/components/schemas/ProductResponse"
            },
            "type" : "array"
          },
          "nextCursor" : {
            "type" : "string"
          }
        },
        "type" : "object"
      },
      "IntegrationPageSaleResponse" : {
        "properties" : {
          "items" : {
            "items" : {
              "$ref" : "#/components/schemas/SaleResponse"
            },
            "type" : "array"
          },
          "nextCursor" : {
            "type" : "string"
          }
        },
        "type" : "object"
      },
      "IntegrationPageServiceResponse" : {
        "properties" : {
          "items" : {
            "items" : {
              "$ref" : "#/components/schemas/ServiceResponse"
            },
            "type" : "array"
          },
          "nextCursor" : {
            "type" : "string"
          }
        },
        "type" : "object"
      },
      "IntegrationTokenRequest" : {
        "properties" : {
          "client_id" : {
            "maxLength" : 40,
            "minLength" : 0,
            "type" : "string"
          },
          "client_secret" : {
            "maxLength" : 100,
            "minLength" : 0,
            "type" : "string"
          },
          "grant_type" : {
            "maxLength" : 40,
            "minLength" : 0,
            "type" : "string"
          }
        },
        "required" : [ "client_id", "client_secret", "grant_type" ],
        "type" : "object"
      },
      "IntegrationTokenResponse" : {
        "properties" : {
          "access_token" : {
            "type" : "string"
          },
          "expires_in" : {
            "format" : "int64",
            "type" : "integer"
          },
          "scope" : {
            "type" : "string"
          },
          "token_type" : {
            "type" : "string"
          }
        },
        "type" : "object"
      },
      "ProblemDetail" : {
        "properties" : {
          "detail" : {
            "type" : "string"
          },
          "instance" : {
            "format" : "uri",
            "type" : "string"
          },
          "properties" : {
            "additionalProperties" : { },
            "type" : "object"
          },
          "status" : {
            "format" : "int32",
            "type" : "integer"
          },
          "title" : {
            "type" : "string"
          },
          "type" : {
            "format" : "uri",
            "type" : "string"
          }
        },
        "type" : "object"
      },
      "ProductResponse" : {
        "properties" : {
          "brand" : {
            "type" : "string"
          },
          "category" : {
            "type" : "string"
          },
          "enabled" : {
            "type" : "boolean"
          },
          "id" : {
            "format" : "int32",
            "type" : "integer"
          },
          "name" : {
            "type" : "string"
          },
          "price" : {
            "type" : "string"
          },
          "reference" : {
            "type" : "string"
          },
          "taxExemption" : {
            "type" : "string"
          },
          "taxRate" : {
            "format" : "int32",
            "type" : "integer"
          },
          "updatedOn" : {
            "type" : "string"
          }
        },
        "type" : "object"
      },
      "SaleLineResponse" : {
        "properties" : {
          "amount" : {
            "type" : "string"
          },
          "description" : {
            "type" : "string"
          },
          "discountPercentage" : {
            "format" : "int32",
            "type" : "integer"
          },
          "id" : {
            "format" : "int64",
            "type" : "integer"
          },
          "productId" : {
            "format" : "int32",
            "type" : "integer"
          },
          "serviceId" : {
            "format" : "int32",
            "type" : "integer"
          },
          "taxExemption" : {
            "type" : "string"
          },
          "taxRate" : {
            "format" : "int32",
            "type" : "integer"
          }
        },
        "type" : "object"
      },
      "SaleResponse" : {
        "properties" : {
          "customerId" : {
            "format" : "int64",
            "type" : "integer"
          },
          "date" : {
            "type" : "string"
          },
          "delegationId" : {
            "format" : "int32",
            "type" : "integer"
          },
          "id" : {
            "format" : "int64",
            "type" : "integer"
          },
          "lines" : {
            "items" : {
              "$ref" : "#/components/schemas/SaleLineResponse"
            },
            "type" : "array"
          },
          "refundOf" : {
            "format" : "int64",
            "type" : "integer"
          },
          "total" : {
            "type" : "string"
          },
          "updatedOn" : {
            "type" : "string"
          }
        },
        "type" : "object"
      },
      "ServiceResponse" : {
        "properties" : {
          "category" : {
            "type" : "string"
          },
          "description" : {
            "type" : "string"
          },
          "durationInMinutes" : {
            "format" : "int32",
            "type" : "integer"
          },
          "enabled" : {
            "type" : "boolean"
          },
          "id" : {
            "format" : "int32",
            "type" : "integer"
          },
          "name" : {
            "type" : "string"
          },
          "price" : {
            "type" : "string"
          },
          "taxExemption" : {
            "type" : "string"
          },
          "taxRate" : {
            "format" : "int32",
            "type" : "integer"
          },
          "updatedOn" : {
            "type" : "string"
          }
        },
        "type" : "object"
      },
      "Slot" : {
        "properties" : {
          "end" : {
            "format" : "time-local",
            "type" : "string"
          },
          "start" : {
            "format" : "time-local",
            "type" : "string"
          }
        },
        "type" : "object"
      }
    },
    "securitySchemes" : {
      "bearerAuth" : {
        "bearerFormat" : "JWT",
        "scheme" : "bearer",
        "type" : "http"
      }
    }
  },
  "info" : {
    "description" : "Lo que un programa de fuera puede leer de un centro y la reserva de huecos de su agenda. Se entra con OAuth 2.0 client credentials: POST /api/v1/integration/token con el client_id y el client_secret que da el centro, y el token en 'Authorization: Bearer <access_token>'. Guía completa: https://devel.es/turnera/api",
    "title" : "Turnera: API de integración",
    "version" : "v1"
  },
  "openapi" : "3.1.0",
  "paths" : {
    "/api/v1/integration/accounting-draft" : {
      "get" : {
        "operationId" : "accountingDraft",
        "parameters" : [ {
          "in" : "query",
          "name" : "from",
          "required" : true,
          "schema" : {
            "type" : "string"
          }
        }, {
          "in" : "query",
          "name" : "to",
          "required" : true,
          "schema" : {
            "type" : "string"
          }
        } ],
        "responses" : {
          "200" : {
            "content" : {
              "*/*" : {
                "schema" : {
                  "$ref" : "#/components/schemas/AccountingDraftResponse"
                }
              }
            },
            "description" : "OK"
          },
          "400" : {
            "content" : {
              "application/problem+json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ProblemDetail"
                }
              }
            },
            "description" : "Bad Request"
          }
        },
        "summary" : "Daily VAT summary of what was settled, as a draft to review with the accountant",
        "tags" : [ "Integration" ]
      }
    },
    "/api/v1/integration/availability" : {
      "get" : {
        "operationId" : "availability",
        "parameters" : [ {
          "in" : "query",
          "name" : "serviceId",
          "required" : true,
          "schema" : {
            "format" : "int32",
            "type" : "integer"
          }
        }, {
          "in" : "query",
          "name" : "day",
          "required" : true,
          "schema" : {
            "format" : "date",
            "type" : "string"
          }
        } ],
        "responses" : {
          "200" : {
            "content" : {
              "*/*" : {
                "schema" : {
                  "$ref" : "#/components/schemas/Availability"
                }
              }
            },
            "description" : "OK"
          }
        },
        "summary" : "Free start times of a day for a service that is booked online",
        "tags" : [ "Integration" ]
      }
    },
    "/api/v1/integration/bookings" : {
      "post" : {
        "operationId" : "book",
        "requestBody" : {
          "content" : {
            "application/json" : {
              "schema" : {
                "$ref" : "#/components/schemas/IntegrationBookingRequest"
              }
            }
          },
          "required" : true
        },
        "responses" : {
          "200" : {
            "content" : {
              "*/*" : {
                "schema" : {
                  "$ref" : "#/components/schemas/Booking"
                }
              }
            },
            "description" : "That reference was already booked: the same appointment"
          },
          "201" : {
            "content" : {
              "*/*" : {
                "schema" : {
                  "$ref" : "#/components/schemas/Booking"
                }
              }
            },
            "description" : "Booked"
          },
          "400" : {
            "content" : {
              "*/*" : {
                "schema" : {
                  "$ref" : "#/components/schemas/Booking"
                }
              }
            },
            "description" : "A field is missing, or the customer has no phone nor email"
          },
          "409" : {
            "content" : {
              "*/*" : {
                "schema" : {
                  "$ref" : "#/components/schemas/Booking"
                }
              }
            },
            "description" : "BOOKING_SLOT_TAKEN, BOOKING_EQUIPMENT_BUSY (the equipment the service needs is in use at that time; the problem detail carries its name in equipmentName), BOOKING_TOO_FAR_AHEAD or BOOKING_MINIMUM_NOTICE, in the 'code' of the problem detail"
          }
        },
        "summary" : "Book a free slot for a customer brought by the integration",
        "tags" : [ "Integration" ]
      }
    },
    "/api/v1/integration/catalog/products" : {
      "get" : {
        "operationId" : "products",
        "parameters" : [ {
          "in" : "query",
          "name" : "updatedSince",
          "required" : false,
          "schema" : {
            "type" : "string"
          }
        }, {
          "in" : "query",
          "name" : "cursor",
          "required" : false,
          "schema" : {
            "type" : "string"
          }
        }, {
          "in" : "query",
          "name" : "limit",
          "required" : false,
          "schema" : {
            "format" : "int32",
            "type" : "integer"
          }
        } ],
        "responses" : {
          "200" : {
            "content" : {
              "*/*" : {
                "schema" : {
                  "$ref" : "#/components/schemas/IntegrationPageProductResponse"
                }
              }
            },
            "description" : "OK"
          },
          "400" : {
            "content" : {
              "application/problem+json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ProblemDetail"
                }
              }
            },
            "description" : "Bad Request"
          }
        },
        "summary" : "Products of the catalogue, with their price and VAT",
        "tags" : [ "Integration" ]
      }
    },
    "/api/v1/integration/catalog/services" : {
      "get" : {
        "operationId" : "services",
        "parameters" : [ {
          "in" : "query",
          "name" : "updatedSince",
          "required" : false,
          "schema" : {
            "type" : "string"
          }
        }, {
          "in" : "query",
          "name" : "cursor",
          "required" : false,
          "schema" : {
            "type" : "string"
          }
        }, {
          "in" : "query",
          "name" : "limit",
          "required" : false,
          "schema" : {
            "format" : "int32",
            "type" : "integer"
          }
        } ],
        "responses" : {
          "200" : {
            "content" : {
              "*/*" : {
                "schema" : {
                  "$ref" : "#/components/schemas/IntegrationPageServiceResponse"
                }
              }
            },
            "description" : "OK"
          },
          "400" : {
            "content" : {
              "application/problem+json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ProblemDetail"
                }
              }
            },
            "description" : "Bad Request"
          }
        },
        "summary" : "Services of the catalogue, with their price and VAT",
        "tags" : [ "Integration" ]
      }
    },
    "/api/v1/integration/customers" : {
      "get" : {
        "operationId" : "customers",
        "parameters" : [ {
          "in" : "query",
          "name" : "updatedSince",
          "required" : false,
          "schema" : {
            "type" : "string"
          }
        }, {
          "in" : "query",
          "name" : "cursor",
          "required" : false,
          "schema" : {
            "type" : "string"
          }
        }, {
          "in" : "query",
          "name" : "limit",
          "required" : false,
          "schema" : {
            "format" : "int32",
            "type" : "integer"
          }
        } ],
        "responses" : {
          "200" : {
            "content" : {
              "*/*" : {
                "schema" : {
                  "$ref" : "#/components/schemas/IntegrationPageCustomerResponse"
                }
              }
            },
            "description" : "OK"
          },
          "400" : {
            "content" : {
              "application/problem+json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ProblemDetail"
                }
              }
            },
            "description" : "Bad Request"
          }
        },
        "summary" : "Administrative customer records; never any clinical content",
        "tags" : [ "Integration" ]
      }
    },
    "/api/v1/integration/customers/exists" : {
      "get" : {
        "operationId" : "customerExists",
        "parameters" : [ {
          "in" : "query",
          "name" : "email",
          "required" : false,
          "schema" : {
            "type" : "string"
          }
        }, {
          "in" : "query",
          "name" : "mobile",
          "required" : false,
          "schema" : {
            "type" : "string"
          }
        } ],
        "responses" : {
          "200" : {
            "content" : {
              "*/*" : {
                "schema" : {
                  "$ref" : "#/components/schemas/CustomerExistsResponse"
                }
              }
            },
            "description" : "OK"
          },
          "400" : {
            "content" : {
              "application/problem+json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ProblemDetail"
                }
              }
            },
            "description" : "Bad Request"
          }
        },
        "summary" : "Whether an email or a mobile number belongs to a customer; nothing else is revealed. Limited to 20 per minute and 2000 per day",
        "tags" : [ "Integration" ]
      }
    },
    "/api/v1/integration/sales" : {
      "get" : {
        "operationId" : "sales",
        "parameters" : [ {
          "in" : "query",
          "name" : "updatedSince",
          "required" : false,
          "schema" : {
            "type" : "string"
          }
        }, {
          "in" : "query",
          "name" : "cursor",
          "required" : false,
          "schema" : {
            "type" : "string"
          }
        }, {
          "in" : "query",
          "name" : "limit",
          "required" : false,
          "schema" : {
            "format" : "int32",
            "type" : "integer"
          }
        } ],
        "responses" : {
          "200" : {
            "content" : {
              "*/*" : {
                "schema" : {
                  "$ref" : "#/components/schemas/IntegrationPageSaleResponse"
                }
              }
            },
            "description" : "OK"
          },
          "400" : {
            "content" : {
              "application/problem+json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ProblemDetail"
                }
              }
            },
            "description" : "Bad Request"
          }
        },
        "summary" : "Settled visits with their lines, VAT and totals",
        "tags" : [ "Integration" ]
      }
    },
    "/api/v1/integration/token" : {
      "post" : {
        "operationId" : "token",
        "requestBody" : {
          "content" : {
            "application/json" : {
              "schema" : {
                "$ref" : "#/components/schemas/IntegrationTokenRequest"
              }
            }
          },
          "required" : true
        },
        "responses" : {
          "200" : {
            "content" : {
              "*/*" : {
                "schema" : {
                  "$ref" : "#/components/schemas/IntegrationTokenResponse"
                }
              }
            },
            "description" : "OK"
          },
          "401" : {
            "content" : {
              "application/problem+json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ProblemDetail"
                }
              }
            },
            "description" : "Unauthorized"
          }
        },
        "summary" : "Exchange the client credentials of an integration for an access token",
        "tags" : [ "Integration" ]
      }
    }
  },
  "security" : [ {
    "bearerAuth" : [ ]
  } ],
  "servers" : [ {
    "description" : "Cada centro tiene su dominio",
    "url" : "https://{centro}.turnera.devel.es",
    "variables" : {
      "centro" : {
        "default" : "sucentro",
        "description" : "El nombre del centro en su dirección de Turnera"
      }
    }
  } ]
}
