diff --git a/courses.schema.json b/courses.schema.json
new file mode 100644
index 0000000..bb44c7c
--- /dev/null
+++ b/courses.schema.json
@@ -0,0 +1,94 @@
+{
+    "$schema": "https://json-schema.org/draft/2019-09/schema",
+    "$id": "./courses.schema.json",
+    "title": "Pingers",
+    "description": "The data store for the pinger definitions for the bot",
+    "type": "object",
+    "definitions": {
+        "commonProps": {
+            "type": "object",
+            "properties": {
+                "subj": { "type": "string" },
+                "crsno": { "type": "string" },
+                "metadata": {
+                    "type": "object",
+                    "properties": {
+                        "user": {
+                            "type": "object",
+                            "patternProperties": {
+                                "^\\d+$": {
+                                    "$comment": "key is user ID, value is sections to ping for",
+                                    "type": "object",
+                                    "patternProperties": {
+                                        "^\\w{4} \\d{3}[A-Z]? \\w{3}$": {
+                                            "$comment": "key is section ID, value is status types to ping for",
+                                            "type": "array",
+                                            "items": {
+                                                "type": "string",
+                                                "enum": ["Available", "Restricted", "Blocked", "Full"]
+                                            }
+                                        }
+                                    },
+                                    "additionalProperties": false
+                                },
+                                "additionalProperties": false
+                            }
+                        },
+                        "courses": {
+                            "type": "array",
+                            "items": {
+                                "type": "string",
+                                "$comment": "same pattern as section ID in metadata.user",
+                                "pattern": "^\\w{4} \\d{3}[A-Z]? \\w{3}$"
+                            }
+                            
+                        }
+                    }
+                },
+                "sessyr": { "type": "string", "pattern": "^\\d{4}$" },
+                "sesscd": { "type": "string", "pattern": "^[WS]$" }
+            },
+            "$comment": "technically sessyr and sesscd is not required, but in practice it will get populated during add_ping",
+            "required": [ "subj", "crsno", "metadata" ]
+        },
+        "searchModeProps": {
+            "allOf": [ { "$ref": "#/definitions/commonProps" } ],
+            "type": "object",
+            "$comment": "all of the properties are technically optional, but in practice it is always populated; days are separate keys each, but technically should all be true or else it wouldn't be defined even though false is also accepted",
+            "properties": {
+                "credit": { "type": "string" },
+                "sTime": { "type": "string" },
+                "eTime": { "type": "string" },
+                "actv": { "type": "string" },
+                "term": { "type": "string" }
+            },
+            "patternProperties": {
+                "^DAY[1-7]$": { "type": "boolean" }
+            },
+            "not": { "required": ["section"] }
+        },
+        "sectionModeProps": {
+            "allOf": [ { "$ref": "#/definitions/commonProps" } ],
+            "type": "object",
+            "properties": {
+                "section": { 
+                    "oneOf": [
+                        { "type": "string", "$comment": "specifies the section to filter with; should be transient and change to true after add_course" },
+                        { "const": true, "$comment": "signify to pinger it is in section mode" }
+                    ]
+                }
+            },
+            "required": [ "section" ]
+        }
+    },
+    "patternProperties": {
+        "^.*$": {
+            "oneOf": [
+                { "$ref": "#/definitions/searchModeProps" },
+                { "$ref": "#/definitions/sectionModeProps" }
+            ],
+            "$comment": "we want a rigid schema so don't allow additional properties (unevaluated to allow for proper composition)",
+            "unevaluatedProperties": false
+        }
+    }
+}
\ No newline at end of file