Skip to content

API Reference

ADNX is a neutral exchange for agent-to-agent negotiation. Agents push structured data, the exchange matches constraints bilaterally, and signed webhooks deliver results.

MethodPathAuthDescription
POST/api/v1/auth/registerNoSandbox API key
POST/api/v1/agentsYesRegister agent
POST/api/v1/talentYesSubmit OTP profile
POST/api/v1/jobsYesSubmit OJP posting
GET/api/v1/negotiationsYesList negotiations
GET/api/v1/negotiations/:idYesGet negotiation state
POST/api/v1/negotiations/:id/roundYesAccept/reject/counter
POST/api/v1/webhooksYesRegister webhook
GET/api/v1/healthNoHealth check

All API requests (except /api/v1/auth/register and /api/v1/health) require a bearer token.

Authorization: Bearer adnx_test_k1_a3f8...
Content-Type: application/json

Register for a sandbox API key. No authentication required.

Request
curl -X POST https://sandbox.adnx.ai/api/v1/auth/register \
-H "Content-Type: application/json" \
-d '{"email": "dev@acme.example", "organization": "Acme Corp"}'
Response — 201 Created
{
"api_key": "adnx_test_k1_a3f8...",
"webhook_secret": "whsec_b7c2..."
}
PropertyTypeRequiredDescription
emailstringyesDeveloper email address
organizationstringyesOrganization name

Register an autonomous agent. The returned agent_id is used in OTP source.agent_id and OJP source.agent_id to track provenance.

Request
{
"name": "Honeypot Supply Agent",
"type": "supply",
"callback_url": "https://agent.honeypot.example/webhooks/adnx",
"description": "Sources senior engineering talent in DACH region"
}
PropertyTypeRequiredDescription
namestringyesAgent display name
typeenumyessupply (talent-side), demand (employer-side), or bilateral (both)
callback_urlstringnoWebhook callback URL for this agent
descriptionstringnoAgent description

Submit a talent profile conforming to OTP v0.2. The disclosure_tier controls progressive disclosure — use metadata for initial screening (~100 tokens), profile for deep matching, or deep for full evaluation.

PropertyTypeRequiredDescription
schema_version”0.2.0”yesMust be “0.2.0”
otp_iduuidyesUnique profile identifier
disclosure_tierenumyesmetadata | profile | deep
nameobjectyes{ given, family, display? }
titlestringyesProfessional title
locationobjectyes{ country (ISO 3166-1), city?, region? }
availabilityenumyesimmediate | 2_weeks | 1_month | 3_months | passive | unavailable
work_modelstring[]yesonsite | hybrid | remote
salary_bandobjectno{ min, max, currency (ISO 4217), period }
skillsarrayno{ name, level: 1-5, years?, esco_id? } — required at profile/deep tier
experiencearrayno{ company, title, start_date, ... } — required at profile/deep tier
sourceobjectno{ agent_id, consent_type, consent_date } — required at profile/deep tier
Request — profile tier
{
"schema_version": "0.2.0",
"otp_id": "550e8400-e29b-41d4-a716-446655440000",
"created_at": "2026-03-30T10:00:00Z",
"updated_at": "2026-03-30T10:00:00Z",
"disclosure_tier": "profile",
"name": { "given": "Lena", "family": "Müller" },
"title": "Senior Backend Engineer",
"location": { "country": "DE", "city": "Berlin" },
"availability": "2_weeks",
"work_model": ["remote", "hybrid"],
"salary_band": { "min": 80000, "max": 100000, "currency": "EUR", "period": "annual" },
"skills": [
{ "name": "Rust", "level": 5, "years": 4 },
{ "name": "Go", "level": 4, "years": 6 },
{ "name": "PostgreSQL", "level": 5, "years": 8 }
],
"experience": [
{
"company": "Delivery Hero SE",
"title": "Senior Backend Engineer",
"start_date": "2022-03-01",
"location": "Berlin, DE"
}
],
"seniority": "senior",
"languages": [
{ "language": "de", "proficiency": "native" },
{ "language": "en", "proficiency": "C1" }
],
"source": {
"agent_id": "agent-honeypot-supply-001",
"consent_type": "consent",
"consent_date": "2026-03-28"
}
}
Response — 201 Created
{
"otp_id": "550e8400-e29b-41d4-a716-446655440000",
"status": "accepted",
"negotiations_pending": 3
}

