diff --git a/go.mod b/go.mod
index 69da80e45d21c911a48c79f14d5acd0dc22c7d80..7e5271f7847104ad370070ff391478dae3e32e33 100644
--- a/go.mod
+++ b/go.mod
@@ -1,6 +1,6 @@
 module github.com/projectrekor/rekor
 
-go 1.15
+go 1.14
 
 require (
 	github.com/asaskevich/govalidator v0.0.0-20200907205600-7a23bdc65eef
@@ -33,6 +33,7 @@ require (
 	github.com/spf13/pflag v1.0.5
 	github.com/spf13/viper v1.7.1
 	github.com/tidwall/sjson v1.1.2
+	github.com/urfave/negroni v1.0.0
 	github.com/xeipuuv/gojsonschema v1.2.0
 	go.etcd.io/etcd v3.3.25+incompatible // indirect
 	go.uber.org/goleak v1.1.10
diff --git a/go.sum b/go.sum
index bcd46a9838a9983b53b6932f9bdc7280c9ca9b68..126b6194a98efb7c8ede8a2648ca6310b37367f8 100644
--- a/go.sum
+++ b/go.sum
@@ -760,6 +760,8 @@ github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljT
 github.com/ultraware/funlen v0.0.1/go.mod h1:Dp4UiAus7Wdb9KUZsYWZEWiRzGuM2kXM1lPbfaF6xhA=
 github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
 github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
+github.com/urfave/negroni v1.0.0 h1:kIimOitoypq34K7TG7DUaJ9kq/N4Ofuwi1sjz0KipXc=
+github.com/urfave/negroni v1.0.0/go.mod h1:Meg73S6kFm/4PpbYdq35yYWoCZ9mS/YSx+lKnmiohz4=
 github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
 github.com/valyala/fasthttp v1.2.0/go.mod h1:4vX61m6KN+xDduDNwXrhIAVZaZaZiQ1luJk8LWSxF3s=
 github.com/valyala/quicktemplate v1.1.1/go.mod h1:EH+4AkTd43SvgIbQHYu59/cJyxDoOVRUAfrukLPuGJ4=
diff --git a/openapi.yaml b/openapi.yaml
index 73adb4e7b17e3991e596a3bb1b615865c991b294..2a1524dce242b53de6dfbb5202bfe4a0c452df13 100644
--- a/openapi.yaml
+++ b/openapi.yaml
@@ -127,6 +127,7 @@ paths:
           name: entryUUID
           type: string
           required: true
+          pattern: '^[0-9a-fA-F]{64}$'
           description: the UUID of the entry to be retrieved from the log. The UUID is also the merkle tree hash of the entry.
       responses:
         200:
@@ -150,6 +151,7 @@ paths:
           name: entryUUID
           type: string
           required: true
+          pattern: '^[0-9a-fA-F]{64}$'
           description: the UUID of the entry for which the inclusion proof information should be returned
       responses:
         200:
@@ -234,6 +236,7 @@ definitions:
         items:
           type: string
           minItems: 1
+          pattern: '^[0-9a-fA-F]{64}$'
       logIndexes:
         type: array
         minItems: 1
@@ -309,7 +312,7 @@ definitions:
   Error:
     type: object
     properties:
-      status:
+      code:
         type: integer
       message:
         type: string
diff --git a/pkg/api/api.go b/pkg/api/api.go
index bb2a38e28e27fa192a25eeb29b87cf55af21df61..092d9dd5dd08cbe8b2580bc480a9a43b6b9140ac 100644
--- a/pkg/api/api.go
+++ b/pkg/api/api.go
@@ -19,6 +19,7 @@ package api
 import (
 	"context"
 	"fmt"
+	"net/http"
 	"time"
 
 	"github.com/google/trillian"
@@ -73,7 +74,23 @@ func NewAPI(ctx context.Context) (*API, error) {
 	}
 
 	return &API{
-		client: TrillianClientInstance(logClient, tLogID),
+		client: TrillianClientInstance(logClient, tLogID, ctx),
 		pubkey: t.PublicKey,
 	}, nil
 }
+
+type ctxKeyRekorAPI int
+
+const rekorAPILookupKey ctxKeyRekorAPI = 0
+
+func AddAPIToContext(ctx context.Context) (context.Context, error) {
+	api, err := NewAPI(ctx)
+	if err != nil {
+		return nil, err
+	}
+	return context.WithValue(ctx, rekorAPILookupKey, api), nil
+}
+
+func apiFromRequest(r *http.Request) *API {
+	return r.Context().Value(rekorAPILookupKey).(*API)
+}
diff --git a/pkg/api/entries.go b/pkg/api/entries.go
index 6671e65616ac5075dec363422a03c8d59b0533ae..7a4ae2c51045843f386c04037d73eec86e32faa4 100644
--- a/pkg/api/entries.go
+++ b/pkg/api/entries.go
@@ -19,9 +19,12 @@ import (
 	"crypto"
 	"crypto/x509"
 	"encoding/hex"
+	"errors"
 	"fmt"
 	"net/http"
 
+	"github.com/google/trillian"
+
 	"github.com/go-openapi/swag"
 
 	"google.golang.org/grpc/codes"
@@ -39,29 +42,23 @@ import (
 )
 
 func GetLogEntryByIndexHandler(params entries.GetLogEntryByIndexParams) middleware.Responder {
-	api, _ := NewAPI(params.HTTPRequest.Context())
+	httpReq := params.HTTPRequest
+	api := apiFromRequest(httpReq)
 
-	indexes := []int64{params.LogIndex}
-	resp, err := api.client.getLeafByIndex(indexes)
-	if err != nil {
-		code := http.StatusInternalServerError
-		return logAndReturnError(entries.NewGetLogEntryByIndexDefault(code), code, err, trillianCommunicationError, params.HTTPRequest)
-	}
+	resp := api.client.getLeafByIndex(params.LogIndex)
 	switch resp.status {
 	case codes.OK:
 	case codes.NotFound, codes.OutOfRange:
-		return logAndReturnError(entries.NewGetLogEntryByIndexNotFound(), http.StatusNotFound, nil, "", params.HTTPRequest)
+		return handleRekorAPIError(params, http.StatusNotFound, fmt.Errorf("grpc error: %w", resp.err), "")
 	default:
-		code := http.StatusInternalServerError
-		return logAndReturnError(entries.NewGetLogEntryByIndexDefault(code), code, nil, trillianCommunicationError, params.HTTPRequest)
+		return handleRekorAPIError(params, http.StatusInternalServerError, fmt.Errorf("grpc err: %w", resp.err), trillianCommunicationError)
 	}
 
-	leaves := resp.getLeafByIndexResult.GetLeaves()
+	leaves := resp.getLeafByRangeResult.GetLeaves()
 	if len(leaves) > 1 {
-		code := http.StatusInternalServerError
-		return logAndReturnError(entries.NewGetLogEntryByIndexDefault(code), code, nil, trillianUnexpectedResult, params.HTTPRequest)
+		return handleRekorAPIError(params, http.StatusInternalServerError, fmt.Errorf("len(leaves): %v", len(leaves)), trillianUnexpectedResult)
 	} else if len(leaves) == 0 {
-		return logAndReturnError(entries.NewGetLogEntryByIndexNotFound(), http.StatusNotFound, nil, "", params.HTTPRequest)
+		return handleRekorAPIError(params, http.StatusNotFound, errors.New("grpc returned 0 leaves with success code"), "")
 	}
 	leaf := leaves[0]
 
@@ -75,30 +72,26 @@ func GetLogEntryByIndexHandler(params entries.GetLogEntryByIndexParams) middlewa
 }
 
 func CreateLogEntryHandler(params entries.CreateLogEntryParams) middleware.Responder {
+	httpReq := params.HTTPRequest
 	entry, err := types.NewEntry(params.ProposedEntry)
 	if err != nil {
-		return logAndReturnError(entries.NewCreateLogEntryBadRequest(), http.StatusBadRequest, err, err.Error(), params.HTTPRequest)
+		return handleRekorAPIError(params, http.StatusBadRequest, err, err.Error())
 	}
 
-	leaf, err := entry.Canonicalize(params.HTTPRequest.Context())
+	leaf, err := entry.Canonicalize(httpReq.Context())
 	if err != nil {
-		code := http.StatusInternalServerError
-		return logAndReturnError(entries.NewCreateLogEntryDefault(code), code, err, failedToGenerateCanonicalEntry, params.HTTPRequest)
+		return handleRekorAPIError(params, http.StatusInternalServerError, err, failedToGenerateCanonicalEntry)
 	}
 
-	api, _ := NewAPI(params.HTTPRequest.Context())
-	resp, err := api.client.addLeaf(leaf)
-	if err != nil {
-		code := http.StatusInternalServerError
-		return logAndReturnError(entries.NewCreateLogEntryDefault(code), code, err, trillianCommunicationError, params.HTTPRequest)
-	}
+	api := apiFromRequest(httpReq)
+
+	resp := api.client.addLeaf(leaf)
 	switch resp.status {
 	case codes.OK:
 	case codes.AlreadyExists, codes.FailedPrecondition:
-		return logAndReturnError(entries.NewCreateLogEntryConflict(), http.StatusConflict, nil, entryAlreadyExists, params.HTTPRequest)
+		return handleRekorAPIError(params, http.StatusConflict, fmt.Errorf("grpc error: %w", resp.err), entryAlreadyExists)
 	default:
-		code := http.StatusInternalServerError
-		return logAndReturnError(entries.NewCreateLogEntryDefault(code), code, nil, trillianUnexpectedResult, params.HTTPRequest)
+		return handleRekorAPIError(params, http.StatusInternalServerError, fmt.Errorf("grpc error: %w", resp.err), trillianUnexpectedResult)
 	}
 
 	queuedLeaf := resp.getAddResult.QueuedLeaf.Leaf
@@ -112,34 +105,30 @@ func CreateLogEntryHandler(params entries.CreateLogEntryParams) middleware.Respo
 		},
 	}
 
-	location := strfmt.URI(fmt.Sprintf("%v/%v", params.HTTPRequest.URL, uuid))
+	location := strfmt.URI(fmt.Sprintf("%v/%v", httpReq.URL, uuid))
 	return entries.NewCreateLogEntryCreated().WithPayload(logEntry).WithLocation(location).WithETag(uuid)
 }
 
 func GetLogEntryByUUIDHandler(params entries.GetLogEntryByUUIDParams) middleware.Responder {
-	api, _ := NewAPI(params.HTTPRequest.Context())
+	httpReq := params.HTTPRequest
+	api := apiFromRequest(httpReq)
 	hashValue, _ := hex.DecodeString(params.EntryUUID)
 	hashes := [][]byte{hashValue}
-	resp, err := api.client.getLeafByHash(hashes)
-	if err != nil {
-		code := http.StatusInternalServerError
-		return logAndReturnError(entries.NewGetLogEntryByUUIDDefault(code), code, err, trillianCommunicationError, params.HTTPRequest)
-	}
+
+	resp := api.client.getLeafByHash(hashes) // TODO: if this API is deprecated, we need to ask for inclusion proof and then use index in proof result to get leaf
 	switch resp.status {
 	case codes.OK:
 	case codes.NotFound:
-		return logAndReturnError(entries.NewGetLogEntryByUUIDNotFound(), http.StatusNotFound, nil, "", params.HTTPRequest)
+		return handleRekorAPIError(params, http.StatusNotFound, fmt.Errorf("grpc error: %w", resp.err), "")
 	default:
-		code := http.StatusInternalServerError
-		return logAndReturnError(entries.NewGetLogEntryByUUIDDefault(code), code, nil, trillianUnexpectedResult, params.HTTPRequest)
+		return handleRekorAPIError(params, http.StatusInternalServerError, fmt.Errorf("grpc error: %w", resp.err), trillianUnexpectedResult)
 	}
 
 	leaves := resp.getLeafResult.GetLeaves()
 	if len(leaves) > 1 {
-		code := http.StatusInternalServerError
-		return logAndReturnError(entries.NewGetLogEntryByUUIDDefault(code), code, nil, trillianUnexpectedResult, params.HTTPRequest)
+		return handleRekorAPIError(params, http.StatusInternalServerError, fmt.Errorf("len(leaves): %v", len(leaves)), trillianUnexpectedResult)
 	} else if len(leaves) == 0 {
-		return logAndReturnError(entries.NewGetLogEntryByUUIDNotFound(), http.StatusNotFound, nil, "", params.HTTPRequest)
+		return handleRekorAPIError(params, http.StatusNotFound, errors.New("grpc returned 0 leaves with success code"), "")
 	}
 	leaf := leaves[0]
 
@@ -155,39 +144,33 @@ func GetLogEntryByUUIDHandler(params entries.GetLogEntryByUUIDParams) middleware
 }
 
 func GetLogEntryProofHandler(params entries.GetLogEntryProofParams) middleware.Responder {
-	api, _ := NewAPI(params.HTTPRequest.Context())
+	httpReq := params.HTTPRequest
+	api := apiFromRequest(httpReq)
 	hashValue, _ := hex.DecodeString(params.EntryUUID)
-	resp, err := api.client.getProofByHash(hashValue)
-	if err != nil {
-		code := http.StatusInternalServerError
-		return logAndReturnError(entries.NewGetLogEntryProofDefault(code), code, err, trillianCommunicationError, params.HTTPRequest)
-	}
+
+	resp := api.client.getProofByHash(hashValue)
 	switch resp.status {
 	case codes.OK:
 	case codes.NotFound:
-		return logAndReturnError(entries.NewGetLogEntryProofNotFound(), http.StatusNotFound, nil, "", params.HTTPRequest)
+		return handleRekorAPIError(params, http.StatusNotFound, fmt.Errorf("grpc error: %w", resp.err), "")
 	default:
-		code := http.StatusInternalServerError
-		return logAndReturnError(entries.NewGetLogEntryProofDefault(code), code, nil, trillianUnexpectedResult, params.HTTPRequest)
+		return handleRekorAPIError(params, http.StatusInternalServerError, fmt.Errorf("grpc error: %w", resp.err), trillianUnexpectedResult)
 	}
 	result := resp.getProofResult
 
 	// validate result is signed with the key we're aware of
 	pub, err := x509.ParsePKIXPublicKey(api.pubkey.Der)
 	if err != nil {
-		code := http.StatusInternalServerError
-		return logAndReturnError(entries.NewGetLogEntryProofDefault(code), code, err, http.StatusText(code), params.HTTPRequest)
+		return handleRekorAPIError(params, http.StatusInternalServerError, err, "")
 	}
 	verifier := tclient.NewLogVerifier(rfc6962.DefaultHasher, pub, crypto.SHA256)
 	root, err := tcrypto.VerifySignedLogRoot(verifier.PubKey, verifier.SigHash, result.SignedLogRoot)
 	if err != nil {
-		code := http.StatusInternalServerError
-		return logAndReturnError(entries.NewGetLogEntryProofDefault(code), code, err, trillianUnexpectedResult, params.HTTPRequest)
+		return handleRekorAPIError(params, http.StatusInternalServerError, err, trillianUnexpectedResult)
 	}
 
 	if len(result.Proof) != 1 {
-		code := http.StatusInternalServerError
-		return logAndReturnError(entries.NewGetLogEntryProofDefault(code), code, nil, trillianUnexpectedResult, params.HTTPRequest)
+		return handleRekorAPIError(params, http.StatusInternalServerError, fmt.Errorf("len(result.Proof) = %v", len(result.Proof)), trillianUnexpectedResult)
 	}
 	proof := result.Proof[0]
 
@@ -207,7 +190,8 @@ func GetLogEntryProofHandler(params entries.GetLogEntryProofParams) middleware.R
 
 func SearchLogQueryHandler(params entries.SearchLogQueryParams) middleware.Responder {
 	resultPayload := []models.LogEntry{}
-	api, _ := NewAPI(params.HTTPRequest.Context())
+	httpReq := params.HTTPRequest
+	api := apiFromRequest(httpReq)
 
 	//TODO: parallelize this into different goroutines to speed up search
 	searchHashes := [][]byte{}
@@ -215,8 +199,7 @@ func SearchLogQueryHandler(params entries.SearchLogQueryParams) middleware.Respo
 		for _, uuid := range params.Entry.EntryUUIDs {
 			hash, err := hex.DecodeString(uuid)
 			if err != nil {
-				code := http.StatusBadRequest
-				return logAndReturnError(entries.NewSearchLogQueryBadRequest(), code, err, http.StatusText(code), params.HTTPRequest)
+				return handleRekorAPIError(params, http.StatusBadRequest, err, malformedUUID)
 			}
 			searchHashes = append(searchHashes, hash)
 		}
@@ -224,37 +207,29 @@ func SearchLogQueryHandler(params entries.SearchLogQueryParams) middleware.Respo
 		for _, e := range params.Entry.Entries() {
 			entry, err := types.NewEntry(e)
 			if err != nil {
-				code := http.StatusBadRequest
-				return logAndReturnError(entries.NewSearchLogQueryBadRequest(), code, err, err.Error(), params.HTTPRequest)
+				return handleRekorAPIError(params, http.StatusBadRequest, err, err.Error())
 			}
 
 			if entry.HasExternalEntities() {
-				if err := entry.FetchExternalEntities(params.HTTPRequest.Context()); err != nil {
-					code := http.StatusBadRequest
-					return logAndReturnError(entries.NewSearchLogQueryDefault(code), code, err, err.Error(), params.HTTPRequest)
+				if err := entry.FetchExternalEntities(httpReq.Context()); err != nil {
+					return handleRekorAPIError(params, http.StatusBadRequest, err, err.Error())
 				}
 			}
 
-			leaf, err := entry.Canonicalize(params.HTTPRequest.Context())
+			leaf, err := entry.Canonicalize(httpReq.Context())
 			if err != nil {
-				code := http.StatusInternalServerError
-				return logAndReturnError(entries.NewSearchLogQueryDefault(code), code, err, err.Error(), params.HTTPRequest)
+				return handleRekorAPIError(params, http.StatusInternalServerError, err, err.Error())
 			}
 			hasher := rfc6962.DefaultHasher
 			leafHash := hasher.HashLeaf(leaf)
 			searchHashes = append(searchHashes, leafHash)
 		}
 
-		resp, err := api.client.getLeafByHash(searchHashes)
-		if err != nil {
-			code := http.StatusInternalServerError
-			return logAndReturnError(entries.NewSearchLogQueryDefault(code), code, err, trillianCommunicationError, params.HTTPRequest)
-		}
+		resp := api.client.getLeafByHash(searchHashes) // TODO: if this API is deprecated, we need to ask for inclusion proof and then use index in proof result to get leaf
 		switch resp.status {
 		case codes.OK, codes.NotFound:
 		default:
-			code := http.StatusInternalServerError
-			return logAndReturnError(entries.NewSearchLogQueryDefault(code), code, nil, trillianUnexpectedResult, params.HTTPRequest)
+			return handleRekorAPIError(params, http.StatusInternalServerError, fmt.Errorf("grpc error: %w", resp.err), trillianUnexpectedResult)
 		}
 
 		for _, leaf := range resp.getLeafResult.Leaves {
@@ -269,19 +244,18 @@ func SearchLogQueryHandler(params entries.SearchLogQueryParams) middleware.Respo
 	}
 
 	if len(params.Entry.LogIndexes) > 0 {
-		resp, err := api.client.getLeafByIndex(swag.Int64ValueSlice(params.Entry.LogIndexes))
-		if err != nil {
-			code := http.StatusInternalServerError
-			return logAndReturnError(entries.NewSearchLogQueryDefault(code), code, err, trillianCommunicationError, params.HTTPRequest)
-		}
-		switch resp.status {
-		case codes.OK, codes.NotFound:
-		default:
-			code := http.StatusInternalServerError
-			return logAndReturnError(entries.NewSearchLogQueryDefault(code), code, nil, trillianUnexpectedResult, params.HTTPRequest)
+		leaves := []*trillian.LogLeaf{}
+		for _, logIndex := range params.Entry.LogIndexes {
+			resp := api.client.getLeafByIndex(swag.Int64Value(logIndex))
+			switch resp.status {
+			case codes.OK, codes.NotFound:
+			default:
+				return handleRekorAPIError(params, http.StatusInternalServerError, fmt.Errorf("grpc error: %w", resp.err), trillianUnexpectedResult)
+			}
+			leaves = append(leaves, resp.getLeafResult.Leaves...)
 		}
 
-		for _, leaf := range resp.getLeafResult.Leaves {
+		for _, leaf := range leaves {
 			logEntry := models.LogEntry{
 				hex.EncodeToString(leaf.MerkleLeafHash): models.LogEntryAnon{
 					LogIndex: &leaf.LeafIndex,
diff --git a/pkg/api/error.go b/pkg/api/error.go
index e6e09f17fc113ce3304ec6fed412417140fda2f9..5121cbae7b3b9304e98a0ae68da270f1aa9b8242 100644
--- a/pkg/api/error.go
+++ b/pkg/api/error.go
@@ -16,11 +16,15 @@ limitations under the License.
 package api
 
 import (
+	"fmt"
 	"net/http"
-	"reflect"
+	"regexp"
 
 	"github.com/go-openapi/runtime/middleware"
+	"github.com/mitchellh/mapstructure"
 	"github.com/projectrekor/rekor/pkg/generated/models"
+	"github.com/projectrekor/rekor/pkg/generated/restapi/operations/entries"
+	"github.com/projectrekor/rekor/pkg/generated/restapi/operations/tlog"
 	"github.com/projectrekor/rekor/pkg/log"
 )
 
@@ -30,22 +34,89 @@ const (
 	failedToGenerateCanonicalEntry = "Error generating canonicalized entry"
 	entryAlreadyExists             = "An equivalent entry already exists in the transparency log"
 	firstSizeLessThanLastSize      = "firstSize(%v) must be less than lastSize(%v)"
+	malformedUUID                  = "UUID must be a 64-character hexadecimal string"
 )
 
 func errorMsg(message string, code int) *models.Error {
-	errObj := models.Error{
-		Status:  int64(code),
+	return &models.Error{
+		Code:    int64(code),
 		Message: message,
 	}
-	return &errObj
 }
 
-func logAndReturnError(returnObj middleware.Responder, code int, err error, message string, r *http.Request) middleware.Responder {
-	log.RequestIDLogger(r).Errorf("returning %T(%v): message '%v', err '%v'", returnObj, code, message, err)
-	errorMsg := errorMsg(message, code)
-	if m, ok := reflect.TypeOf(returnObj).MethodByName("WithPayload"); ok {
-		args := []reflect.Value{reflect.ValueOf(returnObj), reflect.ValueOf(errorMsg)}
-		return m.Func.Call(args)[0].Interface().(middleware.Responder)
+func handleRekorAPIError(params interface{}, code int, err error, message string, fields ...interface{}) middleware.Responder {
+	if message == "" {
+		message = http.StatusText(code)
+	}
+
+	re := regexp.MustCompile("^(.*)Params$")
+	typeStr := fmt.Sprintf("%T", params)
+	handler := re.FindStringSubmatch(typeStr)[1]
+
+	logMsg := func(r *http.Request) {
+		log.RequestIDLogger(r).Errorw("exiting with error", append([]interface{}{"handler", handler, "statusCode", code, "clientMessage", message, "error", err}, fields...)...)
+		paramsFields := map[string]interface{}{}
+		if err := mapstructure.Decode(params, &paramsFields); err == nil {
+			log.RequestIDLogger(r).Debug(paramsFields)
+		}
+	}
+
+	switch params := params.(type) {
+	case entries.GetLogEntryByIndexParams:
+		logMsg(params.HTTPRequest)
+		switch code {
+		case http.StatusNotFound:
+			return entries.NewGetLogEntryByIndexNotFound()
+		default:
+			return entries.NewGetLogEntryByIndexDefault(code).WithPayload(errorMsg(message, code))
+		}
+	case entries.GetLogEntryByUUIDParams:
+		logMsg(params.HTTPRequest)
+		switch code {
+		case http.StatusNotFound:
+			return entries.NewGetLogEntryByUUIDNotFound()
+		default:
+			return entries.NewGetLogEntryByUUIDDefault(code).WithPayload(errorMsg(message, code))
+		}
+	case entries.GetLogEntryProofParams:
+		logMsg(params.HTTPRequest)
+		switch code {
+		case http.StatusNotFound:
+			return entries.NewGetLogEntryProofNotFound()
+		default:
+			return entries.NewGetLogEntryProofDefault(code).WithPayload(errorMsg(message, code))
+		}
+	case entries.CreateLogEntryParams:
+		logMsg(params.HTTPRequest)
+		switch code {
+		case http.StatusBadRequest:
+			return entries.NewCreateLogEntryBadRequest()
+		case http.StatusConflict:
+			return entries.NewCreateLogEntryConflict()
+		default:
+			return entries.NewCreateLogEntryDefault(code).WithPayload(errorMsg(message, code))
+		}
+	case entries.SearchLogQueryParams:
+		logMsg(params.HTTPRequest)
+		switch code {
+		case http.StatusBadRequest:
+			return entries.NewSearchLogQueryBadRequest()
+		default:
+			return entries.NewSearchLogQueryDefault(code).WithPayload(errorMsg(message, code))
+		}
+	case tlog.GetLogInfoParams:
+		logMsg(params.HTTPRequest)
+		return tlog.NewGetLogInfoDefault(code).WithPayload(errorMsg(message, code))
+	case tlog.GetLogProofParams:
+		logMsg(params.HTTPRequest)
+		switch code {
+		case http.StatusBadRequest:
+			return tlog.NewGetLogProofBadRequest()
+		default:
+			return tlog.NewGetLogProofDefault(code).WithPayload(errorMsg(message, code))
+		}
+	default:
+		log.Logger.Errorf("unable to find method for type %T; error: %v", params, err)
+		return middleware.Error(http.StatusInternalServerError, http.StatusText(http.StatusInternalServerError))
 	}
-	return returnObj
 }
diff --git a/pkg/api/tlog.go b/pkg/api/tlog.go
index 5eb4fb7d96ff3a35d9dddcf481a60d96ba3c91fb..c68a0b4fffcfc04d415ce4ce67469704573b9875 100644
--- a/pkg/api/tlog.go
+++ b/pkg/api/tlog.go
@@ -19,10 +19,12 @@ import (
 	"crypto"
 	"crypto/x509"
 	"encoding/hex"
+	"errors"
 	"fmt"
 	"net/http"
 
 	"github.com/projectrekor/rekor/pkg/generated/models"
+	"google.golang.org/grpc/codes"
 
 	"github.com/go-openapi/runtime/middleware"
 	tclient "github.com/google/trillian/client"
@@ -32,26 +34,24 @@ import (
 )
 
 func GetLogInfoHandler(params tlog.GetLogInfoParams) middleware.Responder {
-	api, _ := NewAPI(params.HTTPRequest.Context())
+	httpReq := params.HTTPRequest
+	api, _ := NewAPI(httpReq.Context())
 
-	resp, err := api.client.getLatest(0)
-	if err != nil {
-		code := http.StatusInternalServerError
-		return logAndReturnError(tlog.NewGetLogInfoDefault(code), code, err, trillianCommunicationError, params.HTTPRequest)
+	resp := api.client.getLatest(0)
+	if resp.status != codes.OK {
+		return handleRekorAPIError(params, http.StatusInternalServerError, fmt.Errorf("grpc error: %w", resp.err), trillianCommunicationError)
 	}
 	result := resp.getLatestResult
 
 	// validate result is signed with the key we're aware of
 	pub, err := x509.ParsePKIXPublicKey(api.pubkey.Der)
 	if err != nil {
-		code := http.StatusInternalServerError
-		return logAndReturnError(tlog.NewGetLogInfoDefault(code), code, err, http.StatusText(code), params.HTTPRequest)
+		return handleRekorAPIError(params, http.StatusInternalServerError, err, "")
 	}
 	verifier := tclient.NewLogVerifier(rfc6962.DefaultHasher, pub, crypto.SHA256)
 	root, err := tcrypto.VerifySignedLogRoot(verifier.PubKey, verifier.SigHash, result.SignedLogRoot)
 	if err != nil {
-		code := http.StatusInternalServerError
-		return logAndReturnError(tlog.NewGetLogInfoDefault(code), code, err, trillianUnexpectedResult, params.HTTPRequest)
+		return handleRekorAPIError(params, http.StatusInternalServerError, err, trillianUnexpectedResult)
 	}
 
 	hashString := hex.EncodeToString(root.RootHash)
@@ -65,29 +65,27 @@ func GetLogInfoHandler(params tlog.GetLogInfoParams) middleware.Responder {
 }
 
 func GetLogProofHandler(params tlog.GetLogProofParams) middleware.Responder {
+	httpReq := params.HTTPRequest
 	if *params.FirstSize > params.LastSize {
-		return logAndReturnError(tlog.NewGetLogProofBadRequest(), http.StatusBadRequest, nil, fmt.Sprintf(firstSizeLessThanLastSize, *params.FirstSize, params.LastSize), params.HTTPRequest)
+		return handleRekorAPIError(params, http.StatusBadRequest, nil, fmt.Sprintf(firstSizeLessThanLastSize, *params.FirstSize, params.LastSize))
 	}
-	api, _ := NewAPI(params.HTTPRequest.Context())
+	api, _ := NewAPI(httpReq.Context())
 
-	resp, err := api.client.getConsistencyProof(*params.FirstSize, params.LastSize)
-	if err != nil {
-		code := http.StatusInternalServerError
-		return logAndReturnError(tlog.NewGetLogProofDefault(code), code, err, trillianCommunicationError, params.HTTPRequest)
+	resp := api.client.getConsistencyProof(*params.FirstSize, params.LastSize)
+	if resp.status != codes.OK {
+		return handleRekorAPIError(params, http.StatusInternalServerError, fmt.Errorf("grpc error: %w", resp.err), trillianCommunicationError)
 	}
 	result := resp.getConsistencyProofResult
 
 	// validate result is signed with the key we're aware of
 	pub, err := x509.ParsePKIXPublicKey(api.pubkey.Der)
 	if err != nil {
-		code := http.StatusInternalServerError
-		return logAndReturnError(tlog.NewGetLogProofDefault(code), code, err, http.StatusText(code), params.HTTPRequest)
+		return handleRekorAPIError(params, http.StatusInternalServerError, err, "")
 	}
 	verifier := tclient.NewLogVerifier(rfc6962.DefaultHasher, pub, crypto.SHA256)
 	root, err := tcrypto.VerifySignedLogRoot(verifier.PubKey, verifier.SigHash, result.SignedLogRoot)
 	if err != nil {
-		code := http.StatusInternalServerError
-		return logAndReturnError(tlog.NewGetLogProofDefault(code), code, err, trillianUnexpectedResult, params.HTTPRequest)
+		return handleRekorAPIError(params, http.StatusInternalServerError, err, trillianUnexpectedResult)
 	}
 
 	hashString := hex.EncodeToString(root.RootHash)
@@ -97,6 +95,8 @@ func GetLogProofHandler(params tlog.GetLogProofParams) middleware.Responder {
 		for _, hash := range proof.Hashes {
 			proofHashes = append(proofHashes, hex.EncodeToString(hash))
 		}
+	} else {
+		return handleRekorAPIError(params, http.StatusInternalServerError, errors.New("grpc call succeeded but no proof returned"), trillianUnexpectedResult)
 	}
 
 	consistencyProof := models.ConsistencyProof{
diff --git a/pkg/api/trillian_client.go b/pkg/api/trillian_client.go
index 6763b4c25691b7acadf321a16f44556ad74520f8..283cc74826701f772dd49ee53cfab2c122f388c8 100644
--- a/pkg/api/trillian_client.go
+++ b/pkg/api/trillian_client.go
@@ -18,11 +18,9 @@ package api
 
 import (
 	"context"
-	"fmt"
 	"time"
 
 	"github.com/golang/protobuf/ptypes"
-	"github.com/projectrekor/rekor/pkg/log"
 	"google.golang.org/grpc/codes"
 	"google.golang.org/grpc/status"
 
@@ -36,24 +34,27 @@ import (
 )
 
 type TrillianClient struct {
-	client trillian.TrillianLogClient
-	logID  int64
+	client  trillian.TrillianLogClient
+	logID   int64
+	context context.Context
 }
 
 type Response struct {
 	status                    codes.Code
+	err                       error
 	getAddResult              *trillian.QueueLeafResponse
 	getLeafResult             *trillian.GetLeavesByHashResponse
 	getProofResult            *trillian.GetInclusionProofByHashResponse
-	getLeafByIndexResult      *trillian.GetLeavesByIndexResponse
+	getLeafByRangeResult      *trillian.GetLeavesByRangeResponse
 	getLatestResult           *trillian.GetLatestSignedLogRootResponse
 	getConsistencyProofResult *trillian.GetConsistencyProofResponse
 }
 
-func TrillianClientInstance(client trillian.TrillianLogClient, tLogID int64) *TrillianClient {
+func TrillianClientInstance(client trillian.TrillianLogClient, tLogID int64, ctx context.Context) *TrillianClient {
 	return &TrillianClient{
-		client: client,
-		logID:  tLogID,
+		client:  client,
+		logID:   tLogID,
+		context: ctx,
 	}
 }
 
@@ -61,7 +62,7 @@ func (t *TrillianClient) root() (types.LogRootV1, error) {
 	rqst := &trillian.GetLatestSignedLogRootRequest{
 		LogId: t.logID,
 	}
-	resp, err := t.client.GetLatestSignedLogRoot(context.Background(), rqst)
+	resp, err := t.client.GetLatestSignedLogRoot(t.context, rqst)
 	if err != nil {
 		return types.LogRootV1{}, err
 	}
@@ -72,7 +73,7 @@ func (t *TrillianClient) root() (types.LogRootV1, error) {
 	return root, nil
 }
 
-func (t *TrillianClient) addLeaf(byteValue []byte) (*Response, error) {
+func (t *TrillianClient) addLeaf(byteValue []byte) *Response {
 	leaf := &trillian.LogLeaf{
 		LeafValue: byteValue,
 	}
@@ -80,58 +81,59 @@ func (t *TrillianClient) addLeaf(byteValue []byte) (*Response, error) {
 		LogId: t.logID,
 		Leaf:  leaf,
 	}
-	resp, err := t.client.QueueLeaf(context.Background(), rqst)
-	if err != nil {
-		fmt.Println(err)
-	}
+	resp, err := t.client.QueueLeaf(t.context, rqst)
 
 	return &Response{
-		status:       codes.Code(resp.QueuedLeaf.GetStatus().GetCode()),
+		status:       status.Code(err),
+		err:          err,
 		getAddResult: resp,
-	}, nil
+	}
 }
 
-func (t *TrillianClient) getLeafByHash(hashValues [][]byte) (*Response, error) {
+func (t *TrillianClient) getLeafByHash(hashValues [][]byte) *Response {
 	rqst := &trillian.GetLeavesByHashRequest{
 		LogId:    t.logID,
 		LeafHash: hashValues,
 	}
 
-	resp, err := t.client.GetLeavesByHash(context.Background(), rqst)
-	if err != nil {
-		log.Logger.Fatal(err)
-	}
+	resp, err := t.client.GetLeavesByHash(t.context, rqst)
 
 	return &Response{
 		status:        status.Code(err),
+		err:           err,
 		getLeafResult: resp,
-	}, nil
+	}
 }
 
-func (t *TrillianClient) getLeafByIndex(indexes []int64) (*Response, error) {
+func (t *TrillianClient) getLeafByIndex(index int64) *Response {
 
-	ctx, cancel := context.WithTimeout(context.Background(), 20*time.Second)
+	ctx, cancel := context.WithTimeout(t.context, 20*time.Second)
 	defer cancel()
 
-	resp, err := t.client.GetLeavesByIndex(ctx,
-		&trillian.GetLeavesByIndexRequest{
-			LogId:     t.logID,
-			LeafIndex: indexes,
+	resp, err := t.client.GetLeavesByRange(ctx,
+		&trillian.GetLeavesByRangeRequest{
+			LogId:      t.logID,
+			StartIndex: index,
+			Count:      1,
 		})
 
 	return &Response{
 		status:               status.Code(err),
-		getLeafByIndexResult: resp,
-	}, nil
+		err:                  err,
+		getLeafByRangeResult: resp,
+	}
 }
 
-func (t *TrillianClient) getProofByHash(hashValue []byte) (*Response, error) {
-	ctx, cancel := context.WithTimeout(context.Background(), 20*time.Second)
+func (t *TrillianClient) getProofByHash(hashValue []byte) *Response {
+	ctx, cancel := context.WithTimeout(t.context, 20*time.Second)
 	defer cancel()
 
 	root, err := t.root()
 	if err != nil {
-		return &Response{}, err
+		return &Response{
+			status: status.Code(err),
+			err:    err,
+		}
 	}
 
 	resp, err := t.client.GetInclusionProofByHash(ctx,
@@ -144,26 +146,26 @@ func (t *TrillianClient) getProofByHash(hashValue []byte) (*Response, error) {
 	v := merkle.NewLogVerifier(rfc6962.DefaultHasher)
 
 	if resp != nil {
-		for i, proof := range resp.Proof {
-			hashes := proof.GetHashes()
-			for j, hash := range hashes {
-				log.Logger.Infof("Proof[%d],hash[%d] == %x\n", i, j, hash)
-			}
-			if err := v.VerifyInclusionProof(proof.LeafIndex, int64(root.TreeSize), hashes, root.RootHash, hashValue); err != nil {
-				return &Response{}, err
+		for _, proof := range resp.Proof {
+			if err := v.VerifyInclusionProof(proof.LeafIndex, int64(root.TreeSize), proof.GetHashes(), root.RootHash, hashValue); err != nil {
+				return &Response{
+					status: status.Code(err),
+					err:    err,
+				}
 			}
 		}
 	}
 
 	return &Response{
 		status:         status.Code(err),
+		err:            err,
 		getProofResult: resp,
-	}, nil
+	}
 }
 
-func (t *TrillianClient) getLatest(leafSizeInt int64) (*Response, error) {
+func (t *TrillianClient) getLatest(leafSizeInt int64) *Response {
 
-	ctx, cancel := context.WithTimeout(context.Background(), 20*time.Second)
+	ctx, cancel := context.WithTimeout(t.context, 20*time.Second)
 	defer cancel()
 
 	resp, err := t.client.GetLatestSignedLogRoot(ctx,
@@ -171,19 +173,17 @@ func (t *TrillianClient) getLatest(leafSizeInt int64) (*Response, error) {
 			LogId:         t.logID,
 			FirstTreeSize: leafSizeInt,
 		})
-	if err != nil {
-		return nil, err
-	}
 
 	return &Response{
 		status:          status.Code(err),
+		err:             err,
 		getLatestResult: resp,
-	}, nil
+	}
 }
 
-func (t *TrillianClient) getConsistencyProof(firstSize, lastSize int64) (*Response, error) {
+func (t *TrillianClient) getConsistencyProof(firstSize, lastSize int64) *Response {
 
-	ctx, cancel := context.WithTimeout(context.Background(), 20*time.Second)
+	ctx, cancel := context.WithTimeout(t.context, 20*time.Second)
 	defer cancel()
 
 	resp, err := t.client.GetConsistencyProof(ctx,
@@ -192,14 +192,12 @@ func (t *TrillianClient) getConsistencyProof(firstSize, lastSize int64) (*Respon
 			FirstTreeSize:  firstSize,
 			SecondTreeSize: lastSize,
 		})
-	if err != nil {
-		return nil, err
-	}
 
 	return &Response{
 		status:                    status.Code(err),
+		err:                       err,
 		getConsistencyProofResult: resp,
-	}, nil
+	}
 }
 
 func createAndInitTree(ctx context.Context, adminClient trillian.TrillianAdminClient, logClient trillian.TrillianLogClient) (*trillian.Tree, error) {
diff --git a/pkg/generated/models/error.go b/pkg/generated/models/error.go
index 66d27a7931b792c1276f7abf0fb41dd2b201e46c..4f8232f98bc2d0bdd8b920625467739f8db8e468 100644
--- a/pkg/generated/models/error.go
+++ b/pkg/generated/models/error.go
@@ -34,11 +34,11 @@ import (
 // swagger:model Error
 type Error struct {
 
+	// code
+	Code int64 `json:"code,omitempty"`
+
 	// message
 	Message string `json:"message,omitempty"`
-
-	// status
-	Status int64 `json:"status,omitempty"`
 }
 
 // Validate validates this error
diff --git a/pkg/generated/models/search_log_query.go b/pkg/generated/models/search_log_query.go
index d5b7da50d4346fe4b9a74dca299c2b1b12f064ec..7c27203a18ba5bdb2c4c529aa71bc9b6e829242c 100644
--- a/pkg/generated/models/search_log_query.go
+++ b/pkg/generated/models/search_log_query.go
@@ -140,6 +140,10 @@ func (m *SearchLogQuery) Validate(formats strfmt.Registry) error {
 		res = append(res, err)
 	}
 
+	if err := m.validateEntryUUIDs(formats); err != nil {
+		res = append(res, err)
+	}
+
 	if err := m.validateLogIndexes(formats); err != nil {
 		res = append(res, err)
 	}
@@ -169,6 +173,22 @@ func (m *SearchLogQuery) validateEntries(formats strfmt.Registry) error {
 	return nil
 }
 
+func (m *SearchLogQuery) validateEntryUUIDs(formats strfmt.Registry) error {
+	if swag.IsZero(m.EntryUUIDs) { // not required
+		return nil
+	}
+
+	for i := 0; i < len(m.EntryUUIDs); i++ {
+
+		if err := validate.Pattern("entryUUIDs"+"."+strconv.Itoa(i), "body", string(m.EntryUUIDs[i]), `^[0-9a-fA-F]{64}$`); err != nil {
+			return err
+		}
+
+	}
+
+	return nil
+}
+
 func (m *SearchLogQuery) validateLogIndexes(formats strfmt.Registry) error {
 	if swag.IsZero(m.LogIndexes) { // not required
 		return nil
diff --git a/pkg/generated/restapi/configure_rekor_server.go b/pkg/generated/restapi/configure_rekor_server.go
index be1ef6e8f2f31938edc5deb6bf01c73c5ba95e2b..636712aac3c1a540abb3c6a4874e2972bfcfab9d 100644
--- a/pkg/generated/restapi/configure_rekor_server.go
+++ b/pkg/generated/restapi/configure_rekor_server.go
@@ -19,11 +19,13 @@ package restapi
 
 import (
 	"crypto/tls"
+	"fmt"
 	"net/http"
 
 	"github.com/go-chi/chi/middleware"
 	"github.com/go-openapi/errors"
 	"github.com/go-openapi/runtime"
+	"github.com/mitchellh/mapstructure"
 
 	pkgapi "github.com/projectrekor/rekor/pkg/api"
 	"github.com/projectrekor/rekor/pkg/generated/restapi/operations"
@@ -31,6 +33,8 @@ import (
 	"github.com/projectrekor/rekor/pkg/generated/restapi/operations/tlog"
 	"github.com/projectrekor/rekor/pkg/log"
 	"github.com/projectrekor/rekor/pkg/util"
+
+	"github.com/urfave/negroni"
 )
 
 //go:generate swagger generate server --target ../../generated --name RekorServer --spec ../../../openapi.yaml --principal interface{} --exclude-main
@@ -41,7 +45,7 @@ func configureFlags(api *operations.RekorServerAPI) {
 
 func configureAPI(api *operations.RekorServerAPI) http.Handler {
 	// configure the api here
-	api.ServeError = errors.ServeError
+	api.ServeError = logAndServeError
 
 	// Set your custom logger if needed. Default one is log.Printf
 	// Expected interface func(string, ...interface{})
@@ -50,7 +54,7 @@ func configureAPI(api *operations.RekorServerAPI) http.Handler {
 	// api.Logger = log.Printf
 	api.Logger = log.Logger.Infof
 
-	api.UseSwaggerUI()
+	// api.UseSwaggerUI()
 	// To continue using redoc as your UI, uncomment the following line
 	// api.UseRedoc()
 
@@ -73,6 +77,15 @@ func configureAPI(api *operations.RekorServerAPI) http.Handler {
 
 	api.ServerShutdown = func() {}
 
+	//api object in context
+	api.AddMiddlewareFor("POST", "/api/v1/log/entries", addTrillianAPI)
+	api.AddMiddlewareFor("POST", "/api/v1/log/entries/retrieve", addTrillianAPI)
+	api.AddMiddlewareFor("GET", "/api/v1/log", addTrillianAPI)
+	api.AddMiddlewareFor("GET", "/api/v1/log/proof", addTrillianAPI)
+	api.AddMiddlewareFor("GET", "/api/v1/log/entries/{entryUUID}/proof", addTrillianAPI)
+	api.AddMiddlewareFor("GET", "/api/v1/log/entries", addTrillianAPI)
+	api.AddMiddlewareFor("GET", "/api/v1/log/entries/{entryUUID}", addTrillianAPI)
+
 	//not cacheable
 	api.AddMiddlewareFor("GET", "/api/v1/log", middleware.NoCache)
 	api.AddMiddlewareFor("GET", "/api/v1/log/proof", middleware.NoCache)
@@ -122,7 +135,32 @@ func setupGlobalMiddleware(handler http.Handler) http.Handler {
 
 func cacheForever(handler http.Handler) http.Handler {
 	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
-		w.Header().Set("Cache-Control", "s-maxage=31536000, max-age=31536000, immutable")
-		handler.ServeHTTP(w, r)
+		ww := negroni.NewResponseWriter(w)
+		ww.Before(func(w negroni.ResponseWriter) {
+			if w.Status() >= 200 && w.Status() <= 299 {
+				w.Header().Set("Cache-Control", "s-maxage=31536000, max-age=31536000, immutable")
+			}
+		})
+		handler.ServeHTTP(ww, r)
+	})
+}
+
+func addTrillianAPI(handler http.Handler) http.Handler {
+	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+		apiCtx, err := pkgapi.AddAPIToContext(r.Context())
+		if err != nil {
+			logAndServeError(w, r, fmt.Errorf("error adding trillian API object to request context: %v", err))
+		} else {
+			handler.ServeHTTP(w, r.WithContext(apiCtx))
+		}
 	})
 }
+
+func logAndServeError(w http.ResponseWriter, r *http.Request, err error) {
+	log.RequestIDLogger(r).Error(err)
+	requestFields := map[string]interface{}{}
+	if err := mapstructure.Decode(r, &requestFields); err == nil {
+		log.RequestIDLogger(r).Debug(requestFields)
+	}
+	errors.ServeError(w, r, err)
+}
diff --git a/pkg/generated/restapi/embedded_spec.go b/pkg/generated/restapi/embedded_spec.go
index b25048d76b61ef09c05bf28aaf9633e1096a350d..bf0e81a376a20f62f5ce1c0c8eb41d374badb4ff 100644
--- a/pkg/generated/restapi/embedded_spec.go
+++ b/pkg/generated/restapi/embedded_spec.go
@@ -195,6 +195,7 @@ func init() {
         "operationId": "getLogEntryByUUID",
         "parameters": [
           {
+            "pattern": "^[0-9a-fA-F]{64}$",
             "type": "string",
             "description": "the UUID of the entry to be retrieved from the log. The UUID is also the merkle tree hash of the entry.",
             "name": "entryUUID",
@@ -228,6 +229,7 @@ func init() {
         "operationId": "getLogEntryProof",
         "parameters": [
           {
+            "pattern": "^[0-9a-fA-F]{64}$",
             "type": "string",
             "description": "the UUID of the entry for which the inclusion proof information should be returned",
             "name": "entryUUID",
@@ -320,11 +322,11 @@ func init() {
     "Error": {
       "type": "object",
       "properties": {
+        "code": {
+          "type": "integer"
+        },
         "message": {
           "type": "string"
-        },
-        "status": {
-          "type": "integer"
         }
       }
     },
@@ -425,6 +427,7 @@ func init() {
           "type": "array",
           "items": {
             "type": "string",
+            "pattern": "^[0-9a-fA-F]{64}$",
             "minItems": 1
           }
         },
@@ -671,6 +674,7 @@ func init() {
         "operationId": "getLogEntryByUUID",
         "parameters": [
           {
+            "pattern": "^[0-9a-fA-F]{64}$",
             "type": "string",
             "description": "the UUID of the entry to be retrieved from the log. The UUID is also the merkle tree hash of the entry.",
             "name": "entryUUID",
@@ -707,6 +711,7 @@ func init() {
         "operationId": "getLogEntryProof",
         "parameters": [
           {
+            "pattern": "^[0-9a-fA-F]{64}$",
             "type": "string",
             "description": "the UUID of the entry for which the inclusion proof information should be returned",
             "name": "entryUUID",
@@ -808,11 +813,11 @@ func init() {
     "Error": {
       "type": "object",
       "properties": {
+        "code": {
+          "type": "integer"
+        },
         "message": {
           "type": "string"
-        },
-        "status": {
-          "type": "integer"
         }
       }
     },
@@ -1082,7 +1087,8 @@ func init() {
         "entryUUIDs": {
           "type": "array",
           "items": {
-            "type": "string"
+            "type": "string",
+            "pattern": "^[0-9a-fA-F]{64}$"
           }
         },
         "logIndexes": {
diff --git a/pkg/generated/restapi/operations/entries/get_log_entry_by_uuid_parameters.go b/pkg/generated/restapi/operations/entries/get_log_entry_by_uuid_parameters.go
index 7356743d64b00f125d79965f4c69ae34ebf2c7eb..908383ee56904fb82c5fd9ec4327a34cebbe950a 100644
--- a/pkg/generated/restapi/operations/entries/get_log_entry_by_uuid_parameters.go
+++ b/pkg/generated/restapi/operations/entries/get_log_entry_by_uuid_parameters.go
@@ -28,6 +28,7 @@ import (
 	"github.com/go-openapi/errors"
 	"github.com/go-openapi/runtime/middleware"
 	"github.com/go-openapi/strfmt"
+	"github.com/go-openapi/validate"
 )
 
 // NewGetLogEntryByUUIDParams creates a new GetLogEntryByUUIDParams object
@@ -48,6 +49,7 @@ type GetLogEntryByUUIDParams struct {
 
 	/*the UUID of the entry to be retrieved from the log. The UUID is also the merkle tree hash of the entry.
 	  Required: true
+	  Pattern: ^[0-9a-fA-F]{64}$
 	  In: path
 	*/
 	EntryUUID string
@@ -85,5 +87,19 @@ func (o *GetLogEntryByUUIDParams) bindEntryUUID(rawData []string, hasKey bool, f
 
 	o.EntryUUID = raw
 
+	if err := o.validateEntryUUID(formats); err != nil {
+		return err
+	}
+
+	return nil
+}
+
+// validateEntryUUID carries on validations for parameter EntryUUID
+func (o *GetLogEntryByUUIDParams) validateEntryUUID(formats strfmt.Registry) error {
+
+	if err := validate.Pattern("entryUUID", "path", o.EntryUUID, `^[0-9a-fA-F]{64}$`); err != nil {
+		return err
+	}
+
 	return nil
 }
diff --git a/pkg/generated/restapi/operations/entries/get_log_entry_proof_parameters.go b/pkg/generated/restapi/operations/entries/get_log_entry_proof_parameters.go
index fdb3902fdee72a599cb21851d175da6e861e45c1..2a3cee38c4f151608aa371f7eefb8664b9301d7c 100644
--- a/pkg/generated/restapi/operations/entries/get_log_entry_proof_parameters.go
+++ b/pkg/generated/restapi/operations/entries/get_log_entry_proof_parameters.go
@@ -28,6 +28,7 @@ import (
 	"github.com/go-openapi/errors"
 	"github.com/go-openapi/runtime/middleware"
 	"github.com/go-openapi/strfmt"
+	"github.com/go-openapi/validate"
 )
 
 // NewGetLogEntryProofParams creates a new GetLogEntryProofParams object
@@ -48,6 +49,7 @@ type GetLogEntryProofParams struct {
 
 	/*the UUID of the entry for which the inclusion proof information should be returned
 	  Required: true
+	  Pattern: ^[0-9a-fA-F]{64}$
 	  In: path
 	*/
 	EntryUUID string
@@ -85,5 +87,19 @@ func (o *GetLogEntryProofParams) bindEntryUUID(rawData []string, hasKey bool, fo
 
 	o.EntryUUID = raw
 
+	if err := o.validateEntryUUID(formats); err != nil {
+		return err
+	}
+
+	return nil
+}
+
+// validateEntryUUID carries on validations for parameter EntryUUID
+func (o *GetLogEntryProofParams) validateEntryUUID(formats strfmt.Registry) error {
+
+	if err := validate.Pattern("entryUUID", "path", o.EntryUUID, `^[0-9a-fA-F]{64}$`); err != nil {
+		return err
+	}
+
 	return nil
 }