How to generate DocuSign embedded signing url from apex? - salesforce

I want to generate the DocuSign embedded URL to get the documents signed by the community user.

I am able to achieve the requirement. Here is the solution
Initial things
DocuSign setup from both sides (Salesforce and DocuSign itself).
Signing user must be assigned “DocuSign Sender” permission set to sign the
document(s).
Create and send an envelope – First method
public static String sendEnvelope(String recordId) {
Id mySourceId = recordId; // The ID of the initiating Salesforce object
// Create an empty envelope and add a Salesforce Document and embedded signer
recipient
// The embedded signer will be the current user with sequence and routing
order 1 and role "Signer 1" by default
List<dfsle.Document> myDocuments = new List<dfsle.Document>();
// Content Version need to be param or queried
myDocuments =
dfsle.DocumentService.getDocuments(ContentVersion.getSObjectType(),
new Set<Id> { ContentVersionId(s) });
dfsle.Envelope dsEnvelope = dfsle.EnvelopeService.getEmptyEnvelope(
new dfsle.Entity(mySourceId))//The initiating Salesforce entity current SF user
.withDocuments(myDocuments)
.withRecipients(new List<dfsle.Recipient> {
dfsle.Recipient.newEmbeddedSigner() // An embedded signer
}
);
// Send the envelope.
dsEnvelope = dfsle.EnvelopeService.sendEnvelope(
dsEnvelope, // The envelope to send
true // Send now?
);
// Return string value of DocuSign envelope ID
return String.valueOf(dsEnvelope.docuSignId);
}
Host an embedded signing session – second method
// passing envId as parameter that we will receive from above method
public static String getEmbeddedSigningUrl(String envId) {
// url will be redirect URL
Url mySigningUrl = dfsle.SigningService.getEmbeddedSigningUrl(
dfsle.UUID.parse(envId), // envId value as a UUID
new URL(url) // url value as a URL
);
// Return string value of url to controller
return mySigningUrl.toExternalForm();
}
Variable Source id – It is the parent object record id where we want to store the signed documents back into salesforce.
Set of content version ids which are stored as files with s1,d1 tags etc.
myDocuments =
dfsle.DocumentService.getDocuments(ContentVersion.getSObjectType(),
new Set<Id> { ContentVersionId(s) });
Redirect URL - After signing the document(s) where we want to redirect the user.
In the case of using DocuSign in the context of Community user
Note: In the DocuSign Setup tab choose Configuration in the left menu, then go to the Settings tab and choose a user next to Enable System sender. This allows Community users to send envelopes even if they are not a member of the DocuSign account. In that case, envelopes will be sent from the admin user that you selected.
Important Points to remember
Embedded URL is valid only for 5 mins by default, if we want to increase the time
we will have to talk to the DocuSign support team and it can be increased max up
to 15 mins depending on the service plan.
References
https://developers.docusign.com/docs/salesforce/how-to/embedded-sending-signing/

Related

Salesforce DocuSign Integration

