Download OpenAPI specification:Download
To interact with this API and subsequently validate a Chainlock card you need to read information from the two barcodes on the front and back side of a Chainlock Card.
The barcode on the left contains the CLC (Chainlock Code) which contains signatures as well as other information required for cryptographic offline checks.
There are three different types of CLCs
OES
IMM
COM
The validation process is different for each type.
A CLC is a string made up of at least two parts which are seperated by semicolons. In this example it looks like this:
IMM;MEQCIFy7SDqOiYxVDAV5hqtuZyDyaqIXSJeMz8o9FO54jLLVAiACwDTvMB3IGVDD64LE97iuJoB/lOvw32amVUY5XiiPiA==;10000195472368045826;03390F6A7EA013BE3C2D939DDE2B7571671E08C27728D66D59B1275F48C3F1ECC7
All CLCs start with a 3 character identifier denoting the type. Accordinlgy the
example CLC above is of the type IMM
.
A CLC of this type contains this information:
# ---- # ------------- # ----------- #
| Type | Signature OES | Card Number |
# -----# ------------- # ----------- #
Fields:
Type
: Always OES for this type of CLC.Signature OES
: A base64 encoded cryptographic signature. Verification of
this signature is performed with a public key provided by the backend.Card Number
: The card number of the Chainlock card.When validating a card with an OES CLC these checks have to be performed:
Example of an OES CLC:
OES;MIGIAkIB5/AJ4XSnjyNMP1seUPlL58aaLRVQWxNuN0NeE/MzT7qi99jryDkKabVhjMqGZ2mZZp4VJOFgzVSUVK80nF3HvlQCQgF1BaG+gQvjtEGlr7eO3dHn2LCycKQtbHLZjpnHKwgeC2oKDSjZwBAo+fJWtUv1IU4LMgAV+l2Q8Jp4Qu8dI5Xnuw==;10000195472368045826
A CLC of this type contains this information:
# ---- # ------------- # ----------- # ---------- #
| Type | Signature IMM | Card Number | Public Key |
# -----# ------------- # ----------- # ---------- #
Fields:
Type
: Always IMM for this type of CLCSignature IMM
: A base64 encoded ECDSA signature. Verification of this
signature is performed with a public key contained in the CLC.Card Number
: The card number of the Chainlock card.Public Key
: The elliptic curve public key used to validate the
Signature IMM
in compressed form. The curve used is Secp256k1. You can
find more information about compressed public keys
here.When validating a card with an IMM CLC these checks have to be performed:
Example of an IMM CLC:
IMM;MEQCIFy7SDqOiYxVDAV5hqtuZyDyaqIXSJeMz8o9FO54jLLVAiACwDTvMB3IGVDD64LE97iuJoB/lOvw32amVUY5XiiPiA==;10000195472368045826;03390F6A7EA013BE3C2D939DDE2B7571671E08C27728D66D59B1275F48C3F1ECC7
A CLC of this type contains this information:
# ---- # ------------- # ----------- # ------------- # ---------- #
| Type | Signature OES | Card Number | Signature IMM | Public Key |
# -----# ------------- # ----------- # ------------- # ---------- #
Fields:
Type
: Always COM for this type of CLCSignature OES
: A base64 encoded cryptographic signature. Verification of
this signature id performed with a public key provided by the backend.Card Number
: The card number of the Chainlock card.Signature IMM
: A base64 encoded ECDSA signature. Verification of this
signature is performed with a public key contained in the CLC.Public Key
: The elliptic curve public key used to validate the
Signature IMM
in compressed form. The curve used is Secp256k1. You can
find more information about compressed public keys
here.When validating a card with a COM CLC these checks have to be performed:
Example of a COM CLC:
COM;MIGIAkIB5/AJ4XSnjyNMP1seUPlL58aaLRVQWxNuN0NeE/MzT7qi99jryDkKabVhjMqGZ2mZZp4VJOFgzVSUVK80nF3HvlQCQgF1BaG+gQvjtEGlr7eO3dHn2LCycKQtbHLZjpnHKwgeC2oKDSjZwBAo+fJWtUv1IU4LMgAV+l2Q8Jp4Qu8dI5Xnuw==;10000195472368045826;MEQCIFy7SDqOiYxVDAV5hqtuZyDyaqIXSJeMz8o9FO54jLLVAiACwDTvMB3IGVDD64LE97iuJoB/lOvw32amVUY5XiiPiA==;03390F6A7EA013BE3C2D939DDE2B7571671E08C27728D66D59B1275F48C3F1ECC7
A Chainlock card may only be considered valid if both the online and cryptographic validations are successful.
To perform the online validation these steps have to be performed:
Calculate the SHA512 hash of the CLC.
Perform the validate REST call described here using the CLC hash. The json in the response body should look like this:
{
"valid": true,
"certificate": "-----BEGIN CERTIFICATE-----\nMIIEuDCCAqACCQC1br3+kU8qEzANBgkqhkiG9w0BAQsFADAeMRwwGgYDVQQKDBNZ\nb3VuaXF4IElkZW50aXR5IEFHMB4XDTE5MDEwMzExMjk0NVoXDTIwMDEwMzExMjk0\nNVowHjEcMBoGA1UECgwTWW91bmlxeCBJZGVudGl0eSBBRzCCAiIwDQYJKoZIhvcN\nAQEBBQADggIPADCCAgoCggIBAMVA2eS78EzUO9JtWEEIv8j8HQx50sOkD4iwwzxM\n///K35PkpBCUH5fgxN2ekOmzl4y8TzfRf59Gq+yvJFbBaBUVK86aqS4GKmtmJ4J6\nBiYVCbpQD3XxPOjuJjsg6qU5sOsWg17wts5l40fgJsnfVVV0z97vx+2/LfhzHQOx\nySUPGZEyxD1/bxfu1JrMT5HgTpRGBLmvQRkKgfvyY2r6uDsCN0o2F7Lv8X6hKpOJ\nqOyOFhGkgVnG8LWi/ELhSKh1ixjvE45o41fuUi/990NhYwIMxJQWh/Kaa8AZWo3h\nA8mMK9inrOgLCDjNO6LtQLYuBHOlfvEEkjWNgyI8vV216xoo1wD2evCxtJ5FFZB/\nVtu++EXncyMKIP0K112m7BST1njZ46WDbC6h6o1RCimkfTb2D0vFzXeqrV4GWY98\nKouJqs9Zxxbtd/FYzrCVugvc++b+u9hDur1s/hs0K09L6SE8GFMHXjxtTf6WTrU8\nx0zBngKU4C8OhQFhOVIV0mHnC1BQb3A/FnKnIN5n5sYXNsFdXtV+W7sOazwTU0OL\nlnxrmnCozUzYCnUzcaO7Wtd48g/IqL/2hCz5fvSUUJt6RA9oFytxRImgr3ohFNje\ne+M52bW40S+0BL4yUMKcBqlJ9+H2tv42VH0B2p5b3PiDttnGP1PokSaKr1z732L/\ngH0XAgMBAAEwDQYJKoZIhvcNAQELBQADggIBAEKgE6OfE0HeTdExVnMYRL/WLIHq\nc3Pr8I2sMk2TRtOLgviLCGD7GRI2+jD6LbvoQrC6RrdFsmchAwQDMn+4QGpcGjQI\nDQX2yjvrHbvYzgSWN/ADIZX10WW1SUR1hdQroZQK9LfEsVOgWmR8cOm/jw2Q4VYE\nBZKfc30sDIyDLdEueiGl8zroXouhgtuRgfgtcsRhE+SDhafFL4kdVPrBsFSAdhmC\nYHQ192oj4rYTRBfku1Cx3tFt49zgPRr03EsRaMdopx4O/nmwb1nk77wUYwplhjZb\nYogIoLiwV306Jfepj6AX3AECOAG+baVYAz4v2KVlFW/XzPo0l1b+NsYSFvr4MZ1o\netY18Ye6M+1XsgtrBj/ptuxfPH8OrJy8hXqk57gJbIhxN1f6MyeZ2rxnEpPH+9dO\novejhaFpwhFxy+DdIcljDCjlJeFrgMxQ26Cc+HGoaUqU3W1YmIK+5+LBTfr5DvhD\ndA4Q7ZZUWmfE1b8/yjcyJFoe2U8uO9O6dynzsq7O3CcJ3rXfvYZbTYNHqFE/c2OB\nHPVdBRmIsZCArmPMnKUveOjiVkvT4HdRzXfA0GCkdmgsTs3AYJDtjWVkHQcqTMwE\nOVd/cyrItBc5Yj11n8Ahxt6/RlmhGfNf6f0+b3rq8DTpe/1tDoU/++U2QV2vCOKD\nx7f6mFpKOWOWzr5I\n-----END CERTIFICATE-----\n",
"info": {
"hashOfClc": "538ae1ab0691faa1fb063450f56589f72bfecb57d3beac5c34239b89a3e9545034df019bcec3e0769234ee96f742dac9fda63cbdad2c1f217bfe7f87a3bc5b0b",
"promoteeId": "033048e3ef74e6d51a65d668bfe8b8d6bf5b7a79f66549b2b9a4f7017edde1288c7e6d1d647108237ccba6dfd13f1369d75d13c2322835c31b0045c9cdbfe284",
"currency": "BTC",
"securityChecks": [
"CARD_NUMBER_IS_TACTILE",
"BITCOIN_ADDRESS_MATCHES",
"DOVID_SECURITY_SEAL_VALID_G2",
"DOVID_BITCOIN_ADDRESS_VALID",
"SECURITY_SEAL_HAS_SECURITY_PUNCHES",
"SECURITY_SEAL_IS_INTACT"
]
}
}
The valid
field in the response of the validate call must be true
. If it
is false
the CLC hash is unknown or invalid.
The hashOfClc
field in the info
object of the validate call response must
match the CLC hash you sent to the backend.
To perform the OES Cryptographic Validation these steps have to be performed.
Perform the Online Validation if you haven't already.
Calculate the signature payload like this:
Payload = SHA512(Address || Card Number)
Address
: Refers to the base64 encoded address contained in the barcode on
the front side of the Chainlock card.Card Number
: Refers to the card number which is contained in the CLC.
Information about CLCs can be found here.Example of a payload calculation:
address = "1655J5nqcBvRQHX68nrcwVx3wx4eLiQeCn"
card_number = "10000195472368045826"
payload = SHA512(address + card_number) = "1dd48f03c76d1cf7bcb7fdc0ba20c41750b077012afbc88168fc3229b9812be1f2a9ba635da75bbbaa61433ac24b44f903639c7f5f7a7656b0955189a25ffa16"
The field certificate
in the response of the validate REST call described
here contains a PEM encoded x509
certificate.
Extract only the public key from that certificate.
Use the above calculated signature payload as well as the public key to
validate the signature Signature OES
which is part of the CLC.
To perform the IMM cryptographic validation these steps have to be performed.
Calculate the signature payload like this:
Payload = SHA512(Address || Card Number)
Address
: Refers to the base64 encoded address contained in the barcode on
the front side of the Chainlock card.Card Number
: Refers to the card number which is contained in the CLC.
Information about CLCs can be found here.Example of a payload calculation:
address = "1655J5nqcBvRQHX68nrcwVx3wx4eLiQeCn"
card_number = "10000195472368045826"
payload = SHA512(address + card_number) = "1dd48f03c76d1cf7bcb7fdc0ba20c41750b077012afbc88168fc3229b9812be1f2a9ba635da75bbbaa61433ac24b44f903639c7f5f7a7656b0955189a25ffa16"
Expand the compressed public key from the CLC. A compressed public key is just the X coordinate of an elliptic curve point. By knowing the curve one can calculate the Y coordinate. In this case the curve is Secp256k1. Most frameworks (e.g. OpenSSL) can perform this calculation for you.
Use the above calculated signature payload as well as the public key to
validate the signature Signature IMM
which is part of the CLC.
The security checks are additional manual checks a user can perform on the card itself to make sure that it is genuine and has not been tampered with.
securityChecks
field in the response
of the validate REST call described
here.The following are descriptions of all possible security checks:
CARD_NUMBER_IS_TACTILE
: The user should check if the card number printed on
the card is slightly raised or tactile.ADDRESS_MATCHES
: The user should check that the address read from the
barcode matches the address printed on the card.DOVID_SECURITY_SEAL_VALID_G1
: The user should check that there is an optical
security feature on the security seal which changes based on the viewing
angle. The text "ORIGINAL" should be printed on the security seal.DOVID_SECURITY_SEAL_VALID_G2
: The user should check that there is an optical
security feature on the security seal which changes based on the viewing
angle. The text "chainlock" and "private key" should be printed on the
security seal.DOVID_ADDRESS_VALID
: The user should check that there is an optical security
feature on the address which changes based on the viewing angle.SECURITY_SEAL_HAS_SECURITY_PUNCHES
: The user should check that security
punches are present around the security seal.SECURITY_SEAL_IS_INTACT
: The user should check that the security seal is
present and intact.Deprecated - This keys will be removed soon
BITCOIN_ADDRESS_MATCHES
: The user should check that the bitcoin address read
from the barcode matches the address printed on the card.DOVID_BITCOIN_ADDRESS_VALID
: The user should check that there is an optical
security feature on the bitcoin address which changes based on the viewing
angle.Returns validation information for the supplied CLC hash allowing clients to cryptographically validate a Chainlock card. Regardless of if valid CLC hash bas been supplied this call always responds with a 200 status code. The "valid" property in the response can be used to check if the supplied CLC hash belongs to a valid card.
If the CLC hash is valid information about the card like the currency or the signing certificate as well as information about the promotee will be included as well.
hashOfClc required | string Hex encoded string |
{- "valid": true,
- "certificate": "string",
- "info": {
- "hashOfClc": "string",
- "promoteeId": "string",
- "currency": "BTC",
- "securityChecks": [
- "CARD_NUMBER_IS_TACTILE"
]
}
}
Returns information about a promotee with the supplied id. Regardless of a promotee with the supplied id exists this call always responds with a 200 status code. The "exists" property in the response can be used to check if valid promotee information has been returned.
A promotee is the company or institution which sold a Chainlock Card.
If a valid promoteeId is supplied then information about the promotee like name/logo etc are returned.
promoteeId required | string A string id identifying a specific promotee. |
{- "promoteeId": "string",
- "exists": true,
- "data": {
- "name": "string",
- "imageId": "string"
}
}
Returns the image as binary data identified by the provided image id.
imageId required | string A string id which identifies the requested image. |
width | integer An integer which specifies the maximum height the requested image should have. |
height | integer An integer which specifies the maximum width the requested image should have. |
Fetches crypto and FIAT balances associated with a wallet and its tokens.
Identifies the wallet you want to fetch the balance from
address required | string Address of the wallet. |
cryptoCurrency required | string Enum: "BTC" "ETH" "NEO" "XPU" Crypto currency of the wallet. |
fiatCurrency | string Enum: "USD" "EUR" "GBP" "HKD" "CAD" "JPY" "CHF" "AUD" The desired fiat currency. |
{- "address": "string",
- "cryptoCurrency": "BTC",
- "fiatCurrency": "USD"
}
{- "cryptoBalance": 0,
- "fiatBalance": 0,
- "tokens": [
- {
- "cryptoBalance": 0,
- "fiatBalance": 0,
- "name": "string",
- "logo": "string"
}
], - "logo": "string"
}