Dashboard
The dashboard at https://timetriggers.io/dashboard is where you create API keys and follow your triggers. The API schedules, edits and cancels triggers but doesn't report back on them: a trigger's status, its attempts and your target's responses are only visible here.
| Page | Address | What it's for |
|---|---|---|
| API Keys | /dashboard | Create, copy and delete API keys. |
| Triggers | /dashboard/triggers | Browse and search your triggers, cancel and replay them. Updates live. |
| Executions | /dashboard/executions | Every attempt across your triggers, with filters such as Only dead letters. |
| Tag Policies | /dashboard/tag-policies | Add, edit and delete tag policies. |
The → link on a row of Triggers or Executions opens the trigger page, /dashboard/triggers/<trigger-id>.
Signing in
There are no passwords. You sign in with a one-time code sent by email:
- Go to the sign-in page and enter your email address. Opening the dashboard while signed out takes you there too.
- Click Send code. The code comes from
noreply@timetriggers.io, with the subject "Your TimeTriggers verification code: …". - Enter the 6-digit code and click Verify & sign in. You land on the API Keys page.
Your first sign-in creates your account. There's no separate sign-up, and no way to sign in with a password.
About codes:
- A code is valid for 5 minutes and works once.
- Only the newest code works. Requesting a new code invalidates the previous one. Entering the old one then fails, and counts as a wrong attempt against the new code.
- There's no resend button. To get a new code, click ← Use a different email, then Send code again.
- 3 wrong attempts lock a code. It then fails even if you enter it correctly. Request a new one.
| Message | What to do |
|---|---|
Invalid OTP | The code is wrong, has been replaced by a newer one or was already used. Check the code or request a new one. |
OTP expired | The code is older than 5 minutes. Request a new one. |
Too many attempts | The code was locked after 3 wrong attempts. Request a new one. |
Too many requests. Please try again later. | More than 3 code requests, or more than 3 sign-in attempts, from your IP address within a minute. Wait a minute. |
A session lasts 7 days. Using the dashboard extends it (at most once a day), so you're signed out only after about a week without a visit. Sign out, at the top right, ends the session right away.
Your project
The first time you open the dashboard, a project is created for your account automatically. API keys, triggers, tag policies and the monthly quota belong to the project, not to you or to an API key.
- New projects are on the Free plan, with 500
/schedulecalls per month. The dashboard doesn't show the project's name, plan or remaining quota; see Checking your remaining quota. - You can't invite teammates, rename the project or switch projects from the dashboard.
- If your account is a member of more than one project, Triggers and Executions show the triggers of all of them together, without saying which project each belongs to. API Keys and Tag Policies manage only one of the projects.
API keys
The API Keys page lists your project's keys, newest first, with their name, the start of the key and the date it was created.
To create a key:
- Click Create key.
- Optionally, enter a Key name such as
ProductionorStaging. Without one, the key is namedDefault. Names don't have to be unique. - Click Create.
- Click Copy next to the key to copy it in full.
A key looks like ttr_ followed by 48 hex characters. Send it in the ttr-api-keyheader header; see Authentication.
Good to know
- Keys can be copied at any time. The list shows only the first 12 characters, but Copy copies the whole key whenever you click it, not only right after creation. Anyone who can sign in to your project can copy every key, so protect dashboard access like the keys themselves.
- Every key has full access to the project. Keys have no scopes. Any key can edit or cancel triggers created with another key.
- Keys never expire. A key works until you delete it. Keys can't be renamed.
- Keys are managed only in the dashboard. The endpoints behind this page accept a dashboard session, not an API key.
Deleting a key
Delete removes the key immediately, without confirmation and with no undo. From the next request on, every call that uses that key, in ttr-api-keyheader or in Authorization: Bearer where that's accepted, gets 401 with the message Invalid api key.
Deleting a key doesn't cancel anything. Triggers belong to the project, not to the key that created them. One-shot triggers scheduled with a deleted key still fire, and its recurring triggers keep creating and firing instances. You can't cancel them with the deleted key: use another key of the project, or the dashboard.
Rotating a key
To replace a key, for example after it leaked:
- Create a new key and switch your clients to it.
- Delete the old key.
- Go through your triggers (a recurring trigger shows up as its upcoming instance) and your tag policies. Cancel triggers and delete policies you don't recognize. Triggers created with a leaked key, including any that someone else created with it, keep firing until you cancel them.
To cancel, use DELETE /cancel by ID or custom key, a cancel by tag with /bulk, or the dashboard.
Triggers
The Triggers page lists your triggers, 20 per page. Each run of a recurring trigger is listed as its own trigger, an instance; the recurring trigger itself has no row.
Status. The chips filter the list: All (the default), Scheduled, Queued, Running, Retrying, Completed, Skipped and Cancelled. Scheduled is the API status registered; the other labels match the API names. See Trigger statuses for what each one means.
Completed doesn't mean successful. A trigger whose last attempt failed is Completed too. Check its result badge, or look for a DEAD badge on the trigger page.
Order:
- All: Scheduled triggers first, the next one due at the top, then every other trigger, most recent activity first.
- Scheduled: the next one due first.
- Any other chip: most recent activity first.
A trigger's last activity is the latest of its due time and the times it was created, queued, started, completed or cancelled. Because the due time counts even when it's in the future, a cancelled trigger that was due in 3 days sorts near the top and shows "in 3 days".
The count of matching triggers ("N triggers") appears next to the chips, and the pager reads ← Previous, "Page X of Y", Next →.
Searching
Three search boxes narrow the list. They combine with each other and with the status chip:
| Box | Matches |
|---|---|
| Title | Text anywhere in the title, ignoring case. Needs at least 3 characters. |
| Custom key | Text anywhere in the custom key, ignoring case. Needs at least 3 characters. |
| Tag | One whole tag, exactly as written, case included. |
- The list updates 300 ms after you stop typing and goes back to page 1. Clear search empties all three boxes.
%and_match themselves; they aren't wildcards.- While a Title or Custom key search is active, matches aren't counted: the page shows "N shown" (or "N+ shown") and the pager shows only the page number.
Instances of recurring triggers can't be found by custom key or title. The custom key belongs to the recurring trigger, and its instances have no custom key or title of their own. So the Title and Custom key boxes, like the Custom key filter on the Executions page, only find one-shot triggers. Give recurring triggers a tag and search by Tag instead: each instance gets the recurring trigger's tags when it's created.
Reading a row
From left to right, a row shows:
- Status.
- Result of the latest attempt: the HTTP status your target returned (green below
400, yellow for4xx, red for5xx; hover for its meaning). Without a response, a Completed trigger shows TIMEOUT or ERROR instead; hover for the error message. There's no badge before the first attempt, or while a retry is pending. - Method, title and URL: the title in bold, followed by the URL's host, path and query. Without a title, just the URL. Hover for the full URL.
- Recurring badge, on instances only: the recurring trigger's custom key, or
cronif it has none. Hover for "From generator …", with "(cancelled)" once the recurring trigger is cancelled. - Tags: up to 3, then "+N".
- Duration of the latest attempt, and its lag, such as "+1.2s lag": the time between the trigger's due time and the start of its latest attempt. After a retry or a replay, the lag is still measured from the original due time, so it can be large.
- Last activity, as a relative time. It starts with "ran" once the trigger has started, and with ⚠️ when a Scheduled trigger is past its due time.
- → opens the trigger page.
On narrow screens, the recurring badge and the tags are hidden.
Click a row to expand it. You see the request (URL, title, trigger ID, custom key, the Generator an instance belongs to, tags, headers and the latest error), its lifecycle times and duration, a cancel button for Scheduled triggers, and the trigger's executions with Replay now or Retry now for Completed triggers.
Trigger page
The trigger page shows one trigger in full. Its header shows the status, the method and the title (or the custom key, or the URL if it has neither), and these buttons:
- Cancel for a Scheduled trigger. See Cancelling a trigger.
- Replay now or Retry now for a Completed trigger. See Replay and retry.
Request. Trigger ID, custom key, method, URL, tags, Generator (for an instance: the recurring trigger's custom key or ID, marked cancelled once it's cancelled) and Headers, the stored headers that are sent to your target. Headers are shown in full, credentials included.
Body. Shown as "Body (size)" when the trigger has a body:
- The preview shows the first 200 KB. A longer body is marked TRUNCATED.
- A complete body that is a JSON object or array is indented and marked JSON.
- A body that isn't valid UTF-8 text shows "binary body (size) — no text preview". This can also happen to a text body over 200 KB.
- Hover over the body for a Copy button.
Lifecycle. Created, Due at, then Queued, Started and Completed for the latest attempt, and Cancelled. Only the times that are set appear, each with a relative time. The latest attempt's error, if any, is shown below.
Executions (N). Every attempt, newest first, including one that is planned but not sent yet. Each row shows:
- The attempt number:
#1is the first attempt. - What created it:
scheduler,retryorreplay. See Execution statuses. - DEAD for a dead letter.
- The result: the HTTP status, TIMEOUT, ERROR, or, without a result, the execution status, such as
planned. - When it started, and how long it took.
Click an attempt that has a response or an error to see the Error, the Response headers and the Response body. Only the first 10 KB of a response body is stored (see Response bodies); for a larger response, a note reads "(first 10 KB shown of N bytes)". The note can also appear on a short response that contains non-ASCII characters, even though it's shown in full.
The trigger page doesn't update by itself. It reloads after Cancel, Replay now or Retry now, and when you come back to the browser tab. Otherwise, reload the page to see new attempts.
Cancelling a trigger
You can cancel a Scheduled trigger from the dashboard:
- On the Triggers page, expand the row and click Cancel trigger, or Cancel recurring trigger for an instance.
- On the trigger page, click Cancel.
The trigger is cancelled immediately, without confirmation.
Instances of a recurring trigger. Cancelling an instance (the button reads Cancel recurring trigger) cancels the whole recurring trigger: that instance is cancelled and no more are created. Instances whose time has already come (Queued, Running, Retrying or Completed) aren't cancelled: Queued and Retrying ones still fire. This differs from DELETE /cancel with an instance's ID, which cancels only that instance; the recurring trigger then creates a new one for the same time within seconds.
Limitations:
- The dashboard cancels Scheduled triggers only. To stop a Retrying trigger's pending retry, use
DELETE /cancelwith its trigger ID. - A Queued trigger can't be cancelled from the dashboard, or by ID or custom key. If it has a tag, a cancel by tag stops it, along with every other trigger with that tag. A Running trigger's request can't be stopped.
- If the trigger moved on since the page loaded, for example because it fired, you get "Trigger not found or no longer cancellable".
Replay and retry
A Completed trigger has a Replay now or Retry now button, on its trigger page and in its expanded row on the Triggers page. Both send the trigger's stored request again, right away:
- The button reads Retry now when the latest attempt ended with an error (such as a timeout or a network error) or an HTTP status of
400or higher, and Replay now otherwise, including after a final3xx. - Clicking adds a new attempt planned for now, and the trigger goes back to Queued. The request is usually sent within a second, with the same method, URL, headers and body.
- The trigger's tag policies apply as for any attempt: throughput and concurrency limits can hold it back, and their timeout and retry settings are used.
- Afterwards, the trigger is Completed again.
- Replays don't use quota, and they work when your quota is used up.
The two buttons do the same thing. The only difference is the label of the new attempt: retry or replay.
Good to know
- The attempt count continues. The new attempt gets the next attempt number, such as
#4after#1to#3, and every attempt so far counts toward the tag policy's Max attempts. If the trigger has used all of its attempts, a replay that fails becomes a dead letter right away, without automatic retries. To give a replay retries, raise Max attempts on the tag policy, or clear it (blank = ∞), first. - Exponential backoff continues too. With a 10-second initial delay, a failed replay that is attempt
#4is retried after about 80 seconds, not 10. - Manual retries look like automatic ones. Retry now labels its attempt
retry, like an automatic retry from a tag policy, and nothing else tells the two apart.replayalways comes from Replay now. - Each replay is a real request. The button is disabled while your click is processed and disappears once the trigger is queued. But clicking it again in another tab that still shows it, once the first replay is in flight, sends the request a second time. See Delivery guarantees.
Executions
The Executions page lists attempts across all your triggers, 50 per page: scheduled runs, retries and replays. Each row is one attempt. Scheduled triggers have no attempts until they're due, and Skipped triggers never fire, so neither is listed here. Response headers and bodies are on the trigger page.
Attempts are sorted by last activity, newest first: when they finished, started or, if neither, were planned for. A pending retry is planned for a future time, so it's listed above attempts that already finished.
A row reads like a Triggers row, with these differences:
- Status is the trigger's current status, not the attempt's.
- Result is this attempt's: the HTTP status, TIMEOUT or ERROR, or, without a result yet, the execution status, such as
planned. DEAD marks a dead letter. - Custom key of the trigger, on wide screens, in place of the recurring badge and tags.
- What created the attempt and its number, such as "retry · #2".
- Response size, shown as "≥10MB" once a response reaches the 10 MB read limit.
- Lag is measured from the time the attempt was planned for, and shown only when it's at least a second.
- Last activity: hover for the planned, start and finish times.
Filters:
| Filter | Shows attempts |
|---|---|
| Job ID | Of one trigger. Paste its full trigger ID. |
| Custom key | Of one-shot triggers whose custom key is exactly this, case included. Unlike on the Triggers page, part of a key doesn't match. |
| Job status | Of triggers that have this status now, not when the attempt ran. The values are API names: registered is Scheduled. |
| Execution status | With this status: planned, started, complete or cancelled. |
| HTTP status | Whose response had this status class (2xx to 5xx) or code. Attempts without a response, such as timeouts, network errors and attempts not sent yet, never match. |
| Only dead letters | That are dead letters: final failures with no retry to follow. |
- Filters combine, and the list goes back to page 1 when you change one. The text boxes apply 300 ms after you stop typing.
- With a filter set, Clear filters and a match count appear. More than 10,000 matches show as "10,000+".
- The page doesn't update live: click the refresh button to load new attempts.
Tag policies
Tag Policies manages the same policies as the /tag-policies API, with the same rules. The table has one row per tag, newest first, with the policy as badges:
| Badge | Meaning |
|---|---|
2/10s | Throughput: at most 2 requests per 10 seconds. One badge per window; hover for an explanation. 0.2/1s means one request every 5 seconds, and a rate of 0 blocks the tag. |
Concurrency 2 slots | Concurrency: at most 2 requests in flight. |
Timeout 30 sec | Request timeout. |
retry ≤4× ·exp(5s)·5xx+net | Retries: at most 4 attempts in all (∞× for no limit), exponential from 5 seconds (a fixed delay shows as, for example, 10s), on 5xx+net, net or non-2xx failures. Only shown when retries are on. |
| No policy set | The policy sets nothing. |
Add policy opens a form:
- Tag: lowercase letters, digits,
-and_, up to 50 characters. What you type is lowercased. With any other character, the form doesn't submit and puts the cursor back in the field, without a message. - Throughput: + Add throughput rule adds a row "rate per n sec / min / hr / day". The rate can be a decimal; the window length is a whole number. ✕ removes a row, and a row without a rate is ignored. Each window can appear only once (
60 secand1 mincount as different windows). A hint under each row explains the rule. - Concurrency (slots) and Timeout (sec), whole numbers: leave them blank for no concurrency limit and the default 300-second timeout. The timeout ranges from 1 to 3600 seconds.
- Retry policy: set the Strategy to Fixed delay or Exponential backoff to turn retries on (the default is None (no retries)). The other fields then appear:
- Retry on: 5xx + network (default), Network errors only or Any non-2xx (incl. 4xx).
- Max attempts (blank = ∞): includes the first attempt.
- Delay between attempts (sec), or Initial delay (sec) for exponential backoff: required.
- Max delay cap (sec): exponential backoff only.
- Add jitter.
- Click Create. Errors, such as a missing delay or a policy that sets nothing, appear in a red banner above the table.
Good to know
- Adding a tag that already has a policy replaces that policy, without a warning.
- Edit opens the policy in its row. The tag can't be changed. Save sends every field: a field you leave blank is cleared, and removing every throughput row removes the throughput limit. Unlike Create, Save accepts a policy that sets nothing.
- Retry fields that are hidden after you change the Strategy keep their values, and those values are saved too.
- Delete removes the policy immediately, without confirmation.
- A change applies to triggers you scheduled earlier too, from their next attempt. See Tag policies.
Live updates
Only the Triggers page updates live. The indicator next to its refresh button reads Live when connected, Connecting while it connects or reconnects, and Offline otherwise. The browser reconnects by itself.
- Rows on screen update their status, title and times as triggers move along. With a status chip or a title search active, a row that stops matching disappears.
- Other triggers that are created or change are added at the top of the list, whatever the sort order, but only while you're on page 1 and only if they match your filters and search.
- The executions in an expanded row don't update live: collapse and expand the row to reload them.
After a live update, a row loses its result badge, duration, lag and "ran" prefix until you click the refresh button or reload the page.
The other pages load their data when you open them and again when you come back to the browser tab. To see new data in between, reload the page, or click the refresh button on Executions.
Dates and times
- Your time zone. The dashboard shows times in your browser's time zone, without a time zone label. The API works in UTC: a trigger due at
2030-01-01T09:00:00Zshows asJan 1, 09:00:00in London andJan 1, 04:00:00in New York. - Formats. Times use a 24-hour clock without the year, like
Jan 1, 09:00:00. Hover over a time in a list, or in a trigger's lifecycle, for the full date, likeJan 1, 2030, 9:00:00 AM. API key creation dates use your browser's date format. - Relative times count seconds within a minute of now ("12 seconds ago", "in 5 seconds"), updating every second. Beyond that, a label such as "1 minute ago" or "in about 3 hours" doesn't update by itself: it changes when the page reloads its data or, on Triggers, gets a live update. A future time starts counting down again once it's a minute away.
Dashboard endpoints
The dashboard calls these endpoints of the API, which also appear in the full spec. They accept only a signed-in dashboard session: called with an API key, in ttr-api-keyheader or Authorization: Bearer, they return 401 with the message Unauthorized. They aren't part of the public API; see Dashboard-only endpoints.
| Endpoint | Used for |
|---|---|
GET /keys, POST /keys, DELETE /keys/{id} | The API Keys page |
GET /jobs | The Triggers page and the trigger page |
GET /jobs/{id}/executions | A trigger's executions |
POST /jobs/{id}/executions | Replay now and Retry now |
GET /executions | The Executions page |
GET /jobstakesstatus,id,title,customKey,tag,limit(default 50, at most 100) andoffset. WithtitleorcustomKey, the response'stotalis-1, meaning not counted. The 3-character minimum applies only in the dashboard.GET /executionstakesjobId,customKey,jobStatus,executionStatus,httpStatus(a code, or a class such as4xx),deadLetterOnly=true,limit(default 50, at most 200) andoffset.totalstops counting at10001.POST /jobs/{id}/executionstakes{"triggeredBy": "replay"}or{"triggeredBy": "retry"}({}meansreplay) and returns{"ok": true}. Unlike the dashboard buttons, it doesn't check the trigger's status. On a trigger that hasn't fired yet, was skipped or was cancelled, it sends the request right away, and the trigger ends up Completed. On a Retrying trigger it sends nothing early, but it moves the trigger to Queued, so it can no longer be cancelled; the pending retry still fires at its time.