Skip to content

Emit a business signal (Model B input)

POST
/v1/signals
curl https://api.pacepayments.ai/v1/signals \
--request POST \
--header 'Authorization: Bearer <token>' \
--header 'Idempotency-Key: 7f8c9a4e-2b1d-4e5f-9a3c-d10f2b6e8c11' \
--header 'Content-Type: application/json' \
--data '{
"signal_type": "payment.received",
"subject_reference": "CUST-88213",
"dedupe_key": "payment.received:INV-2026-118442"
}'
Idempotency-Key
Any of:
string

One unique key per logical request (a UUID is recommended). The response is stored against (tenant, key, method, RESOLVED path) - the same key against a different path returns 409 idempotency_key_conflict. Same key plus same body replays the stored response for 48 hours.

Media typeapplication/json
SignalCreate
object
signal_type
required
Signal Type

Your own taxonomy (dot.case). Three types the platform interprets itself, and each stops a sequence: payment.received, claim.withdrawn, claim.disputed.

string
>= 3 characters <= 64 characters /^[a-z][a-z0-9_]*(\.[a-z][a-z0-9_]*)+$/
subject_reference
required
Subject Reference

The same person key as subject.reference on an order. It is how the signal finds the sequence.

string
>= 1 characters <= 128 characters
dedupe_key
required
Dedupe Key

A business key, not a technical one. A repeat returns the ORIGINAL signal with duplicate: true and triggers nothing again. Scoped to (tenant, signal_type), retained 90 days - longer than the Idempotency-Key header, which is why THIS value is what makes an at-least-once producer safe.

string
>= 1 characters <= 255 characters
occurred_at
Any of:
string format: date-time
subject
Any of:
Subject
object
reference
required
Reference

A stable person key ON YOUR SIDE. It carries the suppression check, sequence deduplication and access/erasure requests - it MUST denote the same person across every order. An empty or reused value silently merges two people into one.

string
>= 1 characters <= 128 characters
name
required
PersonName
object
given_name
Any of:
string
<= 100 characters
family_name
required
Family Name
string
>= 1 characters <= 100 characters
salutation
Any of:
string
<= 30 characters
date_of_birth
Any of:
string format: date
address
Any of:
PostalAddress
object
street
Any of:
string
<= 200 characters
house_number
Any of:
string
<= 20 characters
postal_code
Any of:
string
<= 12 characters
city
Any of:
string
<= 100 characters
country
Any of:
string
/^[A-Z]{2}$/
locale
Any of:
string
/^[a-z]{2,3}(-[A-Za-z0-9]{2,8})*$/
timezone
Any of:
string
contacts
Any of:
Array<object>
<= 10 items
ContactChannel
object
channel
required
Channel

V1 dials phone entries only; anything else is context for the agent (‘we emailed you the link’).

string
value
required
Value
string
>= 3 characters <= 320 characters
type
Any of:
string
priority
Any of:
integer
>= 1
context
Any of:
OrderContext

Everything the agent needs for this conversation.

object
claim
required
Claim
object
outstanding
required
Money
object
value
required
Value

An exact decimal, as a string - no float drift.

string
/^-?\d+(\.\d{1,2})?$/
currency
required
Currency

ISO 4217.

string
/^[A-Z]{3}$/
original
Any of:
Money
object
value
required
Value

An exact decimal, as a string - no float drift.

string
/^-?\d+(\.\d{1,2})?$/
currency
required
Currency

ISO 4217.

string
/^[A-Z]{3}$/
breakdown
Any of:
ClaimBreakdown

Itemisation of the claim.

object
principal
Any of:
Money
object
value
required
Value

An exact decimal, as a string - no float drift.

string
/^-?\d+(\.\d{1,2})?$/
currency
required
Currency

ISO 4217.

string
/^[A-Z]{3}$/
interest
Any of:
Money
object
value
required
Value

An exact decimal, as a string - no float drift.

string
/^-?\d+(\.\d{1,2})?$/
currency
required
Currency

ISO 4217.

string
/^[A-Z]{3}$/
dunning_fees
Any of:
Money
object
value
required
Value

An exact decimal, as a string - no float drift.

string
/^-?\d+(\.\d{1,2})?$/
currency
required
Currency

ISO 4217.

string
/^[A-Z]{3}$/
collection_fees
Any of:
Money
object
value
required
Value

An exact decimal, as a string - no float drift.

string
/^-?\d+(\.\d{1,2})?$/
currency
required
Currency

ISO 4217.

string
/^[A-Z]{3}$/
expenses
Any of:
Money
object
value
required
Value

