diff --git a/api/v0/index.js b/api/v0/index.js
new file mode 100644
index 0000000..c762d80
--- /dev/null
+++ b/api/v0/index.js
@@ -0,0 +1,123 @@
+/*
+Copyright (C) 2021 Yarmo Mackenbach
+
+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 .
+
+Also add information on how to contact you by electronic and paper mail.
+
+If your software can interact with users remotely through a computer network,
+you should also make sure that it provides a way for users to get its source.
+For example, if your program is a web application, its interface could display
+a "Source" link that leads users to an archive of the code. There are many
+ways you could offer source, and different solutions will be better for different
+programs; see section 13 for the specific requirements.
+
+You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary. For
+more information on this, and how to apply and follow the GNU AGPL, see .
+*/
+const router = require('express').Router()
+const { check, validationResult } = require('express-validator')
+const kx = require('../../server')
+
+const doVerification = async (data) => {
+ let promises = []
+ let results = []
+
+ for (let iUser = 0; iUser < data.keyData.users.length; iUser++) {
+ const user = data.keyData.users[iUser];
+
+ for (let iClaim = 0; iClaim < user.claims.length; iClaim++) {
+ const claim = user.claims[iClaim];
+
+ promises.push(
+ new Promise(async (resolve, reject) => {
+ await claim.verify()
+ results.push([iUser, iClaim, claim])
+ resolve()
+ })
+ )
+ }
+ }
+ await Promise.all(promises)
+
+ results.forEach(result => {
+ data.keyData.users[result[0]].claims[result[1]] = result[2]
+ })
+
+ return data
+}
+
+router.get('/profile/fetch',
+ check('query').exists(),
+ check('protocol').optional().toLowerCase().isIn(["hkp", "wkd"]),
+ check('doVerification').default(false).isBoolean().toBoolean(),
+ check('returnPublicKey').default(false).isBoolean().toBoolean(),
+ async (req, res) => {
+ const valRes = validationResult(req);
+ if (!valRes.isEmpty()) {
+ res.status(400).send(valRes)
+ return
+ }
+
+ // Generate profile
+ let data
+ switch (req.query.protocol) {
+ case 'wkd':
+ data = await kx.generateWKDProfile(req.query.query)
+ break;
+ case 'hkp':
+ data = await kx.generateHKPProfile(req.query.query)
+ break;
+ default:
+ if (req.query.query.includes('@')) {
+ data = await kx.generateWKDProfile(req.query.query)
+ } else {
+ data = await kx.generateHKPProfile(req.query.query)
+ }
+ break;
+ }
+
+ // Return public key
+ if (req.query.returnPublicKey) {
+ data.keyData.key.data = data.key.publicKey
+ }
+ delete data.key
+
+ // Do verification
+ if (req.query.doVerification) {
+ data = await doVerification(data)
+ }
+
+ res.send(data)
+ }
+)
+
+router.get('/profile/verify',
+ check('data').exists().isJSON(),
+ async (req, res) => {
+ const valRes = validationResult(req);
+ if (!valRes.isEmpty()) {
+ res.status(400).send(valRes)
+ return
+ }
+
+ // Do verification
+ data = await doVerification(req.query.data)
+
+ res.send(data)
+ }
+)
+
+module.exports = router
diff --git a/index.js b/index.js
index d8659a3..1e4df78 100644
--- a/index.js
+++ b/index.js
@@ -66,6 +66,7 @@ app.use('/favicon.svg', express.static('favicon.svg'))
app.use('/robots.txt', express.static('robots.txt'))
app.use('/', require('./routes/main'))
+app.use('/api', require('./routes/api'))
app.use('/static', require('./routes/static'))
app.use('/util', require('./routes/util'))
app.use('/', require('./routes/profile'))
diff --git a/routes/api.js b/routes/api.js
new file mode 100644
index 0000000..352da6e
--- /dev/null
+++ b/routes/api.js
@@ -0,0 +1,34 @@
+/*
+Copyright (C) 2021 Yarmo Mackenbach
+
+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 .
+
+Also add information on how to contact you by electronic and paper mail.
+
+If your software can interact with users remotely through a computer network,
+you should also make sure that it provides a way for users to get its source.
+For example, if your program is a web application, its interface could display
+a "Source" link that leads users to an archive of the code. There are many
+ways you could offer source, and different solutions will be better for different
+programs; see section 13 for the specific requirements.
+
+You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary. For
+more information on this, and how to apply and follow the GNU AGPL, see .
+*/
+const router = require('express').Router()
+
+router.use('/0', require('../api/v0/index.js'))
+
+module.exports = router