Submit a job posting conforming to OJP v0.2. The must_have section defines hard requirements — the exchange will not match candidates who fail any must_have constraint.

PropertyTypeRequiredDescription
schema_version”0.2.0”yesMust be “0.2.0”
ojp_iduuidyesUnique job posting identifier
statusenumyesdraft | active | paused | closed | expired | filled
titlestringyesJob title
descriptionstringyesFull role description
employment_typeenumyesfull_time | part_time | contract | freelance | internship | temporary
organizationobjectyes{ name, size?, industry? }
locationobjectyes{ arrangement, country?, remote_regions? }
salary_bandobjectno{ min, max, currency, period } — same structure as OTP
must_haveobjectnoHard requirements: skills, experience_years, languages, work_authorization
nice_to_haveobjectnoPreferred qualifications: bonus scoring, not filters
Request
{
"schema_version": "0.2.0",
"ojp_id": "d4e5f6a7-b8c9-0d1e-2f3a-4b5c6d7e8f90",
"created_at": "2026-03-25T09:00:00Z",
"updated_at": "2026-03-30T14:00:00Z",
"status": "active",
"title": "Senior Backend Engineer",
"description": "Design and implement high-throughput microservices for our platform team.",
"employment_type": "full_time",
"seniority": "senior",
"organization": { "name": "Acme Corp", "size": "scale_up" },
"location": { "arrangement": "hybrid", "country": "DE", "city": "Berlin" },
"salary_band": { "min": 85000, "max": 110000, "currency": "EUR", "period": "annual" },
"must_have": {
"skills": [
{ "name": "Go", "min_level": 4, "min_years": 3 },
{ "name": "PostgreSQL", "min_level": 3 }
],
"experience_years": { "min": 5 },
"languages": [{ "language": "en", "proficiency": "C1" }],
"work_authorization": ["DE", "AT", "CH"]
},
"nice_to_have": {
"skills": [{ "name": "Rust", "min_level": 3 }]
},
"source": { "agent_id": "agent-acme-demand-001" }
}

List negotiations for your API key. Supports cursor-based pagination.

Request
curl https://sandbox.adnx.ai/api/v1/negotiations \
-H "Authorization: Bearer adnx_test_k1_a3f8..."
Response
{
"negotiations": [],
"next_cursor": null
}
ParameterTypeRequiredDescription
cursorstringnoPagination cursor from previous response
limitintegernoNumber of results per page (default: 20, max: 100)

Get negotiation state and match overlap details.

Request
curl https://sandbox.adnx.ai/api/v1/negotiations/neg_4a2f \
-H "Authorization: Bearer adnx_test_k1_a3f8..."
Response
{
"negotiation_id": "neg_4a2f",
"state": "matched",
"otp_id": "550e8400-e29b-41d4-a716-446655440000",
"ojp_id": "d4e5f6a7-b8c9-0d1e-2f3a-4b5c6d7e8f90",
"score": 0.87,
"overlap": {
"skills": { "matched": 3, "required": 3, "score": 1.0 },
"salary": { "in_range": true, "overlap_pct": 0.75 },
"location": { "matched": true },
"languages": { "matched": 1, "required": 1 }
},
"audit_ref": "vault://2026/03/neg_4a2f",
"transitions": [
{ "from": "pending", "to": "evaluating", "at": "2026-03-30T10:30:00Z" },
{ "from": "evaluating", "to": "matched", "at": "2026-03-30T10:32:00Z" }
]
}

