Getting KP API Schedule to Actually Work
KP API Schedule is one of those tools that sounds straightforward until you actually try to wire it into a production environment. I spent about three weeks untangling it late last year when we needed to migrate our batch jobs off a cron-based system. The documentation is decent but it assumes you already understand how the scheduler handles timezone conversions and retry logic. They don't really tell you that. At its core, KP API Schedule lets you define job definitions with a JSON payload, submit them to an endpoint, and the service handles execution windows, dependencies, and retry attempts. You don't write the polling loops yourself. You don't manage the worker pool. The API takes a request body that looks something like this: That gets POSTed to the /jobs endpoint with your auth token. The scheduler responds with a confirmation and a job reference ID you can query later. Simple on paper. In practice, the first thing that bites you is the timezone handling. The cron expression is evaluated server-side in whatever timezone you specify, but if you're triggering jobs that depend on downstream systems in different timezones, the alignment can drift. I learned this the hard way when a job scheduled for 6 AM Eastern ran successfully on the schedule but hit a data pipeline that hadn't finished its own EOD processing yet because it ran on Pacific time. The data was incomplete. The job reported success anyway because it checked the wrong status endpoint.
Most people skip ahead past the "quick start" section and assume everything else works how it should. A few things that aren't emphasized enough: Idempotency keys are not optional. Every job submission supports an optional idempotency_key field. If two requests come in with the same key within a 24-hour window, the second one is silently dropped and returns the original job's state. This sounds great until you realize that if your client has a network blip and retries the submission without knowing, you might accidentally suppress a legitimate second run. I've seen teams disable idempotency keys in development because they were getting confused by duplicate job states, then deploy to production and lose audit trails. Don't do that. Use proper UUIDs generated at the point of submission, not timestamps or hashes of the payload. The wait_for_completion parameter is async, not blocking. There's a query parameter that lets you poll for completion in the same request, but it has a hard timeout of 30 seconds. If your jobs take longer than that, you get a partial response. The correct pattern is to submit, capture the job ID, then poll /jobs/{id}/status on a delay. Set your polling interval to something reasonable like 15 to 30 seconds depending on your job type. Polling every second just floods the API and gets you rate-limited.
Batch endpoints require careful ordering. You can submit up to 50 jobs in a single batch request. The API guarantees ordering within that batch, but only within that request. If you split 500 jobs across 10 batch requests, there is no cross-request ordering guarantee. If your jobs have hard dependencies, group dependent jobs into the same batch or use the dependency field to declare them explicitly. The scheduler respects dependency declarations and will wait for upstream jobs to complete before triggering downstream ones, but only if the dependencies are in the same tenant context.
Get the Full Details

Rate limits and what happens when you hit them
The default rate limit is 100 requests per minute per API key. This includes both writes and reads. If you're submitting jobs and polling statuses at scale, you can burn through that quickly. The response headers include X-RateLimit-Remaining and X-RateLimit-Reset. Watch those. When you hit the limit, the API returns a 429 with a Retry-After header telling you how many seconds to wait. A proper client should implement exponential backoff starting at 1 second and capping at 30 seconds, not just retry immediately. I wrote a wrapper library around the HTTP client that handles this automatically because I got tired of 429 errors interrupting our deployment scripts. KP API Schedule uses Bearer token authentication. You generate keys from the dashboard under API Settings. Each key is tied to a specific tenant and has scope restrictions you can define at creation time. The scopes control whether a key can read jobs, write jobs, or do both. I recommend creating separate keys for read and write operations and rotating them quarterly. The tokens don't expire on their own, but if one gets leaked, you're stuck waiting for manual revocation through support unless you built a rotation process yourself. We built one. It's a GitHub Actions workflow that generates a new key, updates the secret store, and restarts the scheduler processes with the new token. Takes about four minutes end to end. The biggest one I see is assuming the scheduler timezone and your application timezone are the same. They're not. The scheduler runs on UTC by default unless you explicitly set the timezone in the schedule object. If you send a cron expression without specifying timezone, it assumes UTC. If your monitoring dashboard shows job times in local time, you'll think the schedule is broken when it's just shifted. Always set the timezone field explicitly. It's two extra lines in your payload and it prevents a whole category of debugging sessions.
Another one: not testing the dry_run flag. There's a dry_run parameter you can set to true on job submission. It validates the entire payload, checks timezone parsing, verifies that the targets exist, and confirms the retry policy is well-formed, but it doesn't actually schedule anything. Use it before committing to a job definition. I stopped skipping this step after spending two hours debugging why a batch of 47 jobs failed validation only to find that one of the target server names had a trailing space.
Webhooks versus polling
For production systems, webhooks are the better option if your infrastructure supports them. The API can POST completion events to a URL you register. This eliminates polling entirely and gives you real-time feedback. The tradeoff is that webhook URLs need to be publicly accessible and handle authentication themselves. If you're running behind a firewall or using a private VPC, you'll need a relay or a proxy. We use AWS EventBridge as an intermediary because it handles the public-facing webhook URL while routing internally to our private processing pipeline. KP API Schedule is a scheduler, not an execution engine. It queues jobs and notifies downstream systems. It does not run code, process data, or validate the output of your jobs. If you need validation logic, error handling, or data transformation, that lives in your worker applications, not in the scheduler itself. The retry policy is about rescheduling, not about fixing the underlying problem. A job that fails because of a bad database connection will retry three times and then fail again. The scheduler will mark it as failed and move on. Someone still needs to look at it. If you're building something that requires complex conditional branching between jobs, custom error recovery, or stateful workflows, consider whether a full orchestration tool like Apache Airflow or Temporal would serve you better. KP API Schedule works well for straightforward fire-and-forget or callback-based job queues. It's not designed for DAG-based workflows with branching logic. Mixing the two approaches usually ends badly.

Getting started
You'll need an account at KP's developer portal. The signup process takes about ten minutes. Once you have an API key, the base URL is https://api.kpschedule.com/v2. From there, the workflow is: validate with dry_run, submit the job, poll or listen for the webhook, verify the result in your own system. That's the full loop. Most people get stuck at step one because the dry_run response format isn't clearly documented. It returns a 202 Accepted with a warnings array if there are any non-fatal issues. Read the warnings even if the job seems to validate. Some of them become fatal under certain conditions. I keep a minimal reference script in Python on my machine that handles the common operations. Submit, poll, check status, cancel. It's saved as ~/scripts/kp_schedule.py and I add to it whenever I run into a new edge case. The current version is about 180 lines. It's not beautiful but it works. I'll leave the link off this post since the code changes frequently and I don't want to maintain a stale gist.