Use Case - Salesforce Docusign implementation:
We have Parent and child object in salesforce where Parent have authorize signer and Relationship Manger email information and their each child object have document which we need to sign by authorize signer and relationship manger.
We need to send all the child object documents in single envelope. And when the signing ceremony completed we need to attach respective signed documents to their respective child records.
Currently, we can planning to do through Apex Toolkit or DocuSign rest API.
Example: Authorized signer and RM present on account record. And each contact associated with account having document which are attached by Contact person. Account owner should have button where it should fetch all the document from related contact, create envelope, should tagging the signature on each document and able to send to authorized Signer and RM.
Authorized Signer should received all the document with in single envelope. They signed all the document. Once Signed by them all the signed document should go back to respective contact.
Note: Business wants to see all the Recipients status and document sent to end user in salesforce as well.
Can you please provide input on this and share some sample as per our use case?
The flow here would be to pull the documents with DocumentService.getLinkedDocuments and then set up anchor tabs. If you want to send multiple documents, you'll need to set the Anchor Population Scope to Document. If docs are numbered in the order of the list 1, 2, 3. You will use .withOptions for the writeBack. Example can be found here:
https://www.docusign.com/blog/developers/whats-new-summer-21-apex-toolkit
And a sample code (except for the writeback part):
//Find your contact to add
Contact myContact = [SELECT Id, Name, Email FROM Contact WHERE Name = 'Snow Beard' LIMIT 1];
//This sets tab as an anchor tab. If using this with multiple documents,
// Ask customer support to set Account Setting Anchor Population Scope to Document.
dfsle.Tab hereTab = new dfsle.SignHereTab()
.withScale(1) // 1/2 scale
.withRequired(true) // Signing mandatory
.withDataLabel('SignHereMeHardy')
.withAnchor(
new dfsle.Tab.Anchor(
'Anchor1', // Anchor string
true, // allow white space in anchor string
true, // Anchor string is not case sensitive
'right', // Horizontal alignment in relation to the anchor text
true, // Ignore if the anchor text is not present in the document
true, // Must match the value of the anchor string in its entirety
'pixels', // Unit of the x and y offset properties
10, // X offset
10 // Y offset
)
)
//This places the tab on the first docunent in the list on page one. Requires DocuSign Support to set Anchor Population Scope to Document.
.withPosition(
new dfsle.Tab.Position(
1, //Document id matches order of documents
1, //Page id
null,
null,
20,
20
)
);
//use the Recipient.fromSource method to create the Recipient
dfsle.Recipient myRecipient = dfsle.Recipient.fromSource
(
myContact.Name, // Recipient name
myContact.Email, // Recipient email
null, //Optional phone number
'Signer 1', //Role Name. Specify the exact role name from template if using a template or use Default 'Signer 1'
new dfsle.Entity(myContact.Id) //source object for the Recipient
)
.withTabs(new List<dfsle.Tab> { // Associate the tabs with this recipient
hereTab
});
Opportunity myOpportunity = [SELECT Id FROM Opportunity WHERE Name = 'Sailcloth' LIMIT 1];
//This pulls all the documents from the Opportunity Object and adds them to documents list
List<dfsle.Document> documents = dfsle.DocumentService.getLinkedDocuments
(
ContentVersion.getSObjectType(),
new Set<Id>{myOpportunity.Id},
false
);
// Create an empty envelope.
// This shows how to pull documents from an object in Salesforce. In this case an Opportunity
dfsle.Envelope myEnvelope = dfsle.EnvelopeService.getEmptyEnvelope(new dfsle.Entity(myOpportunity.Id))
.withRecipients(new List<dfsle.Recipient> { myRecipient })
.withDocuments(documents);
// Send the envelope
try {
dfsle.EnvelopeService.sendEnvelope(myEnvelope, true);
} catch (dfsle.APIException ex) {
system.debug(ex);
if (ex.error.code == dfsle.APIErrorCode.CONSENT_REQUIRED) {
// user is a valid member of the DocuSign account, but has not granted consent to this application
} else {
// handle other errors
}
}

Add additional query parameters to the Azure B2C login url

I'm implementing Azure B2C to a .NET MVC app, and I need to add an extra query parameter to the login url.
Here's how I've set it up in the startup.cs
var openIdConnectAuthenticationOptions = new OpenIdConnectAuthenticationOptions
{
// Generate the metadata address using the tenant and policy information
MetadataAddress = String.Format(Globals.WellKnownMetadata, Globals.Tenant, Globals.DefaultPolicy),
// These are standard OpenID Connect parameters, with values pulled from web.config
ClientId = Globals.ClientId,
RedirectUri = Globals.RedirectUri,
PostLogoutRedirectUri = Globals.RedirectUri,
// Specify the callbacks for each type of notifications
Notifications = new OpenIdConnectAuthenticationNotifications
{
RedirectToIdentityProvider = OnRedirectToIdentityProvider,
AuthorizationCodeReceived = OnAuthorizationCodeReceived,
AuthenticationFailed = OnAuthenticationFailed
},
// Specify the claim type that specifies the Name property.
TokenValidationParameters = new TokenValidationParameters
{
NameClaimType = "name",
ValidateIssuer = false
},
// Specify the scope by appending all of the scopes requested into one string (separated by a blank space)
Scope = $"openid",
ResponseType = "id_token",
};
app.UseOpenIdConnectAuthentication(
openIdConnectAuthenticationOptions
);
And when someone tries to visit an [authorized] tagged page, it sends them to this b2c url:
https://mytenant.b2clogin.com/mytenant.onmicrosoft.com/oauth2/v2.0/authorize?p=b2c_custom_signin&client_id=0000-000000-000-00&redirect_uri=https://localhost&response_type=id_token&scope=openid&x-client-SKU=ID_NET461&x-client-ver=5.3.0.0
However, I need to add an extra query parameter onto the end, "&appId=000-000-000", so the resulting login URL is:
https://mytenant.b2clogin.com/mytenant.onmicrosoft.com/oauth2/v2.0/authorize?p=b2c_custom_signin&client_id=0000-000000-000-00&redirect_uri=https://localhost&response_type=id_token&scope=openid&x-client-SKU=ID_NET461&x-client-ver=5.3.0.0 &appId=000-000-000
how would I go about doing this?
I'm afraid you could not add the appId parameter, but I recommend to make use of the state parameter. You could use this parameter to send the value of appid as part of request and it gets returned back in response.
For more details, see here.

