Proof
Proof routes let a recipient inspect, resend, verify, and consume the email challenge for an active job. Create and activate the job first; see Jobs.
Authentication
These routes do not require a bearer token. Each call requires an active proof job ID, supplied as job or its alias job_id. Treat the job ID and the delivered secret as sensitive workflow values.
Only jobs with proof_policy single or any are eligible. Email is the supported proof delivery channel.
Routes
| Route | Required fields | Optional fields and behavior |
|---|---|---|
POST /v1/proof/get |
job or job_id |
kind: code (default) or token. Returns the currently armed proof state without sending a new challenge. |
POST /v1/proof/send |
job or job_id, method_id |
kind: code (default) or token. Sends a new challenge to an eligible email method; the updated proof state is data.item.item. |
POST /v1/proof/verify |
job or job_id, secret |
code and token are accepted aliases for secret; kind selects code or token. Verifies without completing the job. |
POST /v1/proof/consume |
job or job_id, secret |
code and token are accepted aliases for secret; kind selects code or token. Completes the proof and job. |
kind accepts code or token. When omitted it defaults to code, except a supplied token value selects the token kind.
Read the current proof state
Use /v1/proof/get after job activation. It returns the currently armed challenge without changing it.
curl -sS https://api.post.m7.org/v1/proof/get \
-H 'Content-Type: application/json' \
-d '{ "job": "JOB_UUID" }'
{
"status": 1,
"comment": "OK",
"data": {
"item": {
"job": {
"id": "JOB_UUID",
"purpose": "Confirm an email address",
"proof_policy": "single",
"status": "active"
},
"methods": [
{
"id": "METHOD_UUID",
"type": "email",
"masked": "r***@example.test",
"status": "active",
"priority": 0,
"current": true
}
],
"method": {
"id": "METHOD_UUID",
"type": "email",
"masked": "r***@example.test",
"status": "active",
"verified_at": null,
"last_used_at": null
},
"challenge": {
"id": "CHALLENGE_UUID",
"kind": "code",
"type": "email",
"status": "active",
"expires_at": "2030-01-01 00:00:00",
"verified_at": null,
"consumed_at": null
},
"issued": false,
"delivery": null
}
}
}
Use methods to offer eligible email destinations without exposing the full address. method is the current challenge destination. The recipient must complete the flow before challenge.expires_at.
Send a new challenge
Use /v1/proof/send to resend to an eligible email method. method_id must be an ID from data.item.methods for the same job.
curl -sS https://api.post.m7.org/v1/proof/send \
-H 'Content-Type: application/json' \
-d '{
"job_id": "JOB_UUID",
"method_id": "METHOD_UUID"
}'
The response places the updated proof state at data.item.item, with issued: true. data.item also contains armed, delivery, request, and credential records. Use the nested proof state as the integration contract. A new send revokes the prior active challenge and makes the selected method current. Do not send a preselected secret, code, or token to this route.
Verify a proof
/v1/proof/verify validates the secret but does not complete the job or consume the challenge. Use it only when the caller needs a separate confirmation step.
curl -sS https://api.post.m7.org/v1/proof/verify \
-H 'Content-Type: application/json' \
-d '{
"job": "JOB_UUID",
"secret": "DELIVERED_CODE"
}'
The response returns data.item in the proof-state shape with verified: true. The job remains active and the challenge remains available for /consume.
Consume a proof
/v1/proof/consume validates the secret, consumes the current challenge, marks its email method verified, and completes the job.
curl -sS https://api.post.m7.org/v1/proof/consume \
-H 'Content-Type: application/json' \
-d '{
"job": "JOB_UUID",
"secret": "DELIVERED_CODE"
}'
{
"status": 1,
"comment": "OK",
"data": {
"item": {
"job": {
"id": "JOB_UUID",
"status": "completed"
},
"method": {
"id": "METHOD_UUID",
"status": "verified"
},
"challenge": {
"id": "CHALLENGE_UUID",
"status": "consumed"
},
"consumed": true,
"verified": true
}
}
}
After a successful consume, sibling active credentials for the job are revoked. A later proof call cannot reuse the consumed or revoked challenge.
Errors and state
- The job must exist, be
active, and usesingleoranyproof policy. /get,/verify, and/consumerequire a current armed challenge with the requestedkind./sendrequires an active or verified email method that belongs to the job and has a matching message template.- An expired, consumed, revoked, or inactive challenge is no longer armed and cannot be used. An incorrect credential cannot complete the proof.