With the release of our new widget, our developer documentation has changed! Find the complete documentation for our old widget here.
Getting Started
Introduction to CloudSponge
Making your users type their friends email addresses into your refer-a-friend form is a friction point that we’re in business to help you with. Our list of supported address books is growing every week, send us an email if you don’t see one that’s important to you.
The first step is to create your company’s CloudSponge account or get an invitation to your company’s account if someone else already created it.
Once you can log into your account, you’ll see your company’s Universal Snippet that will add our widget to any site you use it on. Everything else you need to know is right here in the developer documentation.
If you’d rather build a completely custom interface, you’re welcome to integrate with our REST API instead of using our widget.
Both options allow you to remove the CloudSponge branding in addition to several other customization options.
No Development Environment Handy? No Problem!
Check out our guide to Getting Started Without a Development Environment.
JavaScript Widget
Our JavaScript widget is the best way to get up and running quickly. You can see it in action on our Test Drive page.
If you don’t like the default style or behavior, read on.
- Don’t like our colors, fonts, corner radiuses, etc? Override our CSS with your own.
- Prefer to use your own brand in OAuth dialogs? Use your own consumer credentials.
- Don’t like a feature in our widget’s UI? Turn if off with JavaScript options.
- Need special behavior in the widget flow? Use our JavaScript callbacks.
- Don’t like the widget, period? Use our REST API and build your own.
The widget is installed on thousands of websites so the chances are pretty good that you’re not the first person to need whatever you have in mind. If you’re not sure how to get it to do what you want, just write us an email and we’ll help you figure it out.
Basic Installation
Once you’ve created a CloudSponge account, you’ll get your own Widget Snippet that you can add to any page to include our widget there. The snippet is a very basic example of using our widget on a page. It does three things that any widget integration must do:
- include your widget javascript,
- provide a way for the end user to launch the widget and,
- do something with the user’s contacts.
1. Add your script.
Your CloudSponge key is the name of your own custom widget script. Add this script to your site in the head
of the page.
<script src="//api.cloudsponge.com/widget/YOUR_WIDGET_KEY.js"></script>
2. Launch the Widget:
Launch the widget and let users pick a source from our UI:
<a class="cloudsponge-launch">Add From Address Book</a>
Or display your own “deep links” to launch directly to a specific address book:
<a class="cloudsponge-launch" data-cloudsponge-source="gmail">Gmail</a>
Read more about our linking options below.
3. Get the Contacts
After users pick their contacts, they will be populated inside an HTML element.
<input type="textarea" class="cloudsponge-contacts"/>
This is the pattern you’ll follow to get started with CloudSponge.
You need to sign in to get your own WIDGET_SCRIPT
:
Internet Explorer Caveat
Please be aware of IE’s Protected Mode settings. Your test page and api.cloudsponge.com
both need to be in zones with the same Protected Mode setting. Usually, api.cloudsponge.com
is in the Internet Zone, and your localhost is in the Local internet Zone.
Our recommendation is to enable Protected Mode for both the Internet Zone and the zone that your test page is in. This ensures that your local environment behaves the same as in production.
This is not an issue in production since both sites are in the same IE zone and will be treated with the same Protected Mode.
Linking Options
Once you’ve got our JavaScript loading on the page, the next important step is figuring out how your user is going to invoke the widget. There are two approaches:
- The default menu link that’s just a simple anchor tag that opens the widget’s main menu.
- Deep links that skip the menu and jump straight to a contact source.
Menu Link
In step 3 above, the Basic Installation code puts an “Add from Address Book” hyperlink on your page that will open our widget to a menu of available contact sources. This is the simplest way to get started. If you want to sort or filter the contact source icons that are displayed on the main menu, use the sources
parameter in your csPageOptions.
For example, if you want to display Gmail, Yahoo, LinkedIn, iCloud and OS X Contacts (in that order) then:
window.csPageOptions = {
sources: ["gmail", "yahoo", "linkedin", "icloud", "addressbook"]
}
Deep Links
In step 3 above, the Basic Installation code puts an “Add from Address Book” hyperlink on your page that will open our widget to a menu of available contact sources.
If you’d like to skip the menu (and eliminate one click for your users) you can use Deep Widget Links instead:
The hyperlinks in the code sample above are basic text; since you are adding this code, you can add css styling and images to suit your site.
You can find several file formats for the icons we’re using plus a couple more styles on IconFinder.
Custom Stylesheets
Our widget is fully customizable via CSS styles. Use the css
option to link to your own copy of our widget stylesheet.
The stylesheet that you include needs to only define the styles you want to override.
Here are examples of common changes
that you might want to make.
If there anything you want to style that’s not included, let us know and we’ll help you with the particulars.
This feature is part of our Standard Plan features and must be enabled by a CloudSponge administrator, please email support@cloudsponge.com to request permission.
Complete Reference
Options
Options should be set by calling cloudsponge.init(options)
. Supported options are listed below.
Variable | Type | Default | Usage |
---|---|---|---|
alwaysShowCTA New! |
boolean | - | Set this value to be true if you want to display the button on the ‘Choose Your Contacts’ screen when there are no contacts selected. See an example here. |
browserContactCacheMin New! |
float | - | The the number of minutes that any successful address book data will persist in the browser’s localStorage cache. The cached copy of the user’s contacts will be displayed without prompting the user to provide consent again if the contacts are available. When not set or set to 0 , the user will always be prompted to provide consent to import their contacts. Fractional minutes are supported. Users have the ability to turn off this feature on their browser. |
contactsDelimiter New! |
string | , |
Set the delimiter used when populating contacts in an HTML element. |
contactsTemplate New! |
string | name+email |
Set the format of the contacts displayed in the textarea after select the contacts. You can use one of the default templates name , email , name+email , name+phone , name+email+phone , name+email+address .Alternatively, you can create your own template using subtitution variables in a string, for example: "${name} - ${email}" . Valid variable names are: name , email , primaryEmail , firstName , lastName , jobTitle , company , companies , groups , dob , birthday , emailsList , phonesList , homeAddress , workAddress , otherAddress , phone , address . |
css New! |
string | - | Specifies a URL to a stylesheet containing your custom CSS classes so that you can make our widget match your website. When specified, your stylesheet is included after our styles on the page. Here are examples of common classes that you might want to override. This feature must be enabled by a CloudSponge administrator, please email support@cloudsponge.com to request permission. See an example here. |
csvProviders |
object | {} |
Lists which providers should use a file upload as the default method for importing. Currently supported by AOL , WINDOWSLIVE , ADDRESSBOOK and OUTLOOK import sources. See an example here. |
displayContactsColumns New! |
array | - | When the array contains phone , display the contact phones column, by default it will alway display name and email columns, if used with filter option, you can filter the contacts to only show the ones that contain phones . See an example here. |
displaySelectAllNone |
boolean | true |
When true , enables the All and None links on the Select Your Contacts page which allow the user to select or de-select all their contacts with a single click. When false , these links are hidden. |
filter New! |
function | - | A function that takes a contact object and decides whether to include it in the contacts UI. If the function returns true the contact will be displayed, if it returns false , the contact will not be displayed. By default, the filter returns true if there is at least one email associated with the contact.e.g. function(contact) { return !!contact.email.length } |
ignoreMultipleEmails |
boolean | false |
When true, the widget only displays one email address when a contact has multiples. We make our best guess based on the contact meta-data, when available. |
ignoreMultiplePhones |
boolean | false |
When true, the widget only displays one phone number when a contact has multiples. We make our best guess based on the contact meta-data, when available. |
include |
array | ["name", "email"] |
Indicates the data to include when automatically populating the contacts in the textarea. When name is included, then both the name and the email address are set in the textarea in the format name <email> . When name is not included, then only the email addresses are set and no additionally formatting is applied. When mailing_address is included in the array, these will be included with the JSON data passed into the callback methods example. See here for the format of the contacts array. |
initiallySelectedContacts |
boolean | false |
Indicates the initial state of the checkboxes associated with each contact. |
inlineOauth |
boolean | true |
When false , OAuth sources will launch a popup window for obtaining authorization from the user. When true , OAuth sources will redirect the entire browser window to obtain authorization. When the authorization flow is complete, the browser will be redirected back to the original page and the widget will open and display the result of the import. You can specify "mobile" which will cause the inline behaviour when the widget loads on a mobile browser only. Note: This option will work as expected when the URL on your site is less than 256 bytes long and is served using a HTTP GET . |
lazyLoad New! |
boolean | false |
When true and set in the csPageOptions this option prevents the cloudsponge object from performing a full initialization. Before the widget is ready, you must call cloudsponge.load() from your code. Example here. |
locale New! |
string | - | Sets the language to one of our standard translations. Currently supports 'fr' , 'pt-br' , or 'bg' . Not for use with localeData . |
localeData New! |
string or object | - | Can be either a literal Object that contains the custom language, or a string URL pointing to a JSON file which contains the object. Not for use with locale . See an example of each here. See our example locale data structure for our default language. |
onlyGroupedContacts |
boolean | false |
When this value is true , contacts that do not belongs to a group will be omitted from the widget view. This option only applies to Gmail currently. |
rootNodeSelector New! |
string | 'body' |
A CSS selector for the node that the widget UI will be appended to. In most cases, appending the widget to the default body node is acceptable. |
selectAccount |
boolean | false |
When true , forces display of the account selection screen during the OAuth flow. Currently only supported by Gmail. |
selectionLimit |
integer | - | When defined limits the number of contacts that can be selected in the list. Specify a value for selectionLimitMessage to set a custom message. Use with displaySelectAllNone:false . |
selectionLimitMessage |
string | - | Specifies the message to display to the user in an alert box when they attempt to select too many contacts. Ignore it to suppress the message. Has not effect unless used with selectionLimit . |
onSelectionLimitReached New! |
function | - | To be used with selectionLimit option. When defined, this function will override the default behavior (display the alert message) when the selection limit is reached. In this function, you can display your own UI to alert the user or add a custom behavior. |
skipContactsDisplay New! |
boolean | false |
When true , suppress the display of the contacts list. You can use it with the beforeDisplayContacts callback in order to manipulate the contacts. See our example. |
skipSourceMenu |
boolean | false |
You can suppress the display of the Choose Your Address Book page which will hide the ‘Back’ links. The widget will close instead of displaying this page, unless you call cloudsponge.launch() with no arguments. |
sources |
array | - | Specifies the sources to display on the contact sources page. Available options: gmail , yahoo , windowslive , csv , linkedin , aol , icloud , outlook , addressbook , plaxo , mail_ru , uol , bol , terra , rediff , mail126 , mail163 , mail_yeah_net , gmx , qip_ru , sapo , mailcom , yandex_ru |
theme |
string | - | Selects an alternate base stylesheet to load from our themes. We currently support two themes. One is called frost and the other is called unresponsive-desktop which effectively disables the mobile view of the widget. |
zIndex New! |
integer | 90000 | A base value for the z-index of the widget. If the widget loads behind other positioned elements on your site, you can override this value to ensure that the widget is positioned correctly. |
Older versions of the widget supported the following options which have been deprecated:
textarea_id |
Deprecated in favor of using the cloudsponge-contacts class to identify the HTML element to add contacts to. |
Older versions of the widget supported the following options which have been disabled:
stylesheet |
Replaced by our new custom stylesheet method. |
skipContactFilter |
Replaced by filter option. |
performEmailValidation |
Replaced by filter option. |
force_mobile_render |
This responsive version of the widget doesn’t use a different view for mobile devices. |
mobile_render |
This responsive version of the widget doesn’t use a different view for mobile devices. |
Find the complete documentation for our old widget here.
Custom Scripts
You can add your own scripts to the widget, to be loaded on each view of the widget. Reach out to us for more information.
JavaScript Callbacks
You may define any of the following callback functions using cloudsponge.init
:
Function | Usage |
---|---|
afterInit() |
Called immediately after the widget is completely initialized and any links to launch the widget can be safely enabled. If your page is launching the widget programatically via the widget API, then ensure that you watch for this callback before attempting to launch the widget. |
beforeLaunch() |
Called immediately before the widget is launched either by the user clicking a “cloudsponge-launch” link or programatically by calling cloudsponge.launch() . If the callback function returns false , then the widget will cancel launching. If the widget has not been initialized, the callback will not be called. No parameters are passed to the callback. |
afterLaunch() |
Called after the widget launches and all UI elements have been created on the page, but the widget content is loaded. No parameters are passed to the callback. |
beforeImport(source) |
Called immediately after the user finishes any authentication/consent and before CloudSponge begins to import the concats. The source of the contacts is passed into the callback. |
afterImport(source, success) |
Called after CloudSponge completes importing the users contacts. The source of the contacts and a boolean value indicating if the import succeeded (true indicates a successful import) are passed into the callback. Example |
beforeDisplayContacts(contacts, source, owner) |
Called before the Choose Your Contacts page renders. The callback may accept array of contacts, the name of the source of the contacts, and the owner contact. Since this callback occurs before the contacts are displayed and the user has the opportunity to filter them, all the contacts of the user’s address book are passed in at this point. These contacts are not guaranteed to have any email addresses. Returning false from this function will immediately cause the widget to close, thus suppressing the display of the Choose Your Contacts page. Example |
afterSubmitContacts(contacts, source, owner) |
Called after the user clicks the Next button on the Choose Your Contacts page and before the widget overlay is dismissed. The callback may accept array of contacts, the name of the source of the contacts, and the owner contact. Only the contacts that the user selected are passed to the function. All these contacts will have at least one email address. Example |
beforeClosing() |
Called just before the widget closes for any reason. No data is passed into the beforeClosing function. |
afterClosing() |
Called just after the widget closes for any reason. No arguments are passed into function. |
JavaScript API
When you include our address_book.js script on your page, we’ll instantiate a Javascript object named cloudsponge
. This is a global object and only one instance is permitted on a page.
Function | Usage |
---|---|
cloudsponge.init(options) |
This function may be called to set cloudsponge options. If you want to dynamically change the csPageOptions, cloudsponge.init(..) can be called to update the cloudsponge options. Valid keys and values for options are referenced in the widget customization options above. |
cloudsponge.launch(source) |
cloudsponge.launch(source) launches the widget. This function does nothing if the widget has not yet completed initialization. This is a handy function for launching the widget on a page load, or when more flexibility is required for starting the import. Passing in a source is optional: when omitted, the widget displays the list of contact sources; when a valid source is specified, the action launches directly to the specific import. Valid sources are: gmail , yahoo , windowslive , csv , linkedin , aol , icloud , outlook , addressbook , plaxo , mail_ru , uol , bol , terra , rediff , mail126 , mail163 , mail_yeah_net , gmx , qip_ru , sapo , mailcom , yandex_ru |
WebHooks API
Use our webhooks to have our widget POST
address book data to any URL you choose.
You might send the content to your own server or to a service like Zapier to handle the data on your behalf.
NB Be careful not to expose any private or secure data (like basic authentication) in the webhook URL. This URL is set in the CloudSponge object’s options and will be exposed in public.
To specify a webhook, add it to your call to cloudsponge.init
. For example:
cloudsponge.init({
webhooks: {
// send the entire address book before it is displayed to the user
beforeDisplayContacts: 'https://example.com/path/to/before/webhook/',
// send the contacts that the user selected and submitted
afterSubmitContacts: 'https://example.com/path/to/after/webhook/'
}
})
Available webhooks:
WebHook | Description |
---|---|
beforeDisplayContacts |
Posted before the user sees their address book in the widget. See a working example here. |
afterSubmitContacts |
Posted after the user submits their selected contacts in our widget. Example. |
Our webhooks send this payload structure:
{
"contacts": [arrayOfContacts],
"source": stringSource,
"owner": ownerContact
}
The value of stringSource
indicates the source of the address book. It will be one of the codes from our list of supported soures.
arrayOfContacts
and ownerContact
both follow our standard contact data structure.
Data Structure
The CloudSponge Widget uses an array of Contact objects to represent a user’s address book. This data structure is most commonly used by developers who implement the beforeDisplayContacts()
and afterSubmitContacts()
callbacks since it’s passed in as an argument there.
Properties | Description |
---|---|
contact.first_name |
The contact’s first name. |
contact.last_name |
The contact’s last name. |
contact.email |
An array of Email objects for the contact. |
contact.email[i].address |
The email address. |
contact.email[i].type |
The type associated with the email. Possible values depend on the address book source. |
contact.phone |
An array of Phone objects for the contact. |
contact.phone[i].number |
The phone number. |
contact.phone[i].type |
The type associated with the phone number. Possible values depend on the address book source. |
contact.address |
undefined or an array of Address objects for the contact. Each address has the properties: address and type . |
contact.address[i].formatted |
undefined or the full mailing address, formatted with line breaks (\n ). |
contact.address[i].street |
The street portion of the mailing address. |
contact.address[i].city |
The city portion of the mailing address. |
contact.address[i].region |
The state or province portion of the mailing address. |
contact.address[i].country |
The city portion of the mailing address. |
contact.address[i].postal_code |
The zip or postal code portion of the mailing address. |
contact.address[i].type |
The type associated with the mailing address. Possible values depend on the address book source. |
contact.job_title |
The job title, if any is associated with the contact. |
contact.companies |
An array of strings representing the companies that the contact is associated with, when available. |
contact.groups |
An array of strings representing the groups that the contact is associated with, when available. The groups are defined by the owner of the addres book. |
contact.dob |
A string representing the date of birth of the contact, if available. The date format is YYYY-MM-DD . |
contact.birthday |
A string representing the month and day of the contact’s birthday, if available. The format is MM-DD . |
Functions | Usage |
---|---|
contact.fullName() |
Returns a string with the first and last name for the contact joined with a space. |
contact.primaryEmail() |
Returns a string with the primary email address for the contact. |
contact.selectedEmail() |
Returns a string with the email address that was selected in a drop down list. If the Choose Contacts page was not displayed, it returns the value of contact.primaryEmail() . |
Sample Code
-
What is the basic widget code?
The following sample code shows all you need to get started with CloudSponge. Everything else is optional. For more information see Basic Installation.
-
How do I use the widget from an iframe?
When your page displays the link to launch the widget on an iframe, you may need to separate the initialization code from the javascript includes. The widget adds 2 of its own iframes to the page where the snippet is included. This may lead to cases where conflicts between libraries and iframe setup can prevent the proper initialization of the widget. Further, the overlay will fill only the iframe that it is loaded on, so if you attempt to launch the widget on a small iframe, it will limit the size of the widget interface which may not be the desired user experience.
To resolve this issue, split the widget initialization and handling code between the parent and child frames on your page. The parent frame is responsible for initializing the widget and handling callbacks. The child frame contains the link to launch the widget.
Here is a trial example demonstrating the mechanics of this pattern. A parent page might look like this:
And here is a child iframe that just contains the link to launch the widget:
-
How can I make the widget return only plain email addresses?
You can have the widget return a list of plain email addresses, excluding the names. The emails will be in the format
contact@domain.com
, instead ofcontact_name <contact@domain.com>
-
How is it possible to filter contacts from the host page?
You cannot apply a filter to the contacts displayed in the widget, but you can render the contacts on your own page before they display to the user. You can implement the
beforeDisplayContacts
callback in order to get all the contacts of the user’ address book before they are displayed. Returnfalse
from this callback to suppress the display of the “Choose Your Contacts” screen. -
How do I handle multiple text areas for email addresses?
You can update the
cloudsponge
options at run-time to reflect which textarea to put the contacts into. -
How do I set up the applet HTML tag?
Here’s a partial HTML that would require replacing the values in curly braces
{}
with the values returned by our API. -
I’ve done the applet branding steps, how do I get the widget to use my version of the applet?
You’ll need to pass the URL to your hosted version of the applet in the csPageOptions as demonstrated below.
-
How do I know when the import completes and if it was successful?
The
afterImport
callback will let you know! -
I want every contact, not just the ones that the user selects. How can I get them all?
Here is a sample code for the
beforeDisplayContacts
callback. -
I don’t like the way the widget formats the contacts. How can I do it myself?
The
afterSubmitContacts
callback is for you. This callback is invoked after the user clicks the Next button on the Choose Your Contacts page and before the widget overlay is dismissed. The callback receives the array of selected contacts, the name of the source of the contacts, and the owner contact.Only the contacts that the user selected are passed to the function. All these contacts will have at least one email address. If the user abandons the import process, this callback will not be invoked.
-
How do I suppress the ‘All’ and ‘None’ links on the contacts form?
There’s a simple
displaySelectAllNone
option for that. -
How can I make all contacts selected by default?
There’s a simple
initiallySelectedContacts
option for that. -
I don’t want all the sources to be displayed or I want to change their order. Can I do that?
Yes! Use the
option
to filter the sources we display, or reorder them how you like. -
How can I include mailing addresses in contacts data?
Use the
include
option and add ‘mailing_address’ to the list. The returned contacts will have either anundefined
value foraddress
or an array of that contact’s mailing addresses.
REST API
CloudSponge offers its very own RESTful Address Book API to connect your web application to the contact sources. Use this method if you want to provide a user experience that is not supported by our widget interface.
Despite there being three different user authentication methods, importing contacts with the API follows a similar 3-stage asynchronous process.
Step 1: Get Permission - Your application initiates an address book import by calling the “Begin Import” URL, specifying the user authentication method, the address book source, plus any other additional information required. The API returns a result object containing a unique identifier for subsequent calls to the API, and in some cases data needs to be displayed in the user’s browser.
Step 2: Wait For Import - Your application polls the “Events” URL and receives a result object indicating the current Import Events. These events notify you of the current progress of the import, if any errors have occurred, or when the import is complete. You can optionally display these Import Events to the user’s browser.
Step 3: Download - Once you have received a successful “complete” Import Event, you can retrieve the contacts payload from the API directly or from a database configured for your account.
Step 1: Get The User’s Permission
This step is a little different depending on which source your user wants to import from.
Which import method should I use?
The table below summarizes which import method to use with each source. Desktop imports use a different import method depending on the configuration of the end user’s system.
Begin User Consent Import (OAuth, OAuth2.0, CSV and VCard)
This import method will send your user to a new window to grant permission to access their contacts. You will call our API to get the URL that you need to load in this window.
- Your application launches a new popup window to accommodate for the user consent URL.
- Once the popup launches, your application calls the
/begin_import/user_consent
endpoint, including the contact source requested. - CloudSponge returns a result object, including the
import_id
to use to fetch the contacts later and aurl
for the user consent page, which needs to be displayed to the user in the popup window. - Your application redirects the popup to the consent page
url
.
Now your application’s main page should go to Step 2 while the user gives CloudSponge permission to access their contacts and we download their address book for you.
Definition
POST https://api.cloudsponge.com/begin_import/user_consent[.format]
Request Arguments
Name | Required? | Description |
---|---|---|
domain_key |
Yes | Your domain key. |
domain_password |
Yes | Your domain password. |
service |
Yes | Service code (see table above) |
include |
No | By specifying mailing_address here, mailing addresses will be returned in addition to the other contact information. |
user_id |
No | Any unique identifier you use to identify a user. This value will be returned on calls to the /events and /contacts endpoints. |
echo |
No | Any customer defined string data to be returned in the response. |
redirect_url |
No | The URL where the browser will be redirected after the consent flow has completed. This parameter is useful when you are redirecting the browser to the consent URL. It is how you tell our application where to redirect the browser after the user has completed the consent flow. Typically, this is be the URL of the page where the user will see their imported address book. NB If you are opening the consent URL in a popup window with window.open , do not specify a value for the parameter. |
Example Request
curl --user 33664218758c5244136965160db455db012b1411:Tpa01z+vVPE7MxXi \
--request POST \
--data "service=yahoo" \
--url "https://api.cloudsponge.com/begin_import/user_consent.json"
Response Variables
Name | Description |
---|---|
status |
success or failure |
url |
User Consent URL where the user’s browser should be directed. |
import_id |
The identifier for this import, used in subsequent calls to fetch events and contacts. |
user_id |
The customer defined string that was passed in as an argument. |
echo |
The customer defined string that was passed in as an argument. |
Example Response (JSON)
{
"status": "success",
"url": "https://api.cloudsponge.com/n/FULNW3D",
"import_id": 1126
}
Example Response (XML)
<?xml version="1.0" encoding="UTF-8"?>
<result>
<status>success</status>
<url>https://api.cloudsponge.com/n/FULNW3D</url>
<import-id>1126</import-id>
</result>
Begin Username/Password Import
This import method requires that you collect your user’s username and password for their address book service.
- Your application collects the user’s username and password combination for the contact source requested.
- Your application calls the
/begin_import/import
endpoint, including the username/password plus the contact source requested. - CloudSponge returns a result object indicating the request has been received and specifying an
import_id
for fetching events and contacts later. - (Optional) Your application displays a status update to the user.
Now your application should go to Step 2 while CloudSponge downloads the address book for you.
Definition
POST https://api.cloudsponge.com/begin_import/import[.format]
Request Arguments
Name | Required? | Description |
---|---|---|
domain_key |
Yes | Your domain key. |
domain_password |
Yes | Your domain password. |
service |
Yes | Service code (see table above) |
username |
Yes | Your user’s username for the contact source. |
password |
Yes | Your user’s password for the contact source. |
include |
No | By specifying mailing_address here, mailing addresses will be returned in addition to the other contact information. |
user_id |
No | Any unique identifier you use to identify a user. |
echo |
No | Any customer defined string data to be returned in the response. |
Example Request
curl --user 33664218758c5244136965160db455db012b1411:Tpa01z+vVPE7MxXi \
--request POST \
--data "service=icloud" \
--data "username=foo" \
--data "password=bar" \
--url "https://api.cloudsponge.com/begin_import/import.json"
Response Variables
Name | Description |
---|---|
status |
success or failure |
import_id |
The identifier for this import, used in subsequent calls to fetch events and contacts. |
user_id |
The customer defined string that was passed in as an argument. |
echo |
The customer defined string that was passed in as an argument. |
Example Response (JSON)
{
"status": "success",
"import_id": 1126
}
Example Response (XML)
<?xml version="1.0" encoding="UTF-8"?>
<result>
<status>success</status>
<import-id>1126</import-id>
</result>
Begin Applet Import
This import method requires that your user grants our applet permission to access the contacts that are stored locally on her computer.
- Your application calls the
/begin_import/desktop_applet
endpoint, including the contact source requested. - CloudSponge returns a result object, including a
url
for the desktop applet, which needs to be downloaded by the user and animport_id
to be used to identify the import to the applet and to fetch the events and contacts. - Your application directs the user’s browser to download the applet from the
url
provided. This is accomplished by inserting theurl
andimport_id
into the HTML snippet at the bottom of this section and rendering it onto the page.
Now your application should go to Step 2 while the user gives CloudSponge permission to access their address book and we download it for you.
Definition
POST https://api.cloudsponge.com/begin_import/desktop_applet[.format]
Request Arguments
Name | Required? | Description |
---|---|---|
domain_key |
Yes | Your domain key. |
domain_password |
Yes | Your domain password. |
service |
Yes | Service code (see table above) |
include |
No | By specifying mailing_address here, mailing addresses will be returned in addition to the other contact information. |
user_id |
No | Any unique identifier you use to identify a user. This value will be returned on calls to the /events and /contacts endpoints. |
echo |
No | Any customer defined string data to be returned in the response. |
Example Request
curl --user 33664218758c5244136965160db455db012b1411:Tpa01z+vVPE7MxXi \
--request POST \
--data "service=outlook" \
--url "https://api.cloudsponge.com/begin_import/desktop_applet.json"
Response Variables
Name | Description |
---|---|
status |
success or failure |
url |
Java applet URL to be used to process the import. |
import_id |
The identifier for this import, used in subsequent calls to fetch events and contacts. |
user_id |
The customer defined string that was passed in as an argument. |
echo |
The customer defined string that was passed in as an argument. |
Example Response (JSON)
{
"status": "success",
"url": "https://api.cloudsponge.com/objects/ContactsApplet_signed.jar",
"import_id": 1126
}
Example Response (XML)
<?xml version="1.0" encoding="UTF-8"?>
<result>
<status>success</status>
<url>https://api.cloudsponge.com/objects/ContactsApplet_signed.jar</url>
<import-id>1126</import-id>
</result>
Insert the url
and import_id
values into the relevant spots in the HTML below and render it on your page to invoke the applet.
Please note Chrome no longer supports the Java browser plugin so when importing from Outlook or Mac OS X contact on Chrome, use the file upload or iCloud import instead.
<!--[if !IE]> Firefox and others will use outer object -->
<object classid="java:ContactsApplet"
type="application/x-java-applet"
archive="[ url ]"
height="1"
width="1">
<!-- Konqueror browser needs the following param -->
<param name="archive" value="[ url ]" />
<param name="importId" value="[ import_id ]"/>
<param name="cookieValue" value="document.cookie"/>
<param name="MAYSCRIPT" value="true">
<!--<![endif]-->
<!-- MSIE (Microsoft Internet Explorer) will use inner object -->
<object classid="clsid:8AD9C840-044E-11D1-B3E9-00805F499D93"
codebase="http://java.sun.com/update/1.6.0/jinstall-6u30-windows-i586.cab"
height="0"
width="0" >
<param name="code" value="ContactsApplet" />
<param name="archive" value="[ url ]" />
<param name="importId" value="[ import_id ]"/>
<param name="cookieValue" value="document.cookie"/>
<param name="MAYSCRIPT" value="true">
<!-- Chrome falls through to this innermost applet -->
<applet archive="[ url ]" code="ContactsApplet" height="1" width="1" MAYSCRIPT>
<param name="importId" value="[ import_id ]"/>
<param name="cookieValue" value="document.cookie" />
<param name="MAYSCRIPT" value="true">
<strong>
This browser does not have a Java Plug-in.<br />
<a href="http://java.sun.com/products/plugin/downloads/index.html">
Get the latest Java Plug-in here.
</a>
</strong>
</applet>
</object>
<!--[if !IE]> close outer object -->
</object>
<!--<![endif]-->
Step 2: Wait For The Import To Finish
After a contact import is initiated, your application must monitor the events as they are generated from CloudSponge. Use the import_id
value that was returned from the call to begin_import
to identify the import request to CloudSponge when fetching events.
- Your application calls the
/events
URL to get the current Import Events, specifying theimport_id
returned in the initial request. - CloudSponge returns the current Event result object.
Please Note The value on this endpoint will only update every second at most. Please limit your queries here to once per second.
Definition
GET https://api.cloudsponge.com/events/[import_id][.format]
Request Arguments
Name | Required? | Description |
---|---|---|
domain_key |
Yes | Your domain key. |
domain_password |
Yes | Your domain password. |
import_id |
Yes | import_id value returned from the call to begin_import in Step 1. |
echo |
No | Any customer defined string data to be returned in the response. |
Example Request
curl --user 33664218758c5244136965160db455db012b1411:Tpa01z+vVPE7MxXi \
--url "https://api.cloudsponge.com/events/1126.json"
Response Variables
Name | Description |
---|---|
events |
An array of events objects for the specified import_id . See the table below for details. |
import_id |
The identifier for this import, used in subsequent calls to fetch events and contacts. |
user_id |
The customer defined string that was passed in as an argument to the call to /begin_import . |
echo |
The customer defined string that was passed in as an argument. |
Example Response (JSON)
{
"events": [
{
"value": 0,
"status": "COMPLETED",
"event_type": "INITIALIZING"
},
{
"value": 2,
"status": "COMPLETED",
"event_type": "GATHERING"
},
{
"value": 0,
"status": "COMPLETED",
"event_type": "COMPLETE"
}
],
"echo": null,
"user_id": "myUserId_0003",
"import_id": 1126
}
Example Response (XML)
<?xml version="1.0" encoding="UTF-8"?>
<eventsResponse>
<events type="array">
<event>
<event-type>INITIALIZING</event-type>
<status>COMPLETED</status>
<value type="integer">0</value>
</event>
<event>
<event-type>GATHERING</event-type>
<status>COMPLETED</status>
<value type="integer">2</value>
</event>
<event>
<event-type>COMPLETE</event-type>
<status>COMPLETED</status>
<value type="integer">0</value>
</event>
</events>
<echo nil="true"></echo>
<user-id>myUserId_0003</user-id>
<import-id>1126</import-id>
</eventsResponse>
API Events
The following table defines the events array elements. Please note that the XML response will have some extra fields included, we do not recommend that you write your code to depend on these fields since we are in the process of deprecating them.
event-type | status | value |
---|---|---|
INITIALIZING | INPROGRESS | n/a |
INITIALIZING | COMPLETED | n/a |
INITIALIZING | ERROR | An error code from the table below. |
GATHERING | INPROGRESS | Number of contacts gathered so far. |
GATHERING | ERROR | An error code from the table below. |
GATHERING | COMPLETED | n/a |
COMPLETE | ERROR | An error code from the table below. |
COMPLETE | COMPLETED | n/a |
API Error Codes
The following table defines all of the error codes that you can expect to receive along with status=ERROR elements in the events array.
Error Code | Error Category | Explanation |
---|---|---|
1 | Failed | Could not authenticate the domain key/password. |
2 | Failed | Invalid parameters supplied to begin_import. |
256 | Failed | Unexpected error occurred during webmail import. |
257 | Failed | Webmail import failed. |
258 | Failed | Timeout occurred during webmail import. |
259 | Failed | Username and password are required. |
260 | Failed | Service is required. |
261 | Failed | Unrecognized service selected. |
262 | Failed | The same import failed to authenticate recently. |
263 | Failed | Username and password do not match. |
264 | Failed | The address book is temporarily unavailable, please try again later. |
265 | Failed | This account has been canceled. |
266 | Failed | The account has been blocked. Reset the password to reenable it. |
267 | Failed | Terms of Service have changed for your account. Sign in to your account to enable it. |
512 | Failed | Unknown error occurred during a user consent import. |
513 | Failed | User consent import failed because the domain is not permitted to use the service. |
514 | Abandoned | User consent import failed because the user did not provide consent to access their contacts. |
516 | Abandoned | Consent was not granted within the allotted time. |
517 | Abandoned | The user abandoned the import before consent was granted. |
518 | Failed | Unable to communicate successfully with the address book provider. |
528 | Failed | Unable to retrieve contacts. New Yahoo! users must wait 14 days to use this feature. |
544 | Failed | Gmail is not configured properly in CloudSponge. Sign into your account and complete the branding set up. |
768 | Failed | Unexpected error occurred during applet import. |
769 | Abandoned | Applet failed to import because user did not trust the applet. |
770 | Failed | Applet failed to import because it could not find an appropriate address book to import. |
771 | Failed | Applet failed to submit contacts to CloudSponge. |
772 | Abandoned | The Desktop Applet was not trusted within the allotted time. |
773 | Abandoned | The user abandoned the import before the Desktop Applet was trusted. |
774 | Abandoned | You must allow access to Microsoft Outlook to import your contacts. |
775 | Failed | The import was denied access to Contacts by the OS. |
1025 | Failed | A file was uploaded that is not of type text/csv. |
1026 | Failed | A CSV file was uploaded but could not be parsed. |
1027 | Failed | File uploads are not supported on the device. |
Step 3: Download The Address Book
When the COMPLETE event is received with the COMPLETED status in Step 2, your application should retrieve the contacts immediately. After a few minutes, they will be deleted from CloudSponge.
- Your application calls the
/contacts
endpoint to retrieve the contacts, specifying theimport_id
from the initial request. - CloudSponge returns the Contacts result object in the format requested.
Definition
GET https://api.cloudsponge.com/contacts/[import_id][.format]
Request Arguments
Name | Required? | Description |
---|---|---|
domain_key |
Yes | Your domain key. |
domain_password |
Yes | Your domain password. |
import_id |
Yes | import_id value returned from the call to /begin_import in Step 1. |
start |
No | For pagination: the 0-based index of the start of the contacts returned. Defaults to 0 . |
count |
No | For pagination: the maximum number of contacts to return in the contacts array. This value is ignored if start is not included. Defaults to 0 (all contacts). |
echo |
No | Any customer defined string data to be returned in the response. |
Example Request
curl --user 33664218758c5244136965160db455db012b1411:Tpa01z+vVPE7MxXi \
--url "https://api.cloudsponge.com/contacts/1126.json?start=0&count=10"
Response Variables
Name | Description |
---|---|
contacts |
An array of contact objects for the specified import_id. |
contacts_owner |
Contact information for the owner of the address book. |
import_id |
The identifier for this import, used in subsequent calls to fetch events and contacts. |
start |
For pagination: The 0-based, starting offset of the array of contacts that are returned. |
count |
For pagination: The number of contacts included in the array of contacts . |
total |
The total number of contacts imported from the address book. |
user_id |
The customer defined string that was passed in as an argument to the call to /begin_import . |
echo |
The customer defined string that was passed in as an argument. |
Example Response (JSON)
{
"echo":null,
"user_id":"myUserId_0003",
"import_id":1126,
"start": 0,
"count": 2,
"total": 2,
"contacts_owner":
{
"first_name":"Joe",
"last_name":"Smith",
"email":[
{
"address":"joe@example.com"
}
]
},
"contacts": [
{
"first_name":"John",
"last_name":"Doe",
"phone": [
{
"number":"555-1234",
"type":"Home"
},
{
"number":"555-2468",
"type":"Work"
}
],
"email": [
{
"address":"johndoe@nowhere.com",
"type":"Email 1"
},
{
"address":"second@email.com",
"type":"Email 2"
}
]
},
{
"first_name":"Jane",
"last_name":"Smith",
"phone":[
{
"number":"555.5678",
"type":"Home"
}
],
"email":[
{
"address":"janesmith@nowhere.com",
"type":"Email 1"
}
],
"addresses": [
{
"street":"3450 Sacramento St., #510",
"city":"San Francisco",
"region":"CA",
"country":"US",
"postal_code":"94118",
"formatted":"3450 Sacramento St., #510 San Francisco, CA 94118"
}
]
}
]
}
Example Response (XML)
<?xml version="1.0" encoding="UTF-8"?>
<contactsResponse>
<echo nil="true"></echo>
<user-id>myUserId_0003</user-id>
<import-id>1126</import-id>
<start>0</start>
<count>2</count>
<total>2</total>
<contacts-owner>
<first-name>Joe</first-name>
<last-name>Smith</last-name>
<email type="array">
<email>
<address>joe@example.com</address>
</email>
</email>
</contacts-owner>
<contacts type="array">
<contact>
<first-name>John</first-name>
<last-name>Doe</last-name>
<phone type="array">
<phone>
<number>555-1234</number>
<type>Home</type>
</phone>
<phone>
<number>555-2468</number>
<type>Work</type>
</phone>
</phone>
<email type="array">
<email>
<address>johndoe@nowhere.com</address>
<type>Email 1</type>
</email>
<email>
<address>second@email.com</address>
<type>Email 2</type>
</email>
</email>
</contact>
<contact>
<first-name>Jane</first-name>
<last-name>Smith</last-name>
<phone type="array">
<phone>
<number>555.5678</number>
<type>Home</type>
</phone>
</phone>
<email type="array">
<email>
<address>janesmith@nowhere.com</address>
<type>Email 1</type>
</email>
</email>
<address type="array">
<address>
<street>3450 Sacramento St., #510</street>
<city>San Francisco</city>
<region>CA</region>
<country>US</country>
<postal-code>94118</postal-code>
<formatted>3450 Sacramento St., #510 San Francisco, CA 94118</formatted>
</address>
</address>
</contact>
</contacts>
</contactsResponse>
API Libraries
We highly recommend that you start by choosing one of the wrappers listed below since most of the hard work is already done, but if you have special needs that aren’t addressed in our wrappers, then feel free to take the do-it-yourself approach.
There are a few open source libraries available, which wrap the API request and response sets into specific programming languages. These may make it easier for you to connect your web application to CloudSponge.
- ColdFusion (Contributed by Jojo Serquina, Senior Developer at SignUpGenius.com)
NOTE: These open source libraries have been built by the open source community. We cannot guarantee 100% support for these libraries.
Replacing CloudSponge OAuth Credentials
Since CloudSponge is the service importing contacts, by default the domain displayed in the user consent window(s) is our domain api.cloudsponge.com
. We recognize this may not be an ideal user experience, as your users are unfamiliar with CloudSponge.
CloudSponge offers you the ability customize the user experience with your own company name, domain, logo, fonts, styles, languages and third party OAuth credentials so that your users don’t feel like they’ve left your website.
There are 3 main steps to white labelling imports for Gmail, Yahoo and Outlook.com.
- Set up a Proxy URL on your domain
- Create developer accounts with Google, Yahoo! and Microsoft
- Configure CloudSponge to use your Google/Yahoo/Outlook.com developer credentials (OAuth Credentials)
Set OAuth Credentials in AOL experience is only possible if you have an existing developer relationship with AOL.
The Proxy URL
The OAuth flows provided by Gmail, Yahoo and Outlook.com are designed for a site like yours to request access to a person’s address book. In order for CloudSponge to be able to do the heavy lifting of importing and normalizing the contacts for your site, your application must hand the consent code over to CloudSponge.
You can accomplish this with a special page on your site that we refer to as Proxy URL.
The sole purpose of this page is to accept the token parameters from the contact source (Gmail, Yahoo or Outlook.com) and proxy that to CloudSponge.
Javascript Proxy URL (Recommended)
We have recently released a Javascript Proxy URL implementation that has no server-side dependencies. It consists of a static HTML page and Javascript file which implements the required behaviour.
Complete the following steps to install and test your OAuth proxy endpoint:
- Download the files here or review the full gist.
- Add
auth-proxy.html
andauth-proxy.js
to the same directory on your web server. Your Proxy URL is done! - Verify the Proxy URL by visiting the
auth-proxy.html
page on your server. You should see some text and a link. Make a note of the URL, you will use this URL as Proxy URL when setting up your Developer Accounts and also the OAuth Credentials in CloudSponge.
Next you can set up your OAuth Credentials for each OAuth source, using the URL for auth-proxy.html
.
This Javascript implementation page is preferred over our older reference implementations because there are no server-side dependencies. Any site that can host a static HTML page can host the Proxy URL.
Server-side Proxy URL (deprecated)
For new integrations, please use our Javascript Proxy URL. The server-side Proxy URL reference implementations are listed below for reference only.
Your Proxy URL should be a transparent pass-through between the client and api.cloudsponge.com
: all request data should be forwarded directly upstream to https://api.cloudsponge.com/auth
. Likewise, all response headers and data should be returned directly to the client. The page you create on your site to proxy requests needs to accept all GET
parameters, make an HTTP connection to https://api.cloudsponge.com/auth
, passing the parameters with the request. When the response comes back from api.cloudsponge.com
, the exact headers and body should be returned to the client. The typical gotcha is following redirects: api.cloudsponge.com/auth
returns a 302 response in many cases. Ensure that your system is configured to not follow redirects for the proper result.
CloudSponge may return a 302 Found
and a Location
in the response header. This response header should be returned to the user’s browser. Some platforms will automatically follow redirects so you must ensure that this functionality is turned off on your system.
Important Note: The Proxy URL cannot follow any redirect response from CloudSponge. It must proxy the request and include any GET parameters with the payload to CloudSponge.
We have several reference implementations of working Proxy URLs:
- HTML/Javascript - Recommended
- PHP (depends on the CloudSponge PHP library)
- Ruby (depends on the CloudSponge Ruby gem)
- ASP .Net
- Java Servlet
- Groovy & Grails
- Python & Django
OAuth Credentials
For your site’s identity to appear on the authentication screens, you will need to register an application at each of the contact sources. Once registered, you will need to add these credentials to your domain’s profile in your CloudSponge account.
Google (Gmail)
After you follow these steps, your users will see your product name in the Google Authentication window.
Important: Google requires you to submit a review of your application before they will allow strangers to use approve your OAuth permission requests. Google warns that the OAuth review may take up to a week. In our experience, the review may be faster than 24 hours as long as Google doesn’t have any questions about your application. We’ve prepared some background and directions to help you navigate the new process successfully. You can still test out your integration immediately.
These are the actions required to set up your Google OAuth:
- If you haven’t already done so, create a Proxy URL on your application’s domain.
- Obtain your Google OAuth 2.0 Credentials.
- Configure your CloudSponge account with your Google OAuth credentials.
- Request a review on Google’s OAuth Developer Verification Form.
Obtain your Google OAuth 2.0 Credentials
Watch how to create a Google OAuth credential in a few minutes.
Or follow the general steps below:
- Sign into the Google Developer Console with your Google account.
- Create a new project, or click on an existing one.
- Ensure that the Contacts API is enabled for your project.
- Configure your consent screen with your product name and other details.
- Create a new credential for your project.
- Under Application type, select Web application,
- Fill
Authorized redirect URIs
with your Proxy URL. - Click Create
- Note your Client ID and Client Secret. You will enter these into CloudSponge.
- Click over your app credentials in order to view details.
- Take note of your
Client ID
,Client secret
.
- Click over your app credentials in order to view details.
Configure your CloudSponge account with your Google OAuth credentials
- Sign in to your CloudSponge account and add a new Gmail OAuth Credential.
- Enter the
Client ID
,Client secret
andRedirect URI
values from Google and click on Save button. - Open your Account Settings page.
- Click the OAuth Credentials Settings button for the desired domain:
- For Gmail, select the newly inserted credential and click on Done button:
- Test a Google import on your site.
NB If you observe a 400 error with a message of “Error: invalid_scope” when you attempt to complete the OAuth flow, then your OAuth account needs to be reviewed before Google will let you request access to people’s address books. This is a new requirement that they introduced on May 11, 2017. We’ve prepared some background and directions for navigating the new review process.
Request a review on Google’s OAuth Developer Verification Form
Read our background and directions for a quick turnaround from the review process.
Yahoo! (Yahoo! Mail)
After you follow these steps, your users will see your domain in the Yahoo Authentication window instead of ours.
- If you haven’t already done so, create a Proxy URL on your application’s domain. Your Proxy URL should be set up to proxy all
GET
requests including the query string to:https://api.cloudsponge.com/auth
- Sign into the Yahoo Developer Portal with a Yahoo ID.
- Create a new project to use the Contacts API. This account must have read access to Contacts. Also, we recommend that you set “Read/Write Public and Private” access to Profiles if you intend to use the
contact_owner
property. - Set the Application Domain to your application’s domain.
- Verify your domain with Yahoo.
- Record the following values from your Yahoo project:
Client ID
&Client Secret
. - Sign in to your CloudSponge account and add a new Yahoo OAuth Credentials.
- Enter the
Consumer Key
,Consumer Secret
andApplication ID
that you recorded above and your Proxy URL from step 1 above. - Submit and test a Yahoo import.
Microsoft (Outlook.com, Office 365, Exchange Online, MSN, Hotmail, Windows Live)
After you follow these steps, your users will see your domain in the Microsoft’s Authentication window instead of ours.
- If you haven’t already done so, create a Proxy URL on your application’s domain.
- Go to My Applications in the Microsoft Registration Portal.
- Click on Add an app, give it a name and click Create application. You will be redirected to the Appication configuration page.
- Note the Application Id; it is your Client ID.
- In Application Secrets click on Generate new password. Note the password; it is your Client Secret.
- In Plataforms, click on Add Plataform, and select Web.
- In Redirect URIs, enter the url for the Proxy URL from step 1.
- In Microsoft Graph Permissions click the “Add” button beside Delegated Permissions.
Select
Contacts.Read
in the modal and click OK. You can removeUser.Read
as it is not required for CloudSponge. - Click Save at the very bottom of the page.
- Sign in to your CloudSponge account and add a new Outlook.com OAuth Credentials.
- Enter the Client ID and Client Secret that you recorded above, and the Redirect URI where you created the CloudSponge Proxy in step 1 above.
- Associate the branding with your site: click Settings, click the OAuth Credentials button beside your site and choose the new branding in the Outlook.com dropdown.
- Submit and test a Outlook.com import.
You can learn more about Microsoft’s Appication Registration Portal here.
Rebranding Our Applet
By default, your users will see api.cloudsponge.com
and “Cloud Copy, Inc.” in the dialog that asks them to give our applet permission to run on their computers.
Replacing our domain name with yours is simple and free. Replacing the digital signature with your company name is a little more complicated and will cost you a little money for a certificate from a third party.
Partial Rebranding
After you follow these steps, our domain name will be replaced with yours but the digital signature will still say “Cloud Copy, Inc.”
- Download the CloudSponge.com Desktop Applet from https://api.cloudsponge.com/objects/ContactsApplet_signed.jar and store in a public folder on your web server.
- Modify your response from the
/begin_import/desktop_applet
endpoint to always return the URL to your signed copy of the Desktop Applet.
Full Rebranding
After you follow these steps, our domain and our digital signature will be removed from the applet.
- Download and install the Java JDK on your server from http://java.sun.com/javase/downloads/widget/jdk6.jsp.
- Using ‘keytool’ (supplied with the JDK), obtain a Code Signing Certificate from a certificate authority such as Thawte or Verisign. More information about keytool and jarsigner can be found at http://java.sun.com/javase/6/docs/technotes/tools/index.html#security.
- Generate a self-signed certificate using keytool
- Generate a CSR using keytool
- Send the CSR to the CA
- Purchase the certificate
- Verify and import the certificate into the keystore generated in #1
- Download the CloudSponge.com signed applet from https://api.cloudsponge.com/objects/ContactsApplet_signed.jar.
- Use jarsigner to sign the ContactsApplet.jar with your Code Signing Certificate.
- Modify your response from the
/begin_import/desktop_applet
endpoint to always return the URL to your signed copy of the Desktop Applet. - Follow @CloudSpongeTech on Twitter. We’ll tweet a notification whenever we issue an update to the applet.
Whenever you update your copy of the applet, you will be required to repeat #3 and #4. The permission request will appear the same as for #2, but the digital signature displayed will correspond to your Code Signing Certificate.