This guide shows how to connect WordPress to a Django backend for AI automations without exposing third-party API keys in WordPress. The pattern: WordPress collects events, signs and forwards them to Django; Django validates, enqueues, calls AI/CRMs, and posts results back.
Core goals
– Never store vendor API keys in WordPress
– Validate every request and avoid duplicate processing
– Keep WordPress fast; move heavy work off-request
– Add clear observability and safe retries
Reference architecture
– WordPress (origin): Triggers on events (form submit, order paid, post published). Sends minimal signed JSON to Django via HTTPS.
– Django API (ingress): DRF view validates auth + HMAC + schema + idempotency-key; enqueues job.
– Task queue: Celery or RQ processes jobs, calls LLMs/CRMs.
– Result callback: Optional webhook back to WordPress or store in Django and let WP fetch.
– Monitoring: Log, trace, alert on failures and high latency.
Data flow
1) WordPress creates payload: {event_type, object_ref, data, idempotency_key, occurred_at}
2) WP adds headers: Authorization: Bearer , X-Signature: sha256=…, X-Idempotency-Key: …
3) Django verifies: JWT, timestamp drift, HMAC signature, schema, idempotency
4) Django enqueues task; returns 202
5) Worker runs task with vendor secrets; stores outcome + optional callback
Authentication and integrity
– JWT: Short-lived (<=5 min). Issuer: WordPress; Audience: Django. Secret or asymmetric keys (RS256 preferred). Include jti (nonce).
– HMAC signature: sha256 over raw body using a shared per-site secret. Header: X-Signature: sha256=. Reject if timestamp skew >5 min.
– IP allowlist (optional) and HTTPS only.
Idempotency
– Client (WP) generates UUIDv4 per business event; send as X-Idempotency-Key and in JSON.
– Server stores key + status for 24–72h. If duplicate, return cached 202/200 without re-enqueue.
– Use Redis or Postgres unique index on (idempotency_key).
WordPress implementation (concise)
– Store: JWT private key or client secret, HMAC secret, Django endpoint in wp_options via Secrets API or environment constants.
– Hook: add_action(‘your_event’, function($payload) { … });
– Create compact JSON, e.g., json_encode([…], JSON_UNESCAPED_SLASHES).
– Compute HMAC: hash_hmac(‘sha256’, $body, HMAC_SECRET).
– Issue JWT (RS256 if possible): include iss, aud, iat, exp, jti.
– Send with wp_remote_post to https://api.your-django.com/ingest with 3s connect and 5s timeout.
– Handle non-2xx: backoff (exponential with jitter), retry max 3, log to error_log or custom table.
Minimal PHP send example (inline, trimmed)
– $body = json_encode($data);
– $sig = hash_hmac(‘sha256’, $body, HMAC_SECRET);
– $jwt = generate_jwt_rs256($claims, PRIVATE_KEY);
– wp_remote_post($url, [
‘method’ => ‘POST’,
‘headers’ => [
‘Authorization’ => ‘Bearer ‘ . $jwt,
‘X-Signature’ => ‘sha256=’ . $sig,
‘X-Idempotency-Key’ => $idempotency_key,
‘Content-Type’ => ‘application/json’
],
‘body’ => $body,
‘timeout’ => 5
]);
Django ingress (DRF) key checks
– Verify Authorization: Bearer . Validate iss, aud, exp, jti (cache jti for replay prevention).
– Verify X-Signature: recompute sha256 HMAC over raw body; constant-time compare.
– Enforce timestamp in body; reject if drift >300s.
– Validate schema: pydantic or DRF serializers.
– Enqueue Celery task and return 202 with request_id.
Python highlights (inline, trimmed)
– jwt.decode(token, public_key, algorithms=[‘RS256′], audience=’django-api’)
– hmac.compare_digest(sig_header, ‘sha256=’ + hex_hmac)
– serializer.is_valid(raise_exception=True)
– Task delay: process_event.delay(request_id, payload)
Queue worker considerations
– Do not call LLMs/CRMs from the request thread.
– Set per-service timeouts (e.g., 10–15s), retries with backoff, and circuit breakers.
– Store vendor responses with redaction of PII/API keys.
Result handling patterns
– Callback to WordPress: WP registers a secret endpoint with HMAC verification; Django posts results.
– Or polling: WP cron fetches new results via GET /results?since=…
– Or dashboard: Keep results in Django, surface via internal UI.
Schema example (compact)
– event_type: string enum (form.submitted, order.paid)
– object_ref: string (post ID, order ID)
– idempotency_key: string UUID
– occurred_at: RFC3339 UTC timestamp
– data: object with validated subfields
Security checklist
– HTTPS everywhere; HSTS; TLS 1.2+
– JWT exp <= 5 minutes, rotate keys regularly
– HMAC secrets per WordPress site; rotate quarterly
– Validate content-type, size limits (e.g., <=256KB)
– Rate limit per IP and per JWT sub (e.g., 60/min)
– Store minimal PII; encrypt at rest if needed
– Log redacted payloads only
Performance notes
– Aim for p95 threshold, repeated signature failures
Local and deployment tips
– Run docker-compose: Nginx, Django, Postgres, Redis, Celery worker/beat
– Use separate Redis DBs for Celery and idempotency to avoid key churn collisions
– Keep WordPress outbound on a static egress IP; add IP to Django allowlist
– Use environment-based config; no secrets in Git
– Add a dry-run mode for new event types before production
Common pitfalls
– Doing LLM calls inside the Django view (timeouts, user-facing latency)
– Missing idempotency causing duplicate CRM/LLM actions
– Storing API keys in WordPress options without protection
– Ignoring replay windows and timestamp validation
– Returning 200 instead of 202, confusing clients about async work
When to use this bridge
– WordPress triggers backend AI workflows (summarize posts, generate assets, score leads)
– Commerce events sync to CRM with AI enrichment
– Form submissions drive multi-step automations with vendor APIs
Deliverables checklist
– WP: event hooks, JWT builder, HMAC signer, resilient http client, logging
– Django: DRF endpoint with JWT+HMAC+schema+idempotency, Celery queue, result store
– Ops: dashboards, alerts, runbooks, key rotation plan