Repository: moov-io/customers
Pull request #160 (2020-09-15 21:32:26)

PUT on account status should return updated Account
This PR returns the updated Account object along with the 200 instead of an empty body. I also moved the endpoint from an admin endpoint into a regular http section. In doing so, I removed `update.go` and the test in `update_test.go` and moved the test for updating an account status with the other tests in `router_test.go`.

codecov-commenter: # [Codecov](https://codecov.io/gh/moov-io/customers/pull/160?src=pr&el=h1) Report
> Merging [#160](https://codecov.io/gh/moov-io/customers/pull/160?src=pr&el=desc) into [master](https://codecov.io/gh/moov-io/customers/commit/ac1e785a808e3cdee5640be596b08660ab3a8302?el=desc) will **increase** coverage by `0.11%`.
> The diff coverage is `54.28%`.


```diff
@@            Coverage Diff             @@
##           master     #160      +/-   ##
==========================================
+ Coverage   64.58%   64.69%   +0.11%     
==========================================
  Files          43       41       -2     
  Lines        2493     2498       +5     
==========================================
+ Hits         1610     1616       +6     
+ Misses        616      614       -2     
- Partials      267      268       +1     
```


Patch:
diff --git a/api/admin.yaml b/api/admin.yaml
index 2588f49..6789c09 100644
--- a/api/admin.yaml
+++ b/api/admin.yaml
@@ -54,42 +54,6 @@ paths:
               schema:
                 type: string
                 example: v0.4.0
-  /customers/{customerID}/accounts/{accountID}/status:
-    put:
-      tags: [Customers]
-      summary: Update Account Status
-      description: Update the status for the specified accountID
-      operationId: updateAccountStatus
-      parameters:
-        - name: customerID
-          in: path
-          description: Customer ID
-          required: true
-          schema:
-            type: string
-            example: e210a9d6-d755-4455-9bd2-9577ea7e1081
-        - name: accountID
-          in: path
-          description: accountID of the Account to validate
-          required: true
-          schema:
-            type: string
-            example: b74d7c51
-      requestBody:
-        required: true
-        content:
-          application/json:
-            schema:
-              $ref: '#/components/schemas/UpdateAccountStatus'
-      responses:
-        '200':
-          description: Account status updated
-        '400':
-          description: See error message
-          content:
-            application/json:
-              schema:
-                $ref: 'https://raw.githubusercontent.com/moov-io/api/master/openapi-common.yaml#/components/schemas/Error'
   /customers/{customerID}/disclaimers:
     post:
       tags: [Customers]
@@ -193,12 +157,6 @@ components:
           type: string
           description: Either an error from checking Customers or good as a string.
           example: good
-    UpdateAccountStatus:
-      properties:
-        status:
-          $ref: 'https://raw.githubusercontent.com/moov-io/customers/master/api/client.yaml#/components/schemas/AccountStatus'
-      required:
-        - status
     CreateUserDisclaimer:
       properties:
         documentId:
diff --git a/api/client.yaml b/api/client.yaml
index 3d98d1d..565e6c8 100644
--- a/api/client.yaml
+++ b/api/client.yaml
@@ -619,6 +619,46 @@ paths:
             application/json:
               schema:
                 $ref: 'https://raw.githubusercontent.com/moov-io/api/master/openapi-common.yaml#/components/schemas/Error'
+  /customers/{customerID}/accounts/{accountID}/status:
+    put:
+      tags: [ Customers ]
+      summary: Update Account Status
+      description: Update the status for the specified accountID
+      operationId: updateAccountStatus
+      parameters:
+        - name: customerID
+          in: path
+          description: Customer ID
+          required: true
+          schema:
+            type: string
+            example: e210a9d6-d755-4455-9bd2-9577ea7e1081
+        - name: accountID
+          in: path
+          description: accountID of the Account to validate
+          required: true
+          schema:
+            type: string
+            example: b74d7c51
+      requestBody:
+        required: true
+        content:
+          application/json:
+            schema:
+              $ref: '#/components/schemas/UpdateAccountStatus'
+      responses:
+        '200':
+          description: Account status updated
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/Account'
+        '400':
+          description: See error message
+          content:
+            application/json:
+              schema:
+                $ref: 'https://raw.githubusercontent.com/moov-io/api/master/openapi-common.yaml#/components/schemas/Error'
   /customers/{customerID}/accounts/{accountID}/validations:
     post:
       tags: [Customers]
@@ -1742,3 +1782,9 @@ components:
           type: string
           format: date-time
           example: '2016-08-29T09:12:33.001Z'
+    UpdateAccountStatus:
+      properties:
+        status:
+          $ref: 'https://raw.githubusercontent.com/moov-io/customers/master/api/client.yaml#/components/schemas/AccountStatus'
+      required:
+        - status
diff --git a/cmd/server/accounts/admin.go b/cmd/server/accounts/admin.go
deleted file mode 100644
index 4e34fbb..0000000
--- a/cmd/server/accounts/admin.go
+++ /dev/null
@@ -1,14 +0,0 @@
-// Copyright 2020 The Moov Authors
-// Use of this source code is governed by an Apache License
-// license that can be found in the LICENSE file.
-
-package accounts
-
-import (
-	"github.com/go-kit/kit/log"
-	"github.com/moov-io/base/admin"
-)
-
-func RegisterAdminRoutes(logger log.Logger, svc *admin.Server, repo Repository) {
-	svc.AddHandler("/customers/{customerID}/accounts/{accountID}/status", updateAccountStatus(logger, repo))
-}
diff --git a/cmd/server/accounts/micro_deposits.go b/cmd/server/accounts/micro_deposits.go
index 48b1833..81bcf22 100644
--- a/cmd/server/accounts/micro_deposits.go
+++ b/cmd/server/accounts/micro_deposits.go
@@ -11,7 +11,7 @@ import (
 	"strings"
 
 	"github.com/moov-io/customers/cmd/server/paygate"
-	"github.com/moov-io/customers/pkg/admin"
+	customerClient "github.com/moov-io/customers/pkg/client"
 	"github.com/moov-io/paygate/pkg/client"
 )
 
@@ -41,7 +41,7 @@ func handleMicroDepositValidation(repo Repository, paygateClient paygate.Client,
 			return err
 		}
 		// Amounts validated, so mark the Account has approved
-		return repo.updateAccountStatus(accountID, admin.VALIDATED)
+		return repo.updateAccountStatus(accountID, customerClient.VALIDATED)
 	}
 
 	return fmt.Errorf("microDepositID=%s is in status: %s", micro.MicroDepositID, micro.Status)
