Skip to main content
This flow lets you build a source configuration experience on top of the Platform API: create a source in draft, hand a secure link to a client or third party so they can fill in the connector credentials (without a Nekt account), and receive a webhook when they finish — then validate and finalize the source. It mirrors the in-app Share a setup link feature, end to end over the API.

Overview

Prerequisites

Step 1: Create a draft source with a callback webhook

Create the source with draft: true. Only connector_slug is required for a draft — you (or a third party) fill in the rest later. Optionally attach a callback_webhook: Nekt POSTs to it once the third party finishes filling in the configuration through the setup link. Use the optional custom header to authenticate the call on your side.
curl --request POST \
  --url https://api.nekt.ai/api/v1/sources/ \
  --header "x-api-key: YOUR_API_KEY" \
  --header "Content-Type: application/json" \
  --data '{
    "draft": true,
    "connector_slug": "facebook-ads",
    "description": "Client Facebook Ads",
    "callback_webhook": {
      "url": "https://your-app.example.com/hooks/nekt",
      "header_name": "X-Webhook-Secret",
      "header_value": "your-shared-secret"
    }
  }'

callback_webhook object

FieldTypeRequiredDescription
urlstringYesHTTPS URL Nekt POSTs to on setup completion. Must be a public https:// endpoint.
header_namestringNoOptional custom header name to send with the callback.
header_valuestringNoValue for the custom header. Required if header_name is set. Stored encrypted and never returned.
callback_webhook is write-only. Responses never echo it back; they expose a read-only boolean has_callback_webhook so you can confirm one is configured. To remove a configured webhook, send "callback_webhook": null on an update.
For security, the URL must use https and resolve to a public host. URLs pointing at localhost, loopback, private (RFC 1918), or link-local addresses are rejected.

Step 2: Create a setup token

Generate a time-limited token scoped to this draft source, then build the link as https://app.nekt.ai/scl/{token} and share it with the third party.
curl --request POST \
  --url https://api.nekt.ai/api/v1/sources/{source_slug}/setup-tokens/ \
  --header "x-api-key: YOUR_API_KEY" \
  --header "Content-Type: application/json" \
  --data '{ "expires_in_seconds": 86400 }'
{
  "id": "0d2c1b47-2902-4c47-8b30-0e7c3fd72609",
  "token": "Qm9vR2k...redactedOnList",
  "expires_at": "2026-06-18T12:00:00Z",
  "created_at": "2026-06-17T12:00:00Z"
}
FieldTypeRequiredDescription
expires_in_secondsintegerNoToken lifetime. Defaults to 24 hours (86400).
The full token is returned only on creation. When listing tokens it is redacted. To revoke a link, delete the token: DELETE /api/v1/sources/{source_slug}/setup-tokens/{id}/.

Step 3: The third party fills in the configuration

The recipient opens https://app.nekt.ai/scl/{token} and enters the connector credentials (or authenticates via OAuth for connectors that support it). No Nekt account is required, and the link is scoped strictly to this draft source. When they submit, Nekt POSTs to your callback_webhook (if configured):
POST https://your-app.example.com/hooks/nekt
Content-Type: application/json
X-Webhook-Secret: your-shared-secret

{
  "event": "source.setup_filled",
  "source": {
    "id": "d2c1b472-902c-477a-b300-e7c3fd72609b",
    "slug": "facebook-ads-UcuH",
    "description": "Client Facebook Ads",
    "draft": true,
    "config_completed": false,
    "missing_required_fields": ["access_token"]
  }
}
FieldTypeDescription
config_completedbooleantrue when all required connector config fields are filled.
missing_required_fieldsarrayDot-paths of required fields still missing (e.g. report_definition.action_report_time). Empty when config_completed is true.
Use config_completed to decide whether you can proceed to validation, or whether you need to send another setup link to collect the remaining fields.

Step 4: Validate the connector configuration

Start a validation for the draft source. This confirms the credentials work and discovers the available streams. The validation uses the configuration already saved on the draft (from the setup link), so you don’t need to send a request body.
curl --request POST \
  --url https://api.nekt.ai/api/v1/sources/{source_slug}/revalidate/ \
  --header "x-api-key: YOUR_API_KEY"
You may optionally pass { "config": { ... } } to merge extra fields into the saved configuration before validating.
The response returns a validation id with status in_progress. Poll it until the status is success or failed:
curl --request GET \
  --url https://api.nekt.ai/api/v1/connector-validations/{validation_id}/ \
  --header "x-api-key: YOUR_API_KEY"
To stream the validation logs (useful for surfacing progress or diagnosing failures):
curl --request GET \
  --url "https://api.nekt.ai/api/v1/connector-validations/{validation_id}/logs/" \
  --header "x-api-key: YOUR_API_KEY"

Step 5: Finalize the source

Once validation succeeds, complete the source by setting draft: false along with the streams, output layer, and trigger. See Update Source for the full set of fields.
curl --request PATCH \
  --url https://api.nekt.ai/api/v1/sources/{source_slug}/ \
  --header "x-api-key: YOUR_API_KEY" \
  --header "Content-Type: application/json" \
  --data '{
    "draft": false,
    "output_layer": "OUTPUT_LAYER_ID",
    "trigger": { "type": "manual" },
    "add_streams": [
      {
        "enabled": true,
        "stream_name": "ads",
        "table_name": "facebook_ads_ads",
        "primary_keys": ["id", "updated_time"],
        "replication_key": "updated_time",
        "sync_type": "INCREMENTAL",
        "extract_all_fields": true,
        "fields": null
      }
    ]
  }'
After finalizing, you can Trigger Source to start the first extraction.
Setup tokens stop working once the source leaves draft. Any unused link for this source is invalidated when you finalize it.