Skip to main content

Outbound Lead Enrollment Guide

This document describes everything required to enroll leads for outbound calling and to unenroll them when calling should stop. A developer can build and operate the sending side from this document alone.

1. Overview​

Your system sends lead information to a single HTTPS endpoint that we host. The same endpoint supports two actions, selected by an action field in the request body:

  • Enroll. Send a new lead you want our team to start calling.
  • Unenroll. Ask us to stop calling a specific lead.

Every request is signed with a shared secret that we issue to you. We answer each request synchronously with a small JSON body and a standard HTTP status code.

2. The endpoint​

AspectContract
MethodHTTPS POST with a JSON body.
Path/services/apexrest/Outbound/Leads. The host is issued to you with your credentials.
Content typeContent-Type: application/json.
ActionsBoth enroll and unenroll go to the same URL. The action field in the body selects the behaviour.
Health checkAn HTTPS GET to the same URL returns a static message and does not process anything. Use it to confirm connectivity only.
LoginNo user account is required. Every request is authenticated by the signature described below.
Character encodingUTF-8.

3. Authentication​

Requests are authenticated with an HMAC-SHA256 signature over the raw request body, using a secret that we issue to your firm. Two headers are required on every request:

HeaderValue
c-nameYour firm's name, exactly as we configured it. We use it to look up your secret.
x-auth-tokenThe HMAC-SHA256 signature of the raw request body, keyed with your secret, encoded as lowercase hexadecimal.

We recreate the signature from the body we received and compare it against x-auth-token. Any mismatch is rejected with HTTP 401.

3.1 Computing the signature​

Sign the exact bytes you send. Serialize the JSON body to a string first, compute the signature over that string, then send that same string unchanged as the request body.

Node.js
import { createHmac } from 'node:crypto';

const body = JSON.stringify(payload);
const signature = createHmac('sha256', SHARED_SECRET).update(body, 'utf8').digest('hex');

await fetch(`${BASE_URL}/services/apexrest/Outbound/Leads`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'c-name': FIRM_NAME,
'x-auth-token': signature,
},
body,
});
Python
import hashlib, hmac, json, requests

body = json.dumps(payload, separators=(",", ":"))
signature = hmac.new(SHARED_SECRET.encode("utf-8"), body.encode("utf-8"), hashlib.sha256).hexdigest()

requests.post(
f"{BASE_URL}/services/apexrest/Outbound/Leads",
headers={
"Content-Type": "application/json",
"c-name": FIRM_NAME,
"x-auth-token": signature,
},
data=body,
)
Sign what you send

Re-serializing the JSON after signing it, or letting an HTTP library reformat the body, changes the bytes and invalidates the signature. Treat the body as an opaque string once it has been signed.

  • Keep the secret confidential. Do not log it, embed it in client-side code, or share it outside the system that signs requests.
  • To rotate the secret, ask your Attorney Assistant account contact. We will issue a new secret for you to put into effect.

4. Request body​

Every request body is a JSON object with a single top-level data object. All values are strings. Omit a field you have no value for.

{
"data": {
"action": "enroll",
"Law_Firm_Name": "Example Law Firm",
"Lead_Phone_No": "5555550147"
}
}

4.1 Fields​

FieldMeaningRequired
actionEither enroll or unenroll.Yes
Law_Firm_NameYour firm's name, exactly as we configured it. Must match the c-name header.Yes
Lead_Phone_NoThe lead's phone number.Enroll: yes. Unenroll: only if External_System_Record_id is not sent.
External_System_Record_idYour own reference ID for the lead. Used to match repeat requests to the same record.Recommended
SourceWhere the lead originated. Free-form label.No
Lead_First_NameThe lead's first name.No
Lead_Last_NameThe lead's last name.No
Lead_EmailThe lead's email address.No
Date_of_BirthThe lead's date of birth.No
Calling_On_Behalf_OfName of the person the lead is calling on behalf of, if not themselves.No
Mailing_AddressThe lead's street address.No
Mailing_CityThe lead's city.No
Mailing_StateThe lead's state.No
Mailing_Postal_ZipThe lead's ZIP or postal code.No
Incident_LocationWhere the incident happened.No
Date_Of_IncidentDate the incident happened.No
Currently_RepresentedWhether the lead already has an attorney.No
Injury_DescriptionShort description of the injury.No
OutcomeOutcome or status detail.No
Best_Callback_TimeThe lead's preferred callback time.No
Other_Questions_And_AnswersAny additional questions and answers captured during your intake.No
Case_TypeType of case. Should match the case-type list agreed for your firm.No
Always send a reference ID

