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 use single or any proof policy.
  • /get, /verify, and /consume require a current armed challenge with the requested kind.
  • /send requires 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.