An exact decimal, as a string - no float drift.

string
/^-?\d+(\.\d{1,2})?$/
currency
required
Currency

ISO 4217.

string
/^[A-Z]{3}$/
already_paid
Any of:
Money
object
value
required
Value

An exact decimal, as a string - no float drift.

string
/^-?\d+(\.\d{1,2})?$/
currency
required
Currency

ISO 4217.

string
/^[A-Z]{3}$/
creditor_name
required
Creditor Name

The CREDITOR on whose behalf you are collecting - not your own name. Named to the debtor on first contact and whenever asked.

string
>= 2 characters <= 200 characters
basis
required
ClaimBasis

Where the claim comes from - the answer to “what is this about?”.

object
kind
required
Kind
string
description
Any of:
string
<= 300 characters
concluded_on
Any of:
string format: date
titled
Titled

True when the claim carries an enforcement title (Mahnbescheid, Vollstreckungsbescheid, judgment). It changes what the agent may say about consequences and it extends the limitation period, so it is NEVER inferred.

boolean
title_reference
Any of:
string
<= 64 characters
disclosure
Any of:
ClaimDisclosure

The written statutory notice you have already sent.

It lets the agent REFER to that notice instead of improvising the disclosure. Whether your calls must carry the disclosure as well is your determination - this field is the record that you have provided it.

object
sent_at
Any of:
string format: date
reference
Any of:
string
<= 64 characters
reference
Any of:
ClaimReference
object
contract_number
Any of:
string
<= 64 characters
invoice_number
Any of:
string
<= 64 characters
invoice_date
Any of:
string format: date
case_number
Any of:
string
<= 64 characters
due_date
Any of:
string format: date
in_default_since
Any of:
string format: date
description
Any of:
string
<= 500 characters
history
History

Earlier touches, newest last. Capped - send what matters, not half your CRM.

Array<object>
<= 50 items
HistoryEntry

An earlier touch, on ANY channel.

The asymmetry with contacts is deliberate: sms, letter and whatsapp are allowed here because they record what YOU have already done. contacts does not know them, because Pace only makes calls. The agent uses the history for tone and continuity (“we have already written to you twice”).

object
channel
required
Channel
string
direction
required
Direction
string
Allowed values: outbound inbound
occurred_at
required
Occurred At
string format: date-time
kind
Any of:
string
<= 64 characters
outcome
Any of:
string
<= 64 characters
summary
Any of:
string
<= 1000 characters
reference
Any of:
string
<= 128 characters
variables
Any of:
object
key
additional properties
any
notes
Any of:
string
<= 2000 characters
metadata
Any of:

Your own opaque key-value pairs; mirrored on resources and in every event. CONTRACTUALLY free of personal data - Pace does not inspect the values. Whatever you put here falls outside the deletion and retention machinery that protects the rest of the order.

object
key
additional properties
any

Successful Response

Media typeapplication/json
Signal
object
signal_type
required
Signal Type
string
subject_reference
required
Subject Reference
string
dedupe_key
required
Dedupe Key
string
occurred_at
Any of:
string format: date-time
subject
Any of:
Subject
object
reference
required
Reference

A stable person key ON YOUR SIDE. It carries the suppression check, sequence deduplication and access/erasure requests - it MUST denote the same person across every order. An empty or reused value silently merges two people into one.

string
>= 1 characters <= 128 characters
name
required
PersonName
object
given_name
Any of:
string
<= 100 characters
family_name
required
Family Name
string
>= 1 characters <= 100 characters
salutation
Any of:
string
<= 30 characters
date_of_birth
Any of:
string format: date
address
Any of:
PostalAddress
object
street
Any of:
string
<= 200 characters
house_number
Any of:
string
<= 20 characters
postal_code
Any of:
string
<= 12 characters
city
Any of:
string
<= 100 characters
country
Any of:
string
/^[A-Z]{2}$/
locale
Any of:
string
/^[a-z]{2,3}(-[A-Za-z0-9]{2,8})*$/
timezone
Any of:
string
contacts
Any of:
Array<object>
ContactChannel
object
channel
required
Channel

V1 dials phone entries only; anything else is context for the agent (‘we emailed you the link’).

string
value
required
Value
string
>= 3 characters <= 320 characters
type
Any of:
string
priority
Any of:
integer
>= 1
context
Any of:
OrderContext

Everything the agent needs for this conversation.

object
claim
required
Claim
object
outstanding
required
Money
object
value
required
Value

An exact decimal, as a string - no float drift.

string
/^-?\d+(\.\d{1,2})?$/
currency
required
Currency

