{
  "openapi": "3.1.0",
  "info": {
    "title": "Onebubbles API",
    "version": "1.0.0",
    "description": "REST API to read your CRM and conversations, inject messages from any source, pull metrics, and draft AI replies from your knowledge base. Get your API key in Onebubbles → Contacts → Connect your app."
  },
  "servers": [
    {
      "url": "https://onebubbles.com/api/v1"
    }
  ],
  "security": [
    {
      "bearerAuth": []
    }
  ],
  "components": {
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "description": "Your workspace API key (od_sk_...)."
      }
    },
    "schemas": {
      "Contact": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "name": {
            "type": [
              "string",
              "null"
            ]
          },
          "email": {
            "type": [
              "string",
              "null"
            ]
          },
          "phone": {
            "type": [
              "string",
              "null"
            ]
          },
          "tags": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "lifecycleStage": {
            "type": "string",
            "enum": [
              "lead",
              "active",
              "customer",
              "churned"
            ]
          },
          "company": {
            "type": [
              "string",
              "null"
            ]
          },
          "blocked": {
            "type": "boolean"
          },
          "createdAt": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "lastSeenAt": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          }
        }
      },
      "Conversation": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "status": {
            "type": "string",
            "enum": [
              "open",
              "pending",
              "closed",
              "snoozed"
            ]
          },
          "channel": {
            "type": "string"
          },
          "subject": {
            "type": [
              "string",
              "null"
            ]
          },
          "lastMessagePreview": {
            "type": [
              "string",
              "null"
            ]
          },
          "rating": {
            "type": [
              "integer",
              "null"
            ]
          },
          "tags": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "lastMessageAt": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "contact": {
            "$ref": "#/components/schemas/Contact"
          },
          "priority": {
            "type": "string",
            "enum": [
              "high",
              "normal"
            ]
          },
          "language": {
            "type": [
              "string",
              "null"
            ]
          }
        }
      },
      "Error": {
        "type": "object",
        "properties": {
          "error": {
            "type": "string"
          }
        }
      }
    }
  },
  "paths": {
    "/contacts": {
      "get": {
        "summary": "List contacts",
        "operationId": "listContacts",
        "parameters": [
          {
            "name": "email",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "tag",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "lifecycle",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "lead",
                "active",
                "customer",
                "churned"
              ]
            }
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 200,
              "default": 50
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "contacts": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Contact"
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "post": {
        "summary": "Create or update a contact",
        "operationId": "upsertContact",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "email"
                ],
                "properties": {
                  "email": {
                    "type": "string"
                  },
                  "name": {
                    "type": "string"
                  },
                  "phone": {
                    "type": "string"
                  },
                  "tags": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean"
                    },
                    "contactId": {
                      "type": "string"
                    },
                    "created": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "email is required",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/messages": {
      "post": {
        "summary": "Send an inbound message (api channel)",
        "operationId": "sendMessage",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "message"
                ],
                "properties": {
                  "message": {
                    "type": "string"
                  },
                  "externalId": {
                    "type": "string",
                    "description": "A stable per-user id (required unless email is given)."
                  },
                  "email": {
                    "type": "string"
                  },
                  "name": {
                    "type": "string"
                  },
                  "phone": {
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean"
                    },
                    "conversationId": {
                      "type": "string"
                    },
                    "contactId": {
                      "type": "string"
                    },
                    "messageId": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/conversations": {
      "get": {
        "summary": "List conversations, or one with its transcript",
        "operationId": "listConversations",
        "parameters": [
          {
            "name": "conversationId",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Return a single conversation with its full message transcript."
          },
          {
            "name": "email",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "contactId",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "status",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "open",
                "pending",
                "closed"
              ]
            }
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 20
            }
          },
          {
            "name": "priority",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "high",
                "normal"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "conversations": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Conversation"
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/stats": {
      "get": {
        "summary": "Workspace metrics",
        "operationId": "getStats",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "conversations": {
                      "type": "object",
                      "properties": {
                        "total": {
                          "type": "integer"
                        },
                        "open": {
                          "type": "integer"
                        },
                        "pending": {
                          "type": "integer"
                        },
                        "closed": {
                          "type": "integer"
                        },
                        "snoozed": {
                          "type": "integer"
                        },
                        "last30d": {
                          "type": "integer"
                        },
                        "urgent": {
                          "type": "integer"
                        }
                      }
                    },
                    "contacts": {
                      "type": "object",
                      "properties": {
                        "total": {
                          "type": "integer"
                        }
                      }
                    },
                    "csat": {
                      "type": "object",
                      "properties": {
                        "average": {
                          "type": [
                            "number",
                            "null"
                          ]
                        },
                        "responseRate": {
                          "type": [
                            "integer",
                            "null"
                          ]
                        },
                        "count": {
                          "type": "integer"
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/ai/reply": {
      "post": {
        "summary": "Draft an AI reply from the knowledge base",
        "operationId": "aiReply",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "message"
                ],
                "properties": {
                  "message": {
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "reply": {
                      "type": "string"
                    },
                    "escalate": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "402": {
            "description": "Out of AI credits",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    }
  }
}
