Profiles - Purchase

Purchase contact details (e.g., business emails/phones) for a set of profile IDs you selected via Profiles — Search.
Designed for compliant, auditable access with clear attribution.

Base URL: https://api.salescaddy.ai/api


Endpoint

POST /profiles/purchase

Headers

  • Authorization: Bearer <token> — required
  • X-On-Behalf-Of-User: [email protected]required (billing/audit attribution)
  • Content-Type: application/json

Request body (JSON)

{
  "profileIds": ["prof_001","prof_002","prof_003"]
}

Send 1–N profile IDs. The API returns a result per requested ID, including status and (when successful) contact data.
Tip: deduplicate profileIds on the client before sending.


Example — Purchase contacts

curl -sS -X POST "https://api.salescaddy.ai/api/profiles/purchase"   -H "Authorization: Bearer $TOKEN"   -H "X-On-Behalf-Of-User: [email protected]"   -H "Content-Type: application/json"   -d '{ "profileIds": ["prof_001","prof_002","prof_003"] }'
const res = await fetch("https://api.salescaddy.ai/api/profiles/purchase", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.TOKEN}`,
    "X-On-Behalf-Of-User": "[email protected]",
    "Content-Type": "application/json"
  },
  body: JSON.stringify({ profileIds: ["prof_001","prof_002","prof_003"] })
});
console.log(await res.json());
import os, requests
payload = {"profileIds": ["prof_001","prof_002","prof_003"]}
r = requests.post("https://api.salescaddy.ai/api/profiles/purchase",
                  headers={
                    "Authorization": f"Bearer {os.environ['TOKEN']}",
                    "X-On-Behalf-Of-User": "[email protected]",
                    "Content-Type": "application/json"
                  },
                  json=payload)
print(r.json())
using System.Text;
using System.Net.Http.Headers;
var http = new HttpClient();
http.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", TOKEN);
http.DefaultRequestHeaders.Add("X-On-Behalf-Of-User","[email protected]");
var payload = new StringContent("{"profileIds":["prof_001","prof_002","prof_003"]}", Encoding.UTF8, "application/json");
var res = await http.PostAsync("https://api.salescaddy.ai/api/profiles/purchase", payload);
Console.WriteLine(await res.Content.ReadAsStringAsync());

Sample response (trimmed):

{
  "results": [
    {
      "profileId": "prof_001",
      "status": "purchased",
      "creditsCharged": 1,
      "fullName": "Alex Johnson",
      "title": "VP Data Platform",
      "companyDomain": "hilton.com",
      "emails": [
        {"value":"[email protected]","type":"work","confidence":0.95, "verified": true}
      ],
      "phones": [
        {"value":"+1-555-123-4567","type":"work","confidence":0.82}
      ],
      "linkedinUrl": "https://www.linkedin.com/in/alexjohnson/"
    },
    {
      "profileId": "prof_002",
      "status": "already_owned",
      "creditsCharged": 0
    },
    {
      "profileId": "prof_003",
      "status": "not_available",
      "creditsCharged": 0,
      "message": "No contact data available for this profile"
    }
  ],
  "summary": {
    "requested": 3,
    "purchased": 1,
    "alreadyOwned": 1,
    "notAvailable": 1,
    "creditsCharged": 1
  }
}

Statuses

  • purchased — contact data returned and credited now.
  • already_owned — you already have access; not re‑charged.
  • not_available — no data available at this time (no charge).

Example — Idempotent retries (transient errors)

# Create a deterministic request key from sorted IDs to deduplicate on your side
REQ_KEY=$(echo '["prof_001","prof_002","prof_003"]' | jq -c 'sort|tostring' | shasum | awk '{print $1}')
curl -sS -X POST "https://api.salescaddy.ai/api/profiles/purchase"   -H "Authorization: Bearer $TOKEN"   -H "X-On-Behalf-Of-User: [email protected]"   -H "Idempotency-Key: $REQ_KEY"   -H "Content-Type: application/json"   -d '{ "profileIds": ["prof_001","prof_002","prof_003"] }'
// Sort IDs to build a stable idempotency key for safe retries
const ids = ["prof_001","prof_002","prof_003"].sort();
const key = require("crypto").createHash("sha1").update(JSON.stringify(ids)).digest("hex");

const res = await fetch("https://api.salescaddy.ai/api/profiles/purchase", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.TOKEN}`,
    "X-On-Behalf-Of-User": "[email protected]",
    "Idempotency-Key": key,
    "Content-Type": "application/json"
  },
  body: JSON.stringify({ profileIds: ids })
});
console.log(await res.json());
import hashlib, json, os, requests
ids = ["prof_001","prof_002","prof_003"]
key = hashlib.sha1(json.dumps(sorted(ids)).encode()).hexdigest()
r = requests.post("https://api.salescaddy.ai/api/profiles/purchase",
                  headers={
                    "Authorization": f"Bearer {os.environ['TOKEN']}",
                    "X-On-Behalf-Of-User": "[email protected]",
                    "Idempotency-Key": key,
                    "Content-Type": "application/json"
                  },
                  json={"profileIds": ids})
print(r.json())
using System.Security.Cryptography;
using System.Text.Json;
var ids = new[]{"prof_001","prof_002","prof_003"}.OrderBy(x=>x).ToArray();
var jsonIds = JsonSerializer.Serialize(ids);
var hash = BitConverter.ToString(SHA1.HashData(System.Text.Encoding.UTF8.GetBytes(jsonIds))).Replace("-","").ToLowerInvariant();
http.DefaultRequestHeaders.Add("Idempotency-Key", hash);
var res2 = await http.PostAsync("https://api.salescaddy.ai/api/profiles/purchase",
                                new StringContent(JsonSerializer.Serialize(new{ profileIds=ids }), System.Text.Encoding.UTF8, "application/json"));
Console.WriteLine(await res2.Content.ReadAsStringAsync());

While the API may not require an Idempotency-Key, including one is a best practice for POSTs you might retry on 429/5xx.


After purchase

  • Call Profiles — Details to fetch the full profile objects by profileId.
  • Respect consent & compliance in your downstream systems; store creditsCharged for audit.
  • Consider caching purchased contacts to avoid re‑purchasing.

Errors

CodeMeaningHow to fix
400Bad requestValidate JSON body and profileIds (non‑empty array of strings).
401UnauthorizedProvide/refresh Bearer token.
402Payment requiredInsufficient credits/plan; top‑up or contact support.
403ForbiddenMissing X-On-Behalf-Of-User or insufficient permissions.
404Not foundOne or more profileIds not recognized.
409ConflictDuplicate request (if Idempotency‑Key reused with different payload).
413Payload too largeReduce number of profileIds per request; batch in smaller chunks.
429Rate limit exceededRetry with exponential backoff; respect Retry-After.
500Internal server errorRetry later; contact support if persistent.