# Discovery API
> Discover people from the open web using natural language queries. Define match conditions and get structured results with source citations.
**Base URL:** `https://api.nyne.ai`
**Endpoint:** `https://api.nyne.ai/person/discovery`

---

## Overview
The Discovery API lets you find people from the open web using natural language queries. Describe who you are looking for, define match conditions, and let the API search, evaluate, and enrich candidates automatically. Each result includes match evaluations with evidence-based reasoning, custom field extractions, and source citations with confidence scores. Delivery is asynchronous: submit a request, receive a request_id, then poll or register a callback.
### What You Get
- **Natural Language Search:** Describe the people you want to find in plain English- **Match Evaluation:** Define requirements and get per-candidate match status with evidence- **Custom Extractions:** Specify enrichment fields to extract for each discovered person- **Source Citations:** Every evaluation backed by reasoning, confidence scores, and source citations
## Authentication

All requests require header authentication:

```
X-API-Key: YOUR_API_KEY
X-API-Secret: YOUR_API_SECRET
```

## Rate Limits

| Limit | Value |
|-------|-------|
| Per Minute | 60 requests |
| Per Hour | 1000 requests |
| Monthly | Varies by plan |

### Response Headers

Responses from endpoints that perform rate-limit checks include both legacy and standard rate-limit headers:

| Header | Description |
|--------|-------------|
| `X-RateLimit-Limit` | Active per-minute or per-hour limit |
| `X-RateLimit-Remaining` | Remaining requests in the active window |
| `X-RateLimit-Reset` | Unix timestamp when the active window resets |
| `RateLimit-Limit` | Active per-minute or per-hour limit |
| `RateLimit-Remaining` | Remaining requests in the active window |
| `RateLimit-Reset` | Seconds until the active window resets |
| `Retry-After` | Seconds to wait before retrying; present on HTTP `429` rate-limit responses |

Monthly quota responses include quota-specific headers when available:

| Header | Description |
|--------|-------------|
| `X-Quota-Limit` | Monthly request or credit limit |
| `X-Quota-Used` | Amount used in the current billing cycle |
| `X-Quota-Remaining` | Amount remaining in the current billing cycle |
| `X-Quota-Reset` | Unix timestamp when the current billing cycle resets |

## Credit Usage

- **Discovery Request:** 10 credits per discovery request (10 credits)
> Credits are charged per submitted request regardless of the number of results returned.
---

## POST /person/discoverySubmit a discovery request to find people from the open web matching your criteria.
### Parameters

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `query` | string | Yes | Natural language query describing the people to find (max 2000 characters) |
| `requirements` | array | No | Array of match conditions, each with name and description (max 20 items) |
| `extract` | array | No | Array of enrichment fields to extract, each with name and description (max 10 items) |
| `limit` | integer | No | Maximum number of results to return. Range: 5-100 (default: `10`) |
| `quality` | string | No | Quality tier for discovery. One of: basic, standard, premium (default: `standard`) |
| `exclude` | array | No | Array of entities to exclude from results, each with name and url (max 100 items) |
| `metadata` | object | No | Pass-through metadata returned with results. Values must be string, number, or boolean. |
| `callback_url` | string | No | HTTPS URL to receive webhook notification when processing completes |

> **Required:** The query parameter is required.
### Request Examples

**With Advanced Features:**

```json
{
  "query": "AI researchers specializing in NLP at top US universities",
  "requirements": [
    {
      "name": "published_papers",
      "description": "Has published research papers in NLP or computational linguistics"
    },
    {
      "name": "university_affiliation",
      "description": "Currently affiliated with a top-50 US university"
    }
  ],
  "extract": [
    {
      "name": "email",
      "description": "Professional or academic email address"
    },
    {
      "name": "recent_publication",
      "description": "Title of their most recent published paper"
    }
  ],
  "limit": 10,
  "quality": "standard",
  "callback_url": "https://yourapp.com/webhook/discovery"
}
```

**Basic Request:**

```json
{
  "query": "AI researchers specializing in NLP at top US universities"
}
```

### Code Examples

**cURL:**

```bash
# Submit a discovery request
curl -X POST https://api.nyne.ai/person/discovery \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "X-API-Secret: YOUR_API_SECRET" \
  -H "Content-Type: application/json" \
  -d '{
    "query": "AI researchers specializing in NLP at top US universities",
    "requirements": [
      {"name": "published_papers", "description": "Has published research papers in NLP"},
      {"name": "university_affiliation", "description": "Currently at a top-50 US university"}
    ],
    "extract": [
      {"name": "email", "description": "Professional email address"}
    ],
    "limit": 10,
    "quality": "standard"
  }'

# Check status (replace REQUEST_ID with the returned request_id)
curl -X GET "https://api.nyne.ai/person/discovery?request_id=REQUEST_ID" \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "X-API-Secret: YOUR_API_SECRET"
```