How to update NetSuite through Salesforce?

How would you go about updating NetSuite through Salesforce.
I know that you would use NetSuite's RESTlet and Salesforce Apex code to connect the two, but how would you actually go about doing this in a step by step process?
To send data from Salesforce to NetSuite (specifically customer/account data) you will need to do some preliminary setup in both.
In NetSuite:
Create a RESTlet Script that has at the bare minimum a get and post.
For instance I would create a javascript file on my desktop that contains:
/**
*#NApiVersion 2.x
*#NScriptType restlet
*/
//Use: Update NS customer with data (context) that is passed from SF
define(['N/record'], function(record) //use the record module
{
function postData(context)
{
//load the customer I'm gonna update
var cust = record.load({type:context.recordtype, id:context.id});
log.debug("postData","loaded the customer with NSID: " + context.id);
//set some body fields
cust.setValue("companyname", context.name);
cust.setValue("entityid", context.name + " (US LLC)");
cust.setValue("custentity12", context.formerName);
cust.setValue("phone",context.phone);
cust.setValue("fax",context.fax);
//remove all addresses
while(cust.getLineCount('addressbook') != 0)
cust.removeLine('addressbook',0);
//add default billing address
cust.insertLine('addressbook',0);
cust.setSublistValue('addressbook','defaultbilling',0,true);
cust.setSublistValue('addressbook','label',0,'BILL_TO');
var billingAddress=cust.getSublistSubrecord('addressbook','addressbookaddress',0);
billingAddress.setValue('country',context.billingCountry);
billingAddress.setValue('addr1', context.billingStreet);
billingAddress.setValue('city',context.billingCity);
billingAddress.setValue('state',context.billingState);
billingAddress.setValue('zip',context.billingZip);
//add default shipping address
cust.insertLine('addressbook',0);
cust.setSublistValue('addressbook','defaultshipping',0,true);
cust.setSublistValue('addressbook','label',0,'SHIP_TO');
var shippingAddress=cust.getSublistSubrecord('addressbook','addressbookaddress',0);
shippingAddress.setValue('country',context.shippingCountry);
shippingAddress.setValue('addr1',context.shippingStreet);
shippingAddress.setValue('city',context.shippingCity);
shippingAddress.setValue('state',context.shippingState);
shippingAddress.setValue('zip',context.shippingZip);
//save the record
var NSID = cust.save();
log.debug("postData","saved the record with NSID: " + NSID);
return NSID; //success return the ID to SF
}
//get and post both required, otherwise it doesn't work
return {
get : function (){return "get works";},
post : postData //this is where the sauce happens
};
});
After You've saved this file, go to NetSuite>Customization>Scripting>Scripts>New.
Select the new file that you've saved and create the script record. Your script record in NetSuite should have GET and POST checked under scripts.
Next, click deploy script and choose who will call this script, specifically the user that will login on the salesforce end into NetSuite.
On the deployment page you will need the External URL it goes something like:
https://1234567.restlets.api.netsuite.com/app/site/hosting/restlet.nl?script=123&deploy=1
Note: If any data that you are updating is critical for a process, I would highly recommond creating this in the sandbox first for testing, before moving to production.
In Salesforce sandbox:
Click YourName>Developer Console
In the developer console click File>New and create an Apex Class:
global class NetSuiteWebServiceCallout
{
#future (callout=true) //allow restlet callouts to run asynchronously
public static void UpdateNSCustomer(String body)
{
Http http = new Http();
HttpRequest request = new HttpRequest();
request.setEndPoint('https://1234567.restlets.api.netsuite.com/app/site/hosting/restlet.nl?script=123&deploy=1'); //external URL
request.setMethod('POST');
request.setHeader('Authorization', 'NLAuth nlauth_account=1234567, nlauth_email=login#login.com, nlauth_signature=password'); //login to netsuite, this person must be included in the NS restlet deployment
request.setHeader('Content-Type','application/json');
request.setBody(body);
HttpResponse response = http.send(request);
System.debug(response);
System.debug(response.getBody());
}
}
You will have to set the endpoint here to the external url, the authorization nlauth_account=[your netsuite account number], and the header to your login email and password to a person who is on the deployment of the NS script, the body will be set in the trigger that calls this class.
Next create the trigger that will call this class. I made this script run every time I update the account in Salesforce.
trigger UpdateNSCustomer on Account (after update)
{
for(Account a: Trigger.new)
{
String data = ''; //what to send to NS
data = data + '{"recordtype":"customer","id":"'+a.Netsuite_Internal_ID__c+'","name":"'+a.Name+'","accountCode":"'+a.AccountCode__c+'",';
data = data + '"formerName":"'+a.Former_Company_Names__c+'","phone":"'+a.Phone+'","fax":"'+a.Fax+'","billingStreet":"'+a.Billing_Street__c+'",';
data = data + '"billingCity":"'+a.Billing_City__c+'","billingState":"'+a.Billing_State_Province__c+'","billingZip":"'+a.Billing_Zip_Postal_Code__c+'",';
data = data + '"billingCountry":"'+a.Billing_Country__c+'","shippingStreet":"'+a.Shipping_Street__c+'","shippingCity":"'+a.Shipping_City__c+'",';
data = data + '"shippingState":"'+a.Shipping_State_Province__c+'","shippingZip":"'+a.Shipping_Zip_Postal_Code__c+'","shippingCountry":"'+a.Shipping_Country__c+'"}';
data = data.replaceAll('null','').replaceAll('\n',',').replace('\r','');
System.debug(data);
NetSuiteWebServiceCallout.UpdateNSCustomer(data); //call restlet
}
}
In this script data is the body that you are sending to NetSuite.
Additionally, you will have to create an authorized endpoint for NetSuite in your remote site setings in salesforce (sandbox and production). Go to setup, and quickfind remote site settings which will be under security controls.
Create a new Remote site that has its remote site URL set to the first half of your external url: https://1234567.restlets.api.netsuite.com.
From here, do some testing in the sandbox.
If all looks well deploy the class and trigger to salesforce production.

