{
  "openapi": "3.1.0",
  "info": {
    "title": "AbuseGraph API",
    "version": "1.0.0",
    "summary": "Signup risk scoring and exposure monitoring",
    "description": "AbuseGraph helps you stop fake signups while keeping good users.\n\n## Bases\n- **Console API** — `https://abusegraph.com` (secret key, server-side)\n- **Edge API** — `https://api.abusegraph.com` (publishable key, browser SDK)\n\n## Auth\n- Secret keys (`sk_live_…` / `sk_test_…`) → `x-api-key` on `/api/v1/*`\n- Publishable keys (`pk_live_…` / `pk_test_…`) → browser SDK / evaluate\n- Never put secret keys in frontend code or public repos\n\n## Errors (RFC 9457)\nError responses use `application/problem+json` with `type`, `title`,\n`status`, optional `detail` / `instance`, plus a legacy `error` code\nfor older clients. Correlate with `X-Request-Id`.\n\n## Rate limits\nResponses include `X-RateLimit-Limit`, `X-RateLimit-Remaining`,\n`X-RateLimit-Reset`, and `Retry-After` on `429`.\n\n## Integration guides\nStep-by-step auth stack guides: [abusegraph.com/guides](https://abusegraph.com/guides).",
    "contact": {
      "name": "AbuseGraph",
      "url": "https://abusegraph.com",
      "email": "hello@abusegraph.com"
    },
    "license": {
      "name": "Proprietary",
      "url": "https://abusegraph.com/terms"
    }
  },
  "servers": [
    {
      "url": "https://abusegraph.com",
      "description": "Console API (secret key)"
    },
    {
      "url": "https://api.abusegraph.com",
      "description": "Edge API (browser SDK / evaluate)"
    }
  ],
  "tags": [
    {
      "name": "Risk Check",
      "description": "Server-side risk scoring with your secret API key."
    },
    {
      "name": "Monitor",
      "description": "Enroll identities for breach / stealer monitoring."
    },
    {
      "name": "Browser Evaluate",
      "description": "Preliminary browser evaluation used by the AbuseGraph SDK."
    }
  ],
  "components": {
    "securitySchemes": {
      "SecretApiKey": {
        "type": "apiKey",
        "in": "header",
        "name": "x-api-key",
        "description": "Workspace secret key (`sk_live_…` or `sk_test_…`). Create keys in the console — never commit real values."
      },
      "BearerSecretKey": {
        "type": "http",
        "scheme": "bearer",
        "description": "Same secret key as `x-api-key`, accepted on Monitor as `Authorization: Bearer sk_…`."
      },
      "PublishableApiKey": {
        "type": "apiKey",
        "in": "header",
        "name": "x-api-key",
        "description": "Publishable key (`pk_live_…` / `pk_test_…`). Safe in the browser; alternatively pass `publicKey` in the JSON body."
      }
    },
    "parameters": {
      "RequestId": {
        "name": "X-Request-Id",
        "in": "header",
        "required": false,
        "schema": {
          "type": "string",
          "minLength": 8,
          "maxLength": 128
        },
        "description": "Optional client correlation id. Echoed on the response; minted when omitted."
      },
      "SiteHeader": {
        "name": "x-abusegraph-site",
        "in": "header",
        "required": false,
        "schema": {
          "type": "string",
          "example": "app.example.com"
        },
        "description": "Licensed site hostname for live secret-key checks (also accepts `x-palisade-site`)."
      }
    },
    "schemas": {
      "Problem": {
        "type": "object",
        "required": [
          "type",
          "title",
          "status",
          "error"
        ],
        "properties": {
          "type": {
            "type": "string",
            "format": "uri",
            "example": "https://abusegraph.com/problems/invalid-api-key"
          },
          "title": {
            "type": "string",
            "example": "Unauthorized"
          },
          "status": {
            "type": "integer",
            "example": 401
          },
          "detail": {
            "type": "string"
          },
          "instance": {
            "type": "string",
            "example": "/api/v1/check"
          },
          "error": {
            "type": "string",
            "description": "Legacy machine-readable code (snake_case).",
            "example": "invalid_api_key"
          },
          "requestId": {
            "type": "string"
          },
          "retryAfterSec": {
            "type": "integer"
          },
          "limit": {
            "type": "integer"
          },
          "remaining": {
            "type": "integer"
          },
          "issues": {
            "type": "object",
            "additionalProperties": true
          }
        }
      },
      "Verdict": {
        "type": "string",
        "enum": [
          "allow",
          "challenge",
          "shadow",
          "block"
        ]
      },
      "RiskReason": {
        "type": "object",
        "required": [
          "type"
        ],
        "properties": {
          "type": {
            "type": "string",
            "example": "disposable_email",
            "description": "Consumer-safe reason code (no weights or provider detail)."
          }
        }
      },
      "CheckRequest": {
        "type": "object",
        "properties": {
          "email": {
            "type": "string",
            "format": "email"
          },
          "userId": {
            "type": "string",
            "maxLength": 256
          },
          "ip": {
            "type": "string",
            "example": "203.0.113.10"
          },
          "fingerprint": {
            "type": "string"
          },
          "userAgent": {
            "type": "string"
          },
          "event": {
            "type": "string",
            "enum": [
              "signup",
              "login"
            ]
          },
          "country": {
            "type": "string"
          },
          "city": {
            "type": "string"
          },
          "region": {
            "type": "string"
          },
          "asn": {
            "type": "integer"
          },
          "asOrganization": {
            "type": "string"
          },
          "site": {
            "type": "string",
            "description": "Licensed site hostname (alternative to header)."
          }
        },
        "additionalProperties": true
      },
      "CheckResponse": {
        "type": "object",
        "required": [
          "score",
          "verdict",
          "riskSignals"
        ],
        "properties": {
          "score": {
            "type": "integer",
            "minimum": 0,
            "maximum": 100
          },
          "verdict": {
            "$ref": "#/components/schemas/Verdict"
          },
          "riskSignals": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/RiskReason"
            }
          },
          "unusual": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "summary": {
            "type": "string"
          },
          "event": {
            "type": "string",
            "enum": [
              "signup",
              "login"
            ]
          }
        },
        "additionalProperties": true
      },
      "MonitorListResponse": {
        "type": "object",
        "properties": {
          "monitorEnabled": {
            "type": "boolean"
          },
          "monitorStealer": {
            "type": "boolean"
          },
          "lastRunAt": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "identities": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "id": {
                  "type": "string",
                  "format": "uuid"
                },
                "emailMasked": {
                  "type": "string",
                  "example": "j***@example.com"
                },
                "emailDomain": {
                  "type": "string"
                },
                "userId": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "status": {
                  "type": "string",
                  "enum": [
                    "active",
                    "paused",
                    "removed"
                  ]
                },
                "enrolledAt": {
                  "type": "string",
                  "format": "date-time"
                },
                "breachHits": {
                  "type": "integer"
                },
                "credentialLogHits": {
                  "type": "integer"
                }
              }
            }
          }
        }
      },
      "MonitorEnrollRequest": {
        "type": "object",
        "properties": {
          "email": {
            "type": "string",
            "format": "email"
          },
          "userId": {
            "type": "string",
            "maxLength": 256
          },
          "emails": {
            "type": "array",
            "maxItems": 50,
            "items": {
              "type": "object",
              "required": [
                "email"
              ],
              "properties": {
                "email": {
                  "type": "string",
                  "format": "email"
                },
                "userId": {
                  "type": "string",
                  "maxLength": 256
                }
              }
            }
          }
        }
      },
      "EvaluateRequest": {
        "type": "object",
        "required": [
          "fingerprint",
          "behavioral",
          "probes",
          "turnstileToken"
        ],
        "properties": {
          "publicKey": {
            "type": "string",
            "description": "Publishable key if not sent via x-api-key."
          },
          "fingerprint": {
            "type": "string",
            "minLength": 8,
            "maxLength": 256
          },
          "fingerprintBase": {
            "type": "string"
          },
          "turnstileToken": {
            "type": "string"
          },
          "userAgent": {
            "type": "string"
          },
          "email": {
            "type": "string",
            "format": "email"
          },
          "userId": {
            "type": "string"
          },
          "behavioral": {
            "type": "object",
            "additionalProperties": true
          },
          "probes": {
            "type": "object",
            "additionalProperties": true
          },
          "tlsFingerprint": {
            "type": "object",
            "required": [
              "ja3",
              "ja4"
            ],
            "properties": {
              "ja3": {
                "type": "string"
              },
              "ja4": {
                "type": "string"
              },
              "ja3String": {
                "type": "string"
              },
              "tlsVersion": {
                "type": "string"
              },
              "clientTlsVersion": {
                "type": "string"
              },
              "alpn": {
                "type": "string"
              },
              "cipherSuite": {
                "type": "string"
              },
              "sni": {
                "type": "string"
              },
              "hasSni": {
                "type": "boolean"
              },
              "clientAlpn": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              },
              "supportedGroupsN": {
                "type": "integer"
              },
              "cipherSuitesN": {
                "type": "integer"
              },
              "extensionsN": {
                "type": "integer"
              }
            }
          },
          "extensionSet": {
            "type": "object",
            "additionalProperties": true
          },
          "attribution": {
            "type": "object",
            "additionalProperties": true
          }
        }
      },
      "EvaluateResponse": {
        "type": "object",
        "required": [
          "verdictToken",
          "score",
          "verdict",
          "riskSignals"
        ],
        "properties": {
          "verdictToken": {
            "type": "object",
            "properties": {
              "token": {
                "type": "string"
              },
              "expiresAt": {
                "type": "string",
                "format": "date-time"
              }
            }
          },
          "score": {
            "type": "integer",
            "minimum": 0,
            "maximum": 100
          },
          "verdict": {
            "$ref": "#/components/schemas/Verdict"
          },
          "riskSignals": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/RiskReason"
            }
          },
          "detection": {
            "type": "object",
            "additionalProperties": true
          }
        }
      }
    },
    "responses": {
      "Problem": {
        "description": "RFC 9457 Problem Details",
        "headers": {
          "X-Request-Id": {
            "schema": {
              "type": "string"
            },
            "description": "Request correlation id"
          },
          "Retry-After": {
            "schema": {
              "type": "integer"
            },
            "description": "Seconds to wait (on 429)"
          },
          "X-RateLimit-Limit": {
            "schema": {
              "type": "integer"
            }
          },
          "X-RateLimit-Remaining": {
            "schema": {
              "type": "integer"
            }
          },
          "X-RateLimit-Reset": {
            "schema": {
              "type": "integer"
            },
            "description": "Unix timestamp (seconds) when the window resets"
          }
        },
        "content": {
          "application/problem+json": {
            "schema": {
              "$ref": "#/components/schemas/Problem"
            }
          }
        }
      }
    }
  },
  "paths": {
    "/api/v1/check": {
      "servers": [
        {
          "url": "https://abusegraph.com"
        }
      ],
      "post": {
        "tags": [
          "Risk Check"
        ],
        "operationId": "createRiskCheck",
        "summary": "Score a signup or login",
        "description": "Server-only risk check. Requires a **secret** API key. Prefer the official SDKs for browser probe payloads.",
        "security": [
          {
            "SecretApiKey": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/RequestId"
          },
          {
            "$ref": "#/components/parameters/SiteHeader"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CheckRequest"
              },
              "example": {
                "email": "user@example.com",
                "ip": "203.0.113.10",
                "event": "signup"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Risk decision",
            "headers": {
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CheckResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Problem"
          },
          "401": {
            "$ref": "#/components/responses/Problem"
          },
          "402": {
            "$ref": "#/components/responses/Problem"
          },
          "403": {
            "$ref": "#/components/responses/Problem"
          },
          "429": {
            "$ref": "#/components/responses/Problem"
          }
        }
      }
    },
    "/api/v1/monitor": {
      "servers": [
        {
          "url": "https://abusegraph.com"
        }
      ],
      "get": {
        "tags": [
          "Monitor"
        ],
        "operationId": "listMonitoredIdentities",
        "summary": "List monitored identities",
        "description": "Returns masked identities enrolled for daily watching.",
        "security": [
          {
            "SecretApiKey": []
          },
          {
            "BearerSecretKey": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/RequestId"
          }
        ],
        "responses": {
          "200": {
            "description": "Monitor settings + identities",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MonitorListResponse"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Problem"
          },
          "429": {
            "$ref": "#/components/responses/Problem"
          }
        }
      },
      "post": {
        "tags": [
          "Monitor"
        ],
        "operationId": "enrollMonitoredIdentities",
        "summary": "Enroll identities for monitoring",
        "description": "Requires a **live** secret key (`sk_live_…`).",
        "security": [
          {
            "SecretApiKey": []
          },
          {
            "BearerSecretKey": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/RequestId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/MonitorEnrollRequest"
              },
              "example": {
                "email": "user@example.com"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Enrollment results",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean"
                    },
                    "results": {
                      "type": "array",
                      "items": {
                        "type": "object"
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Problem"
          },
          "401": {
            "$ref": "#/components/responses/Problem"
          },
          "402": {
            "$ref": "#/components/responses/Problem"
          },
          "403": {
            "$ref": "#/components/responses/Problem"
          },
          "429": {
            "$ref": "#/components/responses/Problem"
          }
        }
      },
      "patch": {
        "tags": [
          "Monitor"
        ],
        "operationId": "updateMonitoredIdentity",
        "summary": "Update monitored identity status",
        "security": [
          {
            "SecretApiKey": []
          },
          {
            "BearerSecretKey": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/RequestId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "id",
                  "status"
                ],
                "properties": {
                  "id": {
                    "type": "string",
                    "format": "uuid"
                  },
                  "status": {
                    "type": "string",
                    "enum": [
                      "active",
                      "paused",
                      "removed"
                    ]
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Updated",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Problem"
          },
          "401": {
            "$ref": "#/components/responses/Problem"
          }
        }
      }
    },
    "/v1/risk/evaluate": {
      "servers": [
        {
          "url": "https://api.abusegraph.com"
        }
      ],
      "post": {
        "tags": [
          "Browser Evaluate"
        ],
        "operationId": "evaluateBrowserRisk",
        "summary": "Preliminary browser evaluation",
        "description": "Called by the AbuseGraph browser SDK with a publishable key. Returns a short-lived verdict token + preliminary score. Do not call this with secret keys. Prefer the hosted SDK: `https://abusegraph.com/sdk/palisade.min.js`.",
        "security": [
          {
            "PublishableApiKey": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/RequestId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/EvaluateRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Preliminary verdict",
            "headers": {
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EvaluateResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Problem"
          },
          "403": {
            "$ref": "#/components/responses/Problem"
          },
          "429": {
            "$ref": "#/components/responses/Problem"
          },
          "503": {
            "$ref": "#/components/responses/Problem"
          }
        }
      }
    }
  }
}