API and quick start
Base URL: https://gettgapi.com/api/open/v1. Call from your server using the remaining uses on an access code. Customers do not need a platform account, Telegram client API credentials, a two-step password or device authorization. Each application still requires the number holder's developer portal verification code.
Download OpenAPI 3.1 · Download the complete Python example · Integration support
- Call
GET /balancewith the access code. - Submit number, app details and consent to
POST /applications. Save the returned applicationid. - Poll at intervals of at least 5 seconds. For
waiting_codewith a non-nullchallenge, ask the number holder for this request's code. - Submit it to
POST /applications/{id}/codeand continue polling. - On
succeeded, readGET /applications/{id}/result. - Save securely in your system, verify the save, then call deletion. Deleted results cannot be reissued.
Existing apps are retrieved; creation is attempted only if none exists. Success is not guaranteed for every number. Restrictions and exceptions may require manual review.
Authorization and format
Every business request requires:
Authorization: Bearer YOUR_AUTHORIZATION_CODE
Accept: application/json
Writes also require:
Content-Type: application/json
Idempotency-Key: 2e8718cd-84ef-4830-b273-66b3afdd682d
Original hyphens in access codes are accepted; letters are case-insensitive. Never put codes in URLs, browser frontends, logs or public repositories. This API does not use website cookies or CSRF tokens and does not enable cross-origin CORS. A leaked code exposes its service permissions: contact the issuer to disable it.
Use HTTPS only. Maximum body size is 8 KiB. Unknown fields, wrong types and invalid formats are rejected. Times are Unix seconds; null means unavailable, not zero.
Success responses use this envelope:
{"data": {"available": 1}, "request_id": "server-generated-trace-id"}
This is illustrative; see each endpoint and OpenAPI for complete fields. X-Request-ID matches request_id. Responses must not be cached. Use the trace ID for support, not as your next write's idempotency key. Example message wording below is translated for readability; integrations must branch on machine-readable codes and statuses.
Access-code balance
GET /balance returns HTTP 200:
{
"data": {
"total": 10,
"available": 8,
"reserved": 1,
"consumed": 1,
"revoked": 0,
"max_concurrent": 2,
"result_retention_seconds": 1800
},
"request_id": "example-trace-id"
}
total = available + reserved + consumed + revoked. Reserved uses are in progress, consumed uses completed successfully, and revoked uses were withdrawn. A code can have at most two reserved applications at once. Website and API share this limit and balance.
Balance queries do not consume uses or redeem a code. An exhausted code can still read its API-created applications and delete temporary results. Disabled or suspended codes cannot access them; contact the issuer.
Create an application
POST /applications returns HTTP 202 on initial acceptance and successful idempotent replay.
{
"phone": "+12025550123",
"title": "My Telegram App",
"short_name": "myapp2026",
"consent": true
}
| Field | Requirement |
|---|---|
| phone | Required, including country code. Digits with optional leading +; spaces are removed and a missing + is added. Other characters are rejected. |
| title | Optional; defaults to My Telegram App. 3–60 characters: letters, numbers, underscore, spaces, dots and hyphens. |
| short_name | Required; 5–32 characters. Starts with an English letter, followed by English letters, digits or underscore. |
| consent | Required boolean true confirming authority to use the number; the string "true" is invalid. |
HTTP 202 means accepted, not that a code arrived or an application succeeded. The response is the application object below. Initial acceptance reserves one use; success consumes it. Confirmed failure, cancellation before creation or a duplicate result releases it. Unknown results retain the reservation while checked.
Unfinished or successful records for the same code and number are not recreated. Matching API-origin details return the original application. Different details or a website-origin record return PHONE_ALREADY_USED. Deleted results still retain usage records; changing idempotency keys does not restore them or create another charge.
Application status
GET /applications/{id} returns HTTP 200 with:
{
"data": {
"id": "28f4a4d0-e69f-48d4-b520-85c479873b1f",
"phone_mask": "+120••••123",
"title": "My Telegram App",
"short_name": "myapp2026",
"status": "waiting_code",
"message": "Check Telegram for the verification code and enter it below.",
"challenge": {"id": "c8a34997-38bd-4a1c-90bb-5baac7dbabcc", "expires_at": 1790998200, "attempts_remaining": 5},
"poll_after_seconds": 5,
"retry_at": null,
"result_expires_at": null,
"quota": "reserved",
"created_at": 1790997600,
"updated_at": 1790997605
},
"request_id": "example-trace-id"
}
| Status | Client action |
|---|---|
| queued | Continue polling. |
| processing | Processing or reconciling; poll without creating again. |
| waiting_code | Submit a code if challenge exists. If null, verification expired; cancel, then apply again if needed. |
| verifying | Code submitted; poll without requesting another send. |
| retry_wait | System wait or automatic retry. Consider retry_at and keep polling; no client resend is needed. |
| review_required | Stop automatic polling. Contact support with application id and request_id. |
| succeeded | Retrieve and securely save the result promptly. |
| failed | Failure confirmed; reservation released. Use a new idempotency key if a new application is needed. |
| cancelled | Cancelled; reservation released. |
| duplicate | This code already has the same app result. No use consumed for this attempt; use your saved result. |
| deleted | Temporary result cleared and unavailable. |
quota is reserved, consumed or released. challenge exists only when code entry is currently allowed. Its id may change after failed input or renewed verification; query again. retry_at is a suggested wait-until time, not a completion guarantee. poll_after_seconds=0 means continuous polling is unnecessary.
GET /applications?limit=20&before={id} lists records. Limit is 1–50, default 20; before is optional. Results are ordered by creation time and id descending. The response has data.items and data.next_before; null means the end. Only this access code's API-created records are visible, excluding website results and other codes.
Submit a verification code
POST /applications/{id}/code returns HTTP 202 with the updated application.
{"challenge_id": "c8a34997-38bd-4a1c-90bb-5baac7dbabcc", "code": "Ab_cd-12"}
Code is 3–64 printable ASCII characters, without spaces, case-sensitive. Submit only the current developer portal code received by the number holder, not a two-step password or an old challenge's code. Each round allows at most 5 entries. Expiry is challenge.expires_at.
Acceptance only means queued for verification. Retry the same HTTP submission with its original key and identical parameters. If the code was wrong, query the new challenge and submit the correct code with a new key.
Cancel
POST /applications/{id}/cancel with {"confirm": true} returns HTTP 200 and the application.
Only cancellable states, such as queued, waiting for code or waiting to retry, permit this. Running applications and uncertain results return STATE_CONFLICT; keep polling or contact support. Repeating cancellation of cancelled or confirmed-failed applications does not return additional uses.
Retrieve and delete the result
GET /applications/{id}/result returns HTTP 200:
{
"data": {"api_id": 12345678, "api_hash": "0123456789abcdef0123456789abcdef", "expires_at": 1790999400},
"request_id": "example-trace-id"
}
These are sample values, not usable credentials. The default delivery window is 30 minutes; the actual expires_at governs. Reads neither extend retention nor consume uses, and multiple reads are allowed. Never put Hash in access logs, analytics, URLs or support chat.
After saving and verifying the result, call POST /applications/{id}/result/deletion with {"confirm": true}. HTTP 200:
{
"data": {"application_id": "28f4a4d0-e69f-48d4-b520-85c479873b1f", "deleted_at": 1790998000, "status": "deleted"},
"request_id": "example-trace-id"
}
Deletion clears our temporary API delivery copy while retaining counts and necessary operation records. It does not delete the Telegram app or your system's saved copy. After deletion, expiry or loss of temporary delivery storage, reads return HTTP 410. Deletion requests can be retried safely. Save first, delete second.
Idempotency, limits and retries
Every POST requires Idempotency-Key: 16–80 letters, digits, dots, underscores, colons or hyphens; UUIDs are recommended. Persist it before sending. Generate a new key per distinct operation. Reuse the original key when retrying after network timeout, disconnect or 5xx.
Within an access code, a key is globally bound to the operation and parameters and cannot be reused across endpoints. Replay returns the original application's current state, not necessarily an identical byte response. It does not resend codes, reserve or charge again. A deleted result does not make that key create a new application. Do not change keys merely because a response is unknown.
| Limit | Current value |
|---|---|
| All requests per access code | 120 / minute |
| Writes per code | 30 / 10 minutes, including idempotent retries |
| New creation requests per code | 10 / 10 minutes |
| Business requests per IP | 180 / minute, plus burst protection |
| Invalid keys per IP | 15 / 10 minutes |
| Applications per number | 5 / hour, shared with the website |
| Concurrent reservations per code | 2, shared with the website |
| Code submissions | 5 per round, plus 10 / 10 minutes per task |
For 429 and 503, honor Retry-After; use exponential backoff with modest jitter. 5xx and network/read timeouts can occur after a write completed. Reuse its key rather than assuming no use was deducted. Usually correct input or check status for 4xx; never retry indefinitely.
Overload or inability to accept new work returns 503. Unaccepted requests do not reserve uses. Durable tasks resume after service failures, and uncertain submitted creations are checked rather than blindly repeated. A single-host deployment still has host and datacenter failure boundaries; no multi-host disaster-recovery SLA is promised.
Errors
{
"error": {"code": "RATE_LIMITED", "message": "Too many requests. Wait before retrying.", "retryable": true, "retry_after_seconds": 60},
"request_id": "provide-this-trace-id-to-support"
}
Use code and HTTP status, not parsed message wording or internal implementation details. Upstream errors are not returned verbatim. Retryable errors also include Retry-After. Trace IDs contain neither access codes nor results.
| HTTP | code | Action |
|---|---|---|
| 401 | INVALID_KEY | Check Authorization and the access code. |
| 403 | KEY_DISABLED | Ask the issuer about disabled or suspended status. |
| 403 | ORIGIN_DENIED / HOST_DENIED | Call the documented base URL from your server. |
| 400 | HTTPS_REQUIRED / IDEMPOTENCY_REQUIRED | Use HTTPS and a valid idempotency key. |
| 422 | INVALID_INPUT / PHONE_INVALID / CONSENT_REQUIRED | Correct fields and formats. |
| 409 | IDEMPOTENCY_CONFLICT | Recover original parameters, or use a new key for a genuinely new operation. |
| 409 | QUOTA_EXHAUSTED / CONCURRENCY_LIMIT | Query balance or wait for current work. |
| 409 | PHONE_ALREADY_USED | Handle the original application instead of recreating it. |
| 404 | APPLICATION_NOT_FOUND | Check id, access code and application channel. |
| 409 | CHALLENGE_EXPIRED / TOO_MANY_ATTEMPTS | Query the application and current challenge. |
| 409 | STATE_CONFLICT | Query progress or contact support. |
| 409 | RESULT_NOT_READY | Continue polling progress. |
| 410 | RESULT_GONE | Use your own saved copy. |
| 429 | RATE_LIMITED | Wait for Retry-After. |
| 503 | SERVICE_BUSY / SERVICE_UNAVAILABLE | Back off and retry with the original key. |
| 408 | REQUEST_TIMEOUT | Retry the original request, retaining its key for writes. |
| 413 | BODY_TOO_LARGE | Reduce the body to 8 KiB or less. |
| 415 | UNSUPPORTED_MEDIA_TYPE | Send uncompressed application/json. |
| 404 / 405 | NOT_FOUND / METHOD_NOT_ALLOWED | Check path and method. |
Example client and secure storage
The Python example requires Python 3.10+ and requests. It stores request state in a restricted local directory, resumes uncertain requests with the same key, and asks about deletion only after safely saving the result. Do not commit its working directory.
python3 -m pip install requests
python3 gettgapi_client.py --work-dir ./private-application
Access codes and verification codes use hidden terminal input and are not logged. The client asks for a number and short_name. Reusing the directory resumes that operation; use a new directory for another number. Test with a number you control. HTTP acceptance and automated tests cannot replace real-number verification.
Encrypt results in your system, restrict staff read access and never expose access codes in a public client. Issue independent codes to different customers: a holder can manage all API-created applications belonging to that code.
For integration help, use gettgapi.com/en/help#contact with request_id and application id, without verification codes, full access codes or API Hash.