External_System_Record_id is optional, but it is what lets us recognise a lead you have sent before. With it, an enroll request for a lead we already hold updates that record instead of creating a second one, and an unenroll request can target the lead precisely. Without it, unenroll has to match on phone number alone.

5. Action: enroll​

Enroll a lead for outbound calling.

5.1 Example request​

enroll
{
"data": {
"action": "enroll",
"Source": "Website form",
"Law_Firm_Name": "Example Law Firm",
"Lead_First_Name": "Jane",
"Lead_Last_Name": "Doe",
"Lead_Phone_No": "5555550147",
"Lead_Email": "jane.doe@example.com",
"Date_of_Birth": "2000-10-05",
"Mailing_Address": "123 Main St",
"Mailing_City": "Denver",
"Mailing_State": "CO",
"Mailing_Postal_Zip": "80202",
"Incident_Location": "Intersection of 1st and Main",
"Date_Of_Incident": "2026-09-03",
"Currently_Represented": "No",
"Injury_Description": "Neck and lower back pain.",
"Best_Callback_Time": "Weekdays after 5pm",
"Case_Type": "Motor Vehicle Accident",
"External_System_Record_id": "LEAD-48213"
}
}

5.2 What happens​

  1. We verify the signature and confirm the firm named in the request is active.
  2. We create a lead record for your firm, or update the existing record if we have seen the same External_System_Record_id before.
  3. If the lead was already in our calling queue, the queue is updated so both sides stay in sync.
  4. We return HTTP 201 with the record's ID.

6. Action: unenroll​

Stop calling a lead. Only the firm name and one identifier are required. You may send other fields, and we keep them for audit, but they play no part in locating the lead or stopping the calls.

6.1 Example request​

unenroll (by reference ID)
{
"data": {
"action": "unenroll",
"Law_Firm_Name": "Example Law Firm",
"External_System_Record_id": "LEAD-48213"
}
}
unenroll (by phone number)
{
"data": {
"action": "unenroll",
"Law_Firm_Name": "Example Law Firm",
"Lead_Phone_No": "5555550147"
}
}

6.2 What happens​

  1. We verify the signature and confirm the firm named in the request is active.
  2. We locate the lead using External_System_Record_id if provided, otherwise Lead_Phone_No.
  3. We record the stop-calling request and return HTTP 201 immediately.
  4. The calling cadence for that lead is ended in the background. You do not need to wait for or confirm this step.

7. Responses​

Every response is a JSON body with three fields.

Example success response
{
"success": true,
"message": "Lead created",
"recordId": "a0X000000000001"
}
FieldTypeMeaning
successbooleanWhether the request was accepted.
messagestringShort human-readable description of the outcome.
recordIdstring or nullThe ID of the record we created or matched, when applicable.

7.1 HTTP status codes​

CodeMeaningWhat to do
201Success. A lead was created or updated, or a stop-calling request was queued.Nothing further.
200Success. A repeat unenroll for a lead we already stopped within the last 60 minutes.Nothing further. Treat as handled.
400Bad request. Required information is missing or invalid.Correct the request. Do not retry unchanged.
401Not authorized. The firm name or signature is invalid.Check c-name, Law_Firm_Name, and your signature computation. Do not retry unchanged.
500Server error on our side.Retry after a short delay. Contact us if it persists.
503The stop-calling service is temporarily unavailable. Enroll requests are unaffected.Retry the unenroll later.

8. Retries and duplicate requests​

Both actions are safe to retry.

  • Enroll. Sending the same External_System_Record_id more than once updates the existing record. No duplicate lead is created.
  • Unenroll. A repeat stop-calling request for the same lead within 60 minutes returns HTTP 200 and performs no further action.

Retry any request that fails with a network error, a timeout, or HTTP 500 or 503. Do not retry a 400 or 401 without first changing the request.

9. What you need to implement​

  1. Store the base URL, firm name, and shared secret we issue to you, keeping the secret out of logs and client-side code.
  2. Build the request body as a JSON object wrapped in data, with the correct action.
  3. Serialize the body once, compute the HMAC-SHA256 hex signature over that exact string, and send the string unchanged.
  4. Send Content-Type: application/json, c-name, and x-auth-token headers on every request.
  5. Include External_System_Record_id on every lead so enroll and unenroll can target the same record.
  6. Handle the status codes above, retrying only on 500, 503, and transport failures.

Need help?​

Integration questions, credential rotation, and endpoint changes go through your Attorney Assistant account contact.