**Python:**

```python
import requests
import time

API_KEY = "YOUR_API_KEY"
API_SECRET = "YOUR_API_SECRET"
BASE_URL = "https://api.nyne.ai"

headers = {
    "X-API-Key": API_KEY,
    "X-API-Secret": API_SECRET,
    "Content-Type": "application/json"
}

# Step 1: Submit discovery request
payload = {
    "query": "AI researchers specializing in NLP at top US universities",
    "requirements": [
        {"name": "published_papers", "description": "Has published research papers in NLP"},
        {"name": "university_affiliation", "description": "Currently at a top-50 US university"}
    ],
    "extract": [
        {"name": "email", "description": "Professional email address"},
        {"name": "recent_publication", "description": "Title of most recent paper"}
    ],
    "limit": 10,
    "quality": "standard"
}

response = requests.post(f"{BASE_URL}/person/discovery", json=payload, headers=headers)
data = response.json()

if not data.get("success"):
    print(f"Error: {data}")
    exit(1)

request_id = data["data"]["request_id"]
print(f"Request submitted: {request_id}")

# Step 2: Poll for results
while True:
    time.sleep(5)
    response = requests.get(
        f"{BASE_URL}/person/discovery",
        params={"request_id": request_id},
        headers=headers
    )
    result = response.json()
    status = result["data"]["status"]
    print(f"Status: {status}")

    if status == "completed":
        discovery = result["data"]["result"]
        print(f"Found {discovery['results_count']} people")
        for person in discovery["results"]:
            print(f"  - {person['name']}: {person['description']}")
            if person.get("extractions"):
                for key, value in person["extractions"].items():
                    print(f"    {key}: {value}")
        break
    elif status == "failed":
        print(f"Discovery failed: {result['data'].get('error', 'Unknown error')}")
        break
```

**JavaScript:**

```javascript
const API_KEY = "YOUR_API_KEY";
const API_SECRET = "YOUR_API_SECRET";
const BASE_URL = "https://api.nyne.ai";

const headers = {
  "X-API-Key": API_KEY,
  "X-API-Secret": API_SECRET,
  "Content-Type": "application/json"
};

async function discoverPeople() {
  // Step 1: Submit discovery request
  const payload = {
    query: "AI researchers specializing in NLP at top US universities",
    requirements: [
      { name: "published_papers", description: "Has published research papers in NLP" },
      { name: "university_affiliation", description: "Currently at a top-50 US university" }
    ],
    extract: [
      { name: "email", description: "Professional email address" },
      { name: "recent_publication", description: "Title of most recent paper" }
    ],
    limit: 10,
    quality: "standard"
  };

  const submitResponse = await fetch(`${BASE_URL}/person/discovery`, {
    method: "POST",
    headers,
    body: JSON.stringify(payload)
  });
  const submitData = await submitResponse.json();

  if (!submitData.success) {
    console.error("Error:", submitData);
    return;
  }

  const requestId = submitData.data.request_id;
  console.log(`Request submitted: ${requestId}`);

  // Step 2: Poll for results
  while (true) {
    await new Promise(resolve => setTimeout(resolve, 5000));

    const statusResponse = await fetch(
      `${BASE_URL}/person/discovery?request_id=${requestId}`,
      { headers }
    );
    const statusData = await statusResponse.json();
    const status = statusData.data.status;
    console.log(`Status: ${status}`);

    if (status === "completed") {
      const discovery = statusData.data.result;
      console.log(`Found ${discovery.results_count} people`);
      discovery.results.forEach(person => {
        console.log(`  - ${person.name}: ${person.description}`);
        if (person.extractions) {
          Object.entries(person.extractions).forEach(([key, value]) => {
            console.log(`    ${key}: ${value}`);
          });
        }
      });
      return statusData;
    } else if (status === "failed") {
      console.error("Discovery failed:", statusData.data.error || "Unknown error");
      return statusData;
    }
  }
}

discoverPeople();
```

**PHP:**

