REST API

Overview

The Loxo plugin exposes a REST API for programmatic control of job synchronization, webhooks, job data, and the Google Indexing integration. All endpoints live under the loxo/v1 namespace on your own site:

https://example.com/wp-json/loxo/v1/

Replace example.com with your site’s domain in every example below. Every endpoint requires an administrator account (the manage_options capability) except Job View Tracking, which is public, and the Webhook Event Listener, which is called by Loxo itself.

Authentication

  • Cookie authentication — used automatically by the plugin’s own admin screens while you are logged in to WordPress.
  • Application passwords — for external integrations (WordPress 5.6+). Create one under Users → Profile → Application Passwords, then send it with HTTP Basic auth.
curl -u "admin:abcd efgh ijkl mnop" \
  https://example.com/wp-json/loxo/v1/job-sync

All examples below assume the -u flag shown here.

Response Conventions

The API answers in two shapes, and knowing which to expect saves confusion:

Status envelope — the job synchronization endpoints reply with WordPress’s code / message / data.status envelope even on success. Read the HTTP status code and the code field, not the presence of an error shape:

{
  "code": "sync_scheduled",
  "message": "Background synchronization scheduled.",
  "data": { "status": 202 }
}

Plain object — everything else replies with a flat JSON object, most often carrying a message key, plus endpoint-specific data:

{ "message": "API Cache cleared." }

Job Synchronization

One resource, five methods. The sync runs in the background; these endpoints start it and control it while it runs.

POST /wp-json/loxo/v1/job-sync

Start a background job synchronization. No parameters.

curl -X POST -u "admin:abcd efgh ijkl mnop" \
  https://example.com/wp-json/loxo/v1/job-sync

Response — 202 Accepted

{
  "code": "sync_scheduled",
  "message": "Background synchronization scheduled.",
  "data": { "status": 202 }
}

Errors: 409 already_running — another sync is already in progress.

GET /wp-json/loxo/v1/job-sync

Get the current synchronization status. message carries progress text while a sync is running.

Response — 200 OK

{
  "running": true,
  "paused": false,
  "cancelled": false,
  "process_running": true,
  "message": "Synchronizing jobs..."
}

PATCH /wp-json/loxo/v1/job-sync

Pause the running synchronization. The pause takes effect at the next safe point, so poll GET until paused is true.

Response — 200 OK

{
  "code": "sync_paused",
  "message": "Pause requested, wait for response.",
  "data": { "status": 200 }
}

Errors: 409 not_running — no sync in progress · 409 already_paused

PUT /wp-json/loxo/v1/job-sync

Resume a paused synchronization.

Response — 202 Accepted

{
  "code": "sync_resumed",
  "message": "Background synchronization resumed.",
  "data": { "status": 202 }
}

Errors: 409 not_paused — nothing to resume · 409 already_running

DELETE /wp-json/loxo/v1/job-sync

Cancel the ongoing synchronization. Like pause, cancellation is picked up at the next safe point.

Response — 200 OK

{
  "code": "sync_cancelled",
  "message": "Cancellation requested, wait for response.",
  "data": { "status": 200 }
}

Webhook Management

Loxo can push job changes to your site in real time through three webhooks: job.create, job.update, and job.destroy. These endpoints register and manage them on the Loxo side. All three accept one optional parameter:

ParameterTypeRequiredDescription
callback_urlstringNoThe URL Loxo should deliver events to. Defaults to this site’s own event listener endpoint.

POST /wp-json/loxo/v1/loxo-webhooks

Register the missing webhooks with Loxo. Already-registered webhooks are left alone, so calling this repeatedly is safe.

curl -X POST -u "admin:abcd efgh ijkl mnop" \
  https://example.com/wp-json/loxo/v1/loxo-webhooks

Response — 200 OK

{ "message": "3 Webhook Registered." }

GET /wp-json/loxo/v1/loxo-webhooks

Check which of the three webhooks are registered.

Response — 200 OK (all present)

{ "message": "All Webhooks are present." }

Response — 200 OK (some missing)

{
  "message": "Missing Webhooks - job.create, job.update.",
  "missing": 2
}

DELETE /wp-json/loxo/v1/loxo-webhooks

Remove all webhooks this site registered with Loxo.

Response — 200 OK

{ "message": "3 Webhook Deleted." }

Webhook Event Listener

POST /wp-json/loxo/v1/loxo-event

The receiving end of the webhooks above: this is the callback URL registered with Loxo, and Loxo calls it when a job is created, updated, or deleted. It is documented here so you know what the URL is for — you never need to call it yourself, and it is not a supported surface for pushing your own data in.

Job Expiration

POST /wp-json/loxo/v1/job-expiration

Set the expiration date of a job. PUT is accepted as an alias.

ParameterTypeRequiredDescription
idintegerYesThe WordPress post ID of the job (not the Loxo job ID).
date_expiresstringYesExpiration date in Y-m-d format, e.g. 2026-12-31.
curl -X POST -u "admin:abcd efgh ijkl mnop" \
  -d "id=123" -d "date_expires=2026-12-31" \
  https://example.com/wp-json/loxo/v1/job-expiration

Response — 200 OK

{
  "success": true,
  "data": { "date_expires": "2026-12-31" }
}

