Skip to content

Migrate from afs-create-sf-lead

This guide walks you through migrating your integration from the legacy afs-create-sf-lead REST API to the new Marketing Lead Automation Service (MLAS) GraphQL API.

Quick Migration Checklist

Use this checklist to track your migration progress:

  • Obtain new MLAS credentials (Client ID, Client Secret, Tenant ID, Scope) from Alleviate
  • Implement OAuth 2.0 Client Credentials token flow (replaces the old token header)
  • Update your endpoint URL to the MLAS GraphQL endpoint
  • Reformat your payload from a flat JSON body to a GraphQL createLead mutation with variables
  • Map your existing fields to the new MLAS field names (see Field Mapping below)
  • Add the new required field: dateOfBirth
  • Test end-to-end in the Sandbox environment
  • Switch to the Production endpoint when ready to go live

What’s Changing

Here is a high-level summary of the key differences between the old and new services.

API Style & Endpoint

Old ServiceNew Service (MLAS)
ProtocolREST (POST)GraphQL
Sandbox URLN/A (single endpoint)https://leads-sandbox.alleviate.com/graphql
Production URL.../lead_creation/https://leads.alleviate.com/graphql

Authentication & Payload

Old ServiceNew Service (MLAS)
Auth MethodCustom encrypted token headerMicrosoft Entra ID OAuth 2.0 Bearer token
Content-Typeapplication/jsonapplication/json
Payload FormatFlat JSON body, snake_case fieldsGraphQL mutation, camelCase variables

Behavior

Old ServiceNew Service (MLAS)
Lead FlowSingle POST requestSingle createLead mutation returning completed workflow results
TestingAdmintesting field in payloadUse the dedicated Sandbox environment
CRM / Convosodtc, list_id, lead_crm fieldsCRM submit path is internally configured based on partner requirements

Step 1: Get Your New Credentials

The old service used a single encrypted token passed in a custom header. MLAS uses industry-standard OAuth 2.0 Client Credentials via Microsoft Entra ID.

You will receive the following credentials during onboarding:

CredentialDescription
Tenant IDAlleviate’s Azure AD tenant identifier
Client IDYour application’s unique identifier
Client SecretYour application’s secret key
Debt Core App IDUsed to construct the API scope (api://{DEBT_CORE_APP_ID}/.default)

Environment-Specific Values

The Tenant ID is the same across all environments. The Debt Core App ID differs per environment:

ValueSandboxProduction
Tenant ID8797fa3f-ba90-4187-97fb-6ab892ea90358797fa3f-ba90-4187-97fb-6ab892ea9035
Debt Core App IDaba793eb-f395-4f86-be59-7a7d0c1bfdb09060a1d0-da3b-4676-ad64-ff64465cce41

For full authentication setup details, see the Authentication page.


Step 2: Update Your Endpoint URL

Replace the old REST endpoint with the MLAS GraphQL endpoint.

EnvironmentURL
Sandboxhttps://leads-sandbox.alleviate.com/graphql
Productionhttps://leads.alleviate.com/graphql

For more details on environments, see the Environments page.


Step 3: Update Authentication

The old service required a custom encrypted token in the token header:

Old Authentication
# Old service -- custom token header
curl -X POST "https://afs-create-sf-leads.bravetree-4acef9d0.westus2.azurecontainerapps.io/lead_creation/" \
-H "token: YOUR_ENCRYPTED_TOKEN" \
-H "Content-Type: application/json" \
-d '{ ... }'

MLAS uses a standard OAuth 2.0 Bearer token in the Authorization header. You first obtain an access token from Microsoft Entra ID, then include it in every request:

Use the same authentication flow across languages: request an Entra ID token, then pass it as Bearer in the GraphQL request.

Step 1: Get an access token
curl -X POST "https://login.microsoftonline.com/{TENANT_ID}/oauth2/v2.0/token" \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=client_credentials" \
-d "client_id={CLIENT_ID}" \
-d "client_secret={CLIENT_SECRET}" \
-d "scope=api://{DEBT_CORE_APP_ID}/.default"
Step 2: Use the token in your GraphQL request
curl -X POST "https://leads-sandbox.alleviate.com/graphql" \
-H "Authorization: Bearer {ACCESS_TOKEN}" \
-H "Content-Type: application/json" \
-d '{ "query": "...", "variables": { ... } }'

Step 4: Update Your Payload

The biggest change is moving from a flat REST JSON body to a GraphQL mutation with typed variables.

Old Payload (REST)

Old afs-create-sf-lead request
import requests
import json
url = "https://afs-create-sf-leads.bravetree-4acef9d0.westus2.azurecontainerapps.io/lead_creation/"
payload = json.dumps({
"offer_code": "abc1234566",
"first_name": "John",
"last_name": "Doe",
"address": "123 Meridian Ave",
"city": "Irvine",
"state": "CA",
"zip_code": "92618",
"home_phone": "7148319225",
"cell_phone": "7148319225",
"email": "john.doe@example.com",
"loan_amount": "72456",
"marketing_lead_source": "VENDOR NAME",
"lead_source": "Online Form",
"est_debt": "100",
"dtc": "yes",
"list_id": "123",
"Admintesting": "true",
"sub_id_1": "tracking-123",
"trustedform_certificate_id": "https://cert.trustedform.com/abcd1234"
})
headers = {
"token": "YOUR_ENCRYPTED_TOKEN",
"Content-Type": "application/json"
}
response = requests.post(url, headers=headers, data=payload)
print(response.json())

New Payload (GraphQL)

Use the same GraphQL mutation payload across languages. Only the HTTP client syntax changes. Note that the full list of available fields can be found on the API reference page.

New MLAS request (cURL)
curl -X POST "https://leads-sandbox.alleviate.com/graphql" \
-H "Authorization: Bearer {ACCESS_TOKEN}" \
-H "Content-Type: application/json" \
-d '{
"query": "mutation CreateLead($input: LeadInput!) { createLead(input: $input) { id resultCode note partnerLeadId bidValue } }",
"variables": {
"input": {
"firstName": "John",
"lastName": "Doe",
"dateOfBirth": "1990-01-15",
"email": "john.doe@example.com",
"homePhone": "7148319225",
"cellPhone": "7148319225",
"address1": "123 Meridian Ave",
"city": "Irvine",
"state": "CA",
"zipCode": "92618",
"loanAmount": 72456,
"leadId": "tracking-123",
"trustedformCertificateID": "https://cert.trustedform.com/abcd1234"
}
}
}'

