Register an endpoint (starts verification challenge)
curl https://api.pacepayments.ai/v1/webhook-endpoints \ --request POST \ --header 'Authorization: Bearer <token>' \ --header 'Content-Type: application/json' \ --data '{ "url": "https://hooks.example.org/pace/v1"}'requests.post( "https://api.pacepayments.ai/v1/webhook-endpoints", headers={ "Authorization": "Bearer <token>", "Content-Type": "application/json" }, json={ "url": "https://hooks.example.org/pace/v1" })fetch('https://api.pacepayments.ai/v1/webhook-endpoints', { method: 'POST', headers: { Authorization: 'Bearer <token>', 'Content-Type': 'application/json' }, body: JSON.stringify({ url: 'https://hooks.example.org/pace/v1' })})using var client = new HttpClient();
var request = new HttpRequestMessage(HttpMethod.Post, "https://api.pacepayments.ai/v1/webhook-endpoints");request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", "<token>");request.Content = new StringContent("""{ "url": "https://hooks.example.org/pace/v1"}""",System.Text.Encoding.UTF8, "application/json");
using var response = await client.SendAsync(request);$ch = curl_init("https://api.pacepayments.ai/v1/webhook-endpoints");
curl_setopt($ch, CURLOPT_POST, true);curl_setopt($ch, CURLOPT_HTTPHEADER, ['Authorization: Bearer <token>', 'Content-Type: application/json']);curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode([ 'url' => 'https://hooks.example.org/pace/v1']));
curl_exec($ch);
curl_close($ch);package main
import ( "fmt" "io" "net/http" "strings")
func main() { requestUrl := "https://api.pacepayments.ai/v1/webhook-endpoints"
payload := strings.NewReader(`{ "url": "https://hooks.example.org/pace/v1"}`)
req, _ := http.NewRequest("POST", requestUrl, payload)
req.Header.Add("Authorization", "Bearer <token>") req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close() body, _ := io.ReadAll(res.Body)
fmt.Println(res) fmt.Println(string(body))
}OkHttpClient client = new OkHttpClient();
MediaType mediaType = MediaType.parse("application/json");RequestBody body = RequestBody.create(mediaType, "{\n \"url\": \"https://hooks.example.org/pace/v1\"\n}");Request request = new Request.Builder() .url("https://api.pacepayments.ai/v1/webhook-endpoints") .post(body) .addHeader("Authorization", "Bearer <token>") .addHeader("Content-Type", "application/json") .build();
Response response = client.newCall(request).execute();Authorizations
Section titled “Authorizations”Request Bodyrequired
Section titled “Request Bodyrequired”object
HTTPS, publicly resolvable, port 443 or 8443. Checked at registration AND before every dispatch.
thin = the envelope with related but WITHOUT data. The client fetches the resource over the API when it needs it.
Responses
Section titled “Responses”Successful Response
object
SHOWN ONCE. At creation and on every rotation - never retrievable afterwards. Store it now.
Example
{ "payload_mode": "full", "api_version": "v1", "status": "pending_verification", "verification": { "state": "pending" }, "health": { "consecutive_failures": 0 }, "secret": "whsec_9f2c4b7e1dREDACTED"}No valid access token. Client action: request a new token from the token endpoint and retry once. Repeated 401 with a fresh token means the client registration is disabled - contact Pace, do not retry in a loop.
object
Examplegenerated
{ "type": "example", "title": "example", "status": 1, "code": "example", "detail": "example", "instance": "example", "trace_id": "example", "errors": [ { "pointer": "example", "code": "example", "message": "example" } ]}Authenticated but not permitted. insufficient_scope names the missing scope in detail; feature_not_enabled means the tenant lacks the feature; ip_not_allowlisted means the source IP is not on the client registration’s allowlist; simulate_not_allowed means a sandbox-only simulate block was sent to the live host. None of these are retryable.
object
Examplegenerated
{ "type": "example", "title": "example", "status": 1, "code": "example", "detail": "example", "instance": "example", "trace_id": "example", "errors": [ { "pointer": "example", "code": "example", "message": "example" } ]}Validation Error
object
object
object
Examplegenerated
{ "detail": [ { "loc": [ "example" ], "msg": "example", "type": "example", "input": "example", "ctx": {} } ]}HTTP rate limit (rate_limited) or execution capacity refusal (quota_exceeded, backlog_full) - two distinct layers. Wait for Retry-After, then retry the identical request with the same Idempotency-Key. backlog_full will not clear in seconds; back off to minutes.
object
Examplegenerated
{ "type": "example", "title": "example", "status": 1, "code": "example", "detail": "example", "instance": "example", "trace_id": "example", "errors": [ { "pointer": "example", "code": "example", "message": "example" } ]}Headers
Section titled “Headers”Seconds until the next attempt is permitted.
default
Section titled “default”Error (RFC 9457). Branch on code, never on title or detail.
object
Examplegenerated
{ "type": "example", "title": "example", "status": 1, "code": "example", "detail": "example", "instance": "example", "trace_id": "example", "errors": [ { "pointer": "example", "code": "example", "message": "example" } ]}