OTP API

Your app sends a one-time code through smsyra; your test reads it back with one call. The call waits for the text to arrive, so a test never sleeps and polls — and no real phone or SIM is involved.

Get the newest code

GET https://api.shriradhatechnologies.com/v1/otp/latest?to=<number>&since=<time or message id>&wait=<0–30>
Authorization: Bearer smy_YOUR_KEY
ParameterWhat it does
toThe number the text went to. 9876543210, +919876543210 and 09876543210 are the same number.
sinceOnly texts after this: an ISO time (when your test started) or a message id. Default: the last 10 minutes.
waitHow long to wait for a text to arrive, 0 to 30 seconds. Default 25.

It answers with the newest accepted text to that number — the code, how it was found, the text and its DLT result:

{"messageId":"0193…","to":"+919876543210","from":"ACMEOT","body":"482913 is your ACME login code. It is valid for 10 minutes.","code":"482913","codeMethod":"template","candidates":["482913"],"receivedAt":"2026-11-15T10:20:30Z","templateId":"1007123456789012345","dlt":{"status":"MATCHED"}}

codeMethod says how the code was found: from your template’s variable (template), the WebOTP line, a keyword nearby, or a lone 4–8 digit number. candidates lists every number that could have been the code. Nothing arrived in time? 404 with code NO_MESSAGE.

curl -G "https://api.shriradhatechnologies.com/v1/otp/latest" \
  -H "Authorization: Bearer smy_YOUR_KEY" \
  --data-urlencode "to=9876543210" \
  --data-urlencode "wait=25"

In a test

// a Playwright test: sign in with a code, no phone needed
const started = new Date().toISOString();
await page.getByLabel("Mobile number").fill("9876543210");
await page.getByRole("button", { name: "Send code" }).click();

const res = await request.get("https://api.shriradhatechnologies.com/v1/otp/latest", {
  params: { to: "9876543210", since: started, wait: "25" },
  headers: { Authorization: `Bearer ${process.env.SMSYRA_KEY}` },
});
expect(res.status()).toBe(200);
const { code } = await res.json();
await page.getByLabel("Code").fill(code);

Keep the key in your CI’s secrets, not in the test file.

More calls for tests

CallWhat it does
GET /v1/messages?to=&limit=20The latest texts to a number, newest first.
GET /v1/messages/{id}One text in full: the body, the DLT check, the request and the answer.
DELETE /v1/messages?to=Delete every text to a number — clean up between tests. Answers {"deleted": n}.

Every call takes the same key as Authorization: Bearer smy_…, whichever provider sent the text. At most 10 waits can be open at once per key; more get 429.

Next: make a key fail on purpose to test your retries.