Overview
A Call Signature is a small set of extra parameters that your application calculates and appends to each Shutterfly Open API call, to digitally "sign" the call.
You calculate the signature parameters anew on each call, using the procedure detailed below (or using a library from Shutterfly that does it). Shutterfly servers verify each call signature by performing the same calculation and comparing the result to yours.
The signature helps Shutterfly know that it has received the parameters you intended to send. If you guard your "shared secret" adequately, the signature also provides MD5-level or SHA1-level proof that the call really came from your app (i.e., was not forged by a third party).
Signature generation can be tricky. For developers working in Java, Shutterfly supplies a library to hide the details discussed below.
An application signs each call by locally gathering and concatenating these pieces of data:
- the application ID and shared secret
- URL path of the Shutterfly Open API call (omitting the "http://hostname" part)
- URL parameters of the Shutterfly Open API call, if any
- these three additional Call Signature parameters: app ID, hash method, and timestamp
The application then generates an MD5 or SHA1 digest of that 'concatenated string'. The digest becomes a fourth parameter, the call signature itself. The app then adds the four Call Signature parameters (app ID, hash method, timestamp and signature digest) to its HTTP call. Notes:
- App ID is always passed as an URL parameter.
- Hash method, timestamp and signature digest may be passed either as URL parameters, or as HTTP request headers. Shutterfly will accept them as URL parameters, but generally recommends that you pass them as HTTP request headers, especially on GET calls, for better Web document caching.
- Do NOT send the shared secret on your calls! Shared secret is needed only when your application generates the signature digest, and should be kept a secret. Do not send it in e-mails!
Signature Generation Details
First, the application must gather its own values for the following three Call Signature parameters:
Next, the app locally creates a string that concatenates these pieces, in order:
- your application's Shared Secret
- URI path for the specific API call. Include a leading slash; omit trailing slash. Example: /userid/000012345678
- A question mark.
- URL parameters for the specific API call, if any. Notes:
- They must be in name=value form, separated by & (ampersand).
- They must be in alphabetical order by parameter name, and in a case-sensitive manner (so that lowercase 'a' sorts after uppercase 'Z').
- The parameter values should NOT be "URL encoded" at this point - e.g., not yet substituting "%20" for blank.
- Finally, add the three Call Signature parameters, as if they were additional URL parameters (i.e., name=value, with & as a separator). They must be in this order: oflyAppId, oflyHashMeth, oflyTimestamp.
Next, if building the above string on a Unicode system, take a UTF-8 encoded byte array of the concatenated string.
Next, take a message digest (a hash) of the byte array, using SHA1 or MD5 as previously chosen.
Finally, convert the hash to a hexadecimal character string. The hex string is the signature. It will become the following parameter:
Your application now has values for all four Call Signature parameters - app ID, hash method, timestamp and signature digest. At this point, build your final URL and make the call. Notes:
- When finally making your Shutterfly Open API call: URL parameters need not be in any special order.
- Again, always put
oflyAppId=as an URL parameter, and the other Call Signature parameters either as additional URL parameters or as HTTP request headers (recommended). - As a very last step, make sure the final URL is "URL encoded". (Substitute %20 for blank, %2B for plus sign, etc.)
Example using the Authentication API
The example below does not necessarily give a real signature value, but shows you how to build one. First, if there were no call signature, your app would POST an URL like this:
https://ws.shutterfly.com/user/asdfasdf4@yahoo.com/auth POST /user/asdfasdf4@yahoo.com/auth HTTP/1.1 Content-Type: [...] Content-Length: [...] [...]
with XML as the POST content body, that gives user password, etc.
To build the signature: Imagine that your app ID is "91d6d14801815dda4be4982e9c0d39fa" and shared secret is "5c2db08d7bd25c2e". Your 'concatenated string' for building the signature should look like this (but all on one line):
5c2db08d7bd25c2e/user/asdfasdf4@yahoo.com/auth?oflyAppId=91d6d14801815dda4be4982e9c0d39fa &oflyHashMeth=SHA1&oflyTimestamp=2007-07-02T11:28:36.776-0700
If your app sets HTTP headers for Call Signature, the final URL and headers look something like this:
https://ws.shutterfly.com/user/asdfasdf4@yahoo.com/auth?&oflyAppId=91d6d14801815dda4be4982e9c0d39fa POST /user/asdfasdf4@yahoo.com/auth HTTP/1.1 Content-Type: [...] Content-Length: [...] oflyTimestamp: 2007-07-02T11:28:36.776-0700 oflyApiSig: 9a2910628acc54caeac6516acdf26f2171a2ab51 oflyHashMeth: SHA1 [...]
Note: when your app finally makes the HTTP call, the order of URL parameters does not matter and the order of HTTP request headers does not matter; their order mattered only when building the 'concatenated string'.
If, instead, your app sets URL parameters for Call Signature, the final URL and headers look something like this (but the URL on one line):
https://ws.shutterfly.com/user/asdfasdf4@yahoo.com/auth?&oflyAppId=91d6d14801815dda4be4982e9c0d39fa &oflyApiSig=9a2910628acc54caeac6516acdf26f2171a2ab51&oflyTimestamp=2007-07-02T11:28:36.776-0700 &oflyHashMeth=SHA1 POST /auth HTTP/1.1 Content-Type: [...] Content-Length: [...]
Again, in the above, the order of URL parameters does not matter. And the POST body (not shown) would contain XML as specified by the Authentication API document.
Example using the "Go To Shutterfly UE" API
The example below does not necessarily give a real signature value, but shows you how to build one. First, if there were no call signature, your app might redirect the user's browser to GET an URL which looks like this:
http://www.shutterfly.com/go2ue/start.sfly?oflyUserid=9BcNWjVsyg&id=5f37cab8905a7c46132ed58780f5ea666cbbd47cbb382743
To build the signature: Imagine that your app ID is "91d6d14801815dda4be4982e9c0d39fa" and shared secret is "5c2db08d7bd25c2e". Your 'concatenated string' for building the signature should look like this (but all one line):
5c2db08d7bd25c2e/go2ue/start.sfly?id=5f37cab8905a7c46132ed58780f5ea666cbbd47cbb382743&oflyUserid=9BcNWjVsyg &oflyAppId=91d6d14801815dda4be4982e9c0d39fa&oflyHashMeth=SHA1&oflyTimestamp=2007-07-02T11:38:53.842-0700
If your app sets HTTP headers for Call Signature, the final URL and headers look something like this (but all on one line):
http://www.shutterfly.com/go2ue/start.sfly?oflyUserid=9BcNWjVsyg&id=5f37cab8905a7c46132ed58780f5ea666cbbd47cbb382743 &oflyAppId=91d6d14801815dda4be4982e9c0d39fa GET /go2ue/start.sfly HTTP/1.1 [...] oflyTimestamp: 2007-07-02T11:38:53.842-0700 oflyApiSig: 792c4e0a43ef00f9b23a0d8b7042030fbc8e9ddc oflyHashMeth: SHA1 [...]
Note: when your app finally makes the HTTP call, the order of URL parameters does not matter and the order of HTTP request headers does not matter; their order mattered only when building the 'concatenated string'.
If, instead, your app sets URL parameters for Call Signature, the final URL looks something like this (but all on one line):
https://ws.shutterfly.com/go2ue/start.sfly?oflyUserid=9BcNWjVsyg&id=5f37cab8905a7c46132ed58780f5ea666cbbd47cbb382743 &oflyAppId=91d6d14801815dda4be4982e9c0d39fa&oflyApiSig=792c4e0a43ef00f9b23a0d8b7042030fbc8e9ddc &oflyTimestamp=2007-07-02T11:38:53.842-0700&oflyHashMeth=SHA1
Again, in the above, the order of URL parameters does not matter.
Example using the "Interactive Sign-in" API
The example below does not necessarily give a real signature value, but shows you how to build one. First, if there were no call signature, your app might redirect the user's browser to GET an URL which looks like this:
https://www.shutterfly.com/oflyuser/createToken.sfly?oflyCallbackUrl=http%3A%2F%2Fmygreatwebsite.com%2FmyAppResumesHere
To build the signature: Imagine that your app ID is "91d6d14801815dda4be4982e9c0d39fa" and shared secret is "5c2db08d7bd25c2e". Your 'concatenated string' for building the signature should look like this (but all one line):
5c2db08d7bd25c2e/oflyuser/createToken.sfly?oflyCallbackUrl=http://mygreatwebsite.com/myAppResumesHere &oflyAppId=91d6d14801815dda4be4982e9c0d39fa&oflyHashMeth=SHA1&oflyTimestamp=2007-07-02T11:38:53.842-0700
Note: for purposes of the 'concatenated string', your callback URL is NOT URL-encoded yet.
If your app sets HTTP headers for Call Signature, the final URL and headers look something like this (but all on one line):
http://www.shutterfly.com/oflyuser/createToken.sfly?oflyCallbackUrl=http%3A%2F%2Fmygreatwebsite.com%2FmyAppResumesHere &oflyAppId=91d6d14801815dda4be4982e9c0d39fa GET /oflyuser/createToken.sfly HTTP/1.1 [...] oflyTimestamp: 2007-07-02T11:38:53.842-0700 oflyApiSig: 792c4e0a43ef00f9b23a0d8b7042030fbc8e9ddc oflyHashMeth: SHA1 [...]
Note: when your app finally makes the HTTP call, the order of URL parameters does not matter and the order of HTTP request headers does not matter; their order mattered only when building the 'concatenated string'.
If, instead, your app sets URL parameters for Call Signature, the final URL looks something like this (but all on one line):
https://ws.shutterfly.com/oflyuser/createToken.sfly?oflyCallbackUrl=http%3A%2F%2Fmygreatwebsite.com%2FmyAppResumesHere &oflyAppId=91d6d14801815dda4be4982e9c0d39fa&oflyApiSig=792c4e0a43ef00f9b23a0d8b7042030fbc8e9ddc &oflyTimestamp=2007-07-02T11:38:53.842-0700&oflyHashMeth=SHA1
Again, in the above, the order of URL parameters does not matter.
Responses
All Shutterfly APIs return a common set of HTTP status codes. See Common Response Codes
API Explorer
You can test the correctness of your signature generation process with Shutterfly's API Explorer for Call Signature.
Frequently Asked Questions
General
Library Support
- Call Signature .jar file for Java 5.0 and later
- Call Signature .jar file for Java 1.4
- Javadoc (same for both of the above)
- A Java 5.0 Sample Program which demonstrates the library
Timestamp
YYYY-MM-DDThh:mm:ss.sssTZD, where:
| YYYY | = | four-digit year | |
| MM | = | two-digit month | (01 through 12) |
| DD | = | two-digit day of month | (01 through 31) |
| hh | = | two-digit hour | (00 through 23; am/pm NOT allowed) |
| mm | = | two-digit minute | (00 through 59) |
| ss | = | two-digit second | (00 through 59) |
| sss | = | three-digit millisecond | (000 through 999) |
| TZD | = | time zone designator | (Z or +hh:mm or -hh:mm) |
The following timestamps will cause different call signatures, but are all recognized as the same moment in universal time:
2008-02-21T17:19:54.330-00:002008-02-21T17:19:54.330Z2008-02-21T12:19:54.330-05:002008-02-21T09:19:54.330-08:002008-02-22T02:49:54.330+09:30
Because of the time zone designator, a timestamp represents a universal moment in time. The time zone designator is either the single character Z to indicate UTC (Coordinated Universal Time), or your time zone's offset from UTC described in hours and minutes.