How to Use the Entire Salesforce API

How to Use the Entire Salesforce API

These posts are modeled after the EXAMPLES file that ships with the Salesforce Python Toolkit, in which I wrote snippets of code on how to use all the method calls in the Salesforce API spec. The posts will be modeled after the four sections of the Salesforce API docs; so they will be ‘Core Calls’, ‘Describe Calls’, ‘Utility Calls’, and ‘SOAP Headers’. There will be an Enterprise and Partner WSDL version of each.

NOTE: These examples are not intended to teach the Salesforce API; rather, they are here to illustrate how the PHP Toolkit implements the Salesforce API.


All examples below assume the Toolkit has been instantiated and the connection has been made.

$crmHandle = new SforcePartnerClient();

Additionally, all examples except login() assume you are logged in, using a call such as
$crmHandle->login(‘′, ‘*passwordhere*’ . ‘*securitytokenhere*’);


<create lead> – implies that you copy and paste the code from create(), so you have a Lead in the variable $lead and a SaveResult in the variable $result

<create 2 leads> – same as create lead, except copy and paste the code from ‘create 2 leads’ in create()

Variable Names

  • $crmHandle – reference to an instance of the Toolkit object
  • $result – the result of a Salesforce method call
  • $lead – a lead object


Date formats are in the SOAP dateTime format (ISO 8601), e.g. ‘2009-06-01T23:01:01Z’.

If you see an error like ‘INVALID_TYPE: Must send a concrete entity type’, most likely, you have forgotten to wrap your object in an array before passing it to a method.


<create lead>
$leadConvert = new SObject();
$leadConvert->leadId = $result->id;
// The possible values for convertedStatus depend on what's in the
// picklist for your org.  You can take a look at the 'Convert Lead' screen
// in the UI for your API user to see what's there
$leadConvert->convertedStatus = 'Qualified';
$leadConvert->doNotCreateOpportunity = true;
$leadConvert->overwriteLeadSource = false;
$leadConvert->sendNotificationEmail = false;
$result = $crmHandle->convertLead($leadConvert);


$lead = new SObject();
$lead->fields = array('FirstName' => 'Joe',
                      'LastName' => 'Moke',
                      'Company' => 'Jamoke, Inc.',
                      'Email' => '');
$lead->type = 'Lead';
$result = $crmHandle->create(array($lead), 'Lead');


<create lead>
$result = $crmHandle->delete(array($result->id));


$result = $crmHandle->emptyRecycleBin(array('*ID OF A DELETED OBJECT HERE*'));


// $startDate must be the later of 30 days prior and the last recycle bin purge
$result = $crmHandle->getDeleted('Lead', $startDate, $endDate);


// $startDate must be later than 30 days prior
$result = $crmHandle->getUpdated('Lead', $startDate, $endDate);

BEWARE there is a bug in versions 13.0 and earlier of the PHP Toolkit where it calls both invalidateSessions() AND logout(), generating an exception. I would strongly discourage use of either call, as they log out all concurrent sessions of the user!

You were warned…

$result = $crmHandle->invalidateSessions($crmHandle->getSessionId());


$crmHandle->login('', '*password*' . '*securitytoken*');

SEE NOTES FOR invalidateSessions()

$result = $crmHandle->logout();


// assume we have two IDs stored in $id and $id2

// retrieve what will be the master record
$result = $crmHandle->retrieve('FirstName, LastName, Company, Email', 'Lead', $id);
$lead = $result[0];

$mergeRequest = new SObject();
$mergeRequest->masterRecord = $lead;
$mergeRequest->recordToMergeIds = $id2;
$result = $crmHandle->merge($mergeRequest, 'Lead');

The Toolkit diverges slightly from the API here, as it doesn’t implement process(), but instead implements processSubmitRequest() and processWorkitemRequest().

processSubmitRequest() (non-standard)
NOTE: The API docs for this call are currently incorrect; the ProcessSubmitRequest object takes a property ‘comments’, not ‘comment’ as stated here.

