diff --git a/packages/component-manuscript-manager/src/TechnicalChecks.js b/packages/component-manuscript-manager/src/TechnicalChecks.js
new file mode 100644
index 0000000000000000000000000000000000000000..67e50c27bb0fdc03bc85a42670a1495d523c1994
--- /dev/null
+++ b/packages/component-manuscript-manager/src/TechnicalChecks.js
@@ -0,0 +1,30 @@
+const bodyParser = require('body-parser')
+
+const TechnicalChecks = app => {
+  app.use(bodyParser.json())
+  const basePath = '/api/collections/:collectionId/status'
+  const routePath = './routes/technicalChecks'
+
+  /**
+   * @api {patch} /api/collections/:collectionId/status Take a EQS or EQA decision.
+   * @apiGroup TechnicalChecks
+   * @apiParam {collectionId} collectionId Collection id
+   *   * @apiParamExample {json} Body
+   *    {
+   *      "token": "12345",
+   *      "agree": true,
+   *      "step": "EQS"
+   *    }
+   * @apiSuccessExample {json} Success
+   *   HTTP/1.1 200 OK
+   *   {
+   *   }
+   * @apiErrorExample {json} Invite user errors
+   *    HTTP/1.1 400 Bad Request
+   *    HTTP/1.1 404 Not Found
+   *    HTTP/1.1 500 Internal Server Error
+   */
+  app.patch(basePath, require(`${routePath}/patch`)(app.locals.models))
+}
+
+module.exports = TechnicalChecks
diff --git a/packages/component-manuscript-manager/src/routes/technicalChecks/patch.js b/packages/component-manuscript-manager/src/routes/technicalChecks/patch.js
new file mode 100644
index 0000000000000000000000000000000000000000..e569f8a7a07c7066eb32866a054280ed70a6df3e
--- /dev/null
+++ b/packages/component-manuscript-manager/src/routes/technicalChecks/patch.js
@@ -0,0 +1,48 @@
+const { get, isEmpty } = require('lodash')
+const { services } = require('pubsweet-component-helper-service')
+
+const TECHNICAL_STEPS = {
+  EQS: 'eqs',
+  EQA: 'eqa',
+}
+
+const setNewStatus = (step, agree) => {
+  if (step === TECHNICAL_STEPS.EQS) {
+    return agree ? 'submitted' : 'rejected'
+  } else if (step === TECHNICAL_STEPS.EQA) {
+    return agree ? 'accepted' : 'rejected'
+  }
+}
+
+module.exports = ({ Collection }) => async (req, res) => {
+  const { collectionId } = req.params
+  const { token, agree, step } = req.body
+
+  try {
+    const collection = await Collection.find(collectionId)
+    const technicalCheckToken = get(collection, `technicalChecks.token`)
+
+    if (isEmpty(technicalCheckToken)) {
+      return res.status(400).json({
+        error: `Manuscript already handled.`,
+      })
+    }
+
+    if (technicalCheckToken !== token) {
+      return res.status(400).json({
+        error: `Invalid token.`,
+      })
+    }
+
+    delete collection.technicalChecks.token
+    collection.status = setNewStatus(step, agree)
+    await collection.save()
+
+    return res.status(200).json(collection)
+  } catch (e) {
+    const notFoundError = await services.handleNotFoundError(e, 'Item')
+    return res.status(notFoundError.status).json({
+      error: notFoundError.message,
+    })
+  }
+}
diff --git a/packages/component-modal/src/components/withModal.js b/packages/component-modal/src/components/withModal.js
index 35bb923623393be380a2af970af01ada1733a88e..685cc748a2b10cbb55dd7ebdfaa4496ec8f3442b 100644
--- a/packages/component-modal/src/components/withModal.js
+++ b/packages/component-modal/src/components/withModal.js
@@ -28,6 +28,7 @@ const withModal = mapperFn => BaseComponent =>
       hideModal,
       modalProps,
       modalError,
+      isFetching,
       setModalError,
       modalsVisibility,
       ...rest
@@ -39,6 +40,7 @@ const withModal = mapperFn => BaseComponent =>
             {...modalProps}
             component={Component}
             hideModal={hideModal}
+            isFetching={isFetching}
             modalError={modalError}
             overlayColor={overlayColor}
             setModalError={setModalError}
diff --git a/packages/components-faraday/src/components/UIComponents/EQSDecisionPage.js b/packages/components-faraday/src/components/UIComponents/EQSDecisionPage.js
index 79651f8428c8ddbf7197b4826e7402abd4c4bbc5..4e3f753ed0e2a52df80411ea6cee56c71a5f5352 100644
--- a/packages/components-faraday/src/components/UIComponents/EQSDecisionPage.js
+++ b/packages/components-faraday/src/components/UIComponents/EQSDecisionPage.js
@@ -1,5 +1,6 @@
 import React from 'react'
 import { isEmpty } from 'lodash'
+import { connect } from 'react-redux'
 import { Button } from '@pubsweet/ui'
 import styled from 'styled-components'
 import { th } from '@pubsweet/ui-toolkit'
