For developers and AI agents

Ruzora agent feeds

Open formats for agents that route hiring requests. Read whether we have vetted engineers for a skill, level and start date, then hand us the role as the schema.org JobPosting you already publish. No API key to read, and a verified work email to write.

Availability feed (JSON)JobPosting intakeNo names or contact details in the feeds

Availability feed

Aggregated supply of the engineers we have already vetted: every one passed our coding test and AI technical interview and confirmed their availability in the last 30 days. The feed is cells of skill, seniority and start window. Refreshed from the live bench and cached for up to 15 minutes.

GET
https://www.ruzora.com/api/public/availability.json

JSON Schema: https://www.ruzora.com/api/public/availability.schema.json. Responses send Cache-Control: public, max-age=300 and allow any origin.

Privacy rules

  • A cell is published only when at least 5 engineers fall in it. Smaller cells are left out, not rounded up.
  • No totals of any kind: no bench size, no per-skill sums. A total next to the cells would let anyone subtract their way to a suppressed cell.
  • No engineer counts at all. A cell says only that supply is available.
  • No location. Beyond what our blind engineer profiles already show (skill, seniority, availability), the feed adds nothing about any engineer except whether a confirmed start date falls in the next 30 days, so it can't be combined with them to work out where someone lives.
  • No names, profiles, employers, cities, rates, scores or per-engineer entries appear in the feed.
  • The whole feed hides itself (published: false) while the bench is too thin to publish anything, exactly when our public engineer page does.

Cell fields

FieldMeaning
skill / skill_labelA technology from our skill taxonomy, as listed on the engineers' resumes.
senioritymid, senior, lead or staff.
windownow (available today) or within_30_days (a confirmed start date in the next 30 days).
supplyAlways available. A cell only exists when it clears the privacy floor.

A skill in this feed is what the engineers list, not what they were assessed on. Per-skill assessment results appear on the blind profiles in a shortlist.

Example (illustrative)

availability.json
{
  "$schema": "https://www.ruzora.com/api/public/availability.schema.json",
  "schema_version": "1.0",
  "published": true,
  "as_of": "2026-10-14",
  "min_cell_size": 5,
  "counts": "none",
  "cells": [
    {
      "skill": "python",
      "skill_label": "Python",
      "seniority": "senior",
      "window": "now",
      "supply": "available"
    }
  ]
}
Full JSON Schema
availability.schema.json
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://www.ruzora.com/api/public/availability.schema.json",
  "title": "Ruzora vetted engineer availability",
  "description": "Anonymized, aggregated supply of Ruzora's vetted engineers in Latin America. Every engineer counted passed Ruzora's coding test and AI technical interview and confirmed availability in the last 30 days. A cell is published only when at least min_cell_size engineers fall in it. There are no totals, counts, names, profiles, locations or per-engineer entries.",
  "type": "object",
  "additionalProperties": false,
  "required": [
    "schema_version",
    "published",
    "as_of",
    "min_cell_size",
    "counts",
    "cells"
  ],
  "properties": {
    "$schema": {
      "type": "string",
      "format": "uri"
    },
    "schema_version": {
      "type": "string",
      "const": "1.0"
    },
    "published": {
      "type": "boolean",
      "description": "False while the bench is too thin to publish anything; cells is then empty."
    },
    "as_of": {
      "type": "string",
      "format": "date",
      "description": "UTC date the data was read."
    },
    "min_cell_size": {
      "type": "integer",
      "minimum": 5,
      "description": "k-anonymity floor: smaller cells are left out, not rounded."
    },
    "counts": {
      "const": "none",
      "description": "Always none: a cell only says supply is available. No engineer numbers are published."
    },
    "dimensions": {
      "type": "object"
    },
    "docs": {
      "type": "string",
      "format": "uri"
    },
    "request_shortlist": {
      "type": "object",
      "properties": {
        "intake": {
          "type": "string",
          "format": "uri"
        },
        "mcp": {
          "type": "string",
          "format": "uri"
        },
        "human": {
          "type": "string",
          "format": "uri"
        }
      }
    },
    "cells": {
      "type": "array",
      "items": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "skill",
          "skill_label",
          "seniority",
          "window",
          "supply"
        ],
        "properties": {
          "skill": {
            "type": "string",
            "pattern": "^[a-z0-9][a-z0-9-]*$",
            "description": "Skill taxonomy slug, as listed on the engineer's resume (not an assessment result)."
          },
          "skill_label": {
            "type": "string"
          },
          "seniority": {
            "enum": [
              "mid",
              "senior",
              "lead",
              "staff"
            ]
          },
          "window": {
            "enum": [
              "now",
              "within_30_days"
            ],
            "description": "now: available today. within_30_days: confirmed start date 1-30 days out."
          },
          "supply": {
            "const": "available"
          }
        }
      }
    }
  }
}

JobPosting intake

Send the schema.org JobPosting for a remote engineering role and it becomes a vetted shortlist request, the same request our MCP tool request_vetted_shortlist makes. A vetted shortlist within 72 hours goes to the verified work email; profiles are blind until an agreement is signed.

POST
https://api.ruzora.com/api/public/jobs/intake

1. Verify the hiring manager’s work email

