In this case, I wanted to be able to POST data from a 3rd party form provider (Cognito Forms) into LeadCapture, but also create a Document that gets associated with that lead based on information from the POST request.
By default, the LeadCapture payload is only equipped to handle data with fields that are mapped to the Lead Entity.
So, what I did:
1. Created a custom route for an API endpoint
2. I hijacked the LeadCapture methods that already existed in order to a) allow for API Key validation and b) so I could keep the logic I had already created related to the LeadCapture
3. Wrote a service that handled the logic in the ways I wanted to.
This is what the implementation looks like (roughly):
custom/Espo/Custom/Resources/routes.json
Code:
[ { “route”: “/ExternalForm/:action/:apiKey”, “method”: “post”, “params”: { “controller”: “ExternalForm”, “action”: “:action”, “apiKey”: “:apiKey” }, “conditions”: { “auth”: false } } ]
The auth: false condition bypasses the default authentication methods, so you don’t need an X-API-Key or HMAC key in order to be able to access the endpoint. This will prevent 401 unauthorized errors and allow you to actually use the controller method specified.
custom/Espo/Custom/Controllers/ExternalForm.php
Code:
namespace Espo\Custom\Controllers; use \Espo\Core\Exceptions\Forbidden; use \Espo\Core\Exceptions\BadRequest; use \Espo\Core\Exceptions\NotFound; class ExternalForm extends \Espo\Core\Controllers\Base { public function postActionSomeExample($params, $data, $request, $response) { if (empty($params[‘apiKey’])) throw new BadRequest(‘No API Key!’); if (empty($data)) throw new BadRequest(‘No payload provided’); $allowOrigin = $this->getConfig()->get(‘leadCaptureAllowOrigin’, ‘*’); $response->headers->set(‘Access-Control-Allow-Origin’, $allowOrigin); $apiKey = $params[‘apiKey’]; $validKey = $this->getServiceFactory()->create(‘LeadCapture’)->isApiKeyValid($apiKey); if ($validKey) { $lead = $this->getServiceFactory()->create(‘Lead’)->someActionName($data, $apiKey); return $lead } else { return ‘some error message!’; } } }
So, to access this action, I would send a POST request to:
https://{espocrm_root}/api/v1/ExternalForm/someExample/{someApiKey}
Here “ExternalForm” matches the identifying controller specified in routes.json and someExample maps to postActionSomeExample - the action in the controller. Note the prefix postAction before the SomeExample - that tells the system what kind of request to expect. If this was a GET request, it would be getActionSomeExample, for instance.
So, here, I first make sure we have an apiKey and data to process.
Then, I send back response request headers, allowing the client to proceed.
Next, I instantiate the LeadCapture service factory and use its isApiKeyValid method in order to validate the API Key, which was generated using the LeadCapture entity in the CRM.
Then, if the key is valid, I send the data to a Lead service (someActionName action) in order to process business logic.
That service is created in custom/Espo/Custom/Services/Lead.php, though both the name of the service, the functions available, and the business logic will all vary depending on your use case.
In my case, my Lead Service Takes a subset of data from the ExternalForm POST request, does some stuff with it, creates a document using some of the payload data, associates it, and then using Workflow tool, I run some other tasks.
Hopefully this helps someone else trying to figure out how to create a custom API endpoint that allows you to take advantage of another applications Webhook POST requests!
Leave a comment: