{
 "openapi": "3.1.0",
 "info": {
  "title": "Switchboard",
  "version": "0.1.0",
  "description": "A directory of humans who chose to be reachable by AI agents, and a crowd-sourced ethics feed. Read endpoints are public and CDN-cacheable."
 },
 "servers": [
  {
   "url": "https://a2h.help"
  }
 ],
 "paths": {
  "/v1/cards": {
   "get": {
    "operationId": "searchCards",
    "summary": "Search calling cards",
    "parameters": [
     {
      "name": "q",
      "in": "query",
      "schema": {
       "type": "string"
      }
     },
     {
      "name": "topic",
      "in": "query",
      "schema": {
       "type": "string"
      }
     },
     {
      "name": "consultants",
      "in": "query",
      "schema": {
       "type": "string",
       "enum": [
        "1",
        "true"
       ]
      }
     },
     {
      "name": "limit",
      "in": "query",
      "schema": {
       "type": "integer",
       "maximum": 100
      }
     },
     {
      "name": "offset",
      "in": "query",
      "schema": {
       "type": "integer"
      }
     }
    ],
    "responses": {
     "200": {
      "description": "OK",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "version": {
           "type": "integer"
          },
          "total": {
           "type": "integer"
          },
          "offset": {
           "type": "integer"
          },
          "limit": {
           "type": "integer"
          },
          "results": {
           "type": "array",
           "items": {
            "$ref": "#/components/schemas/Card"
           }
          }
         }
        }
       }
      }
     }
    }
   },
   "post": {
    "operationId": "submitCard",
    "summary": "Submit a new card (published after email verification)",
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/Submission"
       }
      }
     }
    },
    "responses": {
     "201": {
      "description": "Created",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "id": {
           "type": "string"
          },
          "manage_token": {
           "type": "string"
          },
          "status": {
           "type": "string"
          },
          "message": {
           "type": "string"
          }
         }
        }
       }
      }
     },
     "400": {
      "description": "Invalid",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "429": {
      "description": "Rate limited",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "503": {
      "description": "Email provider unavailable; nothing was saved, try again"
     }
    }
   }
  },
  "/v1/cards/{id}": {
   "get": {
    "operationId": "getCard",
    "parameters": [
     {
      "name": "id",
      "in": "path",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "200": {
      "description": "OK",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Card"
        }
       }
      }
     },
     "404": {
      "description": "Not found",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     }
    }
   },
   "put": {
    "operationId": "updateCard",
    "security": [
     {
      "manageToken": []
     }
    ],
    "parameters": [
     {
      "name": "id",
      "in": "path",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/Submission"
       }
      }
     }
    },
    "responses": {
     "200": {
      "description": "OK",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Card"
        }
       }
      }
     },
     "403": {
      "description": "Forbidden",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     }
    }
   },
   "delete": {
    "operationId": "deleteCard",
    "security": [
     {
      "manageToken": []
     }
    ],
    "parameters": [
     {
      "name": "id",
      "in": "path",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "204": {
      "description": "Deleted"
     }
    }
   }
  },
  "/v1/cards/{id}/owner": {
   "get": {
    "operationId": "getOwnedCard",
    "security": [
     {
      "manageToken": []
     }
    ],
    "parameters": [
     {
      "name": "id",
      "in": "path",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "200": {
      "description": "OK",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "card": {
           "$ref": "#/components/schemas/Card"
          },
          "verified": {
           "type": "boolean"
          }
         }
        }
       }
      }
     }
    }
   }
  },
  "/v1/cards/{id}/signals": {
   "post": {
    "operationId": "reportInteraction",
    "summary": "Report the outcome of contacting this human",
    "parameters": [
     {
      "name": "id",
      "in": "path",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "type": "object",
        "required": [
         "outcome"
        ],
        "properties": {
         "outcome": {
          "type": "string",
          "enum": [
           "helpful",
           "declined",
           "unresponsive",
           "report"
          ]
         }
        }
       }
      }
     }
    },
    "responses": {
     "202": {
      "description": "Recorded"
     }
    }
   }
  },
  "/v1/cards/{id}/conduct": {
   "post": {
    "operationId": "reportConduct",
    "summary": "(Card owners) report agent behaviour",
    "security": [
     {
      "manageToken": []
     }
    ],
    "parameters": [
     {
      "name": "id",
      "in": "path",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/ConductInput"
       }
      }
     }
    },
    "responses": {
     "201": {
      "description": "OK",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Conduct"
        }
       }
      }
     }
    }
   }
  },
  "/v1/verify": {
   "get": {
    "operationId": "verifyCard",
    "parameters": [
     {
      "name": "token",
      "in": "query",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "200": {
      "description": "HTML confirmation"
     }
    }
   }
  },
  "/v1/topics": {
   "get": {
    "operationId": "listTopics",
    "responses": {
     "200": {
      "description": "OK",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "version": {
           "type": "integer"
          },
          "topics": {
           "type": "array",
           "items": {
            "type": "object",
            "properties": {
             "topic": {
              "type": "string"
             },
             "cards": {
              "type": "integer"
             },
             "ethics_consultants": {
              "type": "integer"
             }
            }
           }
          }
         }
        }
       }
      }
     }
    }
   }
  },
  "/v1/consult/{topic}": {
   "get": {
    "operationId": "consultEthics",
    "summary": "Crowd-sourced ethical guidance for a topic",
    "parameters": [
     {
      "name": "topic",
      "in": "path",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "200": {
      "description": "OK",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Consultation"
        }
       }
      }
     }
    }
   }
  },
  "/v1/conduct": {
   "get": {
    "operationId": "listConduct",
    "parameters": [
     {
      "name": "topic",
      "in": "query",
      "schema": {
       "type": "string"
      }
     },
     {
      "name": "limit",
      "in": "query",
      "schema": {
       "type": "integer"
      }
     }
    ],
    "responses": {
     "200": {
      "description": "OK",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "reports": {
           "type": "array",
           "items": {
            "$ref": "#/components/schemas/Conduct"
           }
          }
         }
        }
       }
      }
     }
    }
   }
  },
  "/v1/protocols": {
   "get": {
    "operationId": "listProtocols",
    "responses": {
     "200": {
      "description": "Protocols this deployment speaks"
     }
    }
   }
  },
  "/v1/cards/{id}/resend-verification": {
   "post": {
    "operationId": "resendVerification",
    "summary": "(Card owners) email a fresh confirmation link; earlier links stop working",
    "security": [
     {
      "manageToken": []
     }
    ],
    "parameters": [
     {
      "name": "id",
      "in": "path",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "202": {
      "description": "Sent"
     },
     "403": {
      "description": "Wrong manage token"
     },
     "409": {
      "description": "Card already confirmed"
     },
     "429": {
      "description": "Rate limited"
     },
     "503": {
      "description": "Email provider unavailable; try again"
     }
    }
   }
  }
 },
 "components": {
  "securitySchemes": {
   "manageToken": {
    "type": "http",
    "scheme": "bearer",
    "description": "The manage token returned when the card was created."
   }
  },
  "schemas": {
   "Contact": {
    "type": "object",
    "required": [
     "kind",
     "value"
    ],
    "properties": {
     "kind": {
      "type": "string",
      "enum": [
       "email",
       "url",
       "phone",
       "sms",
       "matrix",
       "signal",
       "telegram",
       "webhook",
       "mcp",
       "a2a",
       "other"
      ]
     },
     "value": {
      "type": "string"
     },
     "label": {
      "type": "string"
     },
     "preferred": {
      "type": "boolean"
     }
    }
   },
   "UseCase": {
    "type": "object",
    "required": [
     "topic",
     "description"
    ],
    "properties": {
     "topic": {
      "type": "string"
     },
     "description": {
      "type": "string"
     }
    }
   },
   "Etiquette": {
    "type": "object",
    "properties": {
     "hours": {
      "type": "string"
     },
     "timezone": {
      "type": "string"
     },
     "languages": {
      "type": "array",
      "items": {
       "type": "string"
      }
     },
     "max_contacts_per_day": {
      "type": "integer"
     },
     "response_time": {
      "type": "string"
     },
     "notes": {
      "type": "string"
     }
    }
   },
   "Card": {
    "type": "object",
    "properties": {
     "id": {
      "type": "string"
     },
     "name": {
      "type": "string"
     },
     "bio": {
      "type": "string"
     },
     "contacts": {
      "type": "array",
      "items": {
       "$ref": "#/components/schemas/Contact"
      }
     },
     "use_cases": {
      "type": "array",
      "items": {
       "$ref": "#/components/schemas/UseCase"
      }
     },
     "principles": {
      "type": "array",
      "items": {
       "type": "string"
      }
     },
     "boundaries": {
      "type": "array",
      "items": {
       "type": "string"
      }
     },
     "ethics_consultant": {
      "type": "boolean"
     },
     "etiquette": {
      "$ref": "#/components/schemas/Etiquette"
     },
     "created_at": {
      "type": "string",
      "format": "date-time"
     },
     "updated_at": {
      "type": "string",
      "format": "date-time"
     },
     "status": {
      "type": "string",
      "enum": [
       "active",
       "under_review"
      ]
     },
     "signals": {
      "type": "object",
      "properties": {
       "helpful": {
        "type": "integer"
       },
       "declined": {
        "type": "integer"
       },
       "unresponsive": {
        "type": "integer"
       },
       "reports": {
        "type": "integer"
       }
      }
     },
     "trust": {
      "type": "number",
      "minimum": 0,
      "maximum": 1
     },
     "agent_protocol": {
      "type": "array",
      "items": {
       "type": "string"
      }
     }
    }
   },
   "Submission": {
    "type": "object",
    "required": [
     "name",
     "contacts",
     "use_cases"
    ],
    "properties": {
     "name": {
      "type": "string"
     },
     "bio": {
      "type": "string"
     },
     "contacts": {
      "type": "array",
      "items": {
       "$ref": "#/components/schemas/Contact"
      }
     },
     "use_cases": {
      "type": "array",
      "items": {
       "$ref": "#/components/schemas/UseCase"
      }
     },
     "principles": {
      "type": "array",
      "items": {
       "type": "string"
      }
     },
     "boundaries": {
      "type": "array",
      "items": {
       "type": "string"
      }
     },
     "ethics_consultant": {
      "type": "boolean"
     },
     "etiquette": {
      "$ref": "#/components/schemas/Etiquette"
     },
     "owner_email": {
      "type": "string",
      "format": "email",
      "description": "Private. Required on create; ignored on update."
     }
    }
   },
   "ConductInput": {
    "type": "object",
    "required": [
     "topic",
     "behavior",
     "severity"
    ],
    "properties": {
     "topic": {
      "type": "string"
     },
     "behavior": {
      "type": "string"
     },
     "guidance": {
      "type": "string"
     },
     "severity": {
      "type": "string",
      "enum": [
       "low",
       "medium",
       "high"
      ]
     }
    }
   },
   "Conduct": {
    "type": "object",
    "properties": {
     "id": {
      "type": "string"
     },
     "topic": {
      "type": "string"
     },
     "behavior": {
      "type": "string"
     },
     "guidance": {
      "type": "string"
     },
     "severity": {
      "type": "string"
     },
     "at": {
      "type": "string",
      "format": "date-time"
     }
    }
   },
   "Consultation": {
    "type": "object",
    "properties": {
     "topic": {
      "type": "string"
     },
     "note": {
      "type": "string"
     },
     "cards_on_topic": {
      "type": "integer"
     },
     "principles": {
      "type": "array"
     },
     "boundaries": {
      "type": "array"
     },
     "conduct_reports": {
      "type": "array",
      "items": {
       "$ref": "#/components/schemas/Conduct"
      }
     },
     "consultants": {
      "type": "array"
     },
     "agent_protocol": {
      "type": "array",
      "items": {
       "type": "string"
      }
     }
    }
   },
   "Error": {
    "type": "object",
    "properties": {
     "error": {
      "type": "object",
      "properties": {
       "status": {
        "type": "integer"
       },
       "message": {
        "type": "string"
       }
      }
     }
    }
   }
  }
 }
}