Skip to main content
Looking for endpoint docs? Browse the v2 API Reference for every route. On Legacy API (v1)? See Legacy API (v1).
Legacy API (https://api.heymilo.network): the original HeyMilo HTTP surface, covering a handful of core actions around postings, ingestion, interviews, and webhooks. v2 API (https://api.heymilo.ai): a REST-first redesign that exposes the full workspace, returns consistent typed envelopes, and is recommended for all new integrations.

Key differences at a glance


Base URL

All v2 endpoints live under a single host and path prefix:

Production base URL

https://api.heymilo.ai/api/v2
The legacy API remains available at https://api.heymilo.network/api for backward compatibility during migration.

Authentication

All requests require an API key in the X-API-KEY header.
Why v2 auth is faster. v2 validates keys once per request and caches the validated result, keyed by a SHA-256 hash of the key. On a cache hit, auth adds sub-millisecond overhead. Failures are explicit and consistent: 401 for a missing key, 403 for invalid or revoked, 503 when the auth layer is unavailable.

Response envelopes

Every v2 response is one of two shapes (single resource or list), so your parsing code stays identical across endpoints.

Single resource

List resource

Object type discriminator

Every resource carries an object field identifying its type. This lets you write one handler that dispatches by object, and it makes logs and debuggers trivially readable.

Receipt pattern on creates

POST /api/v2/postings returns not just the new id and URLs but a full posting object nested under data.posting. Same for POST /api/v2/postings/{id}/candidates (full candidate under data.candidate). You can skip the redundant follow-up GET.

Errors

Every v2 error uses the same envelope:
The legacy API returned {"detail": "some string"}, sometimes a string, sometimes a nested framework tree on 422s. v2 always returns the same envelope, always includes a machine-readable type and code, and for 422s includes a flat errors[] list that maps 1:1 to offending fields (body.title, body.workflow[0].config.voice_id, and so on).

Pagination

List endpoints in v2 use cursor pagination. This is more resilient to concurrent writes than the page/offset model the legacy API used. Query parameters
  • limit: max page size, 1 to 100, default 20.
  • starting_after: the id of the last item from the previous page (use the id field of the last element in data[]).
Response pagination block
Paginate all postings
Stop when pagination.has_more is false. Why cursor beats offset
  • Stable under concurrent writes: new postings created during a paginated scan won’t cause you to skip or re-see items.
  • Constant-time regardless of how deep pagination goes.
  • Matches the convention used by every modern developer-facing API.

Metadata

Every first-class v2 resource (posting, candidate, interview) supports a typed metadata object you can use to stash your own identifiers (ATS IDs, external source tags, correlation IDs) without waiting for us to add a bespoke field.
Limits (enforced server-side)
  • Up to 50 keys per resource.
  • Each key ≤ 40 characters.
  • Each value ≤ 500 characters.
  • All values must be strings (send numbers and booleans as strings).
Set metadata
Get metadata
Delete metadata
Validation errors surface as structured 422 responses with param: "metadata.<key>" so your integration knows exactly which entry to fix.

Timestamps

Every v2 timestamp field is a Unix epoch float (seconds since 1970-01-01T00:00:00Z). Fields with null or pending states are null, never empty strings.
The legacy API mixed ISO strings ("2025-02-15T14:00:00Z"), epoch integers, and occasional nulls depending on the route. v2 normalises this across the surface.

Rate limiting

v2 rate limits per API key. The legacy API rate-limited per client IP, which penalised customers whose outbound traffic was NAT-ed behind a single egress (typical for server-to-server integrations).
  • Default window is configurable per environment; production limits are published in your workspace’s developer portal.
  • On exceed, v2 returns 429 with:
  • Retry with exponential backoff; honour Retry-After headers when present.

HTTP semantics

v2 follows the common REST conventions customers expect. Proxies, API gateways, and OpenAPI tooling all behave better when status codes and verbs are used correctly. 201 on creates, 202 on async, PATCH for partial updates, DELETE for deactivation: small changes, big quality-of-life improvement for anyone writing a client.

Resource coverage

v2 exposes the full workspace surface area, not just the handful of verbs the legacy API shipped. Every resource uses the envelopes, errors, pagination, and metadata conventions above. Highlights
  • Questions / criteria CRUD. Full create, read, update, delete, and reorder for every modality (voice, sms, form, resume_eligibility, resume_scoring, voice_tags). Build question-editing UIs entirely against the API.
  • Interview results hierarchy. GET /interviews/{id}/data returns a typed interview_data object with web_interview, resume, sms, and form sub-results populated for whichever agents the interviewer’s workflow includes. No more guessing which fields will be present.
  • Agentic workflow as a first-class object. Postings expose an ordered workflow: [WorkflowStep] array. Each step has id, type, order, and typed config. Candidate responses carry per-step progress (workflow.steps[]) and agent_summary (resume score, interview score, SMS eligibility, form status).
  • Schema discovery. GET /api/v2/schemas/agents returns the registry of supported agent types, their config fields, and which question modalities they support. GET /api/v2/schemas/question-types does the same for questions. This lets partners build dynamic UIs without hard-coding our product taxonomy.

Endpoint mapping (legacy → v2)

This is the mapping most integrations will reach for during migration. All legacy paths are relative to https://api.heymilo.network; all v2 paths are relative to https://api.heymilo.ai.

Postings (Interviewers)

Candidates & ingestion

Security improvement. v2 intentionally drops URL keys from paths. The legacy API required you to embed the ingestion URL key into every request URL (/api/ingest/x/{url_key}), which caused them to leak into proxy logs, browser referrers, and CDN caches. v2 scopes ingestion by posting ID, which is already authenticated by your API key.

Interviews

Webhooks

New in v2 (no legacy equivalent)

  • GET /api/v2/postings/{id}/questions, POST /api/v2/postings/{id}/questions, PATCH/DELETE .../questions/{qid}, POST .../questions/reorder: full question and criteria CRUD across all modalities.
  • GET /api/v2/voices, /phone-numbers, /sender-emails, /email-templates, /email-template-groups, /design-templates, /design-template-groups, /domains: workspace resource discovery.
  • GET /api/v2/schemas/agents, GET /api/v2/schemas/question-types: self-describing schema for building dynamic UIs.

Appendix: full v2 endpoint list

All paths are relative to https://api.heymilo.ai/api/v2.

Interviewers (/postings)

Candidates (/postings/{posting_id}/candidates)

Interviews (/interviews)

Questions (/postings/{posting_id}/questions)

Webhooks (/webhooks)

Workspace resources

Schema discovery