diff --git a/server/.idea/dataSources.xml b/server/.idea/dataSources.xml
new file mode 100644
index 0000000..9f38ede
--- /dev/null
+++ b/server/.idea/dataSources.xml
@@ -0,0 +1,12 @@
+
+
+  
+    
+      sqlite.xerial
+      true
+      org.sqlite.JDBC
+      jdbc:sqlite:identifier.sqlite
+      $ProjectFileDir$
+    
+  
+
\ No newline at end of file
diff --git a/server/.idea/sqldialects.xml b/server/.idea/sqldialects.xml
new file mode 100644
index 0000000..a5d08e4
--- /dev/null
+++ b/server/.idea/sqldialects.xml
@@ -0,0 +1,7 @@
+
+
+  
+    
+    
+  
+
\ No newline at end of file
diff --git a/server/api/handler/compat.go b/server/api/handler/compat.go
index 66b19a7..9bee99a 100644
--- a/server/api/handler/compat.go
+++ b/server/api/handler/compat.go
@@ -5,7 +5,13 @@ import (
 	"blackforestbytes.com/simplecloudnotifier/api/models"
 	"blackforestbytes.com/simplecloudnotifier/common/ginresp"
 	"blackforestbytes.com/simplecloudnotifier/logic"
+	"context"
+	"database/sql"
+	"fmt"
 	"github.com/gin-gonic/gin"
+	"net/http"
+	"strconv"
+	"time"
 )
 
 type CompatHandler struct {
@@ -21,6 +27,7 @@ func NewCompatHandler(app *logic.Application) CompatHandler {
 // Register swaggerdoc
 //
 // @Summary Register a new account
+// @ID      compat-register
 // @Param   fcm_token query    string true "the (android) fcm token"
 // @Param   pro       query    string true "if the user is a paid account" Enums(true, false)
 // @Param   pro_token query    string true "the (android) IAP token"
@@ -29,28 +36,101 @@ func NewCompatHandler(app *logic.Application) CompatHandler {
 // @Router  /register.php [get]
 func (h CompatHandler) Register(g *gin.Context) ginresp.HTTPResponse {
 	type query struct {
-		FCMToken string `form:"fcm_token"`
-		Pro      string `form:"pro"`
-		ProToken string `form:"pro_token"`
+		FCMToken *string `form:"fcm_token"`
+		Pro      *string `form:"pro"`
+		ProToken *string `form:"pro_token"`
 	}
 	type response struct {
-		Success   string `json:"success"`
+		Success   bool   `json:"success"`
 		Message   string `json:"message"`
 		UserID    string `json:"user_id"`
 		UserKey   string `json:"user_key"`
-		QuotaUsed string `json:"quota"`
-		QuotaMax  string `json:"quota_max"`
-		IsPro     string `json:"is_pro"`
+		QuotaUsed int    `json:"quota"`
+		QuotaMax  int    `json:"quota_max"`
+		IsPro     int    `json:"is_pro"`
 	}
 
-	//TODO
+	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
+	defer cancel()
 
-	return ginresp.NotImplemented(0)
+	var q query
+	if err := g.ShouldBindQuery(&q); err != nil {
+		return ginresp.InternAPIError(0, "Failed to read arguments")
+	}
+
+	if q.FCMToken == nil {
+		return ginresp.InternAPIError(0, "Missing parameter [[fcm_token]]")
+	}
+	if q.Pro == nil {
+		return ginresp.InternAPIError(0, "Missing parameter [[pro]]")
+	}
+	if q.ProToken == nil {
+		return ginresp.InternAPIError(0, "Missing parameter [[pro_token]]")
+	}
+
+	isProInt := 0
+	isProBool := false
+	if *q.Pro == "true" {
+		isProInt = 1
+		isProBool = true
+	} else {
+		q.ProToken = nil
+	}
+
+	if isProBool {
+		ptok, err := h.app.VerifyProToken(*q.ProToken)
+		if err != nil {
+			return ginresp.InternAPIError(0, fmt.Sprintf("Failed to query purchaste status: %v", err))
+		}
+
+		if !ptok {
+			return ginresp.InternAPIError(0, "Purchase token could not be verified")
+		}
+	}
+
+	userKey := h.app.GenerateRandomAuthKey()
+
+	return h.app.RunTransaction(ctx, nil, func(tx *sql.Tx) (ginresp.HTTPResponse, bool) {
+
+		res, err := tx.ExecContext(ctx, "INSERT INTO users (user_key, fcm_token, is_pro, pro_token, timestamp_accessed) VALUES (?, ?, ?, ?, NOW())", userKey, *q.FCMToken, isProInt, q.ProToken)
+		if err != nil {
+			return ginresp.InternAPIError(0, fmt.Sprintf("Failed to create user: %v", err)), false
+		}
+
+		userId, err := res.LastInsertId()
+		if err != nil {
+			return ginresp.InternAPIError(0, fmt.Sprintf("Failed to get user_id: %v", err)), false
+		}
+
+		_, err = tx.ExecContext(ctx, "UPDATE users SET fcm_token=NULL WHERE user_id <> ? AND fcm_token=?", userId, q.FCMToken)
+		if err != nil {
+			return ginresp.InternAPIError(0, fmt.Sprintf("Failed to update fcm: %v", err)), false
+		}
+
+		if isProInt == 1 {
+			_, err := tx.ExecContext(ctx, "UPDATE users SET is_pro=0, pro_token=NULL WHERE user_id <> ? AND pro_token = ?", userId, q.ProToken)
+			if err != nil {
+				return ginresp.InternAPIError(0, fmt.Sprintf("Failed to update ispro: %v", err)), false
+			}
+		}
+
+		return ginresp.JSON(http.StatusOK, response{
+			Success:   true,
+			Message:   "New user registered",
+			UserID:    strconv.FormatInt(userId, 10),
+			UserKey:   userKey,
+			QuotaUsed: 0,
+			QuotaMax:  h.app.QuotaMax(isProBool),
+			IsPro:     isProInt,
+		}), true
+
+	})
 }
 
 // Info swaggerdoc
 //
 // @Summary Get information about the current user
+// @ID      compat-info
 // @Param   user_id  query    string true "the user_id"
 // @Param   user_key query    string true "the user_key"
 // @Success 200      {object} handler.Info.response
@@ -75,12 +155,13 @@ func (h CompatHandler) Info(g *gin.Context) ginresp.HTTPResponse {
 
 	//TODO
 
-	return ginresp.NotImplemented(0)
+	return ginresp.InternAPIError(0, "NotImplemented")
 }
 
 // Ack swaggerdoc
 //
 // @Summary Acknowledge that a message was received
+// @ID      compat-ack
 // @Param   user_id    query    string true "the user_id"
 // @Param   user_key   query    string true "the user_key"
 // @Param   scn_msg_id query    string true "the message id"
@@ -102,12 +183,13 @@ func (h CompatHandler) Ack(g *gin.Context) ginresp.HTTPResponse {
 
 	//TODO
 
-	return ginresp.NotImplemented(0)
+	return ginresp.InternAPIError(0, "NotImplemented")
 }
 
 // Requery swaggerdoc
 //
 // @Summary Return all not-acknowledged messages
+// @ID      compat-requery
 // @Param   user_id  query    string true "the user_id"
 // @Param   user_key query    string true "the user_key"
 // @Success 200      {object} handler.Requery.response
@@ -127,12 +209,13 @@ func (h CompatHandler) Requery(g *gin.Context) ginresp.HTTPResponse {
 
 	//TODO
 
-	return ginresp.NotImplemented(0)
+	return ginresp.InternAPIError(0, "NotImplemented")
 }
 
 // Update swaggerdoc
 //
 // @Summary Set the fcm-token (android)
+// @ID      compat-update
 // @Param   user_id   query    string true "the user_id"
 // @Param   user_key  query    string true "the user_key"
 // @Param   fcm_token query    string true "the (android) fcm token"
@@ -157,12 +240,13 @@ func (h CompatHandler) Update(g *gin.Context) ginresp.HTTPResponse {
 
 	//TODO
 
-	return ginresp.NotImplemented(0)
+	return ginresp.InternAPIError(0, "NotImplemented")
 }
 
 // Expand swaggerdoc
 //
 // @Summary Get a whole (potentially truncated) message
+// @ID      compat-expand
 // @Success 200 {object} handler.Expand.response
 // @Failure 500 {object} ginresp.internAPIError
 // @Router  /expand.php [get]
@@ -180,12 +264,13 @@ func (h CompatHandler) Expand(g *gin.Context) ginresp.HTTPResponse {
 
 	//TODO
 
-	return ginresp.NotImplemented(0)
+	return ginresp.InternAPIError(0, "NotImplemented")
 }
 
 // Upgrade swaggerdoc
 //
 // @Summary Upgrade a free account to a paid account
+// @ID      compat-upgrade
 // @Param   user_id   query    string true "the user_id"
 // @Param   user_key  query    string true "the user_key"
 // @Param   pro       query    string true "if the user is a paid account" Enums(true, false)
@@ -208,33 +293,39 @@ func (h CompatHandler) Upgrade(g *gin.Context) ginresp.HTTPResponse {
 
 	//TODO
 
-	return ginresp.NotImplemented(0)
+	return ginresp.InternAPIError(0, "NotImplemented")
 }
 
 // Send swaggerdoc
 //
-// @Summary Send a message
-// @Description all aeguments can either be supplied in the query or in the json body
-// @Param   user_id   query    string true "the user_id"
-// @Param   user_key  query    string true "the user_key"
-// @Param   title     query    string true "The message title"
-// @Param   content   query    string false "The message content"
-// @Param   priority  query    string false "The message priority" Enum(0, 1, 2)
-// @Param   msg_id    query    string false "The message idempotency id"
-// @Param   timestamp query    string false "The message timestamp"
-// @Param   user_id   body     string true "the user_id"
-// @Param   user_key  body     string true "the user_key"
-// @Param   title     body     string true "The message title"
-// @Param   content   body     string false "The message content"
-// @Param   priority  body     string false "The message priority" Enum(0, 1, 2)
-// @Param   msg_id    body     string false "The message idempotency id"
-// @Param   timestamp body     string false "The message timestamp"
-// @Success 200       {object} handler.Send.response
-// @Failure 500       {object} ginresp.sendAPIError
-// @Router  /send.php [post]
+// @Summary     Send a message
+// @Description (all arguments can either be supplied in the query or in the json body)
+// @ID          compat-send
+// @Accept      json
+// @Produce     json
+// @Param       _         query    handler.Send.query false " "
+// @Param       post_body body     handler.Send.body  false " "
+// @Success     200       {object} handler.Send.response
+// @Failure     500       {object} ginresp.sendAPIError
+// @Router      /send.php [post]
 func (h CompatHandler) Send(g *gin.Context) ginresp.HTTPResponse {
 	type query struct {
-		//TODO
+		UserID    string  `form:"user_id" required:"true"`
+		UserKey   string  `form:"user_key" required:"true"`
+		Title     string  `form:"title" required:"true"`
+		Content   *string `form:"content"`
+		Priority  *string `form:"priority"`
+		MessageID *string `form:"msg_id"`
+		Timestamp *string `form:"timestamp"`
+	}
+	type body struct {
+		UserID    string  `json:"user_id" required:"true"`
+		UserKey   string  `json:"user_key" required:"true"`
+		Title     string  `json:"title" required:"true"`
+		Content   *string `json:"content"`
+		Priority  *string `json:"priority"`
+		MessageID *string `json:"msg_id"`
+		Timestamp *string `json:"timestamp"`
 	}
 	type response struct {
 		Success string `json:"success"`
diff --git a/server/cmd/scnserver/main.go b/server/cmd/scnserver/main.go
index 36281af..5c1287b 100644
--- a/server/cmd/scnserver/main.go
+++ b/server/cmd/scnserver/main.go
@@ -7,6 +7,7 @@ import (
 	"blackforestbytes.com/simplecloudnotifier/common/ginext"
 	"blackforestbytes.com/simplecloudnotifier/db"
 	"blackforestbytes.com/simplecloudnotifier/logic"
+	"context"
 	"fmt"
 	"github.com/rs/zerolog/log"
 )
@@ -18,7 +19,7 @@ func main() {
 
 	log.Info().Msg(fmt.Sprintf("Starting with config-namespace <%s>", conf.Namespace))
 
-	sqlite, err := db.NewDatabase(conf)
+	sqlite, err := db.NewDatabase(context.Background(), conf)
 	if err != nil {
 		panic(err)
 	}
diff --git a/server/common/ginresp/resp.go b/server/common/ginresp/resp.go
index f8f7b9a..a0c368f 100644
--- a/server/common/ginresp/resp.go
+++ b/server/common/ginresp/resp.go
@@ -76,8 +76,8 @@ func InternalError(e error) HTTPResponse {
 	return &errHTTPResponse{statusCode: http.StatusInternalServerError, data: errBody{Success: false, Message: e.Error()}}
 }
 
-func NotImplemented(errid int) HTTPResponse {
-	return &errHTTPResponse{statusCode: http.StatusInternalServerError, data: internAPIError{Success: false, ErrorID: errid, Message: "NotImplemented"}}
+func InternAPIError(errid int, msg string) HTTPResponse {
+	return &errHTTPResponse{statusCode: http.StatusInternalServerError, data: internAPIError{Success: false, ErrorID: errid, Message: msg}}
 }
 
 func SendAPIError(errorid apierr.APIError, highlight int, msg string) HTTPResponse {
diff --git a/server/db/database.go b/server/db/database.go
index 12d57be..532ae20 100644
--- a/server/db/database.go
+++ b/server/db/database.go
@@ -2,10 +2,70 @@ package db
 
 import (
 	scn "blackforestbytes.com/simplecloudnotifier"
+	"context"
 	"database/sql"
+	_ "embed"
+	"errors"
+	"fmt"
 	_ "github.com/mattn/go-sqlite3"
 )
 
-func NewDatabase(conf scn.Config) (*sql.DB, error) {
-	return sql.Open("sqlite3", conf.DBFile)
+//go:embed schema_1.0.sql
+var schema_1_0 string
+
+//go:embed schema_2.0.sql
+var schema_2_0 string
+
+func NewDatabase(ctx context.Context, conf scn.Config) (*sql.DB, error) {
+	db, err := sql.Open("sqlite3", conf.DBFile)
+	if err != nil {
+		return nil, err
+	}
+
+	schema, err := getSchemaFromDB(ctx, db)
+	if schema == 0 {
+
+		_, err = db.ExecContext(ctx, schema_1_0)
+		if err != nil {
+			return nil, err
+		}
+
+		return db, nil
+
+	} else if schema == 1 {
+		return nil, errors.New("cannot autom. upgrade schema 1")
+	} else if schema == 2 {
+		return db, nil
+	} else {
+		return nil, errors.New(fmt.Sprintf("Unknown DB schema: %d", schema))
+	}
+
+}
+
+func getSchemaFromDB(ctx context.Context, db *sql.DB) (int, error) {
+
+	r1, err := db.QueryContext(ctx, "SELECT name FROM sqlite_master WHERE type='table' AND name='meta'")
+	if err != nil {
+		return 0, err
+	}
+
+	if !r1.Next() {
+		return 0, nil
+	}
+
+	r2, err := db.QueryContext(ctx, "SELECT value_int FROM meta WHERE key='schema'")
+	if err != nil {
+		return 0, err
+	}
+	if !r2.Next() {
+		return 0, errors.New("no schema entry in meta table")
+	}
+
+	var schema int
+	err = r2.Scan(&schema)
+	if err != nil {
+		return 0, err
+	}
+
+	return schema, nil
 }
diff --git a/server/db/schema_1.0.sql b/server/db/schema_1.0.sql
new file mode 100644
index 0000000..504798d
--- /dev/null
+++ b/server/db/schema_1.0.sql
@@ -0,0 +1,38 @@
+DROP TABLE IF EXISTS `users`;
+CREATE TABLE `users`
+(
+    `user_id`            INT(11)         NOT NULL   AUTO_INCREMENT,
+    `user_key`           VARCHAR(64)     NOT NULL,
+    `fcm_token`          VARCHAR(256)        NULL   DEFAULT NULL,
+    `messages_sent`      INT(11)         NOT NULL   DEFAULT '0',
+    `timestamp_created`  DATETIME        NOT NULL   DEFAULT CURRENT_TIMESTAMP,
+    `timestamp_accessed` DATETIME            NULL   DEFAULT NULL,
+
+    `quota_today`        INT(11)         NOT NULL   DEFAULT '0',
+    `quota_day`          DATE                NULL   DEFAULT NULL,
+
+    `is_pro`             BIT             NOT NULL   DEFAULT 0,
+    `pro_token`          VARCHAR(256)        NULL   DEFAULT NULL,
+
+    PRIMARY KEY (`user_id`)
+);
+
+DROP TABLE IF EXISTS `messages`;
+CREATE TABLE `messages`
+(
+    `scn_message_id`     INT(11)         NOT NULL   AUTO_INCREMENT,
+    `sender_user_id`     INT(11)         NOT NULL,
+
+    `timestamp_real`     DATETIME        NOT NULL   DEFAULT CURRENT_TIMESTAMP,
+    `ack`                TINYINT(1)      NOT NULL   DEFAULT 0,
+
+    `title`              VARCHAR(256)    NOT NULL,
+    `content`            LONGTEXT            NULL,
+    `priority`           INT(11)         NOT NULL,
+    `sendtime`           BIGINT UNSIGNED NOT NULL,
+
+    `fcm_message_id`     VARCHAR(256)        NULL,
+    `usr_message_id`     VARCHAR(256)        NULL,
+
+    PRIMARY KEY (`scn_message_id`)
+);
\ No newline at end of file
diff --git a/server/db/schema_2.0.sql b/server/db/schema_2.0.sql
new file mode 100644
index 0000000..2032092
--- /dev/null
+++ b/server/db/schema_2.0.sql
@@ -0,0 +1,47 @@
+CREATE TABLE `users`
+(
+    `user_id`            INTEGER                AUTO_INCREMENT,
+    `user_key`           TEXT         NOT NULL,
+    `fcm_token`          TEXT             NULL  DEFAULT NULL,
+    `messages_sent`      INTEGER     NOT NULL   DEFAULT '0',
+    `timestamp_created`  TEXT        NOT NULL   DEFAULT CURRENT_TIMESTAMP,
+    `timestamp_accessed` TEXT            NULL   DEFAULT NULL,
+
+    `quota_today`        INTEGER     NOT NULL   DEFAULT '0',
+    `quota_day`          TEXT            NULL   DEFAULT NULL,
+
+    `is_pro`             INTEGER     NOT NULL   DEFAULT 0,
+    `pro_token`          TEXT            NULL   DEFAULT NULL,
+
+    PRIMARY KEY (`user_id`)
+);
+
+CREATE TABLE `messages`
+(
+    `scn_message_id`     INTEGER                AUTO_INCREMENT,
+    `sender_user_id`     INTEGER     NOT NULL,
+
+    `timestamp_real`     TEXT        NOT NULL   DEFAULT CURRENT_TIMESTAMP,
+    `ack`                INTEGER     NOT NULL   DEFAULT 0,
+
+    `title`              TEXT        NOT NULL,
+    `content`            TEXT            NULL,
+    `priority`           INTEGER     NOT NULL,
+    `sendtime`           INTEGER     NOT NULL,
+
+    `fcm_message_id`     TEXT            NULL,
+    `usr_message_id`     TEXT            NULL,
+
+    PRIMARY KEY (`scn_message_id`)
+);
+
+CREATE TABLE `meta`
+(
+    `key`         TEXT     NOT NULL,
+    `value_int`   INTEGER      NULL,
+    `value_txt`   TEXT         NULL,
+
+    PRIMARY KEY (`key`)
+);
+
+INSERT INTO meta (key, value_int) VALUES ('schema', 2)
\ No newline at end of file
diff --git a/server/go.mod b/server/go.mod
index c4c04a7..df8fd17 100644
--- a/server/go.mod
+++ b/server/go.mod
@@ -32,6 +32,7 @@ require (
 	github.com/modern-go/reflect2 v1.0.2 // indirect
 	github.com/pelletier/go-toml/v2 v2.0.1 // indirect
 	github.com/ugorji/go/codec v1.2.7 // indirect
+	gogs.mikescher.com/BlackForestBytes/goext v0.0.17 // indirect
 	golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97 // indirect
 	golang.org/x/net v0.0.0-20220722155237-a158d28d115b // indirect
 	golang.org/x/sys v0.1.0 // indirect
diff --git a/server/go.sum b/server/go.sum
index 9e02733..b207928 100644
--- a/server/go.sum
+++ b/server/go.sum
@@ -90,6 +90,8 @@ github.com/swaggo/swag v1.8.7/go.mod h1:ezQVUUhly8dludpVk+/PuwJWvLLanB13ygV5Pr9e
 github.com/ugorji/go v1.2.7/go.mod h1:nF9osbDWLy6bDVv/Rtoh6QgnvNDpmCalQV5urGCCS6M=
 github.com/ugorji/go/codec v1.2.7 h1:YPXUKf7fYbp/y8xloBqZOw2qaVggbfwMlI8WM3wZUJ0=
 github.com/ugorji/go/codec v1.2.7/go.mod h1:WGN1fab3R1fzQlVQTkfxVtIBhWDRqOviHU95kRgeqEY=
+gogs.mikescher.com/BlackForestBytes/goext v0.0.17 h1:jsfbvII7aa0SH9qY0fnXBdtNnQe1YY3DgXDThEwLICc=
+gogs.mikescher.com/BlackForestBytes/goext v0.0.17/go.mod h1:TMBOjo3FRFh/GiTT0z3nwLmgcFJB87oSF2VMs4XUCTQ=
 golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97 h1:/UOmuWzQfxxo9UtlXMwuQU8CMgg1eZXqTRwkSQJWKOI=
 golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
 golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 h1:6zppjxzCulZykYSLyVDYbneBfbaBIQPYMevg0bEwv2s=
diff --git a/server/logic/application.go b/server/logic/application.go
index aa61672..91adbe5 100644
--- a/server/logic/application.go
+++ b/server/logic/application.go
@@ -2,10 +2,13 @@ package logic
 
 import (
 	scn "blackforestbytes.com/simplecloudnotifier"
+	"blackforestbytes.com/simplecloudnotifier/common/ginresp"
 	"context"
 	"database/sql"
+	"fmt"
 	"github.com/gin-gonic/gin"
 	"github.com/rs/zerolog/log"
+	"math/rand"
 	"net"
 	"net/http"
 	"os"
@@ -61,3 +64,48 @@ func (app *Application) Run() {
 	}
 
 }
+
+func (app *Application) GenerateRandomAuthKey() string {
+	charset := "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
+	k := ""
+	for i := 0; i < 64; i++ {
+		k += string(charset[rand.Int()%len(charset)])
+	}
+	return k
+}
+
+func (app *Application) RunTransaction(ctx context.Context, opt *sql.TxOptions, fn func(tx *sql.Tx) (ginresp.HTTPResponse, bool)) ginresp.HTTPResponse {
+
+	tx, err := app.Database.BeginTx(ctx, opt)
+	if err != nil {
+		return ginresp.InternAPIError(0, fmt.Sprintf("Failed to create transaction: %v", err))
+	}
+
+	res, commit := fn(tx)
+
+	if commit {
+		err = tx.Commit()
+		if err != nil {
+			return ginresp.InternAPIError(0, fmt.Sprintf("Failed to commit transaction: %v", err))
+		}
+	} else {
+		err = tx.Rollback()
+		if err != nil {
+			return ginresp.InternAPIError(0, fmt.Sprintf("Failed to rollback transaction: %v", err))
+		}
+	}
+
+	return res
+}
+
+func (app *Application) QuotaMax(ispro bool) int {
+	if ispro {
+		return 1000
+	} else {
+		return 50
+	}
+}
+
+func (app *Application) VerifyProToken(token string) (bool, error) {
+	return false, nil //TODO implement pro verification
+}
diff --git a/server/swagger/swagger.json b/server/swagger/swagger.json
index df5327e..75d4068 100644
--- a/server/swagger/swagger.json
+++ b/server/swagger/swagger.json
@@ -12,6 +12,7 @@
         "/ack.php": {
             "get": {
                 "summary": "Acknowledge that a message was received",
+                "operationId": "compat-ack",
                 "parameters": [
                     {
                         "type": "string",
@@ -72,6 +73,7 @@
         "/expand.php": {
             "get": {
                 "summary": "Get a whole (potentially truncated) message",
+                "operationId": "compat-expand",
                 "responses": {
                     "200": {
                         "description": "OK",
@@ -109,6 +111,7 @@
         "/info.php": {
             "get": {
                 "summary": "Get information about the current user",
+                "operationId": "compat-info",
                 "parameters": [
                     {
                         "type": "string",
@@ -226,6 +229,7 @@
         "/register.php": {
             "get": {
                 "summary": "Register a new account",
+                "operationId": "compat-register",
                 "parameters": [
                     {
                         "type": "string",
@@ -272,6 +276,7 @@
         "/requery.php": {
             "get": {
                 "summary": "Return all not-acknowledged messages",
+                "operationId": "compat-requery",
                 "parameters": [
                     {
                         "type": "string",
@@ -306,111 +311,57 @@
         },
         "/send.php": {
             "post": {
-                "description": "all aeguments can either be supplied in the query or in the json body",
+                "description": "(all arguments can either be supplied in the query or in the json body)",
+                "consumes": [
+                    "application/json"
+                ],
+                "produces": [
+                    "application/json"
+                ],
                 "summary": "Send a message",
+                "operationId": "compat-send",
                 "parameters": [
                     {
                         "type": "string",
-                        "description": "the user_id",
-                        "name": "user_id",
-                        "in": "query",
-                        "required": true
-                    },
-                    {
-                        "type": "string",
-                        "description": "the user_key",
-                        "name": "user_key",
-                        "in": "query",
-                        "required": true
-                    },
-                    {
-                        "type": "string",
-                        "description": "The message title",
-                        "name": "title",
-                        "in": "query",
-                        "required": true
-                    },
-                    {
-                        "type": "string",
-                        "description": "The message content",
                         "name": "content",
                         "in": "query"
                     },
                     {
                         "type": "string",
-                        "description": "The message priority",
+                        "name": "messageID",
+                        "in": "query"
+                    },
+                    {
+                        "type": "string",
                         "name": "priority",
                         "in": "query"
                     },
                     {
                         "type": "string",
-                        "description": "The message idempotency id",
-                        "name": "msg_id",
-                        "in": "query"
-                    },
-                    {
-                        "type": "string",
-                        "description": "The message timestamp",
                         "name": "timestamp",
                         "in": "query"
                     },
                     {
-                        "description": "the user_id",
-                        "name": "user_id",
-                        "in": "body",
-                        "required": true,
-                        "schema": {
-                            "type": "string"
-                        }
-                    },
-                    {
-                        "description": "the user_key",
-                        "name": "user_key",
-                        "in": "body",
-                        "required": true,
-                        "schema": {
-                            "type": "string"
-                        }
-                    },
-                    {
-                        "description": "The message title",
+                        "type": "string",
                         "name": "title",
-                        "in": "body",
-                        "required": true,
-                        "schema": {
-                            "type": "string"
-                        }
+                        "in": "query"
                     },
                     {
-                        "description": "The message content",
-                        "name": "content",
-                        "in": "body",
-                        "schema": {
-                            "type": "string"
-                        }
+                        "type": "string",
+                        "name": "userID",
+                        "in": "query"
                     },
                     {
-                        "description": "The message priority",
-                        "name": "priority",
-                        "in": "body",
-                        "schema": {
-                            "type": "string"
-                        }
+                        "type": "string",
+                        "name": "userKey",
+                        "in": "query"
                     },
                     {
-                        "description": "The message idempotency id",
-                        "name": "msg_id",
+                        "description": " ",
+                        "name": "post_body",
                         "in": "body",
                         "schema": {
-                            "type": "string"
-                        }
-                    },
-                    {
-                        "description": "The message timestamp",
-                        "name": "timestamp",
-                        "in": "body",
-                        "schema": {
-                            "type": "string"
+                            "$ref": "#/definitions/handler.Send.body"
                         }
                     }
                 ],
@@ -433,6 +384,7 @@
         "/update.php": {
             "get": {
                 "summary": "Set the fcm-token (android)",
+                "operationId": "compat-update",
                 "parameters": [
                     {
                         "type": "string",
@@ -475,6 +427,7 @@
         "/upgrade.php": {
             "get": {
                 "summary": "Upgrade a free account to a paid account",
+                "operationId": "compat-upgrade",
                 "parameters": [
                     {
                         "type": "string",
@@ -661,19 +614,19 @@
             "type": "object",
             "properties": {
                 "is_pro": {
-                    "type": "string"
+                    "type": "integer"
                 },
                 "message": {
                     "type": "string"
                 },
                 "quota": {
-                    "type": "string"
+                    "type": "integer"
                 },
                 "quota_max": {
-                    "type": "string"
+                    "type": "integer"
                 },
                 "success": {
-                    "type": "string"
+                    "type": "boolean"
                 },
                 "user_id": {
                     "type": "string"
@@ -703,6 +656,32 @@
                 }
             }
         },
+        "handler.Send.body": {
+            "type": "object",
+            "properties": {
+                "content": {
+                    "type": "string"
+                },
+                "msg_id": {
+                    "type": "string"
+                },
+                "priority": {
+                    "type": "string"
+                },
+                "timestamp": {
+                    "type": "string"
+                },
+                "title": {
+                    "type": "string"
+                },
+                "user_id": {
+                    "type": "string"
+                },
+                "user_key": {
+                    "type": "string"
+                }
+            }
+        },
         "handler.Send.response": {
             "type": "object",
             "properties": {
diff --git a/server/swagger/swagger.yaml b/server/swagger/swagger.yaml
index 86dc98c..7f9a6ce 100644
--- a/server/swagger/swagger.yaml
+++ b/server/swagger/swagger.yaml
@@ -87,15 +87,15 @@ definitions:
   handler.Register.response:
     properties:
       is_pro:
-        type: string
+        type: integer
       message:
         type: string
       quota:
-        type: string
+        type: integer
       quota_max:
-        type: string
+        type: integer
       success:
-        type: string
+        type: boolean
       user_id:
         type: string
       user_key:
@@ -114,6 +114,23 @@ definitions:
       success:
         type: string
     type: object
+  handler.Send.body:
+    properties:
+      content:
+        type: string
+      msg_id:
+        type: string
+      priority:
+        type: string
+      timestamp:
+        type: string
+      title:
+        type: string
+      user_id:
+        type: string
+      user_key:
+        type: string
+    type: object
   handler.Send.response:
     properties:
       message:
@@ -212,6 +229,7 @@ info:
 paths:
   /ack.php:
     get:
+      operationId: compat-ack
       parameters:
       - description: the user_id
         in: query
@@ -251,6 +269,7 @@ paths:
             $ref: '#/definitions/ginresp.errBody'
   /expand.php:
     get:
+      operationId: compat-expand
       responses:
         "200":
           description: OK
@@ -274,6 +293,7 @@ paths:
             $ref: '#/definitions/ginresp.errBody'
   /info.php:
     get:
+      operationId: compat-info
       parameters:
       - description: the user_id
         in: query
@@ -348,6 +368,7 @@ paths:
             $ref: '#/definitions/ginresp.errBody'
   /register.php:
     get:
+      operationId: compat-register
       parameters:
       - description: the (android) fcm token
         in: query
@@ -379,6 +400,7 @@ paths:
       summary: Register a new account
   /requery.php:
     get:
+      operationId: compat-requery
       parameters:
       - description: the user_id
         in: query
@@ -402,78 +424,40 @@ paths:
       summary: Return all not-acknowledged messages
   /send.php:
     post:
-      description: all aeguments can either be supplied in the query or in the json
-        body
+      consumes:
+      - application/json
+      description: (all arguments can either be supplied in the query or in the json
+        body)
+      operationId: compat-send
       parameters:
-      - description: the user_id
-        in: query
-        name: user_id
-        required: true
-        type: string
-      - description: the user_key
-        in: query
-        name: user_key
-        required: true
-        type: string
-      - description: The message title
-        in: query
-        name: title
-        required: true
-        type: string
-      - description: The message content
-        in: query
+      - in: query
         name: content
         type: string
-      - description: The message priority
-        in: query
+      - in: query
+        name: messageID
+        type: string
+      - in: query
         name: priority
         type: string
-      - description: The message idempotency id
-        in: query
-        name: msg_id
-        type: string
-      - description: The message timestamp
-        in: query
+      - in: query
         name: timestamp
         type: string
-      - description: the user_id
-        in: body
-        name: user_id
-        required: true
-        schema:
-          type: string
-      - description: the user_key
-        in: body
-        name: user_key
-        required: true
-        schema:
-          type: string
-      - description: The message title
-        in: body
+      - in: query
         name: title
-        required: true
-        schema:
-          type: string
-      - description: The message content
+        type: string
+      - in: query
+        name: userID
+        type: string
+      - in: query
+        name: userKey
+        type: string
+      - description: ' '
         in: body
-        name: content
+        name: post_body
         schema:
-          type: string
-      - description: The message priority
-        in: body
-        name: priority
-        schema:
-          type: string
-      - description: The message idempotency id
-        in: body
-        name: msg_id
-        schema:
-          type: string
-      - description: The message timestamp
-        in: body
-        name: timestamp
-        schema:
-          type: string
+          $ref: '#/definitions/handler.Send.body'
+      produces:
+      - application/json
       responses:
         "200":
           description: OK
@@ -486,6 +470,7 @@ paths:
       summary: Send a message
   /update.php:
     get:
+      operationId: compat-update
       parameters:
       - description: the user_id
         in: query
@@ -514,6 +499,7 @@ paths:
       summary: Set the fcm-token (android)
   /upgrade.php:
     get:
+      operationId: compat-upgrade
       parameters:
       - description: the user_id
         in: query