```php
<?php

$apiKey = "YOUR_API_KEY";
$apiSecret = "YOUR_API_SECRET";
$baseUrl = "https://api.nyne.ai";

// Step 1: Submit discovery request
$payload = [
    "query" => "AI researchers specializing in NLP at top US universities",
    "requirements" => [
        ["name" => "published_papers", "description" => "Has published research papers in NLP"],
        ["name" => "university_affiliation", "description" => "Currently at a top-50 US university"]
    ],
    "extract" => [
        ["name" => "email", "description" => "Professional email address"],
        ["name" => "recent_publication", "description" => "Title of most recent paper"]
    ],
    "limit" => 10,
    "quality" => "standard"
];

$ch = curl_init("$baseUrl/person/discovery");
curl_setopt_array($ch, [
    CURLOPT_POST => true,
    CURLOPT_POSTFIELDS => json_encode($payload),
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => [
        "X-API-Key: $apiKey",
        "X-API-Secret: $apiSecret",
        "Content-Type: application/json"
    ]
]);

$response = curl_exec($ch);
curl_close($ch);

$data = json_decode($response, true);

if (!$data["success"]) {
    echo "Error: " . print_r($data, true);
    exit(1);
}

$requestId = $data["data"]["request_id"];
echo "Request submitted: $requestId\n";

// Step 2: Poll for results
while (true) {
    sleep(5);

    $ch = curl_init("$baseUrl/person/discovery?request_id=$requestId");
    curl_setopt_array($ch, [
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_HTTPHEADER => [
            "X-API-Key: $apiKey",
            "X-API-Secret: $apiSecret"
        ]
    ]);

    $response = curl_exec($ch);
    curl_close($ch);

    $result = json_decode($response, true);
    $status = $result["data"]["status"];
    echo "Status: $status\n";

    if ($status === "completed") {
        $discovery = $result["data"]["result"];
        echo "Found " . $discovery["results_count"] . " people\n";
        foreach ($discovery["results"] as $person) {
            echo "  - " . $person["name"] . ": " . $person["description"] . "\n";
            if (isset($person["extractions"])) {
                foreach ($person["extractions"] as $key => $value) {
                    echo "    $key: $value\n";
                }
            }
        }
        break;
    } elseif ($status === "failed") {
        echo "Discovery failed: " . ($result["data"]["error"] ?? "Unknown error") . "\n";
        break;
    }
}

?>
```

### Response Codes

| Code | Description |
|------|-------------|
| 202 | Discovery request accepted and queued for processing |
| 400 | Invalid or missing request parameters |
| 401 | Invalid API credentials |
| 402 | Insufficient credits (requires 10 credits) |
| 403 | No active subscription or product not available |
| 429 | Rate limit exceeded |

### Response Example

```json
{
  "success": true,
  "data": {
    "request_id": "a1b2c3d4e5f6...",
    "status": "pending",
    "message": "Discovery request queued for processing. Use GET with request_id to check status.",
    "created_on": "2026-02-19T10:30:00"
  },
  "timestamp": "2026-02-19T10:30:00Z"
}
```

---

## GET /person/discovery
Check the status of a request.

### Parameters

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `request_id` | string | Yes | The request ID returned from the POST discovery call |

### Request Example

```
GET /person/discovery?request_id=a1b2c3d4e5f6
```

### Response Codes

| Code | Description |
|------|-------------|
| 200 | Status and results retrieved successfully |
| 400 | Invalid request parameters |
| 401 | Invalid API credentials |
| 404 | Request ID not found |

### Response Example

```json
{
  "success": true,
  "data": {
    "request_id": "a1b2c3d4e5f6...",
    "status": "completed",
    "completed": true,
    "completed_on": "2026-02-19T10:33:00",
    "created_on": "2026-02-19T10:30:00",
    "result": {
      "entity_type": "people",
      "query": "AI researchers specializing in NLP at top US universities",
      "results_count": 10,
      "results": [
        {
          "name": "Dr. Jane Smith",
          "url": "janesmith.ai",
          "description": "NLP researcher at Stanford University specializing in large language models and computational semantics",
          "match_status": "matched",
          "evaluations": {
            "published_papers": {
              "value": "yes",
              "matched": true
            },
            "university_affiliation": {
              "value": "yes",
              "matched": true
            }
          },
          "extractions": {
            "email": "jane@stanford.edu",
            "recent_publication": "Efficient Fine-Tuning Methods for Multilingual NLP Models"
          },
          "sources": [
            {
              "field": "published_papers",
              "reasoning": "Found multiple publications in top NLP venues including ACL and EMNLP",
              "confidence": "high",
              "citations": [
                {
                  "title": "Stanford NLP Lab - Publications",
                  "url": "https://nlp.stanford.edu/pubs",
                  "excerpts": ["Dr. Smith has published over 30 papers in computational linguistics..."]
                }
              ]
            },
            {
              "field": "university_affiliation",
              "reasoning": "Currently listed as Associate Professor at Stanford University",
              "confidence": "high",
              "citations": [
                {
                  "title": "Stanford NLP Lab - People",
                  "url": "https://nlp.stanford.edu/people",
                  "excerpts": ["Jane Smith, Associate Professor of Computer Science"]
                }
              ]
            }
          ]
        }
      ],
      "metrics": {
        "candidates_evaluated": 50,
        "candidates_matched": 10
      }
    }
  },
  "timestamp": "2026-02-19T10:33:00Z"
}
```

