Webhooks

Redeliver a webhook delivery

Re-queues an event for one endpoint.

POST/webhooks/{id}/deliveries/{deliveryId}/redeliver

Re-queues an event for one endpoint. This does not retry the original delivery row - it creates a new one with a fresh id that reuses the source delivery's eventId and eventType, and the response returns both so you can correlate them. The original row is left untouched as the historical record.

Because the eventId is reused, your receiver will see the same webhook-id header again. Idempotency on that value is what stops a redelivery from double-applying.

Only finished deliveries can be redelivered. A source in pending or processing is refused with 409 - the worker still owns it and will retry it on its own schedule. Wait for succeeded or failed.

The delivery must belong to the endpoint in the path; a real delivery id under the wrong {id} gets 404 webhook.delivery_not_found.

The endpoint must be enabled. Redelivering to a disabled endpoint is refused with 409 rather than queuing work that would immediately be marked failed.

The new delivery is created pending and picked up by the worker within a few seconds. The workspace is capped at 500 simultaneously queued (pending plus processing) deliveries; hitting that cap is a 409.

Returns 201 - a new delivery row is created.

Refused for project-restricted keys.

Requires the webhooks:write scope.

curl --request POST \
  --url 'https://api.envless.cloud/webhooks/<id>/deliveries/<deliveryId>/redeliver' \
  --header 'Authorization: Bearer ev_sk_xxxxxxxxxxxx'
Try itPOSThttps://api.envless.cloud/webhooks/{id}/deliveries/{deliveryId}/redeliver
Path parameters

Authorization

  • Authorizationstringrequiredheader

    Bearer token: an Envless API key (ev_sk_…), created in the dashboard or with POST /keys. The key is bound to one workspace; every request runs inside it.

Path parameters

  • idstringrequireduuid

    The endpoint's id (UUIDv7). Must be enabled, and must own the delivery.

  • deliveryIdstringrequireduuid

    The source delivery's id (UUIDv7). Must already be succeeded or failed.

Responses

201Created

Redeliver a webhook delivery succeeded.

  • successbooleanrequired
  • codeintegerrequired

    The HTTP status of this response, repeated in the body.

  • messagestringrequired
  • errornullrequired
  • dataobjectrequired
    Show child attributesHide child attributes
    • idstringrequired

      The NEW delivery's id. Poll GET /webhooks/{id}/deliveries/{deliveryId} with this to watch it.

    • webhookIdstringrequired

      The endpoint the new delivery targets.

    • sourceDeliveryIdstringrequired

      The delivery it was copied from. Its eventId and eventType are reused, so your receiver sees the same webhook-id header.

    • statusstringrequired

      Always pending - the worker has not run yet.

  • _reqobject
    Show child attributesHide child attributes
    • reqIdstring
    • resTimeinteger | null
{
    "success": true,
    "code": 201,
    "message": "OK",
    "error": null,
    "data": {
        "id": "<string>",
        "webhookId": "<string>",
        "sourceDeliveryId": "<string>",
        "status": "pending"
    },
    "_req": {
        "reqId": "<string>",
        "resTime": 1
    }
}

Error envelope

Every failure below returns the same shape with success: false; branch on error.code, never on message.

  • successbooleanrequired
  • codeintegerrequired

    The HTTP status of this response, repeated in the body.

  • messagestringrequired
  • errorobjectrequired

    Machine-readable failure detail. Null on success.

    Show child attributesHide child attributes
    • codeenum<string>required

      Stable error code. Branch on this, never on message.

      Options: "auth.api_key_required", "auth.api_key_not_found", "auth.api_key_user_missing", "auth.api_key_owner_not_member", "auth.scope_missing", "auth.scope_ceiling_exceeded", "auth.key_project_restricted", "auth.product_restricted", "auth.permission_denied", "auth.self_mutation_forbidden", "auth.step_up_required", "auth.step_up_fresh_required", "auth.cli_token_not_accepted", "auth.two_factor_required", "auth.workspace_two_factor_required", "auth.two_factor_invalid", "auth.two_factor_replayed", "auth.two_factor_locked", "auth.two_factor_not_enabled", "auth.two_factor_already_enabled", "request.body_must_be_json", "request.body_invalid", "request.body_too_large", "request.rate_limited", "request.invalid_pagination", "workspace.not_found", "workspace.slug_conflict", "workspace.limit_reached", "workspace.delete_last", "workspace.delete_too_early", "workspace.delete_has_projects", "domain.not_configured", "domain.not_found", "domain.invalid", "domain.taken", "domain.attempt_limit", "product.not_found", "product.slug_conflict", "product.locked", "project.not_found", "project.ambiguous_product", "project.slug_conflict", "environment.not_found", "environment.slug_conflict", "environment.expose_disabled", "environment.expose_private_product", "variable.not_found", "variable.name_conflict", "variable.ciphertext_invalid", "variable.baseline_drifted", "version.not_found", "member.not_found", "member.already_exists", "member.self_invite", "member.self_mutation", "member.owner_immutable", "member.owner_cannot_leave", "member.seat_limit", "invite.already_pending", "role.owner_not_assignable", "role.limit_reached", "role.immutable", "role.in_use", "invite.not_found", "invite.expired", "role.not_found", "role.name_conflict", "key.not_found", "key.limit_reached", "webhook.not_found", "webhook.delivery_not_found", "plan.limit_reached", "plan.upgrade_required", "request.not_found", "request.method_not_allowed", "request.conflict", "auth.unauthorized", "auth.forbidden", "request.invalid", "server.error"

    • resourcestring

      The resource or scope the failure relates to.

    • fieldstring

      The request field that caused the failure.

  • dataobject | nullrequired

    Null on most failures. A plan limit carries { limit, current }.

  • _reqobject
    Show child attributesHide child attributes
    • reqIdstring
    • resTimeinteger | null
{
    "success": false,
    "code": 401,
    "message": "Something went wrong.",
    "error": {
        "code": "auth.api_key_required",
        "resource": "<string>",
        "field": "<string>"
    },
    "data": {},
    "_req": {
        "reqId": "<string>",
        "resTime": 1
    }
}

401Unauthorized

  • auth.api_key_required - the Authorization header is missing, or its value does not start with ev_sk_.
  • auth.api_key_not_found - the key is unknown, inactive or revoked.
  • auth.api_key_user_missing - the key is valid but its owner no longer exists.
  • auth.api_key_owner_not_member - the key's owner is no longer a member of the key's workspace.

403Forbidden

  • auth.key_project_restricted - the calling key is fenced to specific projects.
  • auth.workspace_two_factor_required - the workspace requires two-factor authentication and the key's owner has not turned it on.
  • auth.scope_missing - the key lacks a scope this operation requires; error.resource names it.

404Not Found

  • webhook.not_found - no live endpoint with that id exists in this workspace.
  • webhook.delivery_not_found - no delivery with that id exists on this endpoint, including a real delivery that belongs to a different endpoint.

409Conflict

request.conflict - the source delivery is still pending or processing, the endpoint is disabled, or the workspace already has 500 queued deliveries.

500Internal Server Error

server.error - an unexpected error; retry with backoff.

503Service Unavailable

server.error - the API is in maintenance mode or is missing its configuration; retry with backoff.