{
 "openapi": "3.1.0",
 "info": {
  "title": "Felt Intelligence API",
  "version": "1.0.0",
  "description": "Reads a person only with her consent, only for the speaker she allowed. Never for hiring, pricing, credit, segmentation, ad audiences or retention scoring. Aggregates only at 10 or more opted-in people. Nothing raw from the sky is ever returned. Every read carries a confidence (clock alone is capped at 0.35; never 1) and the line: the clock suggested; her word decided."
 },
 "servers": [
  {
   "url": "https://enter.satya.org/api/fi/v1"
  }
 ],
 "components": {
  "securitySchemes": {
   "app": {
    "type": "http",
    "scheme": "bearer",
    "description": "Your speaker key"
   },
   "consent": {
    "type": "apiKey",
    "in": "header",
    "name": "X-Consent",
    "description": "The person's consent token for your speaker"
   }
  },
  "schemas": {
   "Ask": {
    "type": "object",
    "properties": {
     "question": {
      "type": "string",
      "example": "Right now \u2014 closer to frustrated, or to unsettled?"
     },
     "words": {
      "type": "array",
      "items": {
       "type": "string"
      }
     },
     "follow": {
      "type": "string",
      "example": "heavy, driven, or clear?"
     },
     "basis": {
      "type": "string",
      "enum": [
       "her_last_word",
       "clock"
      ]
     },
     "confidence": {
      "type": "number"
     }
    }
   },
   "Tap": {
    "type": "object",
    "required": [
     "person_id",
     "word"
    ],
    "properties": {
     "person_id": {
      "type": "string",
      "format": "uuid"
     },
     "word": {
      "type": "string"
     },
     "quality": {
      "type": "string",
      "enum": [
       "heavy",
       "driven",
       "clear"
      ]
     },
     "source": {
      "type": "string",
      "enum": [
       "tap",
       "voice"
      ]
     }
    }
   },
   "Read": {
    "type": "object",
    "properties": {
     "state": {
      "type": "object",
      "properties": {
       "word": {
        "type": "string"
       },
       "quality": {
        "type": "string",
        "nullable": true
       },
       "rung_delta": {
        "type": "integer"
       }
      }
     },
     "confidence": {
      "type": "number",
      "maximum": 0.95
     },
     "sources": {
      "type": "array",
      "items": {
       "type": "string",
       "enum": [
        "her_word",
        "speech_shape",
        "clock"
       ]
      }
     },
     "hold": {
      "type": "object",
      "nullable": true,
      "properties": {
       "gap": {
        "type": "integer",
        "description": "her word minus the clock's pressure; positive = she stands above it"
       },
       "since": {
        "type": "string"
       }
      }
     },
     "trusted": {
      "type": "boolean",
      "description": "true only when her own mirror beats her shuffled birth by 15 points over 25 taps"
     },
     "line": {
      "type": "string"
     },
     "as_of": {
      "type": "string"
     }
    }
   },
   "Window": {
    "type": "object",
    "properties": {
     "from": {
      "type": "string"
     },
     "to": {
      "type": "string"
     },
     "direction": {
      "type": "string",
      "enum": [
       "pressure_in",
       "opening",
       "turn"
      ]
     },
     "area": {
      "type": "string",
      "enum": [
       "self",
       "bonds",
       "work",
       "body",
       "money"
      ]
     },
     "strength": {
      "type": "integer",
      "minimum": 1,
      "maximum": 3
     },
     "source_level": {
      "type": "integer"
     },
     "spoken_allowed": {
      "type": "boolean"
     }
    }
   },
   "Tempo": {
    "type": "object",
    "properties": {
     "max_words": {
      "type": "integer"
     },
     "pause_before_reply_s": {
      "type": "integer"
     },
     "style": {
      "type": "string",
      "enum": [
       "clipped",
       "long",
       "flooding",
       "steady"
      ]
     },
     "pull": {
      "type": "string",
      "enum": [
       "self",
       "other"
      ]
     },
     "last_turn": {
      "type": "object"
     }
    }
   },
   "Pulse": {
    "type": "object",
    "properties": {
     "opted_in": {
      "type": "integer"
     },
     "tapped_this_week": {
      "type": "number"
     },
     "heavy": {
      "type": "number",
      "nullable": true
     },
     "driven": {
      "type": "number",
      "nullable": true
     },
     "clear": {
      "type": "number",
      "nullable": true
     }
    }
   }
  }
 },
 "security": [
  {
   "app": []
  }
 ],
 "paths": {
  "/ask": {
   "post": {
    "summary": "The two-word state question for this person, and the quality follow-up",
    "security": [
     {
      "app": [],
      "consent": []
     }
    ],
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "type": "object",
        "required": [
         "person_id"
        ],
        "properties": {
         "person_id": {
          "type": "string"
         },
         "moment": {
          "type": "string",
          "enum": [
           "open",
           "return",
           "night"
          ]
         }
        }
       }
      }
     }
    },
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Ask"
        }
       }
      }
     }
    }
   }
  },
  "/tap": {
   "post": {
    "summary": "Her answer becomes her row \u2014 ground truth",
    "security": [
     {
      "app": [],
      "consent": []
     }
    ],
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/Tap"
       }
      }
     }
    },
    "responses": {
     "200": {
      "description": "row_id, delta_from_last, hold"
     },
     "409": {
      "description": "unknown_word \u2014 kept for the lexicon"
     }
    }
   }
  },
  "/read": {
   "get": {
    "summary": "Her state now, with confidence and sources",
    "security": [
     {
      "app": [],
      "consent": []
     }
    ],
    "parameters": [
     {
      "name": "person_id",
      "in": "query",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Read"
        }
       }
      }
     },
     "409": {
      "description": "unknown \u2014 no word from her in 72 h; ask instead"
     }
    }
   }
  },
  "/window": {
   "get": {
    "summary": "Pressure windows ahead \u2014 direction only",
    "security": [
     {
      "app": [],
      "consent": []
     }
    ],
    "parameters": [
     {
      "name": "person_id",
      "in": "query",
      "required": true,
      "schema": {
       "type": "string"
      }
     },
     {
      "name": "days",
      "in": "query",
      "schema": {
       "type": "integer",
       "default": 7,
       "maximum": 14
      }
     }
    ],
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "windows": {
           "type": "array",
           "items": {
            "$ref": "#/components/schemas/Window"
           }
          }
         }
        }
       }
      }
     }
    }
   }
  },
  "/tempo": {
   "get": {
    "summary": "How to speak to her now",
    "security": [
     {
      "app": [],
      "consent": []
     }
    ],
    "parameters": [
     {
      "name": "person_id",
      "in": "query",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Tempo"
        }
       }
      }
     },
     "404": {
      "description": "no_turns yet"
     }
    }
   }
  },
  "/mission": {
   "get": {
    "summary": "The founder's vow and whether it held",
    "parameters": [
     {
      "name": "org_id",
      "in": "query",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "200": {
      "description": "vow, set_on, checked[], held_rate"
     }
    }
   },
   "post": {
    "summary": "Set the vow, or record a monthly check",
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "type": "object",
        "required": [
         "org_id"
        ],
        "properties": {
         "org_id": {
          "type": "string"
         },
         "vow": {
          "type": "string"
         },
         "check": {
          "type": "string",
          "enum": [
           "held",
           "mostly",
           "not"
          ]
         }
        }
       }
      }
     }
    },
    "responses": {
     "200": {
      "description": "ok"
     }
    }
   }
  },
  "/pulse": {
   "get": {
    "summary": "One aggregate for the room \u2014 never a person",
    "parameters": [
     {
      "name": "org_id",
      "in": "query",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Pulse"
        }
       }
      }
     },
     "403": {
      "description": "too_few \u2014 under 10 opted-in people"
     }
    }
   }
  },
  "/webhook": {
   "post": {
    "summary": "Be told before her next pressure window",
    "security": [
     {
      "app": [],
      "consent": []
     }
    ],
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "type": "object",
        "required": [
         "person_id",
         "url"
        ],
        "properties": {
         "person_id": {
          "type": "string"
         },
         "minutes": {
          "type": "integer",
          "default": 30,
          "maximum": 180
         },
         "url": {
          "type": "string",
          "format": "uri"
         }
        }
       }
      }
     }
    },
    "responses": {
     "200": {
      "description": "ok \u2014 POST {event: turn_ahead, person_id, at, in_minutes, direction, area, strength}"
     }
    }
   }
  },
  "/api/fi/v1/webhook": {
   "delete": {
    "summary": "Remove this speaker's turn-ahead webhook for a person",
    "parameters": [
     {
      "name": "person_id",
      "in": "query",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "200": {
      "description": "{ok:true}"
     }
    }
   }
  }
 }
}