mySDRDocs

API reference

Find Phone

Looks up a phone number for each LinkedIn profile you send, mobile first: up to 25 per call, each with its own entry in results, in the order you sent them.

POSThttps://mysdr.app/api/v1/person/phone
View Markdown

You pay 10 credits for a person when a call returns a number for them, and only once: asking again for the same person returns the number for free. Nobody found, a lookup that is still running, or an error costs nothing. A person without a number is not looked up again for 30 days.

Most lookups answer within seconds; the call waits up to 30 seconds. A person still being looked up after that has the status pending: send the same URLs again after retry_after_seconds. That call charges only the numbers it returns.

The member-id URL that Search People returns works too. Set your HTTP timeout to at least 60 seconds.

Authentication

Send your API key as a Bearer token: Authorization: Bearer gtk_…. Create the key under Connect assistant → API keys. A missing, invalid or revoked key is 401, including while an API is closed. On an endpoint of the Signals API or the Company API, a valid key while that API is closed for your organization answers 403 api_not_enabled, with what the key can do instead; the other endpoints work with every key. Every response includes mySDR-Api-Version, mySDR-Request-Id and Cache-Control: no-store, and a response to an accepted key also X-RateLimit-* (so not a 401, a 405, an OPTIONS or a 404 for an unknown path); every error has type, message, param and request_id.

Body parameters

  • profile_urls string[] · required — 1 to 25 LinkedIn profile URLs, e.g. https://www.linkedin.com/in/jane-example, or the member-id URL from Search People.
  • max_credits integer — Stop before the call costs more than this. A number you already paid for, and a person nobody found a number for in the last 30 days, are free and take no room. Everyone else counts at 10 credits, in the order you sent them, and a person for whom nothing was found leaves the room to the next; who still does not fit is not looked up and gets skipped. Below 10, with nothing free to return, the call is 402 max_credits_exceeded and nothing is looked up.

Response

  • results object[] — One entry per URL you sent, in the same order.
  • results[].input string — The URL as you sent it.
  • results[].status string — found (see phones), not_found (no number known for this person; not looked up again for 30 days), pending (still being looked up: send the URL again after retry_after_seconds), invalid_url (not a LinkedIn profile URL), error (the lookup failed; nothing was charged, retry later) or skipped (max_credits left no room; not looked up). One of: found, not_found, pending, invalid_url, error, skipped.
  • results[].linkedin_url string | null — The public profile URL that was looked up. Null for an invalid URL, or a member-id URL whose profile does not exist.
  • results[].phone string | null — The best number: a mobile number first, then the one with the highest confidence. Null unless the status is found.
  • results[].phones object[] — Every number found, best first: number as the source writes it, type (mobile, work or null when unknown) and confidence (high, likely or null). Empty unless the status is found.
  • results[].credits_charged integer — What this entry cost: 10 when this call returned a number for the first time, otherwise 0. A URL you sent twice is charged on its first entry.
  • results[].error object — With error and skipped: type (upstream_error or max_credits_exceeded) and message.
  • credits_used integer — Credits this call used.
  • retry_after_seconds integer — Only when an entry is pending: send those URLs again after this many seconds (60).

Credits

10 credits per person with a phone number found, once per person; nothing found costs nothing. Errors and empty lookups are free. A call that spent credits puts that number in credits_used, in X-Credits-Used and in X-Credits-Charged. When the wallet can be read, the response also sends X-Credits-Remaining.

Errors

  • 400 invalid_request — The body is not valid JSON, a field is unknown or has the wrong type, or a value is not allowed.
  • 401 authentication_error — The Authorization header is missing, or the key is unknown or revoked.
  • 403 permission_error — API access is not part of your plan, or your account is suspended.
  • 429 rate_limit_error — More than 60 requests per minute, or more than 3 at the same time, on one key. Wait for the Retry-After header.
  • 429 daily_limit_reached — The request could take your organization over its daily credit limit. The limit resets at midnight (Europe/Brussels).
  • 502 upstream_error — The data source did not answer. Retry later.
  • 503 service_unavailable — The API is temporarily unavailable. Retry later.
  • 500 internal_error — Something went wrong on our side.
  • 402 max_credits_exceeded — max_credits is below the price of one phone number (10 credits). Nothing was looked up.

Example

cURL

curl -X POST "https://mysdr.app/api/v1/person/phone" \
  -H "Authorization: Bearer $MYSDR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "profile_urls": [
      "https://www.linkedin.com/in/jane-example",
      "https://www.linkedin.com/in/john-example"
    ]
  }'

JavaScript

const response = await fetch('https://mysdr.app/api/v1/person/phone', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.MYSDR_API_KEY}`,
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    "profile_urls": [
      "https://www.linkedin.com/in/jane-example",
      "https://www.linkedin.com/in/john-example"
    ]
  })
});
const body = await response.json();

Python

import json
import os
import urllib.request

payload = {
  "profile_urls": [
    "https://www.linkedin.com/in/jane-example",
    "https://www.linkedin.com/in/john-example"
  ]
}

request = urllib.request.Request(
    "https://mysdr.app/api/v1/person/phone",
    headers={
    "Authorization": f"Bearer {os.environ['MYSDR_API_KEY']}",
    "Content-Type": "application/json"
    },
    data=json.dumps(payload).encode(),
    method="POST",
)
with urllib.request.urlopen(request) as response:
    body = json.load(response)

Example response

{
  "results": [
    {
      "input": "https://www.linkedin.com/in/jane-example",
      "status": "found",
      "linkedin_url": "https://www.linkedin.com/in/jane-example",
      "phone": "+32 470 12 34 56",
      "phones": [
        {
          "number": "+32 470 12 34 56",
          "type": "mobile",
          "confidence": "high"
        },
        {
          "number": "+32 9 123 45 67",
          "type": "work",
          "confidence": "likely"
        }
      ],
      "credits_charged": 10
    },
    {
      "input": "https://www.linkedin.com/in/john-example",
      "status": "pending",
      "linkedin_url": "https://www.linkedin.com/in/john-example",
      "phone": null,
      "phones": [],
      "credits_charged": 0
    }
  ],
  "credits_used": 10,
  "retry_after_seconds": 60
}