---

## Response Format

All API responses follow a consistent JSON format. All fields in enrichment results are **optional** and only included when data is available:
- Results are returned inside data.result.results as an array of person objects- Each person includes name, url, description, match_status, evaluations, extractions, and sources- The evaluations object contains one key per requirement with value and matched boolean- The extractions object contains one key per extract field with the extracted value- The sources array provides per-field reasoning, confidence level, and citation URLs with excerpts- The metrics object reports candidates_evaluated and candidates_matched counts- Processing stages: pending &rarr; searching &rarr; completed (or failed)
---

## Error Codes

| HTTP Code | Error Code | Description |
|-----------|------------|-------------|
| 400 | `INVALID_PARAMETERS` | Missing or invalid request parameters |
| 400 | `MISSING_PARAMETER` | Required parameter not provided |
| 401 | `AUTHENTICATION_FAILED` | Invalid or missing API credentials |
| 402 | `INSUFFICIENT_CREDITS` | Not enough credits (requires 10 credits) |
| 403 | `NO_ACTIVE_SUBSCRIPTION` | No active subscription found |
| 403 | `PRODUCT_NOT_AVAILABLE` | Discovery not available on your plan |
| 403 | `ACCESS_DENIED` | Not authorized to access this resource |
| 404 | `NOT_FOUND` | Request not found |
| 429 | `RATE_LIMIT_EXCEEDED` | Too many requests, please slow down |
| 500 | `QUEUE_ERROR` | Failed to queue request for processing |

---

## Callbacks

When you provide a `callback_url`, the API sends results to your endpoint via HTTP POST.

### Retry Policy- Maximum 5 retry attempts- Exponential backoff: 1s, 5s, 15s, 1m, 5m- 30-second timeout per request- Your endpoint should return HTTP 2xx for success
Your callback endpoint should respond with HTTP 200-299. Any other code triggers a retry.

### Callback Payload Example

```json
POST your_callback_url
Content-Type: application/json

{
  "request_id": "a1b2c3d4e5f6...",
  "status": "completed",
  "completed": true,
  "result": {
    "entity_type": "people",
    "query": "AI researchers specializing in NLP at top US universities",
    "results_count": 10,
    "results": [
      {
        "name": "Dr. Jane Smith",
        "url": "janesmith.ai",
        "description": "NLP researcher at Stanford University...",
        "match_status": "matched",
        "evaluations": { ... },
        "extractions": { ... },
        "sources": [ ... ]
      }
    ],
    "metrics": {
      "candidates_evaluated": 50,
      "candidates_matched": 10
    }
  }
}
```

---

## Best Practices

Prioritize inputs in this order for best match rates:
1. **Specific Queries** (Best) - Write detailed, specific natural language queries. "AI researchers specializing in NLP at top US universities" outperforms "find AI people".2. **Defined Requirements** (Good) - Add requirements array with clear match conditions. Each requirement is evaluated independently with evidence-based reasoning.3. **Custom Extractions** (Good) - Use the extract array to pull specific fields like email, recent publications, or expertise areas for each discovered person.
**Recommendation:** Use the callback_url parameter for production workflows instead of polling. For best results, combine a detailed query with 2-5 well-defined requirements. Typical processing time is 1-3 minutes; poll every 5 seconds if not using callbacks.
---

## Note for AI Agents
The Discovery API is asynchronous. Submit a POST, receive a request_id, then poll with GET until status is completed or failed. Recommended poll interval is 5 seconds. Maximum wait time before timeout is 10 minutes. Use callback_url instead of polling when possible. The quality parameter controls depth - basic is fastest, premium is most thorough.
---

## Related APIs
- **Person Search API** - Structured contact search by name, company, or role -> `https://api.nyne.ai/documentation/person/search`
- **Person Leads API** - AI-powered lead generation -> `https://api.nyne.ai/documentation/person/leads`
- **Person Enrichment API** - Enrich discovered people with full contact data -> `https://api.nyne.ai/documentation/person/enrichment`