Field Mapping

Use this table to map your existing old-service fields to the new MLAS GraphQL input fields.

Direct Field Mappings

These fields exist in both services. Note the change from snake_case to camelCase naming.

Old Field (afs-create-sf-lead)New Field (MLAS LeadInput)Type ChangeNotes
first_namefirstNameString → StringNo change in type
last_namelastNameString → StringNo change in type
addressaddress1String → StringRenamed; MLAS also supports address2 for apt/suite
citycityString → StringNo change
statestateString → StringTwo-letter code (e.g., "CA")
zip_codezipCodeString → StringFive-digit format
home_phonehomePhoneString → String10-digit format, no country code
cell_phonecellPhoneString → String10-digit format, no country code
emailemailString → StringNo change
loan_amountloanAmountString → IntNow an integer in whole dollars (e.g., 72456 not "72456")
trustedform_certificate_idtrustedformCertificateIDString → StringTrustedForm certificate UUID or URL
est_debtestimatedDebtString → IntNow an integer in whole dollars (e.g., 72456 not "72456")

New Required Fields

These fields are required in MLAS but did not exist in the old service:

New FieldTypeDescription
dateOfBirthString!Applicant’s date of birth in YYYY-MM-DD format (e.g., "1990-01-15")

Removed / Internally Handled Fields

These old-service fields are no longer part of your request. MLAS handles them automatically or they are no longer applicable:

Old FieldWhat Happens in MLAS
offer_codeNo longer needed. Tracking is handled via leadId, ref, and authenticated partner identity.
marketing_lead_sourceAutomatically determined from your authenticated application credentials.
lead_sourceReplaced by leadSourceId, which is automatically set from your authenticated app identity.
dtcNot applicable. Convoso routing is handled internally by MLAS.
list_idNot applicable. Convoso list assignment is handled internally by MLAS.
AdmintestingNot applicable. Use the Sandbox environment for testing instead of a flag in the payload.
lead_crmNot applicable. CRM routing (Salesforce vs Sigma) is handled internally by MLAS.

Tracking / Sub-ID Mappings

Old FieldSuggested MLAS EquivalentNotes
sub_id_1 through sub_id_5leadId, refUse leadId for your primary external tracking ID and ref for a secondary reference. These values are returned in responses as partnerLeadId.

Additional Fields Available in MLAS

MLAS supports many more fields than the old service for enhanced lead qualification. See the full Lead Input Schema for details. Key optional additions include:

FieldTypeDescription
socialSecurityNumberStringRequired for credit pull and qualification (9 digits, no dashes)
grossAnnualIncomeIntGross annual income in whole dollars
monthlyIncomeIntMonthly income in whole dollars
residenceTypeIdIntHome Owner (1), Rent (2), Living with Family (3), Other (4)
incomeSourceIdIntEmployed (1), Social Security (2), Pension (3), etc.
loanPurposeIdIntDebt Consolidation (1), Home Improvement (2), etc.
termsConsentBooleanMust be true for lead to be processed
coApplicantBooleanSet to true and populate co-applicant fields if applicable

Step 5: Understand the New Lead Flow

Old Flow

POST /lead_creation/ → Lead is created and submitted to CRM → Response with CRM record

New Flow

