Project

praxicraft

0.0
The project is in a healthy, maintained state
Official Ruby client for the Praxicraft Assess Public API.
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
 Dependencies

Development

~> 5.0
~> 13.0
 Project Readme

Praxicraft Assess Ruby SDK

Official Ruby client for the Praxicraft Assess Public API.

Use it to invite candidates, check invite quota, manage webhooks, enroll hiring pipelines, and fetch results from your ATS, backend, or automation scripts.

gem install praxicraft

Until RubyGems publish, install from GitHub:

# Gemfile
gem "praxicraft", git: "https://github.com/praxicraft-platform/praxicraft-ruby.git"

Requires Ruby 3.1+. Full API reference: docs.praxicraft.com/sdks/ruby

Table of Contents

  • Authentication
  • Quickstart
  • What you can do
    • Check invite quota before bulk sends
    • Bulk invites
    • Build and activate an assessment via API
    • Register and test a webhook
    • Enroll into a hiring pipeline
    • Paginate cohort results
    • Verify webhook signatures
  • Errors
  • Requirements & support
  • License

Authentication

Create an organisation API key in Assess:

Assess → Developer → API Keys → create key → copy ct_live_… (shown once).

export PRAXICRAFT_API_KEY="ct_live_xxxxxxxxxxxxxxxx"

Or pass the key when constructing the client:

require "praxicraft"

client = Praxicraft::Client.new(api_key: "ct_live_xxxxxxxxxxxxxxxx")

Optional: override the API host with PRAXICRAFT_API_BASE_URL or Praxicraft::Client.new(base_url: "..."). Default host: https://assess.praxicraft.com.

Never commit API keys. Prefer environment variables or a secrets manager.

Scopes and rotation: Authentication


Quickstart

require "praxicraft"

client = Praxicraft::Client.new # reads PRAXICRAFT_API_KEY

page = client.assessments.list
page.fetch("results", []).each do |assessment|
  puts "#{assessment["slug"]} #{assessment["status"]}"
end

# Invite a candidate (idempotent on email — safe to retry)
invite = client.invites.create(
  "senior-backend-screen",
  email: "candidate@example.com",
  name: "Jane Doe",
  send_email: true
)
puts "#{invite["invite_token"]} #{invite["invite_url"]}"

result = client.results.retrieve(invite["invite_token"])
p result

Responses are flat JSON (same shape as the Public API — no { "data": … } wrapper).


What you can do

Resource Common methods
client.org retrieve, stats
client.assessments list, retrieve, create, update, activate, list_tasks, attach_tasks, replace_tasks, remove_task
client.invites create, bulk_create, list, retrieve, remind, cancel
client.results list, retrieve, iter_all
client.webhooks list, create, retrieve, update, delete, test, deliveries
client.pipelines list, retrieve, enroll, bulk_enroll, list_enrollments, get_enrollment
Praxicraft::Webhooks.verify_signature Verify X-Praxicraft-Signature on webhook payloads

All paths target /api/v1/public/… on the Assess host.

Check invite quota before bulk sends

org = client.org.retrieve
if (org["invites_remaining"] || 0) < candidates.length
  abort "Not enough invites remaining this month"
end

Bulk invites

client.invites.bulk_create(
  "senior-backend-screen",
  [
    { "email" => "a@example.com", "name" => "Alex" },
    { "email" => "b@example.com", "name" => "Blair" }
  ],
  send_email: true
)

Build and activate an assessment via API

assessment = client.assessments.create(title: "Backend screen")
client.assessments.attach_tasks(
  assessment["slug"],
  tasks: [{ "task_id" => "<platform-or-org-task-uuid>", "source" => "platform" }]
)
client.assessments.activate(assessment["slug"])

Register and test a webhook

hook = client.webhooks.create(
  url: "https://example.com/hooks/praxicraft",
  events: ["assessment.completed", "candidate.passed"]
)
# Store hook["secret_key"] (whsec_…) — shown once
client.webhooks.test(hook["id"])
client.webhooks.update(hook["id"], is_active: true)

Enroll into a hiring pipeline

enrollment = client.pipelines.enroll(
  "grad-2025",
  email: "alex@example.com",
  name: "Alex Lee",
  send_email: true
)
status = client.pipelines.get_enrollment(enrollment["enrollment_id"])

Paginate cohort results

client.results.iter_all("senior-backend-screen", page_size: 50) do |row|
  puts "#{row["email"]} #{row["score_percentage"]} #{row["passed"]}"
end

Verify webhook signatures

Assess signs the raw request body with your webhook secret (whsec_…):

def handle_webhook(raw_body, signature_header, secret)
  Praxicraft::Webhooks.verify_signature(secret, raw_body, signature_header)
end

Header format: X-Praxicraft-Signature: sha256=<hex>

Event catalog and payload examples: Webhooks


Errors

Public API errors look like:

{
  "error": {
    "code": "INSUFFICIENT_SCOPE",
    "message": "This API key does not have the 'candidates:read' scope."
  }
}

The SDK raises typed exceptions. Branch on exc.error_code (or exc.code), not the message text:

begin
  client.invites.create("demo", email: "candidate@example.com")
rescue Praxicraft::ValidationError => exc
  puts exc.error_code, exc.details
rescue Praxicraft::InsufficientScopeError => exc
  puts exc.error_code
rescue Praxicraft::AuthenticationError => exc
  puts exc.error_code
rescue Praxicraft::RateLimitError => exc
  puts exc.retry_after
end

Error codes: Errors


Requirements & support


License

MIT