Endpoint profiles
An endpoint profile is a named, reusable destination plus its delivery policy. Instead
of repeating the same URL, headers, and retry settings on every schedule, you define them
once as a profile (ep_…) and reference it by endpoint_id. Edit the profile and future
deliveries pick up the change automatically — without rewriting any schedule.
Use a profile when more than one schedule targets the same destination, or when you want a single place to rotate auth headers and tune retry/breaker behavior.
# Create a profile once...curl -sS https://api.schedstack.com/v1/endpoints \ -H "Authorization: Bearer sk_test_…" \ -H "Content-Type: application/json" \ -d '{ "url": "https://example.com/hooks/billing", "method": "POST", "headers": { "X-Api-Key": "whk_abc123" } }'{ "id": "ep_3Qa1bC2dEf", "object": "endpoint", "mode": "test", "url": "https://example.com/hooks/billing", "method": "POST", "timeout": null, "header_keys": ["X-Api-Key"], "metadata": {}, "version": 1, "archived": false, "created_at": "2026-06-27T12:00:00Z", "updated_at": "2026-06-27T12:00:00Z"}Create a profile
Section titled “Create a profile”POST /v1/endpoints. Only url is required, and it must be an https URL.
| Field | Required | Notes |
|---|---|---|
url |
yes | https only. A non-https URL returns 422 url_blocked; an absent one returns 422 missing_url. The URL is not pre-trusted — the resolved IP is re-validated at connect time on every delivery. |
method |
no | Defaults to POST. An unsupported method returns 400 invalid_method. |
headers |
no | Static auth/custom headers (object of string→string). |
retry_policy |
no | Same shape and bounds as a schedule’s retry policy (max_attempts + backoff). |
retry_budget |
no | { "rate": <number>, "burst": <number> }. Caps retry amplification against this destination. Both values must be ≥ 0. |
breaker_policy |
no | Circuit-breaker tuning. See Breaker policy — all four fields are required together. |
timeout |
no | Per-request HTTP timeout (duration string up to 1h). Stored but not yet enforced — see below. |
rate_limit |
no | { "per_second": <number> }, ≥ 0. Stored but not yet enforced — see below. |
metadata |
no | Free-form string→string map for your own bookkeeping. |
Breaker policy
Section titled “Breaker policy”When you set breaker_policy, all four fields are required — an omitted (zero) open or
probe window produces a breaker that re-opens immediately, i.e. no protection, so the API
rejects a partial policy with 422 invalid_breaker_policy.
| Field | Notes |
|---|---|
threshold |
Consecutive failures before the circuit opens. Integer, 1–1000. |
base_open |
Initial open duration. Positive duration string, up to 24h. |
max_open |
Cap on the (backing-off) open duration. Up to 24h. |
probe_timeout |
How long a half-open probe may run before it counts as a failure. Up to 24h. |
curl -sS https://api.schedstack.com/v1/endpoints \ -H "Authorization: Bearer sk_test_…" \ -H "Content-Type: application/json" \ -d '{ "url": "https://example.com/hooks/billing", "method": "POST", "headers": { "X-Api-Key": "whk_abc123" }, "retry_policy": { "max_attempts": 6 }, "retry_budget": { "rate": 10, "burst": 100 }, "breaker_policy": { "threshold": 20, "base_open": "30s", "max_open": "10m", "probe_timeout": "5s" }, "metadata": { "team": "billing" } }'Reference a profile from a schedule
Section titled “Reference a profile from a schedule”On POST /v1/schedules, pass endpoint_id instead of the inline endpoint. The two
are mutually exclusive.
curl -sS https://api.schedstack.com/v1/schedules \ -H "Authorization: Bearer sk_test_…" \ -H "Content-Type: application/json" \ -d '{ "endpoint_id": "ep_3Qa1bC2dEf", "delay": "1h", "body": { "invoice": "inv_123" } }'The schedule inherits the profile’s URL, method, headers, and policies. You still set the
per-schedule fields — timing (delay / fire_at / cron), body, ttl,
idempotency_key, metadata — on the schedule itself.
Live-link and freeze-per-delivery
Section titled “Live-link and freeze-per-delivery”A profile is a live link for future deliveries but a frozen snapshot within a delivery. This is what makes editing a profile safe.
- Every mutating edit (
PATCH) bumps the profile’sversion. - When a delivery is materialized, SchedStack resolves the profile and snapshots the version it resolved onto that delivery. New occurrences re-resolve, so a profile edit (new header, rotated auth, tuned retry) automatically reaches future deliveries.
- That snapshot is frozen for the life of the delivery, including every retry. A single logical delivery never switches destination mid-retry after a profile edit — its retries hit the same URL with the same resolved config it started with.
This keeps receiver dedup correct (a stable Idempotency-Key always lands on one
destination) and keeps history auditable: you can ask which URL and profile version an
attempt actually used, and the answer never changes.
Update a profile
Section titled “Update a profile”PATCH /v1/endpoints/{id} updates any subset of fields and bumps version. Future
deliveries resolve against the new version; in-flight deliveries keep their frozen
snapshot.
curl -sS -X PATCH https://api.schedstack.com/v1/endpoints/ep_3Qa1bC2dEf \ -H "Authorization: Bearer sk_test_…" \ -H "Content-Type: application/json" \ -d '{ "headers": { "X-Api-Key": "whk_rotated456" } }'The same validation as create applies (https-only URL, supported method, full
breaker_policy if present, retry_budget / rate_limit ≥ 0).
Read and list profiles
Section titled “Read and list profiles”-
Fetch one:
Terminal window curl -sS https://api.schedstack.com/v1/endpoints/ep_3Qa1bC2dEf \-H "Authorization: Bearer sk_test_…" -
List them (cursor-paginated). Archived profiles are excluded unless you ask for them:
Terminal window curl -sS "https://api.schedstack.com/v1/endpoints?include_archived=true" \-H "Authorization: Bearer sk_test_…"
Profiles are scoped to (project, mode), like everything else: an sk_test_… key only
sees test profiles, and a schedule can only reference a profile in its own mode. See
Test vs live modes.
Archive a profile
Section titled “Archive a profile”There is no hard delete — history rows reference profiles forever. Instead, soft-archive:
curl -sS -X POST https://api.schedstack.com/v1/endpoints/ep_3Qa1bC2dEf/archive \ -H "Authorization: Bearer sk_test_…"An archived profile stays queryable for history and audit, but cannot back new schedules.
Inline endpoints still work
Section titled “Inline endpoints still work”You never have to use a profile. A schedule can carry its endpoint inline
(endpoint + headers + retry_policy + …) exactly as before — see
One-shot deliveries. Reach for a profile when the same
destination is used by more than one schedule, or when you want one place to rotate auth
and tune delivery policy.