@@ -18,11 +19,21 @@ import {
 
 import { Err, Subtitle } from './FormItems'
 import { parseSearchParams } from '../utils'
+import {
+  technicalDecision,
+  technicalCheckFetcing,
+} from '../../redux/technicalCheck'
 
-const EQSDecisionPage = ({ id, eqsDecision, errorMessage, successMessage }) => (
+const EQSDecisionPage = ({
+  params,
+  eqsDecision,
+  errorMessage,
+  successMessage,
+}) => (
   <Root>
     <Title>
-      Take a decision for manuscript <b>{id}</b>.
+      Take a decision for manuscript <b>{params.customId}</b>.
+      {params.collectionId}
     </Title>
     {errorMessage && <Err>{errorMessage}</Err>}
     {successMessage && <Subtitle>{successMessage}</Subtitle>}
@@ -40,17 +51,30 @@ const EQSDecisionPage = ({ id, eqsDecision, errorMessage, successMessage }) => (
 
 export default compose(
   setDisplayName('EQS Decision page'),
-  withModal(() => ({
+  connect(
+    state => ({
+      isFetching: technicalCheckFetcing(state),
+    }),
+    { technicalDecision },
+  ),
+  withModal(({ isFetching }) => ({
+    isFetching,
     modalComponent: ConfirmationModal,
   })),
-  withState('id', 'setId', null),
+  withState('params', 'setParams', {
+    token: null,
+    customId: null,
+    collectionId: null,
+  }),
   withState('successMessage', 'setSuccess', ''),
   withState('errorMessage', 'setError', ''),
   lifecycle({
     componentDidMount() {
-      const { location, setId } = this.props
-      const { customId } = parseSearchParams(location.search)
-      setId(customId)
+      const { location, setParams } = this.props
+      const { customId, collectionId, token } = parseSearchParams(
+        location.search,
+      )
+      setParams({ customId, collectionId, token })
     },
   }),
   withHandlers({
@@ -59,19 +83,32 @@ export default compose(
       showModal,
       hideModal,
       setSuccess,
+      technicalDecision,
+      params: { collectionId, token },
     }) => decision => () => {
       showModal({
         title: `Are you sure you want to ${
           decision ? 'accept' : 'reject'
         } this EQS package?`,
         onConfirm: () => {
-          setSuccess('Manuscript accepted.')
-          hideModal()
-        },
-        onCancel: () => {
-          setError('There was an error. Please try again.')
-          hideModal()
+          technicalDecision({
+            step: 'eqs',
+            agree: decision,
+            collectionId,
+            token,
+          })
+            .then(() => {
+              setSuccess(
+                'Manuscript accepted. Thank you for your technical check!',
+              )
+              hideModal()
+            })
+            .catch(() => {
+              setError('There was an error. Please try again.')
+              hideModal()
+            })
         },
+        onCancel: hideModal,
       })
     },
   }),
diff --git a/packages/components-faraday/src/index.js b/packages/components-faraday/src/index.js
index b40accf6eaee709b192b849b8ab1290c47363428..be69a5315674890955a7de5fa07fcbfdd22bf9a5 100644
--- a/packages/components-faraday/src/index.js
+++ b/packages/components-faraday/src/index.js
@@ -7,6 +7,7 @@ module.exports = {
       editors: () => require('./redux/editors').default,
       files: () => require('./redux/files').default,
       reviewers: () => require('./redux/reviewers').default,
+      technicalCheck: () => require('./redux/technicalCheck').default,
     },
   },
 }
diff --git a/packages/components-faraday/src/redux/index.js b/packages/components-faraday/src/redux/index.js
index 9e0c549f2498178e77b7c129e3ce4f0ee5c53bae..c7fd43a9557173a35047de82ce6f5e64f18a8e03 100644
--- a/packages/components-faraday/src/redux/index.js
+++ b/packages/components-faraday/src/redux/index.js
@@ -3,4 +3,5 @@ export { default as errors } from './errors'
 export { default as authors } from './authors'
 export { default as editors } from './editors'
 export { default as reviewers } from './reviewers'
+export { default as technicalCheck } from './technicalCheck'
 export { default as recommendations } from './recommendations'
diff --git a/packages/components-faraday/src/redux/technicalCheck.js b/packages/components-faraday/src/redux/technicalCheck.js
new file mode 100644
index 0000000000000000000000000000000000000000..8cb3a074bf9eed5220f56f7f476a7510cda8dc57
--- /dev/null
+++ b/packages/components-faraday/src/redux/technicalCheck.js
@@ -0,0 +1,67 @@
+import { get } from 'lodash'
+import { update } from 'pubsweet-client/src/helpers/api'
+
+const DECISION_REQUEST = 'tc/DECISION_REQUEST'
+const DECISION_SUCCESS = 'tc/DECISION_SUCCESS'
+const DECISION_ERROR = 'tc/DECISION_ERROR'
+
+const decisionRequest = () => ({
+  type: DECISION_REQUEST,
+})
+
+const decisionSuccess = () => ({
+  type: DECISION_SUCCESS,
+})
+
+const decisionError = error => ({
+  type: DECISION_ERROR,
+  error,
+})
+
+export const technicalDecision = ({
+  step,
+  agree,
+  token,
+  collectionId,
+}) => dispatch => {
+  dispatch(decisionRequest())
+  return update(`/collections/${collectionId}/status`, {
+    step,
+    token,
+    agree,
+  }).then(
+    r => {
+      dispatch(decisionSuccess())
+      return r
+    },
+    err => {
+      dispatch(decisionError(err))
+      throw err
+    },
+  )
+}
+
+export const technicalCheckFetcing = state =>
+  get(state, 'technicalCheck.fetching', false)
+
+export default (state = {}, action = {}) => {
+  switch (action.type) {
+    case DECISION_REQUEST:
+      return {
+        ...state,
+        fetching: true,
+      }
+    case DECISION_SUCCESS:
+      return {
+        error: null,
+        fetching: false,
+      }
+    case DECISION_ERROR:
+      return {
+        error: action.error,
+        fetching: false,
+      }
+    default:
+      return state
+  }
+}