Skip to main content
POST
Create a job-change monitor
Job-change monitoring requires a V2 workspace API key. V1 (Bubble) API keys are not supported by these endpoints. Monitors and monitoring credits belong to the V2 workspace associated with the key.
Create an active monitor for one to 10,000 personal LinkedIn profiles with Bearer authentication. All profiles belong to one monitor ID, with one frequency, one results table and an optional webhook. Each successful request creates a new monitor, and creation has no idempotency key. If a network failure leaves the result unknown, list your monitors and reconcile before retrying; blindly retrying can create a second monitor with separate charges.
The frequency can be weekly, every_30_days, or every_90_days (default weekly). If you provide webhook_url, store the returned signing_secret immediately; it is returned only once. If you lose it, rotate it on the existing monitor instead of creating a new one.
Airscale canonicalizes LinkedIn URLs, which must identify a personal /in/ profile, and preserves each profile’s optional external_id in later events. Monitoring admission checks that job-change monitoring is available and that the workspace can pay for a full check before accepting the monitor.

Monitor 10,000 profiles

  1. Prepare a JSON request with name, your chosen frequency, an optional webhook_url, and a profiles array containing up to 10,000 personal LinkedIn URLs. Each entry can include an external_id from your CRM.
  2. Send it to POST /v1/job-change-monitors. The 202 Accepted response contains monitor, profiles, duplicates, skipped_duplicate_count, signing_secret, and signing_secret_warning. Save monitor.id and, if a webhook is configured, the one-time signing_secret.
  3. Use that same ID with Get a monitor to inspect profile statuses and the monitor’s check timestamps. Checks run asynchronously and a large check can take time; 202 confirms acceptance, not completion.
  4. After a profile’s first successful check establishes its baseline, later employer changes appear in List job-change events, are appended to the monitor’s results table, and are sent to the configured webhook. The first baseline does not emit a job-change event.
Monitoring costs 0.1 credit per profile per check. A full check of 10,000 profiles costs up to 1,000 credits. Failed, not-found, and no-current-employer lookups are refunded. A check the workspace cannot pay for in full is not started: the monitor then reports run_block_reason: "insufficient_credits" with run_block_detail until a later check starts.

Results table

Each monitor owns a regular Airscale results table. Every new job-change event appends a row; the initial baseline does not. The monitor reports results_table_id, results_status (pending, ready, or blocked) and results_error. If the table is deleted or full, new rows stay pending and results_error explains why. Deleting the monitor keeps its results table.

Profiles already watched by another monitor

duplicates lists profiles that another monitor in the workspace already watches, with linkedin_url, monitor_id, and monitor_name. Each monitor checks and charges its profiles separately. Send "skip_duplicates": true to leave them out; skipped_duplicate_count reports how many were skipped. A request whose every profile is a duplicate is rejected with 422 all_profiles_duplicated.

Request size and profile limits

One monitor supports at most 10,000 active profiles. Create and Add profiles each accept up to 10,000 profile entries per request, while the monitor’s resulting active count must stay within 10,000. The complete JSON request body must be at most 8 MiB (8,388,608 bytes) in UTF-8. A larger body returns 413. Long URLs, external_id values, and JSON formatting all count toward this limit. If your payload is too large, create the monitor with a smaller set, then add the remaining profiles in smaller requests to the same monitor.id.

Webhook URL rules

webhook_url must be a public HTTPS URL without embedded credentials. Other protocols, internal hostnames, and private or reserved addresses are rejected with 422 invalid_monitor before the monitor is created. Destinations are checked again when sending; a hostname that later resolves to a blocked address cannot receive deliveries.

Verify webhook signatures

Airscale sends each event as a JSON POST to webhook_url. The body has type: "job_change.detected" plus the same fields as an event from List job-change events without read_at or webhook: id, monitor_id, profile_id, linkedin_url, external_id, detected_at, previous_employer, and new_employer (each with identity and name). The request includes X-Airscale-Event: job_change.detected, X-Airscale-Event-Id, X-Airscale-Timestamp, and X-Airscale-Signature: sha256=<hex>. Compute HMAC-SHA256 with the signing_secret over <timestamp>.<raw request body>, compare it in constant time, and reject timestamps more than five minutes from the current time. Return a 2xx response only after durable handling. Airscale makes up to five attempts with exponential backoff. 408, 425, 429, and 5xx responses are retried; other definitive responses fail permanently, and timeouts or dropped connections are marked uncertain because the request may have been received. Retries keep the same event ID and send Idempotency-Key: job-change-event:<event_id>, so process events idempotently. Use Redeliver a webhook to send a failed or uncertain event again.

Next step

Use List job-change monitors to confirm the monitor’s status and next check time.

Authorizations

Authorization
string
header
required

Use an Airscale workspace API key. Never expose the key in client-side code.

Body

application/json

Choose a check frequency and provide 1–10,000 personal LinkedIn profiles in a JSON body of at most 8 MiB (8,388,608 bytes). For larger payloads, create with fewer profiles and add the remainder to the same monitor in smaller requests.

name
string
required
Required string length: 1 - 120
profiles
object[]
required
Required array length: 1 - 10000 elements
frequency
enum<string>
default:weekly
Available options:
weekly,
every_30_days,
every_90_days
webhook_url
string<uri> | null

A public HTTPS URL without embedded credentials. Internal hostnames and private or reserved addresses are rejected.

Maximum string length: 2048
skip_duplicates
boolean
default:false

Leave out profiles that another monitor in this workspace already watches. Without it, duplicates are added and reported in duplicates.

Response

The monitor was accepted and scheduled. Checks run asynchronously; acceptance does not mean a check has completed.

monitor
object
required
profiles
object[]
required
duplicates
object[]
required

Profiles that another monitor in this workspace already watches. Each monitor checks and charges its profiles separately.

skipped_duplicate_count
integer
required
Required range: x >= 0
signing_secret
string | null
required

Returned once when a webhook is configured; null otherwise.

signing_secret_warning
string | null
required