$processRequest = new SObject();
$processRequest->objectId = '*ID OF OBJECT PROCESS REQUEST AFFECTS*';
$processRequest->comments = 'This is what I think.';
$result = $crmHandle->processSubmitRequest(array($processRequest));

processWorkitemRequest() (non-standard)
NOTE: The API docs for this call are currently incorrect; the ProcessWorkitemRequest object takes a property ‘comments’, not ‘comment’ as stated here.

$processRequest = new SObject();
$processRequest->action = 'Approve';
$processRequest->workitemId = '*ID OF OBJECT PROCESS REQUEST AFFECTS*';
$processRequest->comments = 'I approved this request.';
$result = $crmHandle->processWorkitemRequest(array($processRequest));


$result = $crmHandle->query('SELECT FirstName, LastName FROM Lead');

This method is broken in the Partner version as of version 13.1; however, there is a simple fix. Add the following method to SforcePartnerClient.php at line 158:

  public function queryAll($query) {
    return new QueryResult(parent::queryAll($query));

Otherwise, for the following query:

$result = $crmHandle->queryAll('SELECT FirstName, LastName FROM Lead LIMIT 2');

the Toolkit returns

    object(stdClass)#6 (3) {
      string(4) "Lead"
      string(73) "<sf:FirstName>Joe</sf:FirstName><sf:LastName>Moke</sf:LastName>"

instead of

    object(SObject)#5 (2) {
      string(4) "Lead"
      object(stdClass)#9 (2) {
        string(4) "Joe"
        string(5) "Moke"

like the Enterprise version does. The working example is the query above.


// return a maximum of 200 results
$queryOptions = new QueryOptions(200);
$result = $crmHandle->query('SELECT FirstName, LastName FROM Lead');
while ($result->done === false) {
  $result = $crmHandle->queryMore($result->queryLocator);
  // do something with results

NOTE: The Partner version will return a 1-length array with the object in it for a single match, the Enterprise version will return the object itself.

$result = $crmHandle->retrieve('FirstName, LastName, Company, Email', 'Lead', $id);
$lead = $result[0];

Search is currently broken in the Partner Toolkit as of version 13.1, and in order to use it, you must make a couple of modifications to SforcePartnerClient.php. Note that this is not the official implementation, but it does comply with what’s in the partner WSDL.

In the class SforcePartnerClient, after retrieve(), add the following method:

  public function search($searchString) {
    return new SearchResult(parent::search($searchString));

Below the class SforcePartnerClient, add the following class:

class SearchResult {
  public $searchRecords = array();

   * SearchResult ctor
   * SforceBaseClient::search() will return three different structures depending on result count,
   * distinguishable in the following way:
   * 0 results: empty stdClass object
   * 1 result: $response->searchRecords is an object, not an array
   * 2+ results: $response->searchRecords is an array
   * @param stdClass $response  Response from base class
  public function __construct($response) {
    if (!isset($response->searchRecords)) {
    } elseif (!is_array($response->searchRecords)) {
      $this->searchRecords[]->record = new SObject($response->searchRecords->record);
    } else {
      foreach ($response->searchRecords as $searchRecord) {
        $this->searchRecords[]->record = new SObject($searchRecord->record);

You can now use the search() method in the same way as in the Enterprise client:

$result = $crmHandle->search('FIND {Joe Moke} IN Name Fields RETURNING Lead(Name, Phone)');


$result = $crmHandle->undelete(array('*ID HERE*'));

NOTE: Unlike the Enterprise version, you can set more than one field to null in an update() call. However, you must unset() each field as well, not set the field equal to null or ”.

<create lead>

$lead->Id = $result->id;
$lead->fieldsToNull = array('Email', 'Company');
$crmHandle->update(array($lead), 'Lead');


<create lead>

$lead->Id = $result->id;
$lead->FirstName = 'Bob';
$crmHandle->upsert('Id', array($lead), 'Lead');