Unity/Android ServerAuthCode has no idToken on Backend

I have an unity app and use the google-play-games plugin with google *.aar versions 9.4.0. I lately changed my Backend (Google App Engine) from php to java. My problem is the following: in php the serverauthcode is used to get the users data (in JWT format) - it was working fine. So I changed to a Java servlet and I am failing since 2 days to get a valid idtoken. I am able to recieve the server auth code from my app and a valid token response is made by GoogleAuthorizationCodeTokenRequest (see code snippet). Unfortunately it does not contain any idtoken content but a valid auth_token. So I can not get the user id to identifiy the user. When I call tokenResponse.parseIdToken(); it is failing with a NullPointerException.
servlet code (authCode is the serverAuthCode I send from the play-games-plugin inside Unity to my GAE):
// (Receive authCode via HTTPS POST)
// Set path to the Web application client_secret_*.json file you downloaded from the
// Google Developers Console: https://console.developers.google.com/apis/credentials?project=_
// You can also find your Web application client ID and client secret from the
// console and specify them directly when you create the GoogleAuthorizationCodeTokenRequest
// object.
String CLIENT_SECRET_FILE = "/mypath/client_secret.json";
// Exchange auth code for access token
GoogleClientSecrets clientSecrets =
GoogleClientSecrets.load(
JacksonFactory.getDefaultInstance(), new FileReader(CLIENT_SECRET_FILE));
GoogleTokenResponse tokenResponse =
new GoogleAuthorizationCodeTokenRequest(
new NetHttpTransport(),
JacksonFactory.getDefaultInstance(),
clientSecrets.getDetails().getTokenUri(),
clientSecrets.getDetails().getClientId(),
clientSecrets.getDetails().getClientSecret(),
authCode,
REDIRECT_URI) // Specify the same redirect URI that you use with your web
// app. If you don't have a web version of your app, you can
// specify an empty string.
.execute();
String accessToken = tokenResponse.getAccessToken();
// Get profile info from ID token -> HERE IT THROWS AN EXCEPTION.
GoogleIdToken idToken = tokenResponse.parseIdToken();
GoogleIdToken.Payload payload = idToken.getPayload();
String userId = payload.getSubject(); // Use this value as a key to identify a user.
String email = payload.getEmail();
boolean emailVerified = Boolean.valueOf(payload.getEmailVerified());
String name = (String) payload.get("name");
String pictureUrl = (String) payload.get("picture");
String locale = (String) payload.get("locale");
String familyName = (String) payload.get("family_name");
String givenName = (String) payload.get("given_name");
the token response looks like (its invalid now):
{
"access_token" : "ya29.CjA8A7O96w-vX4OCSPm-GMEPGVIEuRTeOxKy_75z6fbYVSXsdi9Ot3NmxlE-j_t-BI",
"expires_in" : 3596,
"token_type" : "Bearer"
}
In my PHP GAE I always had a idToken inside this constuct which contained my encrypted data. But it is missing now?! So I asssume I do somthing differently in Java or I made a mistake creating the new OAuth 2.0 Client on the google console.
I checked the accessToken manually via:
https://www.googleapis.com/oauth2/v1/tokeninfo?access_token=ya29.CjA8A7O96w-vX4OCSPm-GMEPGVIEu-RTeOxKy_75z6fbYVSXsdi9Ot3NmxlE-j_t-BI
{
"issued_to": "48168146---------.apps.googleusercontent.com",
"audience": "48168146---------.apps.googleusercontent.com",
"scope": "https://www.googleapis.com/auth/games_lite",
"expires_in": 879,
"access_type": "offline"
}
Is there something I do not see? Help is very much appreciated...
I found a root cause discussion inside the unity plugin "play-games-services" on github:
https://github.com/playgameservices/play-games-plugin-for-unity/issues/1293
and
https://github.com/playgameservices/play-games-plugin-for-unity/issues/1309
It seems that google switching their authentication flow. In the given links they are talking about adding the email scope inside the plugin to get the idtoken again. I'll try that in the next days and share my experience.
Here is a good explaination about what happens:
http://android-developers.blogspot.de/2016/01/play-games-permissions-are-changing-in.html
If you do what paulsalameh said here (Link to Github) it will work again:
paulsalameh: Sure. After you import the unitypackage, download NativeClient.cs and
PlayGamesClientConfig.cs from my commits (#1295 & #1296), and replace
them in the correct locations.
Afte that "unity play-services-plugin" code update you will be able to add AddOauthScope("email") to PlayGamesClientConfiguration, which allows your server to get the idtoken with the serverAuthCode again...
Code snippet from Unity:
PlayGamesClientConfiguration config = new PlayGamesClientConfiguration.Builder()
.AddOauthScope("email")
.AddOauthScope("profile")
.Build();
Now I am back in business:
{
"access_token" : "ya29.Ci8..7kBR-eBdPw1-P7Pe8QUC7e_Zv7qxCHA",
"expires_in" : 3600,
"id_token" : "eyJhbGciOi......I1NiE0v6kqw",
"refresh_token" : "1/HlSZOo......dQV1y4E",
"token_type" : "Bearer"
}

Gmail (for business) API doesn't allow to send email from Alias?

I want to email my customers using different "roles" (e.g. info# , customer-support#, tech-support#, no-reply#).
I've tried 2 approaches:
Multiple "users"/accounts in my Gmail for business application.
Single gmail
account with multiple aliases.
I started by setting up a Service Account with global delegation for my Gmail for Business application.
To test that it works, I've set up 2 users: lev#mydomain.com and root#mydomain.com. Indeed, I can successfully send email both from lev# and root#.
However, when I tried adding 5 distinct user accounts for my application, Gmail got paranoid of bots/abuse and asked me to prove that all the accounts are "human" including setting up passwords, signing in and SMS-text validation via phone. Moreover, they require different phones for different accounts to prove it's a different person. So the setup of the accounts becomes a major issue.
I also want to avoid creating multiple accounts since I'm paying for each one, and since semantically, all the roles are just a single account. So aliases seem like a better idea.
The problem is that when I'm trying to send email and set the "from" field to the alias (e.g. from:no-reply#mydomain.com), I'm getting the following exception:
Exception in thread "main" com.google.api.client.googleapis.json.GoogleJsonResponseException: 403 Forbidden
{
"code" : 403,
"errors" : [ {
"domain" : "global",
"message" : "Delegation denied for root#mydomain.com",
"reason" : "forbidden"
} ],
"message" : "Delegation denied for root#mydomain.com"
}
Anyone faced and solved this issue?
The authentication/credential code is as follows:
/*
* Set up a hashmap HashMap<String, Gmail> gmailServiceByAccount where
* gmailServiceByAccount.get(emailAccount) contains an authorized Gmail service
*/
private void prepareService(String emailAccount) throws Exception {
if (gmailServiceByAccount.containsKey(emailAccount)) {
return;
}
HttpTransport httpTransport = GoogleNetHttpTransport.newTrustedTransport();
JsonFactory jsonFactory = JacksonFactory.getDefaultInstance();
GoogleCredential credential = new GoogleCredential.Builder()
.setTransport(httpTransport)
.setJsonFactory(jsonFactory)
.setServiceAccountId(Config.getInstance().getProperty(Config.gmail_service_account))
.setServiceAccountPrivateKeyFromP12File(new File(Config.getInstance().getPathToGmailCredential()))
.setServiceAccountScopes(Arrays.asList(GmailScopes.GMAIL_COMPOSE))
.setServiceAccountUser(emailAccount)
.build();
gmailServiceByAccount.put(
emailAccount,
new Gmail.Builder(httpTransport, jsonFactory, credential)
.setApplicationName(Config.getInstance().getProperty(Config.google_client_api_application_name))
.build());
}
And the code which sends the email is as follows:
/**
* Send an email using the parameters provided.
*
* #param fromPersonalName : the free text description of the "from" address (e.g. "Customer Suppport" or "No Reply").
* #param fromAddress : the email address of the sender, the mailbox account (e.g. customer-support#mydomain.com).
* #param to : the email address of the recepient.
* #param subject : Subject of the email.
* #param htmlContent : (may be null) The HTML-styled body text of the email.
* #param plainTextContent : (may be null) The plain text body of the email (e.g if the customer email client does not support or disables html email).
*/
public void sendMail(String fromPersonalName, String fromAddress, String to, String subject, String htmlContent, String plainTextContent)
throws Exception {
prepareService(fromAddress);
Properties props = new Properties();
Session session = Session.getDefaultInstance(props, null);
MimeMessage email = new MimeMessage(session);
InternetAddress tAddress = new InternetAddress(to);
InternetAddress fAddress = new InternetAddress(fromAddress);
fAddress.setPersonal(fromPersonalName);
email.setFrom(fAddress);
email.addRecipient(javax.mail.Message.RecipientType.TO, tAddress);
email.setSubject(subject);
Multipart multiPart = new MimeMultipart("alternative");
if (!StringValidation.isEmpty(plainTextContent)) {
MimeBodyPart textPart = new MimeBodyPart();
textPart.setContent(plainTextContent, "text/plain");
textPart.setHeader("Content-Type", "text/plain; charset=\"UTF-8\"");
multiPart.addBodyPart(textPart);
}
if (!StringValidation.isEmpty(htmlContent)) {
MimeBodyPart htmlPart = new MimeBodyPart();
htmlPart.setContent(htmlContent, "text/html; charset=\"UTF-8\"");
multiPart.addBodyPart(htmlPart);
}
email.setContent(multiPart);
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
email.writeTo(bytes);
String encodedEmail = Base64.encodeBase64URLSafeString(bytes.toByteArray());
Message message = new Message();
message.setRaw(encodedEmail);
gmailServiceByAccount.get(fromAddress).users().messages().send(fromAddress, message).execute();
}
After additional research, it looks like the only option is to have multiple users.
The code I've posted indeed works for multiple users, but not for anything else.
I've tried multiple options including aliases and group email accounts. I'd either get "delegation denied" or "invalid grant" errors.
I've tried contacting Google For Business customer and tech support, but they don't support the API.
There's a great workaround to creating several users without having to go through phone validation. Just specify these users as "existing users" when you're signing into Google For Business initially, and activate them before you even transfer the domain.
For the account I've created without pre-existing users, I had to ask my friend's phones for phone validation.
You can now send emails using aliases as long as those aliases are defined for the user whose login credentials you're using.
This works for the Gmail for business only.
Setting up aliases to non-existent address can be tricky, so have a look at this how to set up a catch-all routing:
catchall-for-domain-aliases-in-gsuite-gmail
Just additionally to Ladi's post, it seem to be easier to setup now. Make an alias account and configure it so you can send emails (https://support.google.com/domains/answer/9437157?hl=en&ref_topic=6293345) and set the 'from' field on the message to the alias (but still use 'me' on the API call)

Resources