Result lifecycle
A data model for Telegram registration results and refresh attempts
Store the exact Telegram registration response fields, distinguish success from undetermined, and keep API errors outside the registration result.

Why one boolean is not enough
A Telegram registration result is a timestamped observation produced by a completed check, not a permanent truth attached to a phone number.
A field such as telegram_valid loses essential context. It does not say which normalized number was checked, when the check ran, whether false was a completed decision, or whether the request actually failed. The database should preserve those distinctions so an application can display and refresh the result honestly.
TG Validator returns a completed decision synchronously, which means the observation can be written as soon as the HTTP response arrives. The returned fields should be stored as they are, without inventing another set of product statuses.
Separate the subject from its observations
Use one stable internal phone record and attach multiple check observations to it. This avoids rewriting history and makes a later refresh easy to understand.
| Record | Suggested fields | Purpose |
|---|---|---|
| Phone source | phone_id, source_phone, source_system |
Preserves the original business record |
| Normalized phone | phone_id, e164_phone, normalized_at |
Records the canonical value used for checks |
| Check observation | phone_id, status, registered, received_at, transaction_id |
Stores one synchronous result |
If normalization changes because the original country context was corrected, create or version the canonical record. Do not silently attach an old Telegram result to a newly interpreted phone number.
Use the exact public response shapes
| Returned shape | registered value |
Meaning |
|---|---|---|
code=0, data.status=success |
true | The completed check reported registered |
code=0, data.status=success |
false | The completed check reported not registered |
code=0, data.status=undetermined |
null | No registration decision; no final charge |
Non-zero API code, data=null |
Not present | API error, not a registration result |
The nullable field is deliberate. Null in the documented undetermined result means the service has no boolean answer. Invalid input, rate limits, insufficient balance, maintenance, and internal failures use the separate error envelope; they do not add more values to data.status.
Keep current state and latest attempt as two views
Two questions are often useful:
- What is the newest completed registration observation?
- What happened in the newest request attempt?
They may point to different rows. If a completed true result at T1 is followed by an API error at T2, the newest completed observation is still true at T1, while a separate request log can record the HTTP status and API code from T2. This prevents an operator from mistaking T1 for a fresh result or T2 for false.
When a later call completes false at T3, the current completed view advances to T3. The T1 and T2 records remain available for audit and troubleshooting.
Define when a refresh is required
TG Validator provides a current synchronous observation when called, but the integrating application owns its freshness policy. Choose a maximum acceptable age based on the decision being made, then make that age visible in the interface.
A refresh policy should specify:
- the maximum age accepted for each workflow;
- whether operators may use an older completed result after a later API error;
- whether an undetermined response should be submitted again later;
- how rate and concurrency limits shape scheduling;
- whether every attempt or only completed observations are retained long term.
Do not retry a completed registered=false merely because it is false. Retry when a newer point-in-time observation is needed or when the previous attempt produced no decision.
A precise current-state query
The current registration state should select the latest observation where the returned status=success, then return its registered value and local received_at together. Never return the boolean without its timestamp.
The latest-attempt state should select the newest observation of any status. If it is not completed, the interface can explain that a newer check was attempted without replacing the last known registration result.
The durable design principle
Append observations, preserve their timestamps, and never coerce operational uncertainty into a Telegram registration value.
This model matches the product exactly. TG Validator answers one registration question synchronously; it does not provide identity or account-profile data. The customer application supplies the stable record, retention policy, refresh schedule, and business decision around each observation.