Note: unlike the other endpoints, a failed call (unknown ID, invalid date) answers { "success": false, "data": false } with HTTP status 200 — check the success field, not the status code.

Job View Tracking

POST /wp-json/loxo/v1/job-view

Increment a job’s view counter. This is the endpoint the plugin’s front end calls on each job page view; it is public — no authentication — and only works while view tracking is enabled in the plugin settings (see Job View Tracking).

ParameterTypeRequiredDescription
idintegerYesThe WordPress post ID of the job.

Response — 200 OK

{ "success": true }

Errors: 403 disabled — view tracking is turned off · 400 invalid_job — the ID is not a job.

A third 403 can come from WordPress rather than the plugin. The route needs no authentication, but if the request sends an X-WP-Nonce header, WordPress checks it before the route runs and rejects a stale one with rest_cookie_invalid_nonce. The plugin’s own front-end script always sends that header, and the token it uses is baked into the page HTML, so on a page served from a cache older than about a day every view request fails this way. Calling the endpoint yourself, send no nonce header at all rather than an old one.

Data Management

DELETE /wp-json/loxo/v1/cache

Clear all cached Loxo API responses. Harmless — the cache rebuilds on demand.

curl -X DELETE -u "admin:abcd efgh ijkl mnop" \
  https://example.com/wp-json/loxo/v1/cache

Response — 200 OK

{ "message": "API Cache cleared." }

DELETE /wp-json/loxo/v1/data

⚠️ Destructive. Deletes every imported job from WordPress — posts, taxonomies, and metadata. There is no undo; the jobs can only be restored by running a fresh synchronization from Loxo.

curl -X DELETE -u "admin:abcd efgh ijkl mnop" \
  https://example.com/wp-json/loxo/v1/data

Response — 200 OK

{ "message": "All data deleted." }

Google Indexing

Programmatic control of the Google Indexing API integration — that guide covers creating the service account and credentials; these endpoints drive the integration once it exists.

GET /wp-json/loxo/v1/google-indexing/status

Current state of the integration: configuration, daily quota, submission queue, and recent activity log.

Response — 200 OK

{
  "enabled": true,
  "configured": true,
  "client_email": "[email protected]",
  "project_id": "my-project",
  "quota": { "used": 12, "limit": 200, "date": "2026-08-09" },
  "queue_count": 3,
  "log": [ ... ]
}

POST /wp-json/loxo/v1/google-indexing/settings

Save the integration settings.

ParameterTypeRequiredDescription
enabledstringNoyes to enable automatic submission, anything else disables it.
credentialsstringNoThe Google service-account key, as its raw JSON text.
remove_credentialsbooleanNotrue deletes the stored key (and wins over credentials).

Response — 200 OK

{
  "message": "Settings saved.",
  "status": { ...same shape as the status endpoint... }
}

POST /wp-json/loxo/v1/google-indexing/test

Test the connection using the stored credentials. No parameters.

Response — 200 OK

{
  "message": "Connected as [email protected]. The Google Indexing API connection is working.",
  "client_email": "[email protected]"
}

Errors: 400 not_configured — no service-account key saved yet.

POST /wp-json/loxo/v1/google-indexing/submit

Submit a single URL to Google.

ParameterTypeRequiredDescription
urlstringYesThe URL to submit. Must belong to this website.
typestringNoURL_UPDATED (default) or URL_DELETED to request removal.
curl -X POST -u "admin:abcd efgh ijkl mnop" \
  -d "url=https://example.com/job/senior-developer/" \
  https://example.com/wp-json/loxo/v1/google-indexing/submit

Response — 200 OK

{
  "message": "URL submitted to Google for indexing.",
  "status": { ...same shape as the status endpoint... }
}

Errors: 400 invalid_url / 400 invalid_url_host — missing or foreign URL · 429 quota_exhausted — the daily quota is used up.

POST /wp-json/loxo/v1/google-indexing/submit-all

Queue every published job for submission. URLs are submitted from the queue over time, respecting the daily quota. No parameters.

Response — 200 OK

{
  "message": "Queued 24 job URLs for submission to Google.",
  "queued": 24,
  "status": { ...same shape as the status endpoint... }
}

Errors: 400 not_configured — enable the integration and save a key first.

POST /wp-json/loxo/v1/google-indexing/url-status

Ask Google what it knows about a URL.

ParameterTypeRequiredDescription
urlstringYesThe URL to check. Must belong to this website.

Response — 200 OK

{
  "message": "Last update notification received by Google on August 9, 2026 10:30 am.",
  "metadata": {
    "url": "https://example.com/job/senior-developer/",
    "latestUpdate": {
      "url": "https://example.com/job/senior-developer/",
      "type": "URL_UPDATED",
      "notifyTime": "2026-08-09T04:30:12.000Z"
    }
  }
}

If Google has never seen the URL, the response is { "message": "Google has no record of this URL." }.

DELETE /wp-json/loxo/v1/google-indexing/log

Clear the integration’s activity log. No parameters.

Response — 200 OK

{ "message": "Activity log cleared." }

Related documentation

  • Synchronizing Jobs — the plugin’s built-in sync process that most of these endpoints control.
  • Webhooks — how to set up and manage real-time job updates.
  • Job View Tracking — the plugin feature behind the job-view endpoint.