ISO 4217.

string
/^[A-Z]{3}$/
original
Any of:
Money
object
value
required
Value

An exact decimal, as a string - no float drift.

string
/^-?\d+(\.\d{1,2})?$/
currency
required
Currency

ISO 4217.

string
/^[A-Z]{3}$/
breakdown
Any of:
ClaimBreakdown

Itemisation of the claim.

object
principal
Any of:
Money
object
value
required
Value

An exact decimal, as a string - no float drift.

string
/^-?\d+(\.\d{1,2})?$/
currency
required
Currency

ISO 4217.

string
/^[A-Z]{3}$/
interest
Any of:
Money
object
value
required
Value

An exact decimal, as a string - no float drift.

string
/^-?\d+(\.\d{1,2})?$/
currency
required
Currency

ISO 4217.

string
/^[A-Z]{3}$/
dunning_fees
Any of:
Money
object
value
required
Value

An exact decimal, as a string - no float drift.

string
/^-?\d+(\.\d{1,2})?$/
currency
required
Currency

ISO 4217.

string
/^[A-Z]{3}$/
collection_fees
Any of:
Money
object
value
required
Value

An exact decimal, as a string - no float drift.

string
/^-?\d+(\.\d{1,2})?$/
currency
required
Currency

ISO 4217.

string
/^[A-Z]{3}$/
expenses
Any of:
Money
object
value
required
Value

An exact decimal, as a string - no float drift.

string
/^-?\d+(\.\d{1,2})?$/
currency
required
Currency

ISO 4217.

string
/^[A-Z]{3}$/
already_paid
Any of:
Money
object
value
required
Value

An exact decimal, as a string - no float drift.

string
/^-?\d+(\.\d{1,2})?$/
currency
required
Currency

ISO 4217.

string
/^[A-Z]{3}$/
creditor_name
required
Creditor Name

The CREDITOR on whose behalf you are collecting - not your own name. Named to the debtor on first contact and whenever asked.

string
>= 2 characters <= 200 characters
basis
required
ClaimBasis

Where the claim comes from - the answer to “what is this about?”.

object
kind
required
Kind
string
description
Any of:
string
<= 300 characters
concluded_on
Any of:
string format: date
titled
Titled

True when the claim carries an enforcement title (Mahnbescheid, Vollstreckungsbescheid, judgment). It changes what the agent may say about consequences and it extends the limitation period, so it is NEVER inferred.

boolean
title_reference
Any of:
string
<= 64 characters
disclosure
Any of:
ClaimDisclosure

The written statutory notice you have already sent.

It lets the agent REFER to that notice instead of improvising the disclosure. Whether your calls must carry the disclosure as well is your determination - this field is the record that you have provided it.

object
sent_at
Any of:
string format: date
reference
Any of:
string
<= 64 characters
reference
Any of:
ClaimReference
object
contract_number
Any of:
string
<= 64 characters
invoice_number
Any of:
string
<= 64 characters
invoice_date
Any of:
string format: date
case_number
Any of:
string
<= 64 characters
due_date
Any of:
string format: date
in_default_since
Any of:
string format: date
description
Any of:
string
<= 500 characters
history
History

Earlier touches, newest last. Capped - send what matters, not half your CRM.

Array<object>
<= 50 items
HistoryEntry

An earlier touch, on ANY channel.

The asymmetry with contacts is deliberate: sms, letter and whatsapp are allowed here because they record what YOU have already done. contacts does not know them, because Pace only makes calls. The agent uses the history for tone and continuity (“we have already written to you twice”).

object
channel
required
Channel
string
direction
required
Direction
string
Allowed values: outbound inbound
occurred_at
required
Occurred At
string format: date-time
kind
Any of:
string
<= 64 characters
outcome
Any of:
string
<= 64 characters
summary
Any of:
string
<= 1000 characters
reference
Any of:
string
<= 128 characters
variables
Any of:
object
key
additional properties
any
notes
Any of:
string
<= 2000 characters
metadata
Any of:

Your own opaque key-value pairs; mirrored on resources and in every event. CONTRACTUALLY free of personal data - Pace does not inspect the values. Whatever you put here falls outside the deletion and retention machinery that protects the rest of the order.

object
key
additional properties
any
id
required
Id
string
received_at
required
Received At
string format: date-time
duplicate
Duplicate

True when dedupe_key matched an earlier signal. This is then the ORIGINAL signal - the repeat triggered nothing again.

boolean
triggered
Triggered

Enrollments this signal created, and exit conditions it satisfied.

Array<object>
SignalTriggered

What this signal set in motion.

While sequence execution is not yet enabled the list is ALWAYS empty. That is not a placeholder but the state of things: with no ladders running, a signal can trigger nothing. It lets you wire up your producer completely and check deduplication against real duplicates BEFORE any of it calls anyone.

object
enrollment_id
Any of:
string
effect
Any of:
string
Example
{
"subject": {
"reference": "CUST-88213",
"locale": "de-DE",
"timezone": "Europe/Berlin"
},
"contacts": [
{
"channel": "phone"
}
],
"context": {
"claim": {
"outstanding": {
"value": "129.90",
"currency": "EUR"
},
"original": {
"value": "129.90",
"currency": "EUR"
},
"breakdown": {
"principal": {
"value": "129.90",
"currency": "EUR"
},
"interest": {
"value": "129.90",
"currency": "EUR"
},
"dunning_fees": {
"value": "129.90",
"currency": "EUR"
},
"collection_fees": {
"value": "129.90",
"currency": "EUR"
},
"expenses": {
"value": "129.90",
"currency": "EUR"
},
"already_paid": {
"value": "129.90",
"currency": "EUR"
}
},
"creditor_name": "Truman Textilien GmbH",
"basis": {
"description": "Jahresabo Textilpflege Premium, abgeschlossen am 12.06.2025"
},
"titled": false
},
"history": [
{
"direction": "outbound"
}
]
},
"metadata": {
"campaign": "q3-onboarding",
"cost_center": "77"
},
"id": "sig_01J40FQ2ZK",
"duplicate": false
}

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.

Media typeapplication/problem+json
Problem
object
type
required
Type
string
title
required
Title
string
status
required
Status
integer
code
required
Code
string
detail
Any of:
string
instance
Any of:
string
trace_id
Any of:
string
errors
Any of:
Array<object>
FieldError
object
pointer
required
Pointer

RFC 6901 pointer to the offending field in the request body. Errors outside the body carry their source as the first segment (e.g. /query/limit).

string
code
required
Code

Stable field error code (open registry).

string
message
Any of:
string
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.

Media typeapplication/problem+json
Problem
object
type
required
Type
string
title
required
Title
string
status
required
Status
integer
code
required
Code
string
detail
Any of:
string
instance
Any of:
string
trace_id
Any of:
string
errors
Any of:
Array<object>
FieldError
object
pointer
required
Pointer

RFC 6901 pointer to the offending field in the request body. Errors outside the body carry their source as the first segment (e.g. /query/limit).

string
code
required
Code

Stable field error code (open registry).

string
message
Any of:
string
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

Media typeapplication/json
HTTPValidationError
object
detail
Detail
Array<object>
ValidationError
object
loc
required
Location
Array
msg
required
Message
string
type
required
Error Type
string
input
Input
ctx
Context
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.

Media typeapplication/problem+json
Problem
object
type
required
Type
string
title
required
Title
string
status
required
Status
integer
code
required
Code
string
detail
Any of:
string
instance
Any of:
string
trace_id
Any of:
string
errors
Any of:
Array<object>
FieldError
object
pointer
required
Pointer

RFC 6901 pointer to the offending field in the request body. Errors outside the body carry their source as the first segment (e.g. /query/limit).

string
code
required
Code

Stable field error code (open registry).

string
message
Any of:
string
Examplegenerated
{
"type": "example",
"title": "example",
"status": 1,
"code": "example",
"detail": "example",
"instance": "example",
"trace_id": "example",
"errors": [
{
"pointer": "example",
"code": "example",
"message": "example"
}
]
}
Retry-After
integer

Seconds until the next attempt is permitted.

RateLimit-Limit
integer
RateLimit-Remaining
integer
RateLimit-Reset
integer

Error (RFC 9457). Branch on code, never on title or detail.

Media typeapplication/problem+json
Problem
object
type
required
Type
string
title
required
Title
string
status
required
Status
integer
code
required
Code
string
detail
Any of:
string
instance
Any of:
string
trace_id
Any of:
string
errors
Any of:
Array<object>
FieldError
object
pointer
required
Pointer

RFC 6901 pointer to the offending field in the request body. Errors outside the body carry their source as the first segment (e.g. /query/limit).

string
code
required
Code

Stable field error code (open registry).

string
message
Any of:
string
Examplegenerated
{
"type": "example",
"title": "example",
"status": 1,
"code": "example",
"detail": "example",
"instance": "example",
"trace_id": "example",
"errors": [
{
"pointer": "example",
"code": "example",
"message": "example"
}
]
}