Get the latest message
GET/messages/latestBearer token required
Returns the newest message for one address. If none has arrived yet, the request holds open until one does — so your test waits on mail rather than polling for it. This is the endpoint you will actually use.
Parameters
| Name | Default | Meaning |
|---|---|---|
addressrequired | — | The full address to read, including your namespace domain. Sending only the local part is rejected |
waitoptional | 25 | Seconds to hold the request open waiting for mail. 0 returns immediately with whatever is already there |
Example
import os, re, requests
reply = requests.get(
"https://api.ravenhook.dev/messages/latest",
params={"address": inbox, "wait": 25},
headers={"Authorization": f"Bearer {os.environ['RAVENHOOK_TOKEN']}"},
timeout=30,
)
message = reply.json()["message"]
if message is None:
raise AssertionError("No mail arrived within 25 seconds")
code = re.search(r"\b\d{6}\b", message["text_body"]).group()const params = new URLSearchParams({ address: inbox, wait: "25" });
const res = await fetch(`https://api.ravenhook.dev/messages/latest?${params}`, {
headers: { Authorization: `Bearer ${process.env.RAVENHOOK_TOKEN}` },
});
const { message } = await res.json();
if (message === null) {
throw new Error("No mail arrived within 25 seconds");
}
const code = message.text_body.match(/\b\d{6}\b/)[0];curl -s -G "https://api.ravenhook.dev/messages/latest" \
--data-urlencode "address=mfa@ex4mple0ns.inbox.ravenhook.dev" \
--data-urlencode "wait=25" \
-H "Authorization: Bearer $RAVENHOOK_TOKEN"Response
{
"message": {
"id": "ed32433d12e145b19ee0117418d688b6",
"subject": "Your verification code",
"from": "noreply@theircompany.com",
"to": "mfa@ex4mple0ns.inbox.ravenhook.dev",
"text_body": "Your code is 483920. It expires in 10 minutes.",
"html_body": null,
"headers": { "Subject": "Your verification code" },
"attachments": [],
"received_at": 1785515448.6,
"has_attachments": false
}
}When nothing arrives
You get 200 with a null message, not a 404 and not an error:
{ "message": null }A timeout is a normal answer. Returning an error would make "the mail is slow" indistinguishable from "the service is down", and send you debugging in the wrong direction. Check for null and fail your test with your own message.
Choosing a wait
wait is capped at 25 seconds. Asking for more returns 422 rather than silently giving you less — a silent downgrade would look like the mail never came. If you need longer than the cap, call again in a loop.
Use wait=0 when you are checking whether mail has already arrived and do not want to block. It also never counts against the concurrent-wait limit, so it keeps working when parallel runs have saturated it.
Why we return the whole body
We do not extract the code for you. Codes are six digits in one app, eight in another, and a link in a third — any extraction we did would be wrong for someone. Returning the full body means you can assert on wording, pull out a URL, or parse whatever shape your codes take.
Errors
| Code | Cause |
|---|---|
400 | Malformed address |
401 | Token missing, malformed, or unknown |
404 | Address outside your namespace |
422 | wait above the 25 second cap |
429 | Too many requests, or too many waiting at once — see About 429 |