Skip to content

Mailbox challenges

Passlock exposes mailbox challenge endpoints for email one-time code flows such as signup verification, passwordless login, and email-change verification.

HTTP Request
POST https://api.passlock.dev/v2/{tenancyId}/challenges HTTP/1.1
Authorization: Bearer {apiKey}
Accept: application/json
Content-Type: application/json
{
"email": "jdoe@example.com",
"name": "Jane Doe",
"purpose": "signup",
"userId": "user_123",
"metadata": {
"signupId": "signup_123"
},
"invalidateOthers": true,
"skipRateLimit": false,
"sendEmail": true
}
HTTP Response
HTTP/1.1 201 Created
Content-Type: application/json
{
"_tag": "ChallengeCreated",
"challenge": {
"challengeId": "abc123def456ghi",
"purpose": "signup",
"email": "jdoe@example.com",
"userId": "user_123",
"createdAt": 1710000000000,
"expiresAt": 1710000600000,
"metadata": {
"signupId": "signup_123"
},
"secret": "ABC123def-GHI456jkl-MNO789pqr",
"code": "123456",
"message": {
"html": "<html><body><p>Your Passlock code is <strong>123456</strong>.</p></body></html>",
"text": "Your Passlock code is 123456."
}
}
}

Create success returns the raw code plus a rendered message object with html and text content. Pass sendEmail: true to have Passlock send the email. To send it yourself, omit sendEmail or pass false, then email the rendered content directly or use code to build your own template.

Create requests require email and purpose. They can also include name, userId, metadata, invalidateOthers, skipRateLimit, and sendEmail. The readable challenge returned by create, get, and verify includes userId when one was supplied and always includes metadata, using null when no metadata was supplied.

  • 429 @error/ChallengeRateLimited with Retry-After and retryAfterSeconds
  • 403 @error/Forbidden
HTTP Request
GET https://api.passlock.dev/v2/{tenancyId}/challenges/{challengeId} HTTP/1.1
Authorization: Bearer {apiKey}
Accept: application/json
HTTP Response
HTTP/1.1 200 OK
Content-Type: application/json
{
"_tag": "Challenge",
"challengeId": "abc123def456ghi",
"purpose": "signup",
"email": "jdoe@example.com",
"userId": "user_123",
"createdAt": 1710000000000,
"expiresAt": 1710000600000,
"metadata": {
"signupId": "signup_123"
}
}
  • 404 @error/NotFound
  • 403 @error/Forbidden
HTTP Request
POST https://api.passlock.dev/v2/{tenancyId}/challenges/verify HTTP/1.1
Authorization: Bearer {apiKey}
Accept: application/json
Content-Type: application/json
{
"challengeId": "abc123def456ghi",
"secret": "ABC123def-GHI456jkl-MNO789pqr",
"code": "123456"
}
HTTP Response
HTTP/1.1 200 OK
Content-Type: application/json
{
"_tag": "ChallengeVerified",
"challenge": {
"_tag": "Challenge",
"challengeId": "abc123def456ghi",
"purpose": "signup",
"email": "jdoe@example.com",
"userId": "user_123",
"createdAt": 1710000000000,
"expiresAt": 1710000600000,
"metadata": {
"signupId": "signup_123"
}
}
}

Verification success returns a readable nested challenge. The secret and one-time code are not returned.

  • 400 @error/InvalidChallenge
  • 400 @error/InvalidChallengeCode
  • 400 @error/ChallengeExpired
  • 400 @error/ChallengeAttemptsExceeded
  • 403 @error/Forbidden
HTTP Request
DELETE https://api.passlock.dev/v2/{tenancyId}/challenges/{challengeId} HTTP/1.1
Authorization: Bearer {apiKey}
Accept: application/json
Response
HTTP/1.1 202 Accepted
Content-Type: application/json
{
"_tag": "ChallengeDeleted"
}
  • 403 @error/Forbidden