{
  "openapi": "3.1.0",
  "info": {
    "title": "Middleman Supplier Integration Preview",
    "version": "0.1.0",
    "description": "Developer preview contract. Check the published release status and the live /me capability response before use. Validation does not persist or publish supplier data."
  },
  "servers": [
    {
      "url": "https://middlemantechnologies.com"
    }
  ],
  "paths": {
    "/api/v1/supplier/me": {
      "get": {
        "operationId": "getSupplierAccess",
        "summary": "Check supplier integration access",
        "security": [
          {
            "SupplierApiKey": []
          }
        ],
        "description": "Integration preview. Returns key scope and supported capabilities; does not imply feed admission.",
        "responses": {
          "200": {
            "description": "Access and capability manifest",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "type": "object",
                      "required": [
                        "keyId",
                        "supplierId",
                        "scopes",
                        "schemaVersion",
                        "stage",
                        "capabilities"
                      ],
                      "properties": {
                        "keyId": {
                          "type": "string"
                        },
                        "supplierId": {
                          "type": "string"
                        },
                        "scopes": {
                          "type": "array",
                          "items": {
                            "type": "string"
                          }
                        },
                        "schemaVersion": {
                          "const": "0.1.0"
                        },
                        "stage": {
                          "const": "integration_preview"
                        },
                        "capabilities": {
                          "type": "object",
                          "properties": {
                            "validate": {
                              "const": true
                            },
                            "ingest": {
                              "const": false
                            },
                            "publish": {
                              "const": false
                            },
                            "quote": {
                              "const": false
                            },
                            "reserve": {
                              "const": false
                            },
                            "order": {
                              "const": false
                            }
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing, malformed, expired or revoked key."
          },
          "403": {
            "description": "Insufficient scope or issuing owner no longer has supplier access."
          },
          "429": {
            "description": "60 requests per minute per key exceeded. Retry-After is 60 seconds."
          },
          "503": {
            "description": "Authentication or supplier API temporarily unavailable."
          }
        }
      }
    },
    "/api/v1/supplier/validate": {
      "post": {
        "operationId": "validateSupplierMapping",
        "summary": "Validate source-derived supplier records",
        "security": [
          {
            "SupplierApiKey": []
          }
        ],
        "description": "No catalogue persistence, source fetching or publication. Limit 50 records / 256 KiB JSON. Dates and quantity-tier ordering are also checked by the server.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SupplierBatch"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Mapping valid; no data saved or admitted",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "valid",
                    "schemaVersion",
                    "recordsValidated",
                    "persisted",
                    "admitted"
                  ],
                  "properties": {
                    "valid": {
                      "const": true
                    },
                    "schemaVersion": {
                      "const": "0.1.0"
                    },
                    "recordsValidated": {
                      "type": "integer",
                      "minimum": 1,
                      "maximum": 50
                    },
                    "persisted": {
                      "const": false
                    },
                    "admitted": {
                      "const": false
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid JSON."
          },
          "401": {
            "description": "Missing, malformed, expired or revoked key."
          },
          "403": {
            "description": "Insufficient scope or issuing owner no longer has supplier access."
          },
          "413": {
            "description": "Body exceeds 256 KiB."
          },
          "415": {
            "description": "Content-Type must be application/json."
          },
          "422": {
            "description": "Mapping or freshness invalid",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "valid",
                    "schemaVersion",
                    "errors"
                  ],
                  "properties": {
                    "valid": {
                      "const": false
                    },
                    "schemaVersion": {
                      "const": "0.1.0"
                    },
                    "errors": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "required": [
                          "path",
                          "message"
                        ],
                        "properties": {
                          "path": {
                            "type": "string"
                          },
                          "message": {
                            "type": "string"
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "60 requests per minute per key exceeded. Retry-After is 60 seconds."
          },
          "503": {
            "description": "Authentication or supplier API temporarily unavailable."
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "SupplierApiKey": {
        "type": "http",
        "scheme": "bearer",
        "description": "Supplier company key issued in the workspace. Send only to the Middleman API origin."
      }
    },
    "schemas": {
      "SupplierBatch": {
        "$schema": "https://json-schema.org/draft/2020-12/schema",
        "type": "object",
        "properties": {
          "schemaVersion": {
            "type": "string",
            "const": "0.1.0"
          },
          "source": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string",
                "minLength": 1,
                "maxLength": 160,
                "pattern": "^[A-Za-z0-9][A-Za-z0-9._:/-]*$"
              },
              "system": {
                "type": "string",
                "minLength": 1,
                "maxLength": 80
              },
              "mode": {
                "type": "string",
                "enum": [
                  "api",
                  "sdk"
                ]
              }
            },
            "required": [
              "id",
              "system",
              "mode"
            ],
            "additionalProperties": false
          },
          "records": {
            "minItems": 1,
            "maxItems": 50,
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "sourceRecordId": {
                  "type": "string",
                  "minLength": 1,
                  "maxLength": 160,
                  "pattern": "^[A-Za-z0-9][A-Za-z0-9._:/-]*$"
                },
                "sourceVersion": {
                  "type": "string",
                  "minLength": 1,
                  "maxLength": 500
                },
                "kind": {
                  "type": "string",
                  "enum": [
                    "product",
                    "capacity",
                    "service"
                  ]
                },
                "title": {
                  "type": "string",
                  "minLength": 1,
                  "maxLength": 500
                },
                "manufacturer": {
                  "anyOf": [
                    {
                      "type": "string",
                      "minLength": 1,
                      "maxLength": 500
                    },
                    {
                      "type": "null"
                    }
                  ]
                },
                "manufacturerPartNumber": {
                  "anyOf": [
                    {
                      "type": "string",
                      "minLength": 1,
                      "maxLength": 500
                    },
                    {
                      "type": "null"
                    }
                  ]
                },
                "unit": {
                  "type": "string",
                  "minLength": 1,
                  "maxLength": 40
                },
                "condition": {
                  "type": "string",
                  "enum": [
                    "new",
                    "used",
                    "refurbished",
                    "unknown"
                  ]
                },
                "availability": {
                  "type": "object",
                  "properties": {
                    "quantity": {
                      "anyOf": [
                        {
                          "type": "string",
                          "pattern": "^(0|[1-9]\\d{0,11})(\\.\\d{1,8})?$"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "window": {
                      "anyOf": [
                        {
                          "type": "object",
                          "properties": {
                            "start": {
                              "type": "string",
                              "format": "date-time",
                              "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"
                            },
                            "end": {
                              "type": "string",
                              "format": "date-time",
                              "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"
                            }
                          },
                          "required": [
                            "start",
                            "end"
                          ],
                          "additionalProperties": false
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "location": {
                      "anyOf": [
                        {
                          "type": "string",
                          "minLength": 1,
                          "maxLength": 500
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "leadTimeDays": {
                      "anyOf": [
                        {
                          "type": "integer",
                          "minimum": 0,
                          "maximum": 3650
                        },
                        {
                          "type": "null"
                        }
                      ]
                    }
                  },
                  "required": [
                    "quantity",
                    "window",
                    "location",
                    "leadTimeDays"
                  ],
                  "additionalProperties": false
                },
                "pricing": {
                  "anyOf": [
                    {
                      "type": "object",
                      "properties": {
                        "currency": {
                          "type": "string",
                          "pattern": "^[A-Z]{3}$"
                        },
                        "country": {
                          "type": "string",
                          "pattern": "^[A-Z]{2}$"
                        },
                        "audience": {
                          "type": "string",
                          "const": "public"
                        },
                        "taxBasis": {
                          "type": "string",
                          "enum": [
                            "net",
                            "gross",
                            "unknown"
                          ]
                        },
                        "taxRate": {
                          "anyOf": [
                            {
                              "type": "string",
                              "pattern": "^(0|[1-9]\\d{0,11})(\\.\\d{1,8})?$"
                            },
                            {
                              "type": "null"
                            }
                          ]
                        },
                        "minimumOrderQuantity": {
                          "type": "string",
                          "pattern": "^(0|[1-9]\\d{0,11})(\\.\\d{1,8})?$"
                        },
                        "orderMultiple": {
                          "type": "string",
                          "pattern": "^(0|[1-9]\\d{0,11})(\\.\\d{1,8})?$"
                        },
                        "tiers": {
                          "minItems": 1,
                          "maxItems": 50,
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "minimumQuantity": {
                                "type": "string",
                                "pattern": "^(0|[1-9]\\d{0,11})(\\.\\d{1,8})?$"
                              },
                              "unitPrice": {
                                "type": "string",
                                "pattern": "^(0|[1-9]\\d{0,11})(\\.\\d{1,8})?$"
                              }
                            },
                            "required": [
                              "minimumQuantity",
                              "unitPrice"
                            ],
                            "additionalProperties": false
                          }
                        }
                      },
                      "required": [
                        "currency",
                        "country",
                        "audience",
                        "taxBasis",
                        "taxRate",
                        "minimumOrderQuantity",
                        "orderMultiple",
                        "tiers"
                      ],
                      "additionalProperties": false
                    },
                    {
                      "type": "null"
                    }
                  ]
                },
                "sourceUpdatedAt": {
                  "anyOf": [
                    {
                      "type": "string",
                      "format": "date-time",
                      "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"
                    },
                    {
                      "type": "null"
                    }
                  ]
                },
                "observedAt": {
                  "type": "string",
                  "format": "date-time",
                  "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"
                },
                "expiresAt": {
                  "type": "string",
                  "format": "date-time",
                  "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"
                },
                "status": {
                  "type": "string",
                  "enum": [
                    "active",
                    "withdrawn"
                  ]
                }
              },
              "required": [
                "sourceRecordId",
                "sourceVersion",
                "kind",
                "title",
                "manufacturer",
                "manufacturerPartNumber",
                "unit",
                "condition",
                "availability",
                "pricing",
                "sourceUpdatedAt",
                "observedAt",
                "expiresAt",
                "status"
              ],
              "additionalProperties": false
            }
          }
        },
        "required": [
          "schemaVersion",
          "source",
          "records"
        ],
        "additionalProperties": false
      }
    }
  }
}
