OTP API

The OTP API allows you to request, check status, and consume one-time verification codes securely.

Endpoints

  • POST /v1/otp/request - Request a new OTP
  • GET /v1/otp/:id - Get OTP request status
  • POST /v1/otp/:id/consume - Consume the OTP
  • DELETE /v1/otp/:id - Cancel the request

Request OTP

Request a new OTP for verification purposes.

Request

POST /v1/otp/request
Content-Type: application/json
Authorization: Bearer ak_live_xxxx

Body Parameters

FieldTypeRequiredDescription
reasonstringYesWhy the agent needs this OTP
publicKeystringYesAgent's RSA public key for E2E encryption
expectedSenderstringNoHint for expected sender (e.g., "Google", "GitHub")
filterobjectNoSource and sender filters
ttlnumberNoRequest TTL in seconds (default: 300, max: 3600)

Filter Object

FieldTypeDescription
sourcesstring[]OTP sources: "sms", "email", "whatsapp"
senderPatternstringGlob pattern for sender (e.g., "*@acme.com")

Example Request

{
  "reason": "Sign up verification for Acme Inc",
  "publicKey": "MIIBIjANBgkqhkiG9w...",
  "expectedSender": "Acme",
  "filter": {
    "sources": ["email"],
    "senderPattern": "*@acme.com"
  },
  "ttl": 300
}

Response

Pending Approval (202 Accepted)

{
  "id": "otp_xxxxxxxxxxxx",
  "status": "pending_approval",
  "reason": "Sign up verification for Acme Inc",
  "expiresAt": "2026-01-28T12:05:00Z",
  "createdAt": "2026-01-28T12:00:00Z"
}

Approved (200 OK)

{
  "id": "otp_xxxxxxxxxxxx",
  "status": "approved",
  "reason": "Sign up verification for Acme Inc",
  "expiresAt": "2026-01-28T12:05:00Z",
  "createdAt": "2026-01-28T12:00:00Z"
}

Denied (403 Forbidden)

{
  "id": "otp_xxxxxxxxxxxx",
  "status": "denied",
  "reason": "User denied the request"
}

Get OTP Status

Check the current status of an OTP request.

Request

GET /v1/otp/:id
Authorization: Bearer ak_live_xxxx

Response

{
  "id": "otp_xxxxxxxxxxxx",
  "status": "otp_received",
  "reason": "Sign up verification for Acme Inc",
  "source": "email",
  "sender": "noreply@acme.com",
  "expiresAt": "2026-01-28T12:05:00Z",
  "createdAt": "2026-01-28T12:00:00Z",
  "receivedAt": "2026-01-28T12:01:30Z"
}

Status Values

StatusDescription
pending_approvalWaiting for user to approve the request
approvedUser approved, waiting for OTP to arrive
otp_receivedOTP captured and ready to consume
consumedOTP has been read and deleted
deniedUser denied the request
expiredRequest expired before completion
cancelledRequest was cancelled by the agent

Consume OTP

Retrieve and delete the OTP. This is a one-time operation.

Request

POST /v1/otp/:id/consume
Authorization: Bearer ak_live_xxxx

Response

{
  "id": "otp_xxxxxxxxxxxx",
  "encryptedPayload": "base64-encoded-encrypted-otp...",
  "source": "email",
  "sender": "noreply@acme.com",
  "consumedAt": "2026-01-28T12:02:00Z"
}

Important: The encryptedPayload must be decrypted using your agent's private key. Use the SDK's decryptOTPPayload() function for this.

Cancel OTP Request

Cancel a pending OTP request.

Request

DELETE /v1/otp/:id
Authorization: Bearer ak_live_xxxx

Response

{
  "success": true,
  "id": "otp_xxxxxxxxxxxx",
  "cancelledAt": "2026-01-28T12:02:00Z"
}

WebSocket Updates

Connect to the WebSocket URL for real-time status updates:

const ws = new WebSocket('wss://api.agentotp.com/ws/otp_xxxx');

ws.onmessage = (event) => {
  const data = JSON.parse(event.data);

  switch (data.type) {
    case 'status_change':
      console.log('Status:', data.status);
      if (data.status === 'otp_received') {
        console.log('OTP is ready to consume!');
      }
      break;
    case 'expired':
      console.log('OTP request expired');
      break;
  }
};

Error Responses

StatusCodeDescription
400VALIDATION_ERRORInvalid request parameters
401UNAUTHORIZEDInvalid or missing API key
404NOT_FOUNDOTP request not found
409ALREADY_CONSUMEDOTP has already been consumed
410EXPIREDOTP request has expired
429RATE_LIMITEDRate limit exceeded

See Also