One-time codes and links

Most sign-up and password-reset tests want one of two things out of a message: the six digits, or the link. Writing the regular expression for that in every project is busywork, so the API does it:

GET /subscriptions/{sid}/messages/{id}/extract

Same authentication and the same 404 rules as reading the message itself. The response:

{
  "codes": ["482913"],
  "links": ["https://example.com/verify?t=a1b2c3"]
}

A message that contains neither answers 200 with two empty arrays. It is not a 404 — the message exists, and "no code in this mail" is an answer your test may want to assert on.

The rules, exactly

Codes are runs of 4 to 8 digits in the text body — or in the HTML body stripped of its tags, when there is no text body — that appear within 40 characters of one of the words code, OTP, PIN, verification, verify or passcode, matched without regard to case. They are returned in order of appearance, with repeats removed.

Links are every http:// or https:// URL in the text body and the HTML body, in order of appearance, with repeats removed. Nothing is followed, and nothing is unwrapped: a link that a mail provider has rewritten through a click tracker is returned as it appears in the message.

These are heuristics, and that is the contract

The rules above are deliberately simple, and they are the whole of what the endpoint promises. It does not understand your email template. A message that puts a five-digit order number next to the word "code" will yield the order number; a message that writes the code as 48-2913 will yield nothing.

Two consequences worth designing around:

Refining the rules for a template that nearly works is the kind of change that the stability policy allows at any time, so do not build a test that depends on a code not being extracted.

The request and response shapes, including every error status, are in the HTTP API contract and the API reference.