API docs

Verify

WeSend creates, sends and checks the one-time code. You never store it.

Confirming a user's phone or email takes two calls: start a verification, then check the code the user typed. WeSend keeps only a hash of the code.

1. Send a code

POST/v1/verify

Creates a code and sends it. If to contains @ it goes by email, otherwise by SMS.

Body

tostringrequired
A phone number or an email address.
fallback_emailstring
Where the code goes if the operator refuses the SMS. Only when to is a phone number.
localestring
The message language: mn (default) or en.
brandstring
The name the message starts with, up to 20 characters. Defaults to the project's brand name.
code_lengthinteger
Digits in the code, 4 to 8. Default 6.
ttlinteger
How long the code is valid, in seconds, 60 to 600. Default 300.
curl -X POST https://api.wesend.mn/v1/verify \
  -H "Authorization: Bearer $WESEND_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "to": "99112233",
  "brand": "Shop.mn",
  "fallback_email": "[email protected]"
}'
Response200 OK
{
  "id": "c4f1e2d3-7a8b-4c9d-a0e1-f2a3b4c5d6e7",
  "status": "pending",
  "channel": "sms",
  "to": "99112233",
  "expires_at": "2026-10-06T08:20:30.000Z",
  "credits": 70,
  "balance": 4930
}

The recipient gets “Shop.mn: Your verification code is 482913”. Keep the id for the next step. The price is that of an ordinary one-part SMS, or of an email.

To resend a code, call /verify again. The recipient's earlier pending code stops working.

2. Check the code

POST/v1/verify/{id}/check

Checks the code the user typed.

Body

codestringrequired
The code the user typed.
curl -X POST https://api.wesend.mn/v1/verify/c4f1e2d3-7a8b-4c9d-a0e1-f2a3b4c5d6e7/check \
  -H "Authorization: Bearer $WESEND_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "code": "482913"
}'
Response200 OK
{
  "id": "c4f1e2d3-7a8b-4c9d-a0e1-f2a3b4c5d6e7",
  "status": "approved",
  "channel": "sms",
  "to": "99112233",
  "expires_at": "2026-10-06T08:20:30.000Z"
}

A correct code answers 200 with status approved. Otherwise:

AnswerMeaning
422 invalid_codeWrong code. The error's attempts_remaining says how many tries are left.
429 max_attempts_reachedFive wrong codes. Start a new verification with /verify.
410 verification_expiredThe code expired, or a newer code replaced it.
400 invalid_requestThis verification was already approved.

One recipient may enter at most 10 wrong codes in 24 hours across all verifications. After that even a request for a new code answers 429 max_attempts_reached. This is what stops code guessing.

Read the status

GET/v1/verify/{id}

Returns the current state of a verification.

StatusMeaning
pendingThe code was sent and waits to be checked.
approvedThe correct code was entered.
expiredThe code ran out of time.
failedToo many wrong codes.
canceledReplaced by a newer code.