diff --git a/go.mod b/go.mod
index fb7ce231d..9942f9920 100644
--- a/go.mod
+++ b/go.mod
@@ -3,7 +3,6 @@ module github.com/gotosocial/gotosocial
 go 1.16
 
 require (
-	github.com/gin-gonic/gin v1.6.3
 	github.com/go-fed/activity v1.0.0
 	github.com/go-pg/pg/extra/pgdebug v0.2.0
 	github.com/go-pg/pg/v10 v10.8.0
diff --git a/go.sum b/go.sum
index 07ae1d3fd..46675ca8b 100644
--- a/go.sum
+++ b/go.sum
@@ -13,10 +13,6 @@ github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7
 github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
 github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
 github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
-github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
-github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
-github.com/gin-gonic/gin v1.6.3 h1:ahKqKTFpO5KTPHxWZjEdPScmYaGtLo8Y4DMHoEsnp14=
-github.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M=
 github.com/go-fed/activity v1.0.0 h1:j7w3auHZnVCjUcgA1mE+UqSOjFBhvW2Z2res3vNol+o=
 github.com/go-fed/activity v1.0.0/go.mod h1:v4QoPaAzjWZ8zN2VFVGL5ep9C02mst0hQYHUpQwso4Q=
 github.com/go-fed/httpsig v0.1.1-0.20190914113940-c2de3672e5b5 h1:WLvFZqoXnuVTBKA6U/1FnEHNQ0Rq0QM0rGhY8Tx6R1g=
@@ -28,14 +24,6 @@ github.com/go-pg/pg/v10 v10.8.0 h1:7L1VmOwW/VMmPtz5K3TWWMdM68MDgRs8Yb3c3NTMNgI=
 github.com/go-pg/pg/v10 v10.8.0/go.mod h1:0ZZA18+5xlUPvKjlDxoMyU79ZSuJtI+EeM2/GEd4RVo=
 github.com/go-pg/zerochecker v0.2.0 h1:pp7f72c3DobMWOb2ErtZsnrPaSvHd2W4o9//8HtF4mU=
 github.com/go-pg/zerochecker v0.2.0/go.mod h1:NJZ4wKL0NmTtz0GKCoJ8kym6Xn/EQzXRl2OnAe7MmDo=
-github.com/go-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A=
-github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
-github.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8ceBS/t7Q=
-github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8=
-github.com/go-playground/universal-translator v0.17.0 h1:icxd5fm+REJzpZx7ZfpaD876Lmtgy7VtROAbHHXk8no=
-github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA=
-github.com/go-playground/validator/v10 v10.2.0 h1:KgJ0snyC2R9VXYN2rneOtQcw5aHQB1Vv0sFl1UcHBOY=
-github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI=
 github.com/go-test/deep v1.0.1 h1:UQhStjbkDClarlmv0am7OXXO4/GaPdCGiUiMTvi28sg=
 github.com/go-test/deep v1.0.1/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA=
 github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
@@ -45,7 +33,6 @@ github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfb
 github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
 github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
 github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
-github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
 github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
 github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
 github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
@@ -54,7 +41,6 @@ github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:W
 github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
 github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
 github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
-github.com/golang/protobuf v1.4.3 h1:JjCZWpVbqXDqFVmTfYWEVTMIYrL/NPdPSCHPJ0T/raM=
 github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
 github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
 github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
@@ -64,28 +50,17 @@ github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
 github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
 github.com/google/go-cmp v0.5.4 h1:L8R9j+yAqZuZjsqh/z+F1NCffTKKLShY6zXTItVIZ8M=
 github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
-github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
 github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
 github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
 github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
-github.com/json-iterator/go v1.1.9 h1:9yzud/Ht36ygwatGx56VwCZtlI/2AD15T1X2sjSuGns=
-github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
 github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
 github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI=
 github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
 github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
 github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
 github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
-github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y=
-github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII=
 github.com/magefile/mage v1.10.0 h1:3HiXzCUY12kh9bIuyXShaVe529fJfyqoVM42o/uom2g=
 github.com/magefile/mage v1.10.0/go.mod h1:z5UZb/iS3GoOSn0JgWuiw7dxlurVYTu+/jHXqQg881A=
-github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
-github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
-github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 h1:ZqeYNhU3OHLH3mGKHDcjJRFFRrJa6eAM5H+CtDdOsPc=
-github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
-github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742 h1:Esafd1046DLDQ0W1YjYsBW+p8U2u7vzgW2SQVmlNazg=
-github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
 github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
 github.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78=
 github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
@@ -110,18 +85,12 @@ github.com/sirupsen/logrus v1.8.0 h1:nfhvjKcUMhBMVqbKHJlk5RPrrfYr/NMo3692g0dwfWU
 github.com/sirupsen/logrus v1.8.0/go.mod h1:4GuYW9TZmE769R5STWrRakJc4UqQ3+QQ95fyz7ENv1A=
 github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
 github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
-github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
-github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
 github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
 github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
 github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
 github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
 github.com/tmthrgd/go-hex v0.0.0-20190904060850-447a3041c3bc h1:9lRDQMhESg+zvGYmW5DyG0UqvY96Bu5QYsTLvCHdrgo=
 github.com/tmthrgd/go-hex v0.0.0-20190904060850-447a3041c3bc/go.mod h1:bciPuU6GHm1iF1pBvUfxfsH0Wmnc2VbpgvbI9ZWuIRs=
-github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo=
-github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw=
-github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs=
-github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY=
 github.com/urfave/cli/v2 v2.3.0 h1:qph92Y649prgesehzOrQjdWyxFOp/QVM+6imKHad91M=
 github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI=
 github.com/vmihailenco/bufpool v0.1.11 h1:gOq2WmBrq0i2yW5QJ16ykccQ4wH9UyEsgLm6czKAd94=
@@ -189,7 +158,6 @@ golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7w
 golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -214,7 +182,6 @@ golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4f
 golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
-golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
 golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
 google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
@@ -234,7 +201,6 @@ google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzi
 google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
 google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
 google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
-google.golang.org/protobuf v1.25.0 h1:Ejskq+SyPohKW+1uil0JJMtmHCgJPJ/qWTxr8qp+R4c=
 google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
 gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
@@ -247,7 +213,6 @@ gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWD
 gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
 gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
 gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
-gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
 gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
 gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
 gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
diff --git a/internal/cache/cache.go b/internal/cache/cache.go
index ed13aded4..1d2d0533b 100644
--- a/internal/cache/cache.go
+++ b/internal/cache/cache.go
@@ -20,6 +20,6 @@ package cache
 
 // Cache defines an in-memory cache that is safe to be wiped when the application is restarted
 type Cache interface {
-   Store(k string, v interface{}) error
-   Fetch(k string) (interface{}, error)
+	Store(k string, v interface{}) error
+	Fetch(k string) (interface{}, error)
 }
diff --git a/internal/client/media.go b/internal/client/media.go
deleted file mode 100644
index add204a35..000000000
--- a/internal/client/media.go
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
-   GoToSocial
-   Copyright (C) 2021 GoToSocial Authors admin@gotosocial.org
-
-   This program is free software: you can redistribute it and/or modify
-   it under the terms of the GNU Affero General Public License as published by
-   the Free Software Foundation, either version 3 of the License, or
-   (at your option) any later version.
-
-   This program is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU Affero General Public License for more details.
-
-   You should have received a copy of the GNU Affero General Public License
-   along with this program.  If not, see <http://www.gnu.org/licenses/>.
-*/
-
-package client
-
-import "mime/multipart"
-
-// MediaRequest represents the form data parameters submitted by a client during a media upload request.
-// See: https://docs.joinmastodon.org/methods/statuses/media/
-type MediaRequest struct {
-	File        *multipart.FileHeader `form:"file"`
-	Thumbnail   *multipart.FileHeader `form:"thumbnail"`
-	Description string                `form:"description"`
-	Focus       string                `form:"focus"`
-}
-
-// MediaResponse represents the object returned to a client after a successful media upload request.
-// See: https://docs.joinmastodon.org/methods/statuses/media/
-type MediaResponse struct {
-	ID          string    `json:"id"`
-	Type        string    `json:"type"`
-	URL         string    `json:"url"`
-	PreviewURL  string    `json:"preview_url"`
-	RemoteURL   string    `json:"remote_url"`
-	TextURL     string    `json:"text_url"`
-	Meta        MediaMeta `json:"meta"`
-	Description string    `json:"description"`
-	Blurhash    string    `json:"blurhash"`
-}
-
-// MediaMeta describes the media that's just been uploaded. It should be returned to the caller as part of MediaResponse.
-type MediaMeta struct {
-	Focus    MediaFocus      `json:"focus"`
-	Original MediaDimensions `json:"original"`
-	Small    MediaDimensions `json:"small"`
-}
-
-// MediaFocus describes the focal point of a piece of media. It should be returned to the caller as part of MediaMeta.
-type MediaFocus struct {
-	X float32 `json:"x"` // should be between -1 and 1
-	Y float32 `json:"y"` // should be between -1 and 1
-}
-
-// MediaDimensions describes the physical properties of a piece of media. It should be returned to the caller as part of MediaMeta.
-type MediaDimensions struct {
-	Width  int     `json:"width"`
-	Height int     `json:"height"`
-	Size   string  `json:"size"`
-	Aspect float32 `json:"aspect"`
-}
diff --git a/internal/gotosocial/gotosocial.go b/internal/gotosocial/gotosocial.go
index 8ad79e09d..cf4305ee2 100644
--- a/internal/gotosocial/gotosocial.go
+++ b/internal/gotosocial/gotosocial.go
@@ -35,20 +35,20 @@ type Gotosocial interface {
 
 func New(db db.DB, cache cache.Cache, clientAPI client.API, federationAPI pub.FederatingActor, config *config.Config) (Gotosocial, error) {
 	return &gotosocial{
-		db: db,
-      cache: cache,
-      clientAPI: clientAPI,
-      federationAPI: federationAPI,
-      config: config,
+		db:            db,
+		cache:         cache,
+		clientAPI:     clientAPI,
+		federationAPI: federationAPI,
+		config:        config,
 	}, nil
 }
 
 type gotosocial struct {
-	db    db.DB
-	cache cache.Cache
-   clientAPI client.API
-   federationAPI pub.FederatingActor
-   config *config.Config
+	db            db.DB
+	cache         cache.Cache
+	clientAPI     client.API
+	federationAPI pub.FederatingActor
+	config        *config.Config
 }
 
 func (gts *gotosocial) Start(ctx context.Context) error {
diff --git a/internal/media/media.go b/internal/media/media.go
index 8ff8693f4..644edb8e4 100644
--- a/internal/media/media.go
+++ b/internal/media/media.go
@@ -20,5 +20,4 @@ package media
 
 // API provides an interface for parsing, storing, and retrieving media objects like photos and videos
 type API interface {
-	
 }
diff --git a/pkg/mastotypes/README.md b/pkg/mastotypes/README.md
new file mode 100644
index 000000000..38f9e89c4
--- /dev/null
+++ b/pkg/mastotypes/README.md
@@ -0,0 +1,5 @@
+# Mastotypes
+
+This package contains Go types/structs for Mastodon's REST API.
+
+See [here](https://docs.joinmastodon.org/methods/apps/).
diff --git a/pkg/mastotypes/model/account.go b/pkg/mastotypes/model/account.go
new file mode 100644
index 000000000..4de7f4d19
--- /dev/null
+++ b/pkg/mastotypes/model/account.go
@@ -0,0 +1,4 @@
+package mastotypes
+
+type Account struct {
+}
diff --git a/pkg/mastotypes/model/application.go b/pkg/mastotypes/model/application.go
new file mode 100644
index 000000000..d2f894306
--- /dev/null
+++ b/pkg/mastotypes/model/application.go
@@ -0,0 +1,29 @@
+/*
+   GoToSocial
+   Copyright (C) 2021 GoToSocial Authors admin@gotosocial.org
+
+   This program is free software: you can redistribute it and/or modify
+   it under the terms of the GNU Affero General Public License as published by
+   the Free Software Foundation, either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU Affero General Public License for more details.
+
+   You should have received a copy of the GNU Affero General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+package mastotypes
+
+// Application represents a mastodon-api Application, as defined here: https://docs.joinmastodon.org/entities/application/
+type Application struct {
+	// The name of your application.
+	Name string `json:"name"`
+	// The website associated with your application (url)
+	Website string `json:"website"`
+	// Used for Push Streaming API. Returned with POST /api/v1/apps. Equivalent to https://docs.joinmastodon.org/entities/pushsubscription/#server_key
+	VapidKey string `json:"vapid_key"`
+}
diff --git a/pkg/mastotypes/model/attachment.go b/pkg/mastotypes/model/attachment.go
new file mode 100644
index 000000000..4d4d0955a
--- /dev/null
+++ b/pkg/mastotypes/model/attachment.go
@@ -0,0 +1,96 @@
+/*
+   GoToSocial
+   Copyright (C) 2021 GoToSocial Authors admin@gotosocial.org
+
+   This program is free software: you can redistribute it and/or modify
+   it under the terms of the GNU Affero General Public License as published by
+   the Free Software Foundation, either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU Affero General Public License for more details.
+
+   You should have received a copy of the GNU Affero General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+package mastotypes
+
+import "mime/multipart"
+
+// AttachmentRequest represents the form data parameters submitted by a client during a media upload request.
+// See: https://docs.joinmastodon.org/methods/statuses/media/
+type AttachmentRequest struct {
+	File        *multipart.FileHeader `form:"file"`
+	Thumbnail   *multipart.FileHeader `form:"thumbnail"`
+	Description string                `form:"description"`
+	Focus       string                `form:"focus"`
+}
+
+// Attachment represents the object returned to a client after a successful media upload request.
+// See: https://docs.joinmastodon.org/methods/statuses/media/
+type Attachment struct {
+	// The ID of the attachment in the database.
+	ID string `json:"id"`
+	// The type of the attachment.
+	// 	unknown = unsupported or unrecognized file type.
+	// 	image = Static image.
+	// 	gifv = Looping, soundless animation.
+	// 	video = Video clip.
+	// 	audio = Audio track.
+	Type string `json:"type"`
+	// The location of the original full-size attachment.
+	URL string `json:"url"`
+	// The location of a scaled-down preview of the attachment.
+	PreviewURL string `json:"preview_url"`
+	// The location of the full-size original attachment on the remote website.
+	RemoteURL string `json:"remote_url,omitempty"`
+	// A shorter URL for the attachment.
+	TextURL string `json:"text_url,omitempty"`
+	// Metadata returned by Paperclip.
+	// May contain subtrees small and original, as well as various other top-level properties.
+	// More importantly, there may be another top-level focus Hash object as of 2.3.0, with coordinates can be used for smart thumbnail cropping.
+	// See https://docs.joinmastodon.org/methods/statuses/media/#focal-points points for more.
+	Meta MediaMeta `json:"meta,omitempty"`
+	// Alternate text that describes what is in the media attachment, to be used for the visually impaired or when media attachments do not load.
+	Description string `json:"description,omitempty"`
+	// A hash computed by the BlurHash algorithm, for generating colorful preview thumbnails when media has not been downloaded yet.
+	// See https://github.com/woltapp/blurhash
+	Blurhash string `json:"blurhash,omitempty"`
+}
+
+// MediaMeta describes the returned media
+type MediaMeta struct {
+	Length        string          `json:"length,omitempty"`
+	Duration      float32         `json:"duration,omitempty"`
+	FPS           uint16          `json:"fps,omitempty"`
+	Size          string          `json:"size,omitempty"`
+	Width         int             `json:"width,omitempty"`
+	Height        int             `json:"height,omitempty"`
+	Aspect        float32         `json:"aspect,omitempty"`
+	AudioEncode   string          `json:"audio_encode,omitempty"`
+	AudioBitrate  string          `json:"audio_bitrate,omitempty"`
+	AudioChannels string          `json:"audio_channels,omitempty"`
+	Original      MediaDimensions `json:"original"`
+	Small         MediaDimensions `json:"small,omitempty"`
+	Focus         MediaFocus      `json:"focus,omitempty"`
+}
+
+// MediaFocus describes the focal point of a piece of media. It should be returned to the caller as part of MediaMeta.
+type MediaFocus struct {
+	X float32 `json:"x"` // should be between -1 and 1
+	Y float32 `json:"y"` // should be between -1 and 1
+}
+
+// MediaDimensions describes the physical properties of a piece of media. It should be returned to the caller as part of MediaMeta.
+type MediaDimensions struct {
+	Width     int     `json:"width,omitempty"`
+	Height    int     `json:"height,omitempty"`
+	FrameRate string  `json:"frame_rate,omitempty"`
+	Duration  float32 `json:"duration,omitempty"`
+	Bitrate   int     `json:"bitrate,omitempty"`
+	Size      string  `json:"size,omitempty"`
+	Aspect    float32 `json:"aspect,omitempty"`
+}
diff --git a/pkg/mastotypes/model/card.go b/pkg/mastotypes/model/card.go
new file mode 100644
index 000000000..cddc42d5b
--- /dev/null
+++ b/pkg/mastotypes/model/card.go
@@ -0,0 +1,22 @@
+/*
+   GoToSocial
+   Copyright (C) 2021 GoToSocial Authors admin@gotosocial.org
+
+   This program is free software: you can redistribute it and/or modify
+   it under the terms of the GNU Affero General Public License as published by
+   the Free Software Foundation, either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU Affero General Public License for more details.
+
+   You should have received a copy of the GNU Affero General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+package mastotypes
+
+type Card struct {
+}
diff --git a/pkg/mastotypes/model/emoji.go b/pkg/mastotypes/model/emoji.go
new file mode 100644
index 000000000..ba666023e
--- /dev/null
+++ b/pkg/mastotypes/model/emoji.go
@@ -0,0 +1,22 @@
+/*
+   GoToSocial
+   Copyright (C) 2021 GoToSocial Authors admin@gotosocial.org
+
+   This program is free software: you can redistribute it and/or modify
+   it under the terms of the GNU Affero General Public License as published by
+   the Free Software Foundation, either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU Affero General Public License for more details.
+
+   You should have received a copy of the GNU Affero General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+package mastotypes
+
+type Emoji struct {
+}
diff --git a/pkg/mastotypes/model/mention.go b/pkg/mastotypes/model/mention.go
new file mode 100644
index 000000000..81a593d99
--- /dev/null
+++ b/pkg/mastotypes/model/mention.go
@@ -0,0 +1,31 @@
+/*
+   GoToSocial
+   Copyright (C) 2021 GoToSocial Authors admin@gotosocial.org
+
+   This program is free software: you can redistribute it and/or modify
+   it under the terms of the GNU Affero General Public License as published by
+   the Free Software Foundation, either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU Affero General Public License for more details.
+
+   You should have received a copy of the GNU Affero General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+package mastotypes
+
+// Mention represents the mastodon-api mention type, as documented here: https://docs.joinmastodon.org/entities/mention/
+type Mention struct {
+	// The account id of the mentioned user.
+	ID string `json:"id"`
+	// The username of the mentioned user.
+	Username string `json:"username"`
+	// The location of the mentioned user's profile.
+	URL string `json:"url"`
+	// The webfinger acct: URI of the mentioned user. Equivalent to username for local users, or username@domain for remote users.
+	Acct string `json:"acct"`
+}
diff --git a/pkg/mastotypes/model/poll.go b/pkg/mastotypes/model/poll.go
new file mode 100644
index 000000000..799fe35bf
--- /dev/null
+++ b/pkg/mastotypes/model/poll.go
@@ -0,0 +1,35 @@
+/*
+   GoToSocial
+   Copyright (C) 2021 GoToSocial Authors admin@gotosocial.org
+
+   This program is free software: you can redistribute it and/or modify
+   it under the terms of the GNU Affero General Public License as published by
+   the Free Software Foundation, either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU Affero General Public License for more details.
+
+   You should have received a copy of the GNU Affero General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+package mastotypes
+
+type Poll struct {
+}
+
+// PollRequest represents a mastodon-api poll attached to a status POST request, as defined here: https://docs.joinmastodon.org/methods/statuses/
+// It should be used at the path https://mastodon.example/api/v1/statuses
+type PollRequest struct {
+	// Array of possible answers. If provided, media_ids cannot be used, and poll[expires_in] must be provided.
+	Options []string `form:"options"`
+	// Duration the poll should be open, in seconds. If provided, media_ids cannot be used, and poll[options] must be provided.
+	ExpiresIn int `form:"expires_in"`
+	// Allow multiple choices?
+	Multiple bool `form:"multiple"`
+	// Hide vote counts until the poll ends?
+	HideTotals bool `form:"hide_totals"`
+}
diff --git a/pkg/mastotypes/model/status.go b/pkg/mastotypes/model/status.go
new file mode 100644
index 000000000..e98504e27
--- /dev/null
+++ b/pkg/mastotypes/model/status.go
@@ -0,0 +1,110 @@
+/*
+   GoToSocial
+   Copyright (C) 2021 GoToSocial Authors admin@gotosocial.org
+
+   This program is free software: you can redistribute it and/or modify
+   it under the terms of the GNU Affero General Public License as published by
+   the Free Software Foundation, either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU Affero General Public License for more details.
+
+   You should have received a copy of the GNU Affero General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+package mastotypes
+
+// StatusRequest represents a mastodon-api status POST request, as defined here: https://docs.joinmastodon.org/methods/statuses/
+// It should be used at the path https://mastodon.example/api/v1/statuses
+type StatusRequest struct {
+	// Text content of the status. If media_ids is provided, this becomes optional. Attaching a poll is optional while status is provided.
+	Status string `form:"status"`
+	// Array of Attachment ids to be attached as media. If provided, status becomes optional, and poll cannot be used.
+	MediaIDs []string `form:"media_ids"`
+	// Poll to include with this status.
+	Poll *PollRequest `form:"poll"`
+	// ID of the status being replied to, if status is a reply
+	InReplyToID string `form:"in_reply_to_id"`
+	// Mark status and attached media as sensitive?
+	Sensitive bool `form:"sensitive"`
+	// Text to be shown as a warning or subject before the actual content. Statuses are generally collapsed behind this field.
+	SpoilerText string `form:"spoiler_text"`
+	// Visibility of the posted status. Enumerable oneOf public, unlisted, private, direct.
+	Visibility string `form:"visibility"`
+	// ISO 8601 Datetime at which to schedule a status. Providing this paramter will cause ScheduledStatus to be returned instead of Status. Must be at least 5 minutes in the future.
+	ScheduledAt string `form:"scheduled_at"`
+	// ISO 639 language code for this status.
+	Language string `form:"language"`
+}
+
+// Status represents a mastodon-api Status type, as defined here: https://docs.joinmastodon.org/entities/status/
+type Status struct {
+	// ID of the status in the database.
+	ID string `json:"id"`
+	// The date when this status was created (ISO 8601 Datetime)
+	CreatedAt string `json:"created_at"`
+	// ID of the status being replied.
+	InReplyToID string `json:"in_reply_to_id"`
+	// ID of the account being replied to.
+	InReplyToAccountID string `json:"in_reply_to_account_id"`
+	// Is this status marked as sensitive content?
+	Sensitive bool `json:"sensitive"`
+	// Subject or summary line, below which status content is collapsed until expanded.
+	SpoilerText string `json:"spoiler_text"`
+	// Visibility of this status.
+	// 	public = Visible to everyone, shown in public timelines.
+	// 	unlisted = Visible to public, but not included in public timelines.
+	// 	private = Visible to followers only, and to any mentioned users.
+	// 	direct = Visible only to mentioned users.
+	Visibility string `json:"visibility"`
+	// Primary language of this status. (ISO 639 Part 1 two-letter language code)
+	Language string `json:"language"`
+	// URI of the status used for federation.
+	URI string `json:"uri"`
+	// A link to the status's HTML representation.
+	URL string `json:"url"`
+	// How many replies this status has received.
+	RepliesCount int `json:"replies_count"`
+	// How many boosts this status has received.
+	ReblogsCount int `json:"reblogs_count"`
+	// How many favourites this status has received.
+	FavouritesCount int `json:"favourites_count"`
+	// Have you favourited this status?
+	Favourited bool `json:"favourited"`
+	// Have you boosted this status?
+	Reblogged bool `json:"reblogged"`
+	// Have you muted notifications for this status's conversation?
+	Muted bool `json:"muted"`
+	// Have you bookmarked this status?
+	Bookmarked bool `json:"bookmarked"`
+	// Have you pinned this status? Only appears if the status is pinnable.
+	Pinned bool `json:"pinned"`
+	// HTML-encoded status content.
+	Content string `json:"content"`
+	// The status being reblogged.
+	Reblog *Status `json:"reblog"`
+	// The application used to post this status.
+	Application *Application `json:"application"`
+	// The account that authored this status.
+	Account *Account `json:"account"`
+	// Media that is attached to this status.
+	MediaAttachments []Attachment `json:"media_attachments"`
+	// Mentions of users within the status content.
+	Mentions []Mention `json:"mentions"`
+	// Hashtags used within the status content.
+	Tags []Tag `json:"tags"`
+	// Custom emoji to be used when rendering status content.
+	Emojis []Emoji `json:"emojis"`
+	// Preview card for links included within status content.
+	Card *Card `json:"card"`
+	// The poll attached to the status.
+	Poll *Poll `json:"poll"`
+	// Plain-text source of a status. Returned instead of content when status is deleted,
+	// so the user may redraft from the source text without the client having to reverse-engineer
+	// the original text from the HTML content.
+	Text string `json:"text"`
+}
diff --git a/pkg/mastotypes/model/tag.go b/pkg/mastotypes/model/tag.go
new file mode 100644
index 000000000..d34314b0b
--- /dev/null
+++ b/pkg/mastotypes/model/tag.go
@@ -0,0 +1,22 @@
+/*
+   GoToSocial
+   Copyright (C) 2021 GoToSocial Authors admin@gotosocial.org
+
+   This program is free software: you can redistribute it and/or modify
+   it under the terms of the GNU Affero General Public License as published by
+   the Free Software Foundation, either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU Affero General Public License for more details.
+
+   You should have received a copy of the GNU Affero General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+package mastotypes
+
+type Tag struct {
+}