Trade Code Solutions

TCS API — HRIS Integration

Sync employee rosters, electrical-licensing credentials, CE completions, and audit-trail records between your HRIS and TCS License Management. Built for enterprise — multi-tenant, rate-limited, audit-logged, HMAC-signed.

REST + JSONBearer authHMAC-signed webhooks100 req/min defaultSOC 2-aligned audit log

1. Authentication

Every request to /api/v1/tcs/* must include a Bearer token in the Authorization header. Generate keys in the API Keys page of your company dashboard. Keys are shown once at creation and can be revoked at any time.

curl https://tradecodesolutions.com/api/v1/tcs/companies/me \
  -H "Authorization: Bearer tcs_team_a3k9..."

Scopes

2. Rate limits

Defaults: 100 req/min per key (Trial + Team tiers), 1,000 req/min per key (Enterprise tier). Plus an IP-level burst guard of 30 req/min for unauthenticated probes.

Every response includes:

X-RateLimit-Limit:     100
X-RateLimit-Remaining: 73
X-RateLimit-Reset:     1714849920000
X-Request-ID:          req_a1b2c3d4e5f6g7h8

On 429 responses we also include Retry-After (seconds). Treat the limit as a soft cap — exponential backoff on 429 is the recommended client behavior.

3. Endpoints

GET/api/v1/tcs/companies/meread_only

Return the Company tied to the authenticated API key — verifies tenant binding before fan-out queries.

Response

{
  "ok": true,
  "data": {
    "id": "co_a3b9...",
    "name": "Acme Electric, Inc.",
    "legal_name": "Acme Electric, Inc.",
    "subscription_tier": "smb",
    "employee_count": 12,
    "states_operating": ["TX", "FL", "OH"],
    "industry": "electrical_contractor"
  },
  "request_id": "req_a1b2c3d4e5f6g7h8"
}
GET/api/v1/tcs/employeesread_only

List every employee in the caller's tenant. Tenant boundary enforced server-side.

Response

{
  "ok": true,
  "data": {
    "employees": [
      {
        "id": "p_x1y2...",
        "email": "j.doe@acme.com",
        "full_name": "Jane Doe",
        "role_at_company": "electrician",
        "primary_state_abbr": "TX",
        "external_hris_id": null
      }
    ],
    "count": 1
  }
}
POST/api/v1/tcs/employeesread_write

Create / upsert an employee from your HRIS.

Request body

{
  "email": "j.doe@acme.com",
  "first_name": "Jane",
  "last_name": "Doe",
  "external_hris_id": "bhr-101",
  "primary_state_abbr": "TX",
  "job_title": "Master Electrician",
  "start_date": "2022-04-11",
  "hris_provider": "bamboohr"
}

Response

{
  "ok": true,
  "data": {
    "status": "queued",
    "email": "j.doe@acme.com",
    "external_hris_id": "bhr-101"
  }
}
GET/api/v1/tcs/employees/{id}read_only

Fetch one employee with their compliance summary.

Response

{
  "ok": true,
  "data": {
    "id": "p_x1y2...",
    "email": "j.doe@acme.com",
    "full_name": "Jane Doe",
    "compliance_summary": {
      "total_licenses": 3,
      "active": 2,
      "expiring_soon": 1,
      "expired": 0,
      "pending": 0
    }
  }
}
PUT/api/v1/tcs/employees/{id}read_write

Update an existing employee.

Request body

{
  "primary_state_abbr": "FL",
  "job_title": "Senior Master Electrician",
  "employment_status": "active"
}

Response

{
  "ok": true,
  "data": {
    "status": "queued",
    "id": "p_x1y2...",
    "updates": {
      "primary_state_abbr": "FL",
      "job_title": "Senior Master Electrician"
    }
  }
}
GET/api/v1/tcs/employees/{id}/licensesread_only

List every electrical license held by one employee — state, type, number, expiration, CE progress, bucket.

Response

{
  "ok": true,
  "data": {
    "licenses": [
      {
        "id": "lic_a1b2...",
        "state_abbr": "TX",
        "state_name": "Texas",
        "license_type": "Master Electrician",
        "license_number": "152679",
        "issue_date": "2018-09-01",
        "expiration_date": "2026-09-01",
        "status": "Active",
        "bucket": "active",
        "days_to_expiration": 487,
        "ceu_requirement_current_cycle": 4,
        "ceus_completed_current_cycle": 4,
        "managed_by_tcs": true
      }
    ],
    "count": 1
  }
}
POST/api/v1/tcs/employees/{id}/licensesread_write

Add a license to an employee's record.

Request body

{
  "state_abbr": "TX",
  "license_type": "Master Electrician",
  "license_number": "152679",
  "issue_date": "2018-09-01",
  "expiration_date": "2026-09-01",
  "status": "Active"
}

Response

{
  "ok": true,
  "data": {
    "status": "queued",
    "employee_id": "p_x1y2...",
    "state_abbr": "TX",
    "license_type": "Master Electrician"
  }
}
GET/api/v1/tcs/employees/{id}/audit-trailread_only

Per-employee audit log. Used for SOX / ISO 27001 internal-audit packets.

Response

{
  "ok": true,
  "data": {
    "entries": [
      {
        "ts": "2026-05-04T17:42:11.000Z",
        "request_id": "req_...",
        "api_key_id_suffix": "a3b9c4d5",
        "method": "POST",
        "pathname": "/api/v1/tcs/employees/p_.../licenses",
        "status": 202,
        "duration_ms": 124
      }
    ],
    "count": 1
  }
}
GET/api/v1/tcs/compliance/state/{state_code}read_only

Per-state compliance summary — workforce-wide buckets + per-employee drill-down.

Response

{
  "ok": true,
  "data": {
    "state_abbr": "TX",
    "summary": {
      "state_abbr": "TX",
      "total_employees_with_license": 5,
      "compliant": 3,
      "at_risk": 1,
      "expired": 1,
      "percent_compliant": 60
    },
    "employees": [...]
  }
}
POST/api/v1/tcs/webhook/{slug}webhook_only

Inbound webhook receiver. Slug: 'bamboohr' | 'rippling' | 'gusto'. Auth is HMAC-SHA256 signature, not Bearer.

Response

{
  "ok": true,
  "provider": "bamboohr",
  "received": { "external_id": "bhr-101" }
}

4. Outbound webhooks (TCS → your HRIS)

When key events happen on the TCS side, we POST a JSON payload to your configured endpoint. Configure URLs + secrets in the dashboard API Keys page. Every webhook ships with HMAC-SHA256 signing.

Headers

X-TCS-Event:      employee.created
X-TCS-Signature:  sha256=<hex>
X-TCS-Timestamp:  1714849920000
X-TCS-Delivery:   dlv_a1b2c3d4e5f6
User-Agent:       TCS-Webhook/1.0

Verifying the signature

// Node.js
import { createHmac, timingSafeEqual } from "node:crypto";

function verify(secret, headerSig, headerTs, rawBody) {
  const expected = "sha256=" + createHmac("sha256", secret)
    .update(`${headerTs}.${rawBody}`, "utf8")
    .digest("hex");
  return timingSafeEqual(
    Buffer.from(expected),
    Buffer.from(headerSig)
  );
}

Event catalog

Retry policy

Failed deliveries retry on this schedule: 5s, 30s, 5m, 30m, 4h — total 5 attempts before dead-letter. Your endpoint must respond with a 2xx within 10 seconds; 4xx and 5xx both trigger retries.

5. Inbound webhooks (your HRIS → TCS)

For HRIS systems that prefer to PUSH employee data to TCS, configure your provider to POST to /api/v1/tcs/webhook/{slug} where slug is one of:

6. SDKs

Reference SDKs (typed wrappers around fetch / requests):

Production-grade SDKs (with retries, paging helpers, typed event unions) ship after the first wave of enterprise pilots. Email the TCS Engineering team if you'd like a customized client.

7. Pre-built HRIS connectors

The following providers ship with first-party connector scaffolds — OAuth handshake (or API-key model) plus inbound webhook handling. Connectors marked "demo" ship with a synthetic roster so your team can run a sales-demo flow without a live HRIS account.

8. Errors

Every error response uses this shape:

{
  "ok": false,
  "error": {
    "code": "missing_authorization",
    "message": "Missing Authorization header. Supply `Authorization: Bearer tcs_...`."
  },
  "request_id": "req_a1b2c3d4e5f6g7h8"
}

Common codes