{
  "openapi": "3.1.0",
  "info": {
    "title": "api.careers",
    "version": "0.1.0",
    "description": "Staffing & talent placement as a payable machine face: O*NET-typed Candidate and Placement records, job orders, and the O*NET-SOC occupation vocabulary — anon sandbox floor, typed envelopes, agent-first (B2A) onboarding."
  },
  "servers": [
    {
      "url": "https://api.careers"
    }
  ],
  "paths": {
    "/placements": {
      "get": {
        "operationId": "listPlacements",
        "summary": "Placements — the branching typed collection (O*NET-typed, 90-day-validatable outcomes; labeled example seed)",
        "description": "The keyless, branching collection (AXP Clauses 4 + 7): plain GET answers 200 OK with substantive typed content to an anonymous caller; a non-matching filter answers 200 EMPTY; a reserved scope answers 403 BLOCKED. Collection member name: \"placements\".",
        "parameters": [
          {
            "name": "status",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "filter the collection by status; a non-matching value answers a typed 200 EMPTY, never a fake success"
          },
          {
            "name": "occupation",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "filter the collection by occupation; a non-matching value answers a typed 200 EMPTY, never a fake success"
          },
          {
            "name": "scope",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "reserved scopes (admin, internal) answer a typed 403 BLOCKED"
          },
          {
            "name": "spend",
            "in": "query",
            "required": false,
            "schema": {
              "type": "number"
            },
            "description": "requested spend in the same unit as hardCeiling (25); above the ceiling answers a typed 402 OFFER re-authorization boundary"
          }
        ],
        "responses": {
          "200": {
            "description": "OK or EMPTY envelope",
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/OkEnvelope"
                    },
                    {
                      "$ref": "#/components/schemas/EmptyEnvelope"
                    }
                  ]
                }
              }
            }
          },
          "402": {
            "description": "OFFER envelope — the hard-ceiling re-authorization boundary",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OfferEnvelope"
                }
              }
            }
          },
          "403": {
            "description": "BLOCKED envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BlockedEnvelope"
                }
              }
            }
          }
        }
      },
      "post": {
        "operationId": "createPlacement",
        "summary": "Record a placement — headless ATS door; keyless calls auto-mint an ephemeral sandbox workspace",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "candidateId",
                  "jobOrderId",
                  "onetCode"
                ],
                "properties": {
                  "candidateId": {
                    "type": "string"
                  },
                  "jobOrderId": {
                    "type": "string"
                  },
                  "onetCode": {
                    "type": "string"
                  },
                  "startDate": {
                    "type": "string"
                  },
                  "feeModel": {
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "OK envelope with the minted record and retention disclosure"
          },
          "400": {
            "description": "BLOCKED envelope — missing required members"
          }
        }
      }
    },
    "/pricing": {
      "get": {
        "operationId": "getPricing",
        "summary": "The Pricing Document (AXP Appendix A.2)",
        "description": "This API is metered with a hard ceiling of 25 (usd-per-month); the caller can never be metered past it without explicit re-authorization. This price is NOT bound by published terms: it is a stated intent, and the document says so in its `binding` and `statement` members. Budget against it; do not contract on it.",
        "responses": {
          "200": {
            "description": "the Pricing Document",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PricingDocument"
                }
              }
            }
          }
        }
      }
    },
    "/family.json": {
      "get": {
        "operationId": "getFamilyRegistry",
        "summary": "The family registry — sibling properties and their seams as typed edges",
        "description": "Lists the sibling doors of this property's family so an agent at this door discovers the others as contracts, not links.",
        "responses": {
          "200": {
            "description": "the family registry",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        }
      }
    },
    "/offer": {
      "get": {
        "operationId": "getOffer",
        "summary": "The offer boundary (AXP Appendix A.5)",
        "description": "Always answers 402 with a typed OFFER body — the machine-readable start of the paid conversation.",
        "responses": {
          "402": {
            "description": "OFFER envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OfferEnvelope"
                }
              }
            }
          }
        }
      }
    },
    "/placements/{id}": {
      "get": {
        "operationId": "getPlacement",
        "summary": "Get one placement (typed envelope; 404 EMPTY when the id was never minted)",
        "parameters": [
          {
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "name": "id",
            "description": "the record id"
          }
        ],
        "responses": {
          "200": {
            "description": "OK envelope with the record (references resolved as links)"
          },
          "404": {
            "description": "EMPTY envelope — no such record"
          }
        }
      }
    },
    "/candidates": {
      "get": {
        "operationId": "listCandidates",
        "summary": "List candidates (O*NET-typed skills; labeled example seed + your workspace records)",
        "parameters": [
          {
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "name": "status",
            "description": "filter by status; a non-matching value answers a typed 200 EMPTY"
          },
          {
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "name": "occupation",
            "description": "filter by occupation; a non-matching value answers a typed 200 EMPTY"
          }
        ],
        "responses": {
          "200": {
            "description": "OK or EMPTY envelope"
          }
        }
      },
      "post": {
        "operationId": "createCandidate",
        "summary": "Create a candidate — headless ATS door; keyless calls auto-mint an ephemeral sandbox workspace",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "name",
                  "onetCode"
                ],
                "properties": {
                  "name": {
                    "type": "string"
                  },
                  "onetCode": {
                    "type": "string"
                  },
                  "skills": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    }
                  },
                  "metro": {
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "OK envelope with the minted record and retention disclosure"
          },
          "400": {
            "description": "BLOCKED envelope — missing required members"
          }
        }
      }
    },
    "/candidates/{id}": {
      "get": {
        "operationId": "getCandidate",
        "summary": "Get one candidate",
        "parameters": [
          {
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "name": "id",
            "description": "the record id"
          }
        ],
        "responses": {
          "200": {
            "description": "OK envelope with the record"
          },
          "404": {
            "description": "EMPTY envelope — no such record"
          }
        }
      }
    },
    "/job-orders": {
      "get": {
        "operationId": "listJobOrders",
        "summary": "List job orders",
        "parameters": [
          {
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "name": "status",
            "description": "filter by status; a non-matching value answers a typed 200 EMPTY"
          },
          {
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "name": "occupation",
            "description": "filter by occupation; a non-matching value answers a typed 200 EMPTY"
          }
        ],
        "responses": {
          "200": {
            "description": "OK or EMPTY envelope"
          }
        }
      },
      "post": {
        "operationId": "createJobOrder",
        "summary": "Create a job order — headless ATS door; keyless calls auto-mint an ephemeral sandbox workspace",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "client",
                  "title",
                  "onetCode"
                ],
                "properties": {
                  "client": {
                    "type": "string"
                  },
                  "title": {
                    "type": "string"
                  },
                  "onetCode": {
                    "type": "string"
                  },
                  "billRateUsdHour": {
                    "type": "number"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "OK envelope with the minted record and retention disclosure"
          },
          "400": {
            "description": "BLOCKED envelope — missing required members"
          }
        }
      }
    },
    "/job-orders/{id}": {
      "get": {
        "operationId": "getJobOrder",
        "summary": "Get one job order",
        "parameters": [
          {
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "name": "id",
            "description": "the record id"
          }
        ],
        "responses": {
          "200": {
            "description": "OK envelope with the record"
          },
          "404": {
            "description": "EMPTY envelope — no such record"
          }
        }
      }
    },
    "/occupations": {
      "get": {
        "operationId": "listOccupations",
        "summary": "List the O*NET-SOC occupation vocabulary excerpt — real G1 reference data (U.S. DOL, CC BY 4.0)",
        "responses": {
          "200": {
            "description": "OK or EMPTY envelope"
          }
        }
      }
    },
    "/occupations/{id}": {
      "get": {
        "operationId": "getOccupation",
        "summary": "Get one O*NET-SOC occupation by code",
        "parameters": [
          {
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "name": "id",
            "description": "the record id"
          }
        ],
        "responses": {
          "200": {
            "description": "OK envelope with the record"
          },
          "404": {
            "description": "EMPTY envelope — no such record"
          }
        }
      }
    },
    "/icp.json": {
      "get": {
        "operationId": "getIcp",
        "summary": "G2 coordinates: ICP (CompanyType × JobTypes), personas, and the System coordinate this substrate serves",
        "responses": {
          "200": {
            "description": "OK"
          }
        }
      }
    },
    "/verify": {
      "get": {
        "operationId": "getVerify",
        "summary": "The published runnable suites for this property — the /verify export",
        "responses": {
          "200": {
            "description": "OK"
          }
        }
      }
    },
    "/projection.json": {
      "get": {
        "operationId": "getProjection",
        "summary": "this projection's G4 coordinates (hostname, substrate, brand, account/payments pointers)",
        "responses": {
          "200": {
            "description": "OK"
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "OkEnvelope": {
        "type": "object",
        "required": [
          "type"
        ],
        "properties": {
          "type": {
            "const": "OK"
          }
        },
        "description": "200 — substantive content. The collection member name (results/items/events…) is this API's own choice, documented on the operation."
      },
      "EmptyEnvelope": {
        "type": "object",
        "required": [
          "type",
          "message"
        ],
        "properties": {
          "type": {
            "const": "EMPTY"
          },
          "message": {
            "type": "string"
          }
        },
        "description": "200 — a truthful empty collection, never a bare [] masquerading as data."
      },
      "BlockedEnvelope": {
        "type": "object",
        "required": [
          "type",
          "reason"
        ],
        "properties": {
          "type": {
            "const": "BLOCKED"
          },
          "reason": {
            "type": "string"
          }
        },
        "description": "401/403 — a permission boundary with a worded reason."
      },
      "OfferEnvelope": {
        "type": "object",
        "required": [
          "type"
        ],
        "properties": {
          "type": {
            "const": "OFFER"
          },
          "id": {
            "type": "string"
          },
          "title": {
            "type": "string"
          },
          "price": {},
          "checkoutUrl": {
            "type": "string"
          },
          "alternatives": {
            "type": "array"
          }
        },
        "description": "402 — a payment or ceiling re-authorization boundary; an offer to proceed, never a refusal."
      },
      "PricingDocument": {
        "type": "object",
        "required": [
          "model"
        ],
        "properties": {
          "model": {
            "enum": [
              "free",
              "metered"
            ]
          },
          "hardCeiling": {
            "type": "number",
            "exclusiveMinimum": 0
          },
          "unit": {
            "type": "string"
          },
          "price": {
            "type": "number"
          },
          "rates": {
            "type": "array",
            "items": {
              "type": "object",
              "required": [
                "operation"
              ],
              "properties": {
                "operation": {
                  "type": "string",
                  "description": "The canonical camelCase-verb operationId this rate keys on (axp-ext/rates-g2 §1) — the ONE cross-face operation name: OpenAPI operationId = MCP tool name = suite coverage reference = SDK method name = this key."
                },
                "price": {
                  "description": "Scalar amount >= 0, or a §2 price object: compound {fixed?, percent?, basis, cap?, floor?, min_fee?} (A1, ad-valorem), {passthrough: {provider, reference?, markup?}} (A2, third-party-owned price plus markup), or {discovery: 'market', reference?, buyer_cap?} (A2, auction/spot). Absent or null ONLY under a non-published `disclosure` (A8).",
                  "oneOf": [
                    {
                      "type": "number",
                      "minimum": 0
                    },
                    {
                      "type": "object"
                    },
                    {
                      "type": "null"
                    }
                  ]
                },
                "unit": {
                  "type": "string"
                },
                "included": {
                  "description": "A5 — the allowance: quantity, \"unlimited\", or {qty, period: \"day\"|\"month\"|\"once\", rollover?, at_limit?}. `freeQuota` is the legacy shorthand for {qty, period: \"month\"} — never both."
                },
                "freeQuota": {
                  "type": "number",
                  "exclusiveMinimum": 0
                },
                "modifiers": {
                  "type": "array",
                  "description": "A3 — relative/derived pricing: [{op: 'multiply'|'add', value, scope?: 'rate'|'offer'|'card', condition?: {attribute, op?, value?}, stacking_order?}]. See also `derived_from`."
                },
                "derived_from": {
                  "type": "string",
                  "description": "A3 — the rate-card row this row's price derives from (an operationId on this same card)."
                },
                "meter": {
                  "type": "object",
                  "description": "G3 lite — {aggregation: 'sum'|'distinct'|'high-watermark'|'gauge'|'peak', basis?: 'consumed'|'provisioned'|'standing', reset_period?, definition_url?}: how the billable unit aggregates, so identical-looking rows cannot mean bills 10x apart."
                },
                "volume_breaks": {
                  "type": "object",
                  "description": "A7 — {mode: 'graduated'|'retroactive'|'reprice-offer' (REQUIRED), basis?: 'units'|'spend'|'instantaneous-rate', breaks: [{from, price|discount_percent}], formula_url?, approximate?}."
                },
                "disclosure": {
                  "enum": [
                    "published",
                    "calculator-only",
                    "quote-only",
                    "undisclosed"
                  ],
                  "description": "A8 — a meter may exist with its price withheld; 'priced on request' is distinguishable from 'no such meter'. Price may be absent/null only when this is present and not 'published'."
                },
                "estimate": {
                  "type": "object",
                  "description": "A8 — {low, high, provenance?}: third-party estimate, legal only under a withheld disclosure."
                },
                "note": {
                  "type": "string"
                }
              }
            },
            "description": "axp-ext/rates-g2 §2 — the operationId-keyed operation rate card, TOP-LEVEL in the Pricing Document. Additive and descriptive: `model` and `hardCeiling` keep answering Appendix A.2; every row names an operation this origin's own contract declares. Offer-level A4/A5 members (spend_cap, pooled allowances[]) ride monetization.offers. Deferred-amendment names (credits, base_fee, minimum, relations, entitlements, keys, payment, direction, recurrence, effective, eligibility, currencies) are RESERVED."
          },
          "binding": {
            "type": "boolean",
            "description": "Whether published terms bind this price. `model` answers what it costs; `binding` answers whether you can hold us to it. Absent means not declared — never assume bound."
          },
          "statement": {
            "type": "string",
            "description": "Present when binding is false: the stated intent, in the same words the human pages use."
          },
          "termsUrl": {
            "type": "string",
            "description": "Present when binding is true: the terms document that binds this price."
          },
          "ledgerUrl": {
            "type": "string",
            "description": "Where the open item to bind this price is tracked."
          }
        },
        "description": "AXP Appendix A.2 — closed model \"free\" | \"metered\"; hardCeiling required and > 0 when metered. `binding` is a descriptive member on an axis orthogonal to `model`: binding: true carries termsUrl, binding: false carries statement."
      }
    }
  }
}