I think the best approach would be to implement your own API method based on existing customer and address methods. You'll have to create a custom module.
Module structure:
-Foo/
--Bar/
---etc/
----api.xml
----config.xml
----wsdl.xml
---Model/
----Customer/
-----Api/
------V2.php
-----Api.php
etc/api.xml
<?xml version="1.0"?>
<config>
<api>
<resources>
<foo_bar translate="title" module="foo_bar">
<model>foo_bar/customer_api</model>
<title>Customer API</title>
<acl>foo_bar</acl>
<methods>
<create translate="title" module="foo_bar">
<title>Create customer</title>
<acl>foo_bar/create</acl>
</create>
</methods>
<faults module="foo_bar">
<data_invalid>
<code>100</code>
<message>Invalid customer data. Details in error message.</message>
</data_invalid>
</faults>
</foo_bar>
</resources>
<v2>
<resources_function_prefix>
<foo_bar>fooBar</foo_bar>
</resources_function_prefix>
</v2>
<acl>
<resources>
<foo_bar translate="title" module="foo_bar">
<title>Foo Bar</title>
<sort_order>3</sort_order>
<create translate="title" module="foo_bar">
<title>Create</title>
</create>
</foo_bar>
</resources>
</acl>
</api>
</config>
etc/wsdl.xml
<?xml version="1.0" encoding="UTF-8"?>
<definitions xmlns:typens="urn:{{var wsdl.name}}" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns="http://schemas.xmlsoap.org/wsdl/"
name="{{var wsdl.name}}" targetNamespace="urn:{{var wsdl.name}}">
<types>
<schema xmlns="http://www.w3.org/2001/XMLSchema" targetNamespace="urn:Magento">
<import namespace="http://schemas.xmlsoap.org/soap/encoding/" schemaLocation="http://schemas.xmlsoap.org/soap/encoding/" />
<complexType name="fooBarCreateCustomerData">
<all>
<element name="customer_id" type="xsd:int" minOccurs="0" />
<element name="email" type="xsd:string" minOccurs="0" />
<element name="firstname" type="xsd:string" minOccurs="0" />
<element name="lastname" type="xsd:string" minOccurs="0" />
<element name="middlename" type="xsd:string" minOccurs="0" />
<element name="password" type="xsd:string" minOccurs="0" />
<element name="website_id" type="xsd:int" minOccurs="0" />
<element name="store_id" type="xsd:int" minOccurs="0" />
<element name="group_id" type="xsd:int" minOccurs="0" />
<element name="prefix" type="xsd:string" minOccurs="0" />
<element name="suffix" type="xsd:string" minOccurs="0" />
<element name="dob" type="xsd:string" minOccurs="0" />
<element name="taxvat" type="xsd:string" minOccurs="0" />
<element name="gender" type="xsd:int" minOccurs="0" />
</all>
</complexType>
<complexType name="fooBarCreateAddressData">
<all>
<element name="city" type="xsd:string" minOccurs="0" />
<element name="company" type="xsd:string" minOccurs="0" />
<element name="country_id" type="xsd:string" minOccurs="0" />
<element name="fax" type="xsd:string" minOccurs="0" />
<element name="firstname" type="xsd:string" minOccurs="0" />
<element name="lastname" type="xsd:string" minOccurs="0" />
<element name="middlename" type="xsd:string" minOccurs="0" />
<element name="postcode" type="xsd:string" minOccurs="0" />
<element name="prefix" type="xsd:string" minOccurs="0" />
<element name="region_id" type="xsd:int" minOccurs="0" />
<element name="region" type="xsd:string" minOccurs="0" />
<element name="street" type="typens:ArrayOfString" minOccurs="0" />
<element name="suffix" type="xsd:string" minOccurs="0" />
<element name="telephone" type="xsd:string" minOccurs="0" />
<element name="is_default_billing" type="xsd:boolean" minOccurs="0" />
<element name="is_default_shipping" type="xsd:boolean" minOccurs="0" />
</all>
</complexType>
</schema>
</types>
<message name="fooBarCreateRequest">
<part name="sessionId" type="xsd:string" />
<part name="customerData" type="typens:fooBarCreateCustomerData" />
<part name="addressData" type="typens:fooBarCreateAddressData" />
</message>
<message name="fooBarCreateResponse">
<part name="result" type="xsd:int" />
</message>
<portType name="{{var wsdl.handler}}PortType">
<operation name="fooBarCreate">
<documentation>Create customer</documentation>
<input message="typens:fooBarCreateRequest" />
<output message="typens:fooBarCreateResponse" />
</operation>
</portType>
<binding name="{{var wsdl.handler}}Binding" type="typens:{{var wsdl.handler}}PortType">
<soap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http" />
<operation name="fooBarCreate">
<soap:operation soapAction="urn:{{var wsdl.handler}}Action" />
<input>
<soap:body namespace="urn:{{var wsdl.name}}" use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" />
</input>
<output>
<soap:body namespace="urn:{{var wsdl.name}}" use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" />
</output>
</operation>
</binding>
</definitions>
Model/Customer/Api.php
<?php
class Foo_Bar_Model_Customer_Api extends Mage_Customer_Model_Customer_Api
{
public function create($customerData, $addressData)
{
$customer = Mage::getModel('customer/customer');
Mage::log($customerData, null, 'customerData.log', true);
try {
$customer->setData($this->_prepareData($customerData));
$address = Mage::getModel('customer/address');
foreach ($this->getAllowedAttributes($address) as $attributeCode=>$attribute) {
if (isset($addressData->$attributeCode)) {
$address->setData($attributeCode, $addressData->$attributeCode);
}
}
if (isset($addressData->is_default_billing)) {
$address->setIsDefaultBilling($addressData->is_default_billing);
}
if (isset($addressData->is_default_shipping)) {
$address->setIsDefaultShipping($addressData->is_default_shipping);
}
$customer->addAddress($address)
->save();
} catch (Mage_Core_Exception $e) {
$this->_fault('data_invalid', $e->getMessage());
}
return $customer->getId();
}
}
Model/Customer/Api/V2.php
<?php
class Foo_Bar_Model_Customer_Api_V2 extends Foo_Bar_Model_Customer_Api
{
protected function _prepareData($data)
{
if (null !== ($_data = get_object_vars($data))) {
return parent::_prepareData($_data);
}
return array();
}
}
And that's it. Code could use some minor tuning but it works. I did not include etc/config.xml
as it's already a long answer and you can easily figure it out on your own.
And finally the sample API call:
<?php
$client = new SoapClient('http://magento.local/api/v2_soap?wsdl=1');
$customer = array(
'email' => '[email protected]',
'firstname' => 'Firstname',
'lastname' => 'Lastname',
'password' => 'password',
'website_id' => 1,
'store_id' => 1,
'group_id' => 1,
);
$address = array(
'firstname' => 'Firstname',
'lastname' => 'Lastname',
'create_address' => true,
'city' => 'City',
'company' => 'Company',
'country_id' => 'US',
'region_id' => 12,
'postcode' => '90210',
'street' => array('Street Line 1', 'Street Line 2'),
'telephone' => '1234567890',
'is_default_billing' => true,
'is_default_shipping' => true
);
try {
$session = $client->login('apiuser', 'apipassword');
$result = $client->fooBarCreate($session, $customer, $address);
} catch (SoapFault $fault) {
echo $fault->getMessage();
}