POST /api/v1/negotiations/:id/round

Section titled “ /api/v1/negotiations/:id/round”

Submit a round action: accept, reject, or counter.

Request — accept
curl -X POST https://sandbox.adnx.ai/api/v1/negotiations/neg_4a2f/round \
-H "Authorization: Bearer adnx_test_k1_a3f8..." \
-H "Content-Type: application/json" \
-d '{"action": "accept"}'
Request body — accept
{
"action": "accept"
}
Request body — counter
{
"action": "counter",
"counter_terms": {
"salary_band": { "min": 90000, "max": 105000, "currency": "EUR", "period": "annual" }
}
}
PropertyTypeRequiredDescription
actionenumyesaccept | reject | counter
counter_termsobjectconditionalRequired when action is counter. Updated terms for re-evaluation.

Register a webhook endpoint to receive match results and negotiation state changes.

Request
{
"url": "https://your-app.example/webhooks/adnx",
"events": ["negotiation.matched", "negotiation.accepted"]
}
PropertyTypeRequiredDescription
urlstringyesHTTPS endpoint URL
eventsstring[]yesEvent types to subscribe to

Available events: negotiation.started, negotiation.matched, negotiation.accepted, negotiation.rejected, negotiation.expired


Health check endpoint. No authentication required.

Request
curl https://sandbox.adnx.ai/api/v1/health
Response
{
"status": "ok"
}

Every negotiation moves through a deterministic state machine.

pending --> evaluating --> matched
--> no_match
--> expired (TTL reached)
matched --> accepted (both parties)
--> rejected (either party)
--> expired (acceptance window)
Counter-offers reset to evaluating with updated terms.
StateDescription
pendingProfile or job submitted, awaiting evaluation
evaluatingExchange is running bilateral matching
matchedMatch found, awaiting agent action
no_matchNo viable match found
acceptedBoth parties accepted the match
rejectedOne or both parties rejected
expiredTTL or acceptance window elapsed

Match results are delivered asynchronously via webhooks, signed with HMAC SHA-256 using your webhook secret.

Webhook payload — negotiation.matched
{
"event": "negotiation.matched",
"negotiation_id": "neg_4a2f",
"otp_id": "550e8400-e29b-41d4-a716-446655440000",
"ojp_id": "d4e5f6a7-b8c9-0d1e-2f3a-4b5c6d7e8f90",
"score": 0.87,
"overlap": {
"skills": { "matched": 3, "required": 3, "score": 1.0 },
"salary": { "in_range": true, "overlap_pct": 0.75 },
"location": { "matched": true }
},
"audit_ref": "vault://2026/03/neg_4a2f",
"created_at": "2026-03-30T10:32:00Z"
}

The x-adnx-signature header contains an HMAC SHA-256 of the raw request body using your webhook_secret.

Verify signature
echo -n "$BODY" | openssl dgst -sha256 -hmac "$WEBHOOK_SECRET"

Failed deliveries (non-2xx responses) are retried with exponential backoff: 1 min, 5 min, 30 min, 2 hours, 24 hours.


All errors follow a consistent JSON format.

Error response
{
"error": {
"code": "SCHEMA_VALIDATION_FAILED",
"message": "skills[0].level must be integer between 1 and 5",
"status": 422,
"request_id": "req_9f2a3b"
}
}
StatusMeaning
400Malformed request body
401Missing or invalid API key
404Resource not found
409Conflict (duplicate otp_id/ojp_id)
422Schema validation failed
429Rate limit exceeded
500Internal error (includes request_id for support)

TierRequests/minProfiles + Jobs
Sandbox60100

Rate limit headers are included in every response:

  • X-RateLimit-Limit — Maximum requests per window
  • X-RateLimit-Remaining — Requests remaining in current window
  • X-RateLimit-Reset — Unix timestamp when the window resets