https://api.certo.bio/v1openapi.json

Ask to read a passport

POST/v1/access-requestsscope hiring:ask

Asks the holder of a published passport to let the organisation read it, by its public address. One credit is held (none for a subscribed or sponsored passport) and comes back if they decline or nobody answers in 30 days. Owners, admins and recruiters. Requires an Idempotency-Key; try it first with ?dry_run=true.

As an MCP tool: ask_to_read_passport

Query parameters

NameTypeDescription
dry_runbooleantrue: the same checks and the same answer per row, and the credits it would take; nothing is written, sent or spent.

Request body

NameTypeRequiredDescription
passportstringYesThe passport's public address: certo.bio/<address>, https://certo.bio/<address> or <address>.
scope_typesarray of one of employment, education, certification, role, language, right_to_work or nullWhat the candidate is asked to share: record types, or null (or every one) for all of them.
include_contactbooleanAsk for their contact details too.
include_birth_datebooleanAsk for their date of birth too (with birth_date_reason).
birth_date_reasonstring or nullWhy the date of birth is needed, 3 to 280 characters; required with include_birth_date. The candidate reads it.
requirementsobject or nullWhat the candidate must have ready, docs/request-requirements.md: {"v": 1, "work_years", "education_min_level", "certifications", "right_to_work", "contact"}; null for the defaults.
notestring or nullWhy you ask, at most 280 characters: the holder reads it.
position_iduuid or nullAn open position of the organisation it is for.
custom_dataobject or nullYour own data on the ask: any JSON object (an id from your ATS or HR system, a requisition number), at most 4096 bytes. certo stores it and answers it back on the reads and in your webhook events; it never reads it, and the candidate never sees it. The holder never sees it.

Response fields

dry_run
boolean. Whether this was a dry run.
access_request
object. The ask (would be made, in a dry run).
access_request.id
uuid or null. The ask's id; null in a dry run (nothing was made).
access_request.passport_url
string. The passport asked about.
access_request.status
one of open. open once made.
access_request.funding
one of credit, free. credit: one credit held, back if it is not approved; free: the passport is subscribed or sponsored and reading it costs nothing.
access_request.position_id
uuid or null. The position it is under.
access_request.custom_data
object or null. Your own data on the ask, as you sent it; null for none.
access_request.expires_at
string or null. When it expires unanswered (30 days); null in a dry run.
credits
object. The credits.
credits.needed
integer. Credits the rows to send take: one per new invitation (or graduate), none for already.
credits.spent
integer. Credits spent now (0 in a dry run).
credits.balance
integer. The balance after the call (before it, in a dry run).

Errors

  • 400 access_request.passport_invalid
  • 404 access_request.not_askable
  • 409 access_request.own_passport
  • 409 access_request.already_open
  • 409 access_request.already_granted
  • 400 access_request.scope_invalid
  • 400 access_request.reason_too_long
  • 400 access_request.birth_date_reason_required
  • 400 company_request.requirements_invalid
  • 409 organisation.profile_incomplete
  • 409 position.closed_or_missing
  • 402 credit.none_left
  • 400 request.unknown_field
  • 400 api.idempotency_key_required
  • 409 api.idempotency_mismatch
  • 409 api.idempotency_in_progress
  • 400 api.credential_in_url
  • 401 api.key_invalid
  • 401 api.key_expired
  • 401 api.key_revoked
  • 401 api.key_suspended
  • 403 api.scope_missing
  • 429 api.rate_limited