diff --git a/cmd/server/accounts/mock_repository.go b/cmd/server/accounts/mock_repository.go
index bf7550e..a552b08 100644
--- a/cmd/server/accounts/mock_repository.go
+++ b/cmd/server/accounts/mock_repository.go
@@ -5,7 +5,6 @@
 package accounts
 
 import (
-	"github.com/moov-io/customers/pkg/admin"
 	"github.com/moov-io/customers/pkg/client"
 )
 
@@ -46,7 +45,7 @@ func (r *mockRepository) deactivateCustomerAccount(accountID string) error {
 	return r.Err
 }
 
-func (r *mockRepository) updateAccountStatus(accountID string, status admin.AccountStatus) error {
+func (r *mockRepository) updateAccountStatus(accountID string, status client.AccountStatus) error {
 	return r.Err
 }
 
diff --git a/cmd/server/accounts/repository.go b/cmd/server/accounts/repository.go
index 21e3220..04e5afa 100644
--- a/cmd/server/accounts/repository.go
+++ b/cmd/server/accounts/repository.go
@@ -11,7 +11,6 @@ import (
 	"time"
 
 	"github.com/moov-io/base"
-	"github.com/moov-io/customers/pkg/admin"
 	"github.com/moov-io/customers/pkg/client"
 
 	"github.com/go-kit/kit/log"
@@ -24,7 +23,7 @@ type Repository interface {
 	createCustomerAccount(customerID, userID string, req *createAccountRequest) (*client.Account, error)
 	deactivateCustomerAccount(accountID string) error
 
-	updateAccountStatus(accountID string, status admin.AccountStatus) error
+	updateAccountStatus(accountID string, status client.AccountStatus) error
 
 	getEncryptedAccountNumber(customerID, accountID string) (string, error)
 
@@ -135,7 +134,7 @@ func (r *sqlAccountRepository) deactivateCustomerAccount(accountID string) error
 	return err
 }
 
-func (r *sqlAccountRepository) updateAccountStatus(accountID string, status admin.AccountStatus) error {
+func (r *sqlAccountRepository) updateAccountStatus(accountID string, status client.AccountStatus) error {
 	query := `update accounts set status = ? where account_id = ? and deleted_at is null;`
 	stmt, err := r.db.Prepare(query)
 	if err != nil {
diff --git a/cmd/server/accounts/router.go b/cmd/server/accounts/router.go
index 5613861..432756a 100644
--- a/cmd/server/accounts/router.go
+++ b/cmd/server/accounts/router.go
@@ -34,6 +34,8 @@ func RegisterRoutes(logger log.Logger, r *mux.Router, accounts Repository, valid
 	r.Methods("GET").Path("/customers/{customerID}/accounts/{accountID}/ofac").HandlerFunc(getAccountOfacSearch(logger, accounts))
 	r.Methods("PUT").Path("/customers/{customerID}/accounts/{accountID}/refresh/ofac").HandlerFunc(refreshAccountOfac(logger, accounts, ofac))
 
+	r.Methods("PUT").Path("/customers/{customerID}/accounts/{accountID}/status").HandlerFunc(updateAccountStatus(logger, accounts))
+
 	r.Methods("POST").Path("/customers/{customerID}/accounts/{accountID}/validations").HandlerFunc(initAccountValidation(logger, accounts, validations, validationStrategies))
 	r.Methods("GET").Path("/customers/{customerID}/accounts/{accountID}/validations/{validationID}").HandlerFunc(getAccountValidation(logger, accounts, validations))
 	r.Methods("PUT").Path("/customers/{customerID}/accounts/{accountID}/validations/{validationID}").HandlerFunc(completeAccountValidation(logger, accounts, validations, keeper, validationStrategies))
@@ -250,6 +252,7 @@ func refreshAccountOfac(logger log.Logger, repo Repository, ofac *AccountOfacSea
 		requestID := moovhttp.GetRequestID(r)
 		customerID, accountID := route.GetCustomerID(w, r), getAccountID(w, r)
 		if customerID == "" || accountID == "" {
+			moovhttp.Problem(w, errors.New("customerID and accountID required"))
 			return
 		}
 		account, err := repo.getCustomerAccount(customerID, accountID)
@@ -271,3 +274,43 @@ func refreshAccountOfac(logger log.Logger, repo Repository, ofac *AccountOfacSea
 		json.NewEncoder(w).Encode(result)
 	}
 }
+
+func updateAccountStatus(logger log.Logger, repo Repository) http.HandlerFunc {
+	return func(w http.ResponseWriter, r *http.Request) {
+		w = route.Responder(logger, w, r)
+		w.Header().Set("Content-Type", "application/json; charset=utf-8")
+
+		customerID, accountID := route.GetCustomerID(w, r), getAccountID(w, r)
+		if customerID == "" || accountID == "" {
+			moovhttp.Problem(w, errors.New("customerID and accountID required"))
+			return
+		}
+
+		var req client.UpdateAccountStatus
+		if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
+			moovhttp.Problem(w, err)
+			return
+		}
+		switch req.Status {
+		case client.NONE, client.VALIDATED:
+			// do nothing
+		default:
+			moovhttp.Problem(w, fmt.Errorf("invalid status: %s", req.Status))
+			return
+		}
+
+		if err := repo.updateAccountStatus(accountID, req.Status); err != nil {
+			moovhttp.Problem(w, err)
+			return
+		}
+
+		account, err := repo.getCustomerAccount(customerID, accountID)
+		if err != nil {
+			moovhttp.Problem(w, errors.New("there was an error getting the account"))
+			return
+		}
+
+		w.WriteHeader(http.StatusOK)
+		json.NewEncoder(w).Encode(account)
+	}
+}
diff --git a/cmd/server/accounts/update.go b/cmd/server/accounts/update.go
deleted file mode 100644
index 957a3dc..0000000
--- a/cmd/server/accounts/update.go
+++ /dev/null
@@ -1,54 +0,0 @@
-// Copyright 2020 The Moov Authors
-// Use of this source code is governed by an Apache License
-// license that can be found in the LICENSE file.
-
-package accounts
-
-import (
-	"encoding/json"
-	"fmt"
-	"net/http"
-
-	moovhttp "github.com/moov-io/base/http"
-	"github.com/moov-io/customers/cmd/server/route"
-	"github.com/moov-io/customers/pkg/admin"
-
-	"github.com/go-kit/kit/log"
-)
-
-func updateAccountStatus(logger log.Logger, repo Repository) http.HandlerFunc {
-	return func(w http.ResponseWriter, r *http.Request) {
-		w = route.Responder(logger, w, r)
-		w.Header().Set("Content-Type", "application/json; charset=utf-8")
-
-		if r.Method != "PUT" {
-			moovhttp.Problem(w, fmt.Errorf("unsupported HTTP verb %s", r.Method))
-			return
-		}
-
-		accountID := getAccountID(w, r)
-		if accountID == "" {
-			return
-		}
-
-		var req admin.UpdateAccountStatus
-		if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
-			moovhttp.Problem(w, err)
-			return
-		}
-		switch req.Status {
-		case admin.NONE, admin.VALIDATED:
-			// do nothing
-		default:
-			moovhttp.Problem(w, fmt.Errorf("invalid status: %s", req.Status))
-			return
-		}
-
-		if err := repo.updateAccountStatus(accountID, req.Status); err != nil {
-			moovhttp.Problem(w, err)
-			return
-		}
-
-		w.WriteHeader(http.StatusOK)
-	}
-}
diff --git a/cmd/server/accounts/validate.go b/cmd/server/accounts/validate.go
index 151d9f6..d8e4d15 100644
--- a/cmd/server/accounts/validate.go
+++ b/cmd/server/accounts/validate.go
@@ -14,7 +14,6 @@ import (
 	moovhttp "github.com/moov-io/base/http"
 	"github.com/moov-io/customers/cmd/server/accounts/validator"
 	"github.com/moov-io/customers/cmd/server/route"
-	"github.com/moov-io/customers/pkg/admin"
 	"github.com/moov-io/customers/pkg/client"
 	"github.com/moov-io/customers/pkg/secrets"
 
@@ -221,7 +220,7 @@ func completeAccountValidation(logger log.Logger, repo Repository, validations v
 			return
 		}
 
-		err = repo.updateAccountStatus(accountID, admin.VALIDATED)
+		err = repo.updateAccountStatus(accountID, client.VALIDATED)
 		if err != nil {
 			moovhttp.Problem(w, err)
 			return
diff --git a/cmd/server/main.go b/cmd/server/main.go
index 6aea1ed..d322013 100644
--- a/cmd/server/main.go
+++ b/cmd/server/main.go
@@ -131,7 +131,6 @@ func main() {
 	// Register our admin routes
 	addApprovalRoutes(logger, adminServer, customerRepo, customerSSNRepo, ofac)
 	addDisclaimerAdminRoutes(logger, adminServer, disclaimerRepo, documentRepo)
-	accounts.RegisterAdminRoutes(logger, adminServer, accountsRepo)
 
 	// Setup Customer SSN storage wrapper
 	ctx := context.Background()
diff --git a/go.mod b/go.mod
index b00ba33..abd560b 100644
--- a/go.mod
+++ b/go.mod
@@ -40,6 +40,7 @@ require (
 	gocloud.dev v0.20.0
 	gocloud.dev/secrets/hashivault v0.20.0
 	golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a // indirect
+	golang.org/x/net v0.0.0-20200904194848-62affa334b73 // indirect
 	golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d
 	golang.org/x/sys v0.0.0-20200821140526-fda516888d29 // indirect
 	golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e // indirect
diff --git a/go.sum b/go.sum
index 787596a..0e8df41 100644
--- a/go.sum
+++ b/go.sum
@@ -1140,6 +1140,8 @@ golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81R
 golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
 golang.org/x/net v0.0.0-20200813134508-3edf25e44fcc h1:zK/HqS5bZxDptfPJNq8v7vJfXtkU7r9TLIoSr1bXaP4=
 golang.org/x/net v0.0.0-20200813134508-3edf25e44fcc/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
+golang.org/x/net v0.0.0-20200904194848-62affa334b73 h1:MXfv8rhZWmFeqX3GNZRsd6vOLoaCHjYEX3qkRo3YBUA=
+golang.org/x/net v0.0.0-20200904194848-62affa334b73/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
 golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
 golang.org/x/oauth2 v0.0.0-20181106182150-f42d05182288/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
 golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
diff --git a/pkg/client/README.md b/pkg/client/README.md
index 4659613..88d51ee 100644
--- a/pkg/client/README.md
+++ b/pkg/client/README.md
@@ -59,6 +59,7 @@ Class | Method | HTTP request | Description
 *CustomersApi* | [**RefreshOFACSearch**](docs/CustomersApi.md#refreshofacsearch) | **Put** /customers/{customerID}/refresh/ofac | Refresh customer OFAC search
 *CustomersApi* | [**ReplaceCustomerMetadata**](docs/CustomersApi.md#replacecustomermetadata) | **Put** /customers/{customerID}/metadata | Update customer metadata
 *CustomersApi* | [**SearchCustomers**](docs/CustomersApi.md#searchcustomers) | **Get** /customers | Get customers
+*CustomersApi* | [**UpdateAccountStatus**](docs/CustomersApi.md#updateaccountstatus) | **Put** /customers/{customerID}/accounts/{accountID}/status | Update Account Status
 *CustomersApi* | [**UpdateCustomerStatus**](docs/CustomersApi.md#updatecustomerstatus) | **Put** /customers/{customerID}/status | Update customer status
 *CustomersApi* | [**UploadCustomerDocument**](docs/CustomersApi.md#uploadcustomerdocument) | **Post** /customers/{customerID}/documents | Upload document
 
@@ -90,6 +91,7 @@ Class | Method | HTTP request | Description
  - [OfacSearch](docs/OfacSearch.md)
  - [Phone](docs/Phone.md)
  - [TransitAccountNumber](docs/TransitAccountNumber.md)
+ - [UpdateAccountStatus](docs/UpdateAccountStatus.md)
  - [UpdateCustomerStatus](docs/UpdateCustomerStatus.md)
  - [UpdateValidation](docs/UpdateValidation.md)
 
diff --git a/pkg/client/api/openapi.yaml b/pkg/client/api/openapi.yaml
index ccf273e..aa754c7 100644
--- a/pkg/client/api/openapi.yaml
+++ b/pkg/client/api/openapi.yaml
@@ -781,6 +781,51 @@ paths:
       summary: Refresh Account OFAC search
       tags:
       - Customers
+  /customers/{customerID}/accounts/{accountID}/status:
+    put:
+      description: Update the status for the specified accountID
+      operationId: updateAccountStatus
+      parameters:
+      - description: Customer ID
+        explode: false
+        in: path
+        name: customerID
+        required: true
+        schema:
+          example: e210a9d6-d755-4455-9bd2-9577ea7e1081
+          type: string
+        style: simple
+      - description: accountID of the Account to validate
+        explode: false
+        in: path
+        name: accountID
+        required: true
+        schema:
+          example: b74d7c51
+          type: string
+        style: simple
+      requestBody:
+        content:
+          application/json:
+            schema:
+              $ref: '#/components/schemas/UpdateAccountStatus'
+        required: true
+      responses:
+        "200":
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/Account'
+          description: Account status updated
+        "400":
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/Error'
+          description: See error message
+      summary: Update Account Status
+      tags:
+      - Customers
   /customers/{customerID}/accounts/{accountID}/validations:
     post:
       description: |
@@ -2208,6 +2253,14 @@ components:
           format: date-time
           type: string
       type: object
+    UpdateAccountStatus:
+      example:
+        status: validated
+      properties:
+        status:
+          $ref: '#/components/schemas/AccountStatus'
+      required:
+      - status
     Error:
       properties:
         error:
diff --git a/pkg/client/api_customers.go b/pkg/client/api_customers.go
index 6162bf3..1e0e1de 100644
--- a/pkg/client/api_customers.go
+++ b/pkg/client/api_customers.go
@@ -2180,6 +2180,99 @@ func (a *CustomersApiService) SearchCustomers(ctx _context.Context, localVarOpti
 	return localVarReturnValue, localVarHTTPResponse, nil
 }
 
+/*
+UpdateAccountStatus Update Account Status
+Update the status for the specified accountID
+ * @param ctx _context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background().
+ * @param customerID Customer ID
+ * @param accountID accountID of the Account to validate
+ * @param updateAccountStatus
+@return Account
+*/
+func (a *CustomersApiService) UpdateAccountStatus(ctx _context.Context, customerID string, accountID string, updateAccountStatus UpdateAccountStatus) (Account, *_nethttp.Response, error) {
+	var (
+		localVarHTTPMethod   = _nethttp.MethodPut
+		localVarPostBody     interface{}
+		localVarFormFileName string
+		localVarFileName     string
+		localVarFileBytes    []byte
+		localVarReturnValue  Account
+	)
+
+	// create path and map variables
+	localVarPath := a.client.cfg.BasePath + "/customers/{customerID}/accounts/{accountID}/status"
+	localVarPath = strings.Replace(localVarPath, "{"+"customerID"+"}", _neturl.QueryEscape(parameterToString(customerID, "")), -1)
+
+	localVarPath = strings.Replace(localVarPath, "{"+"accountID"+"}", _neturl.QueryEscape(parameterToString(accountID, "")), -1)
+
+	localVarHeaderParams := make(map[string]string)
+	localVarQueryParams := _neturl.Values{}
+	localVarFormParams := _neturl.Values{}
+
+	// to determine the Content-Type header
+	localVarHTTPContentTypes := []string{"application/json"}
+
+	// set Content-Type header
+	localVarHTTPContentType := selectHeaderContentType(localVarHTTPContentTypes)
+	if localVarHTTPContentType != "" {
+		localVarHeaderParams["Content-Type"] = localVarHTTPContentType
+	}
+
+	// to determine the Accept header
+	localVarHTTPHeaderAccepts := []string{"application/json"}
+
+	// set Accept header
+	localVarHTTPHeaderAccept := selectHeaderAccept(localVarHTTPHeaderAccepts)
+	if localVarHTTPHeaderAccept != "" {
+		localVarHeaderParams["Accept"] = localVarHTTPHeaderAccept
+	}
+	// body params
+	localVarPostBody = &updateAccountStatus
+	r, err := a.client.prepareRequest(ctx, localVarPath, localVarHTTPMethod, localVarPostBody, localVarHeaderParams, localVarQueryParams, localVarFormParams, localVarFormFileName, localVarFileName, localVarFileBytes)
+	if err != nil {
+		return localVarReturnValue, nil, err
+	}
+
+	localVarHTTPResponse, err := a.client.callAPI(r)
+	if err != nil || localVarHTTPResponse == nil {
+		return localVarReturnValue, localVarHTTPResponse, err
+	}
+
+	localVarBody, err := _ioutil.ReadAll(localVarHTTPResponse.Body)
+	localVarHTTPResponse.Body.Close()
+	if err != nil {
+		return localVarReturnValue, localVarHTTPResponse, err
+	}
+
+	if localVarHTTPResponse.StatusCode >= 300 {
+		newErr := GenericOpenAPIError{
+			body:  localVarBody,
+			error: localVarHTTPResponse.Status,
+		}
+		if localVarHTTPResponse.StatusCode == 400 {
+			var v Error
+			err = a.client.decode(&v, localVarBody, localVarHTTPResponse.Header.Get("Content-Type"))
+			if err != nil {
+				newErr.error = err.Error()
+				return localVarReturnValue, localVarHTTPResponse, newErr
+			}
+			newErr.model = v
+		}
+		return localVarReturnValue, localVarHTTPResponse, newErr
+	}
+
+	err = a.client.decode(&localVarReturnValue, localVarBody, localVarHTTPResponse.Header.Get("Content-Type"))
+	if err != nil {
+		newErr := GenericOpenAPIError{
+			body:  localVarBody,
+			error: err.Error(),
+		}
+		return localVarReturnValue, localVarHTTPResponse, newErr
+	}
+
+	return localVarReturnValue, localVarHTTPResponse, nil
+}
+
 // UpdateCustomerStatusOpts Optional parameters for the method 'UpdateCustomerStatus'
 type UpdateCustomerStatusOpts struct {
 	XRequestID optional.String
diff --git a/pkg/client/docs/CustomersApi.md b/pkg/client/docs/CustomersApi.md
index 6e8da16..90a3f44 100644
--- a/pkg/client/docs/CustomersApi.md
+++ b/pkg/client/docs/CustomersApi.md
@@ -25,6 +25,7 @@ Method | HTTP request | Description
 [**RefreshOFACSearch**](CustomersApi.md#RefreshOFACSearch) | **Put** /customers/{customerID}/refresh/ofac | Refresh customer OFAC search
 [**ReplaceCustomerMetadata**](CustomersApi.md#ReplaceCustomerMetadata) | **Put** /customers/{customerID}/metadata | Update customer metadata
 [**SearchCustomers**](CustomersApi.md#SearchCustomers) | **Get** /customers | Get customers
+[**UpdateAccountStatus**](CustomersApi.md#UpdateAccountStatus) | **Put** /customers/{customerID}/accounts/{accountID}/status | Update Account Status
 [**UpdateCustomerStatus**](CustomersApi.md#UpdateCustomerStatus) | **Put** /customers/{customerID}/status | Update customer status
 [**UploadCustomerDocument**](CustomersApi.md#UploadCustomerDocument) | **Post** /customers/{customerID}/documents | Upload document
 
@@ -1010,6 +1011,42 @@ No authorization required
 [[Back to README]](../README.md)
 
 
+## UpdateAccountStatus
+
+> Account UpdateAccountStatus(ctx, customerID, accountID, updateAccountStatus)
+
+Update Account Status
+
+Update the status for the specified accountID
+
+### Required Parameters
+
+
+Name | Type | Description  | Notes
+------------- | ------------- | ------------- | -------------
+**ctx** | **context.Context** | context for authentication, logging, cancellation, deadlines, tracing, etc.
+**customerID** | **string**| Customer ID | 
+**accountID** | **string**| accountID of the Account to validate | 
+**updateAccountStatus** | [**UpdateAccountStatus**](UpdateAccountStatus.md)|  | 
+
+### Return type
+
+[**Account**](Account.md)
+
+### Authorization
+
+No authorization required
+
+### HTTP request headers
+
+- **Content-Type**: application/json
+- **Accept**: application/json
+
+[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints)
+[[Back to Model list]](../README.md#documentation-for-models)
+[[Back to README]](../README.md)
+
+
 ## UpdateCustomerStatus
 
 > Customer UpdateCustomerStatus(ctx, customerID, updateCustomerStatus, optional)
diff --git a/pkg/client/docs/UpdateAccountStatus.md b/pkg/client/docs/UpdateAccountStatus.md
new file mode 100644
index 0000000..dadabc5
--- /dev/null
+++ b/pkg/client/docs/UpdateAccountStatus.md
@@ -0,0 +1,11 @@
+# UpdateAccountStatus
+
+## Properties
+
+Name | Type | Description | Notes
+------------ | ------------- | ------------- | -------------
+**Status** | [**AccountStatus**](AccountStatus.md) |  | 
+
+[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)
+
+
diff --git a/pkg/client/model_update_account_status.go b/pkg/client/model_update_account_status.go
new file mode 100644
index 0000000..9cf5112
--- /dev/null
+++ b/pkg/client/model_update_account_status.go
@@ -0,0 +1,15 @@
+/*
+ * Customers API
+ *
+ * Customers focuses on solving authentic identification of humans who are legally able to hold and transfer currency within the US. Primarily this project solves [Know Your Customer](https://en.wikipedia.org/wiki/Know_your_customer) (KYC), [Customer Identification Program](https://en.wikipedia.org/wiki/Customer_Identification_Program) (CIP), [Office of Foreign Asset Control](https://www.treasury.gov/about/organizational-structure/offices/Pages/Office-of-Foreign-Assets-Control.aspx) (OFAC) checks and verification workflows to comply with US federal law and ensure authentic transfers. Customers has an objective to be a service for detailed due diligence on individuals and companies for Financial Institutions and services in a modernized and extensible way.  Customer phone numbers and addresses are stored and partially used in KYC/OFAC validation. Arbitrary key/value pairs can be stored for a Customer. Documents and Disclaimers, and their acknowledgement are also stored under a Customer as they're accepted. Bank Accounts, which can be validated with micro-deposits currently, are stored under each Customer.  ![](https://raw.githubusercontent.com/adamdecaf/customers/create-accounts/docs/images/customer.png)
+ *
+ * API version: v1
+ * Generated by: OpenAPI Generator (https://openapi-generator.tech)
+ */
+
+package client
+
+// UpdateAccountStatus struct for UpdateAccountStatus
+type UpdateAccountStatus struct {
+	Status AccountStatus `json:"status"`
+}


Test patch:
diff --git a/cmd/server/accounts/repository_test.go b/cmd/server/accounts/repository_test.go
index 22cd5ec..467746c 100644
--- a/cmd/server/accounts/repository_test.go
+++ b/cmd/server/accounts/repository_test.go
@@ -9,7 +9,6 @@ import (
 
 	"github.com/moov-io/base"
 	"github.com/moov-io/customers/internal/database"
-	"github.com/moov-io/customers/pkg/admin"
 	"github.com/moov-io/customers/pkg/client"
 	"github.com/moov-io/customers/pkg/secrets"
 	"github.com/stretchr/testify/require"
@@ -128,7 +127,7 @@ func TestRepository__updateAccountStatus(t *testing.T) {
 	}
 
 	// update status
-	if err := repo.updateAccountStatus(acct.AccountID, admin.VALIDATED); err != nil {
+	if err := repo.updateAccountStatus(acct.AccountID, client.VALIDATED); err != nil {
 		t.Fatal(err)
 	}
 
diff --git a/cmd/server/accounts/router_test.go b/cmd/server/accounts/router_test.go
index 648baf3..1574a0e 100644
--- a/cmd/server/accounts/router_test.go
+++ b/cmd/server/accounts/router_test.go
@@ -8,8 +8,11 @@ import (
 	"bytes"
 	"context"
 	"encoding/json"
+	"errors"
 	"fmt"
+	"github.com/moov-io/customers/internal/testclient"
 	watchman "github.com/moov-io/watchman/client"
+	"github.com/stretchr/testify/assert"
 	"net/http"
 	"net/http/httptest"
 	"strings"
@@ -200,6 +203,52 @@ func TestRoutes__EmptyAccounts(t *testing.T) {
 	}
 }
 
+func TestUpdateAccountStatus(t *testing.T) {
+	customerID := base.ID()
+	accountID := base.ID()
+
+	repo := &mockRepository{
+		Accounts: []*client.Account{
+			{
+				AccountID: accountID,
+			},
+		},
+	}
+
+	router := setupRouterWithRepo(t, repo)
+	c := testclient.New(t, router)
+
+	req := client.UpdateAccountStatus{
+		Status: client.VALIDATED,
+	}
+	account, resp, err := c.CustomersApi.UpdateAccountStatus(context.TODO(), customerID, accountID, req)
+	if resp != nil && resp.Body != nil {
+		resp.Body.Close()
+	}
+	assert.NotNil(t, account)
+	if resp != nil {
+		if resp.StatusCode != http.StatusOK || err != nil {
+			t.Errorf("bogus HTTP status: %d", resp.StatusCode)
+			t.Fatal(err)
+		}
+	}
+
+	// retry, but expect an error
+	repo.Err = errors.New("bad error")
+	router = setupRouterWithRepo(t, repo)
+	c = testclient.New(t, router)
+
+	_, resp, err = c.CustomersApi.UpdateAccountStatus(context.TODO(), customerID, accountID, req)
+	if resp != nil && resp.Body != nil {
+		resp.Body.Close()
+	}
+	if resp != nil && err != nil {
+		if resp.StatusCode != http.StatusBadRequest {
+			t.Errorf("bogus HTTP status: %d", resp.StatusCode)
+		}
+	}
+}
+
 func setupRouter(t *testing.T) *mux.Router {
 	handler := mux.NewRouter()
 
@@ -216,6 +265,21 @@ func setupRouter(t *testing.T) *mux.Router {
 	return handler
 }
 
+func setupRouterWithRepo(t *testing.T, repo *mockRepository) *mux.Router {
+	handler := mux.NewRouter()
+
+	testFedClient := &fed.MockClient{}
+	validations := &validator.MockRepository{}
+	keeper := secrets.TestStringKeeper(t)
+	validationStrategies := map[validator.StrategyKey]validator.Strategy{
+		{Strategy: "test", Vendor: "moov"}: testvalidator.NewStrategy(),
+	}
+
+	RegisterRoutes(log.NewNopLogger(), handler, repo, validations, testFedClient, keeper, keeper, validationStrategies, createTestOFACSearcher(repo, nil))
+
+	return handler
+}
+
 func httpReadAccounts(t *testing.T, handler *mux.Router, customerID string) []*client.Account {
 	w := httptest.NewRecorder()
 	req := httptest.NewRequest("GET", fmt.Sprintf("/customers/%s/accounts", customerID), nil)
diff --git a/cmd/server/accounts/update_test.go b/cmd/server/accounts/update_test.go
deleted file mode 100644
index 1e5a7c1..0000000
--- a/cmd/server/accounts/update_test.go
+++ /dev/null
@@ -1,58 +0,0 @@
-// Copyright 2020 The Moov Authors
-// Use of this source code is governed by an Apache License
-// license that can be found in the LICENSE file.
-
-package accounts
-
-import (
-	"context"
-	"errors"
-	"net/http"
-	"testing"
-
-	"github.com/moov-io/base"
-	"github.com/moov-io/customers/internal/testclient"
-	"github.com/moov-io/customers/pkg/admin"
-	"github.com/moov-io/customers/pkg/client"
-
-	"github.com/go-kit/kit/log"
-)
-
-func TestAdmin__updateAccountStatus(t *testing.T) {
-	customerID := base.ID()
-	accountID := base.ID()
-
-	repo := &mockRepository{
-		Accounts: []*client.Account{
-			{
-				AccountID: accountID,
-			},
-		},
-	}
-
-	svc, c := testclient.Admin(t)
-	RegisterAdminRoutes(log.NewNopLogger(), svc, repo)
-
-	req := admin.UpdateAccountStatus{
-		Status: admin.VALIDATED,
-	}
-	resp, err := c.CustomersApi.UpdateAccountStatus(context.TODO(), customerID, accountID, req)
-	if resp != nil && resp.Body != nil {
-		resp.Body.Close()
-	}
-	if resp.StatusCode != http.StatusOK || err != nil {
-		t.Errorf("bogus HTTP status: %d", resp.StatusCode)
-		t.Fatal(err)
-	}
-
-	// retry, but expect an error
-	repo.Err = errors.New("bad error")
-
-	resp, _ = c.CustomersApi.UpdateAccountStatus(context.TODO(), customerID, accountID, req)
-	if resp != nil && resp.Body != nil {
-		resp.Body.Close()
-	}
-	if resp.StatusCode != http.StatusBadRequest {
-		t.Errorf("bogus HTTP status: %d", resp.StatusCode)
-	}
-}
diff --git a/cmd/server/accounts/validate_test.go b/cmd/server/accounts/validate_test.go
index 5b652f8..bdd1922 100644
--- a/cmd/server/accounts/validate_test.go
+++ b/cmd/server/accounts/validate_test.go
@@ -18,7 +18,6 @@ import (
 	"github.com/moov-io/customers/cmd/server/accounts/validator/microdeposits"
 	"github.com/moov-io/customers/cmd/server/accounts/validator/testvalidator"
 	"github.com/moov-io/customers/cmd/server/paygate"
-	"github.com/moov-io/customers/pkg/admin"
 	"github.com/moov-io/customers/pkg/client"
 	"github.com/moov-io/customers/pkg/secrets"
 	payclient "github.com/moov-io/paygate/pkg/client"
@@ -119,7 +118,7 @@ func TestRouter__InitAccountValidation(t *testing.T) {
 		})
 		require.NoError(t, err)
 
-		err = accounts.updateAccountStatus(acc.AccountID, admin.VALIDATED)
+		err = accounts.updateAccountStatus(acc.AccountID, client.VALIDATED)
 		require.NoError(t, err)
 
 		params := map[string]string{
@@ -268,7 +267,7 @@ func TestRouter__CompleteAccountValidation(t *testing.T) {
 		})
 		require.NoError(t, err)
 
-		err = repo.updateAccountStatus(acc.AccountID, admin.VALIDATED)
+		err = repo.updateAccountStatus(acc.AccountID, client.VALIDATED)
 		require.NoError(t, err)
 
 		// build request for test strategy
diff --git a/cmd/server/accounts/validator/mx/strategy_test.go b/cmd/server/accounts/validator/mx/strategy_test.go
index 9535656..530020f 100644
--- a/cmd/server/accounts/validator/mx/strategy_test.go
+++ b/cmd/server/accounts/validator/mx/strategy_test.go
@@ -15,6 +15,8 @@ import (
 )
 
 func TestStrategy(t *testing.T) {
+	t.Skip("MX has limits for development API keys that’s why let’s skip for now")
+
 	if os.Getenv("ATRIUM_API_KEY") == "" {
 		t.Skip("No configuration found for MX")
 	}