diff --git a/.gx/lastpubver b/.gx/lastpubver
index 38e7732..a19ded8 100644
--- a/.gx/lastpubver
+++ b/.gx/lastpubver
@@ -1 +1 @@
-0.1.2: QmbfKu17LbMWyGUxHEUns9Wf5Dkm8PT6be4uPhTkk4YvaV
+0.1.4: QmckgkstbdXagMTQ4e1DW2SzxGcjjudbqEvA5H2Rb7uvAT
diff --git a/apicid/apicid.go b/apicid/apicid.go
new file mode 100644
index 0000000..22c4ea7
--- /dev/null
+++ b/apicid/apicid.go
@@ -0,0 +1,61 @@
+package apicid
+
+import (
+	cid "github.com/ipfs/go-cid"
+	"github.com/ipfs/go-cidutil/cidenc"
+	mbase "github.com/multiformats/go-multibase"
+)
+
+// JSONBase is the base to use when Encoding into JSON.
+var JSONBase mbase.Encoder = mbase.MustNewEncoder(mbase.Base58BTC)
+
+// apicid.Hash is a type to respesnt a CID in the API which marshals
+// as a string
+type Hash struct {
+	str string
+}
+
+// FromCid creates an APICid from a Cid
+func FromCid(c cid.Cid) Hash {
+	return Hash{c.Encode(JSONBase)}
+}
+
+// Cid converts an APICid to a CID
+func (c Hash) Cid() (cid.Cid, error) {
+	return cid.Decode(c.str)
+}
+
+func (c Hash) String() string {
+	return c.Encode(cidenc.Default)
+}
+
+func (c Hash) Encode(enc cidenc.Interface) string {
+	if c.str == "" {
+		return ""
+	}
+	str, err := enc.Recode(c.str)
+	if err != nil {
+		return c.str
+	}
+	return str
+}
+
+func (c *Hash) UnmarshalText(b []byte) error {
+	c.str = string(b)
+	return nil
+}
+
+func (c Hash) MarshalText() ([]byte, error) {
+	return []byte(c.str), nil
+}
+
+// Cid is type to represent a normal CID in the API which marshals
+// like a normal CID i.e. ({"/": <HASH>}) but may uses cidenc.Default
+// for the String() to optionally upgrade a version 0 CID to version 1
+type Cid struct {
+	cid.Cid
+}
+
+func (c Cid) String() string {
+	return cidenc.Default.Encode(c.Cid)
+}
diff --git a/apicid/apicid_test.go b/apicid/apicid_test.go
new file mode 100644
index 0000000..b967f88
--- /dev/null
+++ b/apicid/apicid_test.go
@@ -0,0 +1,48 @@
+package apicid
+
+import (
+	"encoding/json"
+	"testing"
+
+	cid "github.com/ipfs/go-cid"
+)
+
+func TestJson(t *testing.T) {
+	cid, _ := cid.Decode("zb2rhak9iRgDiik36KQBRr2qiCJHdyBH7YxFmw7FTdM6zo31m")
+	hash := FromCid(cid)
+	data, err := json.Marshal(hash)
+	if err != nil {
+		t.Fatal(err)
+	}
+	if string(data) != `"zb2rhak9iRgDiik36KQBRr2qiCJHdyBH7YxFmw7FTdM6zo31m"` {
+		t.Fatalf("json string incorrect: %s\n", data)
+	}
+	var hash2 Hash
+	err = json.Unmarshal(data, &hash2)
+	if err != nil {
+		t.Fatal(err)
+	}
+	if hash != hash2 {
+		t.Fatal("round trip failed")
+	}
+}
+
+func TestJsonMap(t *testing.T) {
+	cid1, _ := cid.Decode("zb2rhak9iRgDiik36KQBRr2qiCJHdyBH7YxFmw7FTdM6zo31m")
+	cid2, _ := cid.Decode("QmRJggJREPCt7waGQKMXymrXRvrvsSiiPjgFbLK9isuM8K")
+	hash1 := FromCid(cid1)
+	hash2 := FromCid(cid2)
+	m := map[Hash]string{hash1: "a value", hash2: "something else"}
+	data, err := json.Marshal(m)
+	if err != nil {
+		t.Fatal(err)
+	}
+	m2 := map[Hash]string{}
+	err = json.Unmarshal(data, &m2)
+	if err != nil {
+		t.Fatal(err)
+	}
+	if len(m2) != 2 || m[hash1] != m2[hash1] || m[hash2] != m2[hash2] {
+		t.Fatal("round trip failed")
+	}
+}
diff --git a/cid-fmt/main.go b/cid-fmt/main.go
index 3aae3ee..8735658 100644
--- a/cid-fmt/main.go
+++ b/cid-fmt/main.go
@@ -1,7 +1,9 @@
 package main
 
 import (
+	"bufio"
 	"fmt"
+	"io"
 	"os"
 	"strings"
 
@@ -12,7 +14,9 @@ import (
 )
 
 func usage() {
-	fmt.Fprintf(os.Stderr, "usage: %s [-b multibase-code] [-v cid-version] <fmt-str> <cid> ...\n\n", os.Args[0])
+	fmt.Fprintf(os.Stderr, "usage: %s [-b multibase-code] [-v cid-version] [--filter] <fmt-str> <cid> ...\n", os.Args[0])
+	fmt.Fprintf(os.Stderr, "--filter will read from stdin and convert anything that looks like a <cid>\n")
+	fmt.Fprintf(os.Stderr, "         -- including any non-cids that are valid Multihashes).\n")
 	fmt.Fprintf(os.Stderr, "<fmt-str> is either 'prefix' or a printf style format string:\n%s", cidutil.FormatRef)
 	os.Exit(2)
 }
@@ -24,8 +28,9 @@ func main() {
 	newBase := mb.Encoding(-1)
 	var verConv func(cid c.Cid) (c.Cid, error)
 	args := os.Args[1:]
+	filter := false
 outer:
-	for {
+	for len(args) > 0 {
 		switch args[0] {
 		case "-b":
 			if len(args) < 2 {
@@ -52,11 +57,14 @@ outer:
 				os.Exit(2)
 			}
 			args = args[2:]
+		case "--filter":
+			filter = true
+			args = args[1:]
 		default:
 			break outer
 		}
 	}
-	if len(args) < 2 {
+	if len(args) < 1 {
 		usage()
 	}
 	fmtStr := args[0]
@@ -69,41 +77,73 @@ outer:
 			os.Exit(2)
 		}
 	}
-	for _, cidStr := range args[1:] {
-		cid, err := c.Decode(cidStr)
-		if err != nil {
-			fmt.Fprintf(os.Stdout, "!INVALID_CID!\n")
-			errorMsg("%s: %v", cidStr, err)
-			// Don't abort on a bad cid
-			continue
-		}
+	format := func(cid c.Cid, cidStr string) (string, error) {
 		base := newBase
-		if newBase == -1 {
+		if base == -1 {
 			base, _ = c.ExtractEncoding(cidStr)
 		}
+		var err error
 		if verConv != nil {
 			cid, err = verConv(cid)
 			if err != nil {
-				fmt.Fprintf(os.Stdout, "!ERROR!\n")
-				errorMsg("%s: %v", cidStr, err)
-				// Don't abort on a bad conversion
-				continue
+				return "", err
+			}
+		}
+		return cidutil.Format(fmtStr, base, cid)
+	}
+	if filter {
+		scanner := bufio.NewScanner(os.Stdin)
+		for scanner.Scan() {
+			buf := scanner.Bytes()
+			for {
+				i, j, cid, cidStr := cidutil.ScanForCid(buf)
+				os.Stdout.Write(buf[0:i])
+				if i == len(buf) {
+					os.Stdout.Write([]byte{'\n'})
+					break
+				}
+				str, err := format(cid, cidStr)
+				switch err.(type) {
+				case cidutil.FormatStringError:
+					fmt.Fprintf(os.Stderr, "Error: %v\n", err)
+					os.Exit(2)
+				default:
+					// just use the orignal sting on non-fatal error
+					str = cidStr
+				case nil:
+				}
+				io.WriteString(os.Stdout, str)
+				buf = buf[j:]
 			}
 		}
-		str, err := cidutil.Format(fmtStr, base, cid)
-		switch err.(type) {
-		case cidutil.FormatStringError:
+		if err := scanner.Err(); err != nil {
 			fmt.Fprintf(os.Stderr, "Error: %v\n", err)
 			os.Exit(2)
-		default:
-			fmt.Fprintf(os.Stdout, "!ERROR!\n")
-			errorMsg("%s: %v", cidStr, err)
-			// Don't abort on cid specific errors
-			continue
-		case nil:
-			// no error
 		}
-		fmt.Fprintf(os.Stdout, "%s\n", str)
+	} else {
+		for _, cidStr := range args[1:] {
+			cid, err := c.Decode(cidStr)
+			if err != nil {
+				fmt.Fprintf(os.Stdout, "!INVALID_CID!\n")
+				errorMsg("%s: %v", cidStr, err)
+				// Don't abort on a bad cid
+				continue
+			}
+			str, err := format(cid, cidStr)
+			switch err.(type) {
+			case cidutil.FormatStringError:
+				fmt.Fprintf(os.Stderr, "Error: %v\n", err)
+				os.Exit(2)
+			default:
+				fmt.Fprintf(os.Stdout, "!ERROR!\n")
+				errorMsg("%s: %v", cidStr, err)
+				// Don't abort on cid specific errors
+				continue
+			case nil:
+				// no error
+			}
+			fmt.Fprintf(os.Stdout, "%s\n", str)
+		}
 	}
 	os.Exit(exitCode)
 }
diff --git a/cidenc/encoder.go b/cidenc/encoder.go
new file mode 100644
index 0000000..1310821
--- /dev/null
+++ b/cidenc/encoder.go
@@ -0,0 +1,85 @@
+package cidenc
+
+import (
+	"context"
+
+	cid "github.com/ipfs/go-cid"
+	mbase "github.com/multiformats/go-multibase"
+)
+
+// Encoder is a basic Encoder that will encode Cid's using a specifed
+// base and optionally upgrade a CidV0 to CidV1
+type Encoder struct {
+	Base    mbase.Encoder
+	Upgrade bool
+}
+
+// Interface is a generic interface to the Encoder functionally.
+type Interface interface {
+	Encode(c cid.Cid) string
+	Recode(v string) (string, error)
+}
+
+// Default is the default encoder
+var Default = Encoder{
+	Base:    mbase.MustNewEncoder(mbase.Base58BTC),
+	Upgrade: false,
+}
+
+func (enc Encoder) Encode(c cid.Cid) string {
+	if enc.Upgrade && c.Version() == 0 {
+		c = cid.NewCidV1(c.Type(), c.Hash())
+	}
+	return c.Encode(enc.Base)
+}
+
+// Recode reencodes the cid string to match the paramaters of the
+// encoder
+func (enc Encoder) Recode(v string) (string, error) {
+	skip, err := enc.noopRecode(v)
+	if skip || err != nil {
+		return v, err
+	}
+
+	c, err := cid.Decode(v)
+	if err != nil {
+		return v, err
+	}
+
+	return enc.Encode(c), nil
+}
+
+func (enc Encoder) noopRecode(v string) (bool, error) {
+	if len(v) < 2 {
+		return false, cid.ErrCidTooShort
+	}
+	ver := cidVer(v)
+	skip := ver == 0 && !enc.Upgrade || ver == 1 && v[0] == byte(enc.Base.Encoding())
+	return skip, nil
+}
+
+func cidVer(v string) int {
+	if len(v) == 46 && v[:2] == "Qm" {
+		return 0
+	} else {
+		return 1
+	}
+}
+
+type encoderKey struct{}
+
+// Enable "enables" the encoder in the context using WithValue
+func Enable(ctx context.Context, enc Interface) context.Context {
+	return context.WithValue(ctx, encoderKey{}, enc)
+}
+
+// Get gets an encoder from the context if it exists, otherwise the
+// default context is called.
+func Get(ctx context.Context) Interface {
+	enc, ok := ctx.Value(encoderKey{}).(Interface)
+	if !ok {
+		// FIXME: Warning?
+		enc = Default
+	}
+	return enc
+}
diff --git a/cidenc/encoder_test.go b/cidenc/encoder_test.go
new file mode 100644
index 0000000..2a6829e
--- /dev/null
+++ b/cidenc/encoder_test.go
@@ -0,0 +1,18 @@
+package cidenc
+
+import (
+	"context"
+	"testing"
+
+	mbase "github.com/multiformats/go-multibase"
+)
+
+func TestContext(t *testing.T) {
+	enc := Encoder{Base: mbase.MustNewEncoder(mbase.Base64)}
+	ctx := context.Background()
+	ctx = Enable(ctx, enc)
+	e, ok := Get(ctx).(Encoder)
+	if !ok || e.Base.Encoding() != mbase.Base64 {
+		t.Fatal("Failed to retrive encoder from context")
+	}
+}
diff --git a/format.go b/format.go
index 873d3ec..300277d 100644
--- a/format.go
+++ b/format.go
@@ -150,3 +150,48 @@ func encode(base mb.Encoder, data []byte, strip bool) string {
 	}
 	return str
 }
+
+// ScanForCid scans bytes for anything resembling a CId. If one is
+// found `i` will point to the begging of the cid and `j` to to the end
+// and the cid will be returned, otherwise `i` will point the end of the
+// buffer and the cid will be `Undef`.
+func ScanForCid(buf []byte) (i, j int, cid c.Cid, cidStr string) {
+	i = 0
+	for {
+		i = j
+		for i < len(buf) && !asciiIsAlpha(buf[i]) {
+			i++
+		}
+		j = i
+		if i == len(buf) {
+			return
+		}
+		for j < len(buf) && asciiIsAlpha(buf[j]) {
+			j++
+		}
+		if j-i <= 1 || j-i > 128 || !supported[buf[i]] {
+			continue
+		}
+		var err error
+		cidStr = string(buf[i:j])
+		cid, err = c.Decode(cidStr)
+		if err == nil {
+			return
+		}
+	}
+}
+
+var supported = make([]bool, 256)
+
+func init() {
+	// for now base64 encoding are not supported as they contain non
+	// alhphanumeric characters
+	supportedPrefixes := []byte("QfFbBcCvVtThzZ")
+	for _, b := range supportedPrefixes {
+		supported[b] = true
+	}
+}
+
+func asciiIsAlpha(b byte) bool {
+	return ('A' <= b && b <= 'Z') || ('a' <= b && b <= 'z') || ('0' <= b && b <= '9')
+}
diff --git a/misc.go b/misc.go
new file mode 100644
index 0000000..9ea665e
--- /dev/null
+++ b/misc.go
@@ -0,0 +1,20 @@
+package cidutil
+
+import (
+	cid "github.com/ipfs/go-cid"
+	mh "github.com/multiformats/go-multihash"
+)
+
+func TryOtherCidVersion(c cid.Cid) cid.Cid {
+	prefix := c.Prefix()
+	if prefix.Codec != cid.DagProtobuf || prefix.MhType != mh.SHA2_256 || prefix.MhLength != 32 {
+		return cid.Undef
+	}
+	var c1 cid.Cid
+	if prefix.Version == 0 {
+		c1 = cid.NewCidV1(cid.DagProtobuf, c.Hash())
+	} else {
+		c1 = cid.NewCidV0(c.Hash())
+	}
+	return c1
+}
diff --git a/package.json b/package.json
index 1a6b20e..87ef6e4 100644
--- a/package.json
+++ b/package.json
@@ -29,6 +29,6 @@
   "license": "",
   "name": "go-cidutil",
   "releaseCmd": "git commit -a -m \"gx publish $VERSION\"",
-  "version": "0.1.2"
+  "version": "0.1.4"
 }