API Documentation

    Integrate your job board, ATS, or scraper with NewLocal Jobs. Send jobs via webhook with HMAC-SHA256 signing, idempotency, and full audit trails.

    Authentication

    Every request must include your API key in the Authorization header.

    Authorization: Bearer nlk_your_api_key_here

    API keys are issued by the NewLocal team. Contact us or use the employer portal to request one. Keys can have scoped permissions (jobs:write, jobs:read, content:write).

    Send Jobs (POST)

    Send up to 500 jobs per request. The endpoint deduplicates by content hash (title + employer + location).

    Endpoint
    POST /functions/v1/receive-job-webhook
    curl -X POST "https://<your-project>.supabase.co/functions/v1/receive-job-webhook" \
      -H "Content-Type: application/json" \
      -H "Authorization: Bearer nlk_your_api_key" \
      -H "X-Timestamp: $(date +%s)" \
      -H "X-Idempotency-Key: import-2024-01-15-batch1" \
      -d '{
        "source_name": "My Job Board",
        "jobs": [
          {
            "title": "Senior Backend Engineer",
            "company": "TechCorp",
            "location": "Toronto, ON",
            "country": "Canada",
            "country_code": "CA",
            "description": "We are looking for...",
            "url": "https://example.com/jobs/123",
            "salary_text": "CAD 120,000 - 160,000/yr",
            "employment_type": "full-time",
            "remote_option": "Hybrid",
            "experience_level": "Senior",
            "tech_stack": ["Node.js", "PostgreSQL", "AWS"]
          }
        ]
      }'

    Request Format

    Each job object supports the following fields:

    FieldTypeRequiredDescription
    titlestringYesJob title (max 500 chars)
    companystringNoCompany name (alias: employer)
    locationstringYesCity, province/state (max 200)
    countrystringNoCountry name (auto-detected from location)
    country_codestringNoISO 3166-1 alpha-2 code (e.g. CA, US)
    descriptionstringNoFull job description (max 50,000 chars)
    urlstringNoOriginal job listing URL (alias: source_url)
    salary_textstringNoSalary range as text (e.g. 'CAD 80k-120k')
    employment_typestringNofull-time, part-time, contract, internship
    remote_optionstringNoRemote, Hybrid, On-site
    experience_levelstringNoEntry, Mid, Senior, Executive
    tech_stackstring[]NoTechnology tags (max 50)
    requirementsstringNoRequirements (max 10,000 chars)
    benefitsstringNoBenefits (max 5,000 chars)

    Response Format

    {
      "success": true,
      "request_id": "550e8400-e29b-41d4-a716-446655440000",
      "summary": {
        "received": 10,
        "saved": 8,
        "duplicates": 2,
        "errors": 0
      }
    }

    The request_id is also returned in the X-Request-Id response header.

    HMAC-SHA256 Signing

    Signing is optional but recommended. It proves the request hasn't been tampered with and prevents replay attacks.

    1

    Get current Unix timestamp (seconds)

    Send this as X-Timestamp

    2

    Concatenate: timestamp + "." + request_body

    3

    Compute HMAC-SHA256 using your API key as the secret

    Send as X-Signature: sha256=<hex>

    Timestamps older than 5 minutes are rejected to prevent replay attacks.

    Idempotency

    Send the X-Idempotency-Key header to prevent duplicate processing if you retry a failed request.

    X-Idempotency-Key: import-2024-01-15-batch1

    If the same idempotency key is sent again, the original response is returned without reprocessing. Keys are scoped to your API key.

    Rate Limits

    Each API key has a configurable rate limit (default: 60 requests/minute). Exceeding the limit returns 429 Too Many Requests.

    Max jobs per request500
    Max body size5 MB
    Default rate limit60 req/min
    Timestamp window5 minutes

    Outbound Webhook Events

    Subscribe your endpoint to receive notifications when events happen on NewLocal Jobs. All payloads are HMAC-signed.

    Event TypeDescription
    application.createdA candidate applied to one of your jobs
    application.status_changedApplication moved to a new pipeline stage
    job.createdA new job was posted on the platform
    job.updatedA job listing was modified
    job.deletedA job listing was removed
    candidate.profile_updatedA candidate in your talent pool updated their profile

    Deliveries retry with exponential backoff (1m, 5m, 30m, 2h, 12h). After 5 failures, the endpoint is auto-disabled.

    Error Codes

    CodeMeaning
    200Success — jobs processed
    400Bad request — invalid JSON, missing fields, too many jobs
    401Unauthorized — invalid/expired API key or bad signature
    403Forbidden — API key lacks required scope
    413Payload too large (max 5 MB)
    429Rate limited — slow down
    500Internal server error — retry with backoff
    503Webhook not configured — contact admin