> ## Documentation Index
> Fetch the complete documentation index at: https://schedy.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Create a task

> POST /tasks - schedule an HTTP request for a future time.

```
POST /tasks
```

Schedule an HTTP request for a future time.

## Request fields

| Field            | Type   | Description                                                                                                                                                                   |
| ---------------- | ------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `execute_at`     | string | When to run (RFC3339, UTC). Must be in the future. Exactly one of `execute_at` or `execute_in` is required.                                                                   |
| `execute_in`     | string | How long from now to run, as a positive Go duration (`"5m"`, `"2h"`). The server stores the resolved absolute time. Exactly one of `execute_at` or `execute_in` is required.  |
| `url`            | string | **Required.** Where to send the request.                                                                                                                                      |
| `method`         | string | Optional HTTP verb: `GET`, `POST`, `PUT`, `PATCH`, `DELETE`, `HEAD` (default `POST`). `GET`/`HEAD` send no body.                                                              |
| `headers`        | object | Optional map of HTTP headers to send.                                                                                                                                         |
| `payload`        | any    | Optional body: JSON object, string, or form data.                                                                                                                             |
| `retries`        | int    | Optional number of retries.                                                                                                                                                   |
| `retry_interval` | int    | Optional ms between retries (default `2000`).                                                                                                                                 |
| `retry_mode`     | string | Optional retry timing: `fixed` (default) or `exponential` (backoff + jitter). See [Retries](/concepts/retries).                                                               |
| `schedule`       | string | Optional recurrence interval as a Go duration (`"15m"`, `"2h"`). After each fire, a fresh one-shot task is enqueued at `fire_time + schedule`. See [Recurrence](#recurrence). |

## Recurrence

Set `schedule` to an interval and the task becomes recurring: each time it fires, Schedy enqueues a fresh one-shot task at `fire_time + schedule`.
The interval is a [Go duration](https://pkg.go.dev/time#ParseDuration) - `"30s"`, `"15m"`, `"2h"` - and must be positive.

```bash theme={null}
curl -X POST http://localhost:8080/tasks \
  -H "Content-Type: application/json" \
  -H "X-API-Key: your-secret" \
  -d '{
    "execute_at": "2030-05-26T15:00:00Z",
    "url": "https://example.com/heartbeat",
    "schedule": "15m"
  }'
```

To stop a recurring task, [cancel](/api/cancel) the current pending task - the chain stops because no successor is enqueued.

<Note>
  This is **interval-only recurrence, deliberately not cron.** There is no cron syntax, no timezones, no DST handling, and no catch-up for missed fires - the next fire is always measured forward from the moment the task actually ran. If you need calendar scheduling, run cron on your side and POST one-shot tasks.
</Note>

## Example

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST http://localhost:8080/tasks \
    -H "Content-Type: application/json" \
    -H "X-API-Key: your-secret" \
    -d '{
      "url": "https://example.com/webhook",
      "execute_at": "2030-01-01T09:00:00Z",
      "payload": { "event": "user.created" }
    }'
  ```

  ```javascript JavaScript theme={null}
  const res = await fetch("http://localhost:8080/tasks", {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      "X-API-Key": "your-secret",
    },
    body: JSON.stringify({
      url: "https://example.com/webhook",
      execute_at: "2030-01-01T09:00:00Z",
      payload: { event: "user.created" },
    }),
  });

  const task = await res.json();
  console.log(task);
  ```

  ```python Python theme={null}
  import requests

  resp = requests.post(
      "http://localhost:8080/tasks",
      headers={
          "Content-Type": "application/json",
          "X-API-Key": "your-secret",
      },
      json={
          "url": "https://example.com/webhook",
          "execute_at": "2030-01-01T09:00:00Z",
          "payload": {"event": "user.created"},
      },
  )

  print(resp.json())
  ```

  ```go Go theme={null}
  package main

  import (
  	"bytes"
  	"encoding/json"
  	"fmt"
  	"io"
  	"net/http"
  )

  func main() {
  	body, _ := json.Marshal(map[string]any{
  		"url":        "https://example.com/webhook",
  		"execute_at": "2030-01-01T09:00:00Z",
  		"payload":    map[string]any{"event": "user.created"},
  	})

  	req, _ := http.NewRequest("POST", "http://localhost:8080/tasks", bytes.NewReader(body))
  	req.Header.Set("Content-Type", "application/json")
  	req.Header.Set("X-API-Key", "your-secret")

  	resp, err := http.DefaultClient.Do(req)
  	if err != nil {
  		panic(err)
  	}
  	defer resp.Body.Close()

  	out, _ := io.ReadAll(resp.Body)
  	fmt.Println(string(out))
  }
  ```
</CodeGroup>

The `X-API-Key` header is only required when the server is started with `SCHEDY_API_KEY` set; otherwise you can omit it.
Send an optional `Idempotency-Key` header to make retries safe - a repeat with the same key returns the task the first call created instead of scheduling a duplicate.
See [Idempotency](/concepts/idempotency).

Payloads are flexible - a JSON object (default `Content-Type: application/json`), form data (`application/x-www-form-urlencoded`), or plain text; set the `Content-Type` header to match.

## Responses

| Response          | Meaning                                              |
| ----------------- | ---------------------------------------------------- |
| `201 Created`     | Task scheduled; returns the task.                    |
| `200 OK`          | Idempotent match; returns the existing pending task. |
| `400 Bad Request` | Invalid body, bad time format, or time in the past.  |