POST /graphql (createLead mutation) → Lead is processed and qualified → Response with final result

createLead handles deduplication, credit pull, and qualification, then returns the completed result.

CRM submission behavior is partner-configuration based:

  • Some partners have automatic CRM submission for qualified leads.
  • Others use manual submitLead for qualified leads (1013-1017).

Here is a complete example:

Complete MLAS lead submission
import requests
BASE_URL = "https://leads-sandbox.alleviate.com/graphql"
headers = {
"Authorization": f"Bearer {access_token}",
"Content-Type": "application/json"
}
# Submit the lead — processing and qualification happen before response
response = requests.post(BASE_URL, json={
"query": """
mutation CreateLead($input: LeadInput!) {
createLead(input: $input) {
id
resultCode
note
partnerLeadId
bidValue
}
}
""",
"variables": {
"input": {
"firstName": "John",
"lastName": "Doe",
"dateOfBirth": "1990-01-15",
"email": "john.doe@example.com",
"homePhone": "7148319225",
"cellPhone": "7148319225",
"address1": "123 Meridian Ave",
"city": "Irvine",
"state": "CA",
"zipCode": "92618",
"loanAmount": 72456,
"leadId": "your-tracking-id-123",
"trustedformCertificateID": "https://cert.trustedform.com/abcd1234"
}
}
}, headers=headers)
result = response.json()
lead = result["data"]["createLead"]
print(f"Lead ID: {lead['id']}")
print(f"Result Code: {lead['resultCode']}")
print(f"Note: {lead['note']}")
print(f"Partner Lead ID: {lead['partnerLeadId']}")
print(f"Bid Value: {lead['bidValue']}")

Response Format Changes

Old Response (Success)

{
"response": {
"recordId": "a1MUl000001RM5VMAW"
},
"status": 200,
"c_result": {
"status": 200,
"message": 51167
}
}

New Response (createLead — Success)

{
"data": {
"createLead": {
"id": "d5faed99-51c3-4181-959e-5557d1eef042",
"resultCode": 1020,
"note": "Lead processing complete",
"partnerLeadId": "your-tracking-id-123",
"bidValue": "$25.00"
}
}
}

Key Response Fields

FieldDescription
idUnique internal MLAS lead identifier
resultCodeFinal processing status code (see Result Codes)
noteHuman-readable description of the result
partnerLeadIdYour leadId echoed back for correlation
bidValueCalculated bid amount for qualified leads (null if not qualified)

Error Handling Changes

Old Error Responses

ScenarioOld Response
Invalid token{"status": {"code": 401, "message": "Token is invalid."}, "response": []}
Missing fields{"response": "Insert failed. First exception on row 0; ...", "status": 400}

New Error Responses

MLAS returns standard GraphQL error responses:

{
"errors": [
{
"message": "Unauthorized",
"extensions": {
"code": "UNAUTHENTICATED"
}
}
]
}

Frequently Asked Questions

Do I still need to set Admintesting for test leads?

No. Use the Sandbox environment (https://leads-sandbox.alleviate.com/graphql) for all testing. The sandbox is completely isolated from production. There is no need for a test flag in the payload.

Do I still control Convoso routing with dtc and list_id?

No. Convoso routing and list assignment are now handled internally by MLAS. You do not need to include these fields.

What happened to lead_source and marketing_lead_source?

These are now automatically determined from your authenticated application credentials. When you authenticate with your Client ID, MLAS knows your partner identity and assigns the correct lead source.

What happened to offer_code?

This field is no longer needed. Use the leadId field to pass your own tracking/reference ID, and ref for a secondary identifier. Both are returned in responses for correlation.

How do I handle the loan_amount type change?

The old service accepted loan_amount as a string (e.g., "72456"). MLAS expects loanAmount as an integer (e.g., 72456). Remove any string wrapping and pass the numeric value directly.

Why is dateOfBirth now required?

MLAS performs credit-based qualification and scoring as part of the lead processing pipeline. Date of birth is essential for this process.

How do I map my sub_id values?

Use leadId for your primary external tracking identifier (returned as partnerLeadId in responses) and ref for a secondary reference. If you need additional tracking parameters, contact Alleviate engineering.

What happened to est_debt?

The old service accepted est_debt as a partner-supplied estimated debt amount. In MLAS, actual debt amounts are determined automatically through the credit pull pipeline. If you need to communicate the applicant’s estimated debt, use the loanAmount field (requested loan amount in whole dollars) as the closest equivalent.

Do I need to implement polling?

No. createLead now waits for workflow completion and returns the completed result.

If your partner configuration uses manual CRM submission, call submitLead for qualified leads (1013-1017).


Need Help?

If you run into issues during migration, contact the Alleviate engineering team. Be sure to include:

  • Your Partner/Client ID
  • The environment you’re testing against (Sandbox or Production)
  • The full request and response (with sensitive data redacted)
  • Any error messages you’re receiving

Next Steps