Writes need a buyer token for a verified work email. Personal inboxes such as Gmail are refused. Get one from the Ruzora MCP server at https://mcp.ruzora.com/mcp: call verify_work_email, which emails a 6-digit code, then confirm_work_email with that code. Confirming that code creates a Sol account for that email (or signs you into the one you already have), and the role and its shortlist appear in Sol at sol.ruzora.com. See your Sol account in our privacy policy. MCP install guide.

The token lasts 7 days and only ever acts for that email: the shortlist always goes to it, whatever the posting says. Treat it like a password. Anyone holding it can post roles for that email from anywhere until it expires, so keep it out of shared transcripts and logs.

2. Post the JobPosting

Terminal
curl -X POST https://api.ruzora.com/api/public/jobs/intake \
  -H "Authorization: Bearer $RUZORA_BUYER_TOKEN" \
  -H "Content-Type: application/ld+json" \
  --data @job-posting.json
job-posting.json
{
  "@context": "https://schema.org",
  "@type": "JobPosting",
  "title": "Senior Backend Engineer",
  "description": "<p>Own our payments API and its Postgres schema. Small team, weekly releases.</p>",
  "skills": [
    "Python",
    "PostgreSQL",
    "AWS"
  ],
  "employmentType": "CONTRACTOR",
  "jobLocationType": "TELECOMMUTE",
  "applicantLocationRequirements": [
    {
      "@type": "Country",
      "name": "Brazil"
    }
  ],
  "hiringOrganization": {
    "@type": "Organization",
    "name": "Acme",
    "sameAs": "https://acme.example"
  },
  "baseSalary": {
    "@type": "MonetaryAmount",
    "currency": "USD",
    "value": {
      "@type": "QuantitativeValue",
      "minValue": 90000,
      "maxValue": 120000,
      "unitText": "YEAR"
    }
  },
  "totalJobOpenings": 1,
  "applicationContact": {
    "@type": "ContactPoint",
    "name": "Casey Lee"
  }
}

The body can also be a list, or a document with an @graph, that contains one JobPosting. Up to 64 KB. The token can go in X-Ruzora-Buyer-Token instead of Authorization.

How fields are read

FieldRequiredWhat happens
titleyesThe role. Seniority is read from it (Senior, Staff, Lead...).
descriptionyesNotes for the shortlist (HTML is stripped). It can't ask for a protected characteristic (age, sex, national origin, accent...).
skillsyesList must-haves first. The first 3 that name a technology in our skill taxonomy are hard requirements; every other skill (more technologies, soft skills, words we don't recognise) only ranks matches, up to 12.
hiringOrganization.nameyesThe company.
jobLocationTypeTELECOMMUTERuzora places remote engineers who live in Latin America.
experienceRequirements.monthsOfExperienceif the title has no level36+ mid, 60+ senior, 96+ staff. Junior roles are declined.
employmentTypenoNoted. INTERN and VOLUNTEER are declined.
applicantLocationRequirementsnoNoted. A list without a Latin American country returns a warning, not an error.
baseSalarynoNoted as the budget.
totalJobOpeningsnoEngineers wanted, 1 to 20.
identifier / urlnoNoted. Two postings with the same title but different identifiers are two requests.
validThroughnoAn expired posting is declined.
applicationContact.namenoWho we greet. Its email, if given, must be the verified one.

3. Read the answer

201 Created
{
  "accepted": true,
  "already_submitted": false,
  "reference": "3f9c2a1b",
  "shortlist_status": "preview",
  "message": "Thanks Casey, here are your first matches. I'm sourcing a few more to round out your shortlist.",
  "first_matches": [
    {
      "position": 1,
      "headline": "Senior backend engineer",
      "top_skills": [
        "Python",
        "PostgreSQL"
      ]
    }
  ],
  "next_steps": [
    "A vetted shortlist within 72 hours goes to the verified work email. Profiles are blind until an agreement is signed."
  ],
  "warnings": [],
  "sol_app_url": "https://sol.ruzora.com/roles/…",
  "link_emailed": true
}

To meet anyone: pick who you want to meet, Roberto (founder) sets up a quick call, you sign the service agreement, and then interviews are scheduled with the engineers’ full identity.

Errors and limits

Every error is {"detail": {"code", "message", "docs", "next_step"}}. Validation errors list every field to fix in one response.

StatusCodeMeaning
201acceptedA new shortlist request.
200already_submittedThe same posting (same title and identifier, or the same skills when there is no identifier) came in during the last 30 minutes. Same reference and Sol link; it never counts toward, or is refused by, the daily limit.
400invalid_json / personal_emailBody is not JSON (or is nested too deeply), or the verified address is a personal inbox.
401buyer_token_missing / _invalid / _expired / _revokedVerify the work email again (next_step says how).
413payload_too_largeOver 64 KB.
422invalid_job_postingerrors[] names every field to fix and the next step for each.
429rate_limitedPer connection (20 an hour), per work email (5 new requests a day) or per email domain (20 a day). Retry-After is set.
202acceptedThe request was saved but part of the processing failed. Same answer shape, with a warning; nothing to retry.
500shortlist_failedThe request did not go through and the daily limit was not used. Retrying is safe: a retry within 30 minutes never creates a duplicate.
503verification_unavailableVerified actions are paused. Nothing was submitted.

More for agents

Canonical: https://www.ruzora.com/developers/feeds