diff --git a/helm/api/Chart.yaml b/helm/api/Chart.yaml
index a072fe46dd74f5a265d5ba48f84125527d5a64a3..cdf0ae7fe01fbcc05dffdb5a5bba6a9eb61bbcbd 100644
--- a/helm/api/Chart.yaml
+++ b/helm/api/Chart.yaml
@@ -15,10 +15,10 @@ type: application
 # This is the chart version. This version number should be incremented each time you make changes
 # to the chart and its templates, including the app version.
 # Versions are expected to follow Semantic Versioning (https://semver.org/)
-version: 0.3.2
+version: 0.3.3
 
 # This is the version number of the application being deployed. This version number should be
 # incremented each time you make changes to the application. Versions are not expected to
 # follow Semantic Versioning. They should reflect the version the application is using.
 # It is recommended to use it with quotes.
-appVersion: "2.3.0"
+appVersion: "2.4.0"
diff --git a/package.json b/package.json
index a79e183827866d56bc1e0703ba6a8c2a255f4255..c6f5cd0b490bb49ddd843577df4defe81fa09e15 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
 {
   "name": "jetsam-api",
-  "version": "2.3.0",
+  "version": "2.4.0",
   "description": "The Jetsam App API Server",
   "main": "server.js",
   "scripts": {
diff --git a/src/core/errors/InputValidationError.js b/src/core/errors/InputValidationError.js
index 1a97aef27efdefed093e24b1bb7b66e11450238b..115cb4ded35d53d773cee4a574467e3621967155 100644
--- a/src/core/errors/InputValidationError.js
+++ b/src/core/errors/InputValidationError.js
@@ -4,4 +4,22 @@ module.exports = class InputValidationError extends HttpError {
 	constructor(fields) {
 		super(422, 'The supplied input was not valid', { fields })
 	}
+
+	toJSON() {
+		return {
+			status: this._status,
+			message: this._message,
+			...this._payload,
+		}
+	}
+
+	respondTo(ctx) {
+		ctx.status = this._status
+		ctx.body = {
+			errors: {
+				general: [this._message],
+				...this._payload,
+			}
+		}
+	}
 }
diff --git a/src/database/models/Metric.js b/src/database/models/Metric.js
index a47f28aa6601a9306d12911bff2c0b131d5a1754..d19aadd9ecc25a6a70bca01dab8322e98a02117d 100644
--- a/src/database/models/Metric.js
+++ b/src/database/models/Metric.js
@@ -4,6 +4,18 @@ const BaseModel = require('./BaseModel')
 const metricConversionMap = {
 	trash: Number,
 	numeric: Number,
+	'pm2.5': Number,
+	co2_ppm: Number,
+	wind_mph: Number,
+	wind_kph: Number,
+	temp_c: Number,
+	temp_f: Number,
+	temp_k: Number,
+	pressure_pa: Number,
+	pressure_mbar: Number,
+	rain_mm: Number,
+	custom_string: String,
+	custom_number: Number,
 }
 
 class Metric extends BaseModel {
diff --git a/src/domain/auth/AuthenticationService.js b/src/domain/auth/AuthenticationService.js
index 6ad4ea3e722b8b0a677d9dd03d69eceffeb97c24..57d17f8766a6131365d697c52f5d6fc2f7e739aa 100644
--- a/src/domain/auth/AuthenticationService.js
+++ b/src/domain/auth/AuthenticationService.js
@@ -77,8 +77,11 @@ module.exports = class AuthenticationService extends ContextualModule {
 			}
 
 			if (accessToken == null) {
-				console.log('oidc token', token)
 				accessToken = await this.ctx.services['auth.oidc'].withProvider(provider => provider.AccessToken.find(token))
+				if (accessToken) {
+					const user = await User.findByPk(accessToken.accountId)
+					accessToken.User = user
+				}
 			} else {
 				if (accessToken?.User) {
 					this.authenticateAs(accessToken.User, 'oauth_token', accessToken)
diff --git a/src/domain/auth/oidc/DBAdapter.js b/src/domain/auth/oidc/DBAdapter.js
index baf2d7088c2491e84eb8cfc36377fad031da8930..797fa27e51fd989da4a31a8b2b8439c5f4504b3e 100644
--- a/src/domain/auth/oidc/DBAdapter.js
+++ b/src/domain/auth/oidc/DBAdapter.js
@@ -2,7 +2,9 @@ const moment = require('moment')
 const { OIDCEntity, User, OAuthClient, AccessToken, RefreshToken, sequelize, Sequelize } = require('database/models')
 const debug = require('debug')('server:auth:oidc:adapter')
 
-const key = (id, name) => `urn:jetsam:resources:oidc:${name}/${id}`
+const key = (id, name) => {
+	return `urn:jetsam:resources:oidc:${name}/${id}`;
+}
 
 class DBAdapter {
 	constructor(name, { model = OIDCEntity } = {}) {
@@ -16,6 +18,7 @@ class DBAdapter {
 		const oidc = await this.model.upsert({
 			id: key(id, this.name),
 			grant_id: data.grantId ?? null,
+			related_user_id: data.accountId ?? null,
 			user_code: data.user_code ?? null,
 			uid: data.uid ?? null,
 			data,
diff --git a/src/domain/auth/oidc/OIDCServer.js b/src/domain/auth/oidc/OIDCServer.js
index 0c59af73298b4b8077554921a84589ad0a225663..1d5fe26a08a5e0eed0c027f18fcd1fe40b858ffb 100644
--- a/src/domain/auth/oidc/OIDCServer.js
+++ b/src/domain/auth/oidc/OIDCServer.js
@@ -8,7 +8,7 @@ module.exports = async function createOIDCServer() {
 	const {validScopes} = require("../OAuthFlow");
 
 	debug(`Creating OIDC Provider with base ${config('app.host.web')}`)
-	const provider = new Provider( /*config('app.host.web') + 'oidc/' */ 'http://trash.4l2.uk/oidc/', {
+	const provider = new Provider(config('app.host.web') + 'oidc/', {
 		clients: [
 			{
 				client_id: 'kbyuFDidLLm280LIwVFiazOqjO3ty8KH',
diff --git a/src/http/controllers/api/content.js b/src/http/controllers/api/content.js
index 0bf47a95f53516a8ea61e1641e83ed85de54619b..5db0f4cd00fd50c5fba288c6a737ec5ffad3577a 100644
--- a/src/http/controllers/api/content.js
+++ b/src/http/controllers/api/content.js
@@ -2,6 +2,7 @@ const HttpError = require('core/errors/HttpError')
 const { Sequelize, sequelize, Metric } = require('database/models')
 const { Op } = Sequelize
 const moment = require('moment')
+const InputValidationError = require("../../../core/errors/InputValidationError");
 
 exports.postMetric = async ctx => {
 	const allowedTypes = new Set(Metric.getSupportedMetricTypes())
@@ -20,19 +21,16 @@ exports.postMetric = async ctx => {
 						transaction: t,
 						ctx,
 					})
-
 					metrics.push(result)
 				}
 			})
 		} catch (e) {
 			console.log(e)
-
-			throw new HttpError({
-				status: 400,
-				code: 'MTR-001',
-				title: 'Failed to save metric',
-				description: 'Something went wrong trying to save the metric',
-			})
+			if (e instanceof HttpError) {
+				throw e
+			} else {
+				throw new HttpError(500, 'Failed to save metric')
+			}
 		}
 
 		ctx.body = {
@@ -56,12 +54,7 @@ const save = async (
 		location.longitude == null ||
 		location.latitude == null
 	) {
-		throw new HttpError({
-			status: 400,
-			code: 'MTR-001',
-			title: 'Invalid Metric',
-			description: 'A location must be provided for metrics',
-		})
+		throw new HttpError(422, 'A location must be provided for metrics')
 	}
 
 	if (allowedTypes.has(type)) {
@@ -73,12 +66,7 @@ const save = async (
 			transaction,
 		)
 	} else {
-		throw new HttpError({
-			status: 400,
-			code: 'MTR-002',
-			title: 'Invalid Metric',
-			description: `${type} is not a supported type`,
-		})
+		throw new HttpError(422, `${type} is not a supported type`)
 	}
 }
 
@@ -134,7 +122,13 @@ exports.getWithin = async ctx => {
 		format = 'full',
 	} = ctx.request.query
 
-	const pointBufferData = within ? bufferFromPolygon(within) : bufferFromCorners(point_from, point_to)
+	let pointBufferData = null
+
+	try {
+		pointBufferData = within ? bufferFromPolygon(within) : bufferFromCorners(point_from, point_to)
+	} catch (e) {
+		throw new InputValidationError(['within', 'point_from', 'point_to'])
+	}
 	const pointBuffer = pointBufferData.map(pb => pb.map(Number).join(' ')).join(',')
 
 	const fromDate = moment.utc(date_from)
@@ -142,7 +136,6 @@ exports.getWithin = async ctx => {
 
 	const metricTypes = splitString(types)
 
-
 	const query =
 		format === 'marker'
 			? ctx.services['data.metrics'].queryAggregate
diff --git a/src/http/middleware/DeviceProperties.js b/src/http/middleware/DeviceProperties.js
index ae8f9578b6bf2aa6dd2c3c7d250323538daf2dc5..cbe1fee27a05b78bc92b8a70d6ee600e4af48d42 100644
--- a/src/http/middleware/DeviceProperties.js
+++ b/src/http/middleware/DeviceProperties.js
@@ -1,7 +1,7 @@
 exports.extractDevice = async (ctx, next) => {
-	const deviceId = ctx.get('x-request-device')
-	const platform = ctx.get('x-request-platform')
-	const rawSlug = ctx.get('x-request-slug')
+	const deviceId = ctx.get('x-request-device') || ctx.get('Request-Device')
+	const platform = ctx.get('x-request-platform') || ctx.get('Request-Platform')
+	const rawSlug = ctx.get('x-request-slug') || ctx.get('Request-Info')
 
 	const slug = rawSlug ? Buffer.from(rawSlug, 'base64').toString('utf-8') : null
 
diff --git a/src/http/routers/routes_v2.js b/src/http/routers/routes_v2.js
index 7c4683decf9c17d75353189f3c77c6d882cb18fc..5e1c91183b3fcf34d8450ad130459c13150daf15 100644
--- a/src/http/routers/routes_v2.js
+++ b/src/http/routers/routes_v2.js
@@ -22,6 +22,7 @@ router.get(
 	ctx =>
 		(ctx.body = {
 			name: 'Jetsam Data API',
+			version: require('../../../package.json').version,
 			prefix: ctx.path,
 		}),
 )