Vendor PortalSubmitting Leads

Submitting Leads

This guide covers how to submit leads to Ledly via the Vendor API.

API Endpoint

POST https://api.ledly.io/api/leads/inbound

For bulk submissions:

POST https://api.ledly.io/api/leads/inbound/batch

Authentication

Include your API key in the Authorization header:

Authorization: Bearer your_vendor_api_key
🚫

Never expose your API key in client-side code, URLs, or logs.


Single Lead Submission

Request

curl -X POST https://api.ledly.io/api/leads/inbound \
  -H "Authorization: Bearer your_vendor_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "email": "[email protected]",
    "first_name": "Jane",
    "last_name": "Doe",
    "phone": "+1-555-123-4567",
    "program_interest": "MBA",
    "source": "landing-page-a",
    "custom_fields": {
      "preferred_start": "Fall 2025",
      "time_preference": "Evening"
    }
  }'

Response

Success (201 Created):

{
  "success": true,
  "lead_id": "lead_abc123xyz",
  "message": "Lead accepted",
  "timestamp": "2024-12-25T10:30:00Z"
}

Validation Error (400 Bad Request):

{
  "success": false,
  "error": "Validation failed",
  "details": [
    { "field": "email", "message": "Invalid email format" },
    { "field": "phone", "message": "Invalid phone number" }
  ]
}

Duplicate (409 Conflict):

{
  "success": false,
  "error": "Duplicate lead detected",
  "duplicate_of": "lead_existing123",
  "similarity_score": 95
}

Bulk Lead Submission

Submit up to 100 leads in a single request.

Request

curl -X POST https://api.ledly.io/api/leads/inbound/batch \
  -H "Authorization: Bearer your_vendor_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "leads": [
      {
        "email": "[email protected]",
        "first_name": "John",
        "last_name": "Smith"
      },
      {
        "email": "[email protected]",
        "first_name": "Jane",
        "last_name": "Doe"
      }
    ]
  }'

Response

{
  "success": true,
  "total": 2,
  "accepted": 1,
  "rejected": 1,
  "results": [
    {
      "index": 0,
      "success": true,
      "lead_id": "lead_abc123"
    },
    {
      "index": 1,
      "success": false,
      "error": "Duplicate lead detected"
    }
  ]
}

Field Reference

Standard Fields

FieldTypeRequiredDescription
emailstringYesLead’s email address
first_namestringNoFirst name
last_namestringNoLast name
phonestringNoPhone number (any format)
program_intereststringNoProgram of interest
sourcestringNoLead source identifier
ip_addressstringNoLead’s IP address
user_agentstringNoBrowser user agent
landing_pagestringNoLanding page URL
referrerstringNoReferrer URL

UTM Parameters

Track marketing attribution:

FieldTypeDescription
utm_sourcestringCampaign source
utm_mediumstringCampaign medium
utm_campaignstringCampaign name
utm_termstringCampaign term
utm_contentstringCampaign content

Custom Fields

Include additional fields in the custom_fields object:

{
  "email": "[email protected]",
  "custom_fields": {
    "preferred_start": "Fall 2025",
    "education_level": "Bachelor's",
    "years_experience": 5,
    "interested_in_scholarship": true
  }
}

Custom field names must be configured by your organization. Check with your administrator for available fields.


Phone Number Formatting

Phone numbers are automatically normalized. These are all equivalent:

+1-555-123-4567
(555) 123-4567
555.123.4567
5551234567

For international numbers, include the country code:

+44 20 7123 4567  (UK)
+49 30 12345678   (Germany)
+61 2 1234 5678   (Australia)

Email Validation

Emails are validated for:

  1. Format - Must be valid email syntax
  2. Domain - Must have valid MX records
  3. Disposable - Temporary email services may be blocked
  4. Typos - Common typos are flagged (gmial.com, etc.)

Disposable Domains (Blocked)

Common blocked domains include:

  • mailinator.com
  • tempmail.com
  • guerrillamail.com
  • 10minutemail.com
⚠️

Disposable email blocking is organization-specific. Some organizations may allow them.


Error Handling

HTTP Status Codes

CodeMeaning
201Lead created successfully
400Bad request (validation error)
401Unauthorized (invalid API key)
409Conflict (duplicate lead)
422Unprocessable (lead rejected by rules)
429Too many requests (rate limited)
500Server error

Retry Strategy

Implement exponential backoff for retries:

async function submitWithRetry(lead, maxRetries = 3) {
  for (let attempt = 0; attempt < maxRetries; attempt++) {
    try {
      const response = await submitLead(lead);
 
      if (response.status === 429) {
        // Rate limited - wait and retry
        const retryAfter = response.headers.get('Retry-After') || 30;
        await sleep(retryAfter * 1000);
        continue;
      }
 
      if (response.status >= 500) {
        // Server error - retry with backoff
        await sleep(Math.pow(2, attempt) * 1000);
        continue;
      }
 
      return await response.json();
    } catch (error) {
      if (attempt === maxRetries - 1) throw error;
      await sleep(Math.pow(2, attempt) * 1000);
    }
  }
}

Tracking Submissions

Request ID

Each request receives a unique ID in the response headers:

X-Request-ID: req_abc123xyz

Include this ID when contacting support about specific submissions.

Checking Lead Status

After submission, you can check lead status:

GET /api/vendor-portal/leads/{lead_id}

Response:

{
  "id": "lead_abc123",
  "status": "accepted",
  "submitted_at": "2024-12-25T10:30:00Z",
  "processed_at": "2024-12-25T10:30:01Z",
  "crm_status": "synced",
  "crm_id": "00Q1234567890ABC"
}

Best Practices

  1. Validate before submitting - Check email format and required fields client-side

  2. Handle errors gracefully - Don’t retry 400-level errors (fix the data first)

  3. Use bulk endpoint for batches - More efficient for multiple leads

  4. Include source tracking - Always include source and UTM parameters

  5. Log request IDs - Store X-Request-ID for debugging

  6. Monitor acceptance rates - Low rates indicate data quality issues

  7. Test in sandbox first - Use the sandbox environment before production


Sandbox Environment

Test your integration without affecting production:

Endpoint: https://sandbox.api.ledly.io/api/leads/inbound
API Key: Your sandbox API key (different from production)

Sandbox leads are automatically deleted after 24 hours.