Events
Beta8 events we post to your endpoint, each signed, and retried when your endpoint does not answer 2xx.
EVENT activation.code_receivedCode received
A code landed on a one-time number.
Verify `GhostSMS-Signature` over the raw body before trusting it, and deduplicate on `GhostSMS-Event-Id`: delivery is at least once.
Headers
GhostSMS-Event-IdstringRequired- Unique per event, and the same on every retry of it.
GhostSMS-Event-Type"activation.code_received"Required- The event, so the body can be parsed as the right thing.
GhostSMS-SignaturestringRequired- `t=<unix seconds>,v1=<hex HMAC-SHA256 of "<t>.<raw body>">`, keyed with the endpoint's signing secret. Reject a timestamp more than 5 minutes old.
Body
The activation object, exactly as a GET of it returns, frozen at the moment the event happened.
{
"object": "activation",
"id": "…",
"status": "…",
"service": {
"id": "…",
"name": "…"
},
"country": "…",
"phone_number": "…",
"price": {
"amount": 0,
"currency": "…"
},
"client_reference": "…",
"created_at": "2026-09-18T10:35:00Z",
"expires_at": "2026-09-18T10:35:00Z",
"cancel_available_at": "2026-09-18T10:35:00Z",
"no_code_available_at": "2026-09-18T10:35:00Z",
"messages_count": 0,
"messages": [
{
"object": "activation",
"id": "…",
"received_at": "2026-09-18T10:35:00Z",
"from": "…",
"text": "…",
"code": "…"
}
]
}EVENT activation.number_changedNumber replaced
A dead number was swapped for a new one; the activation carries on, on the number in the body.
Verify `GhostSMS-Signature` over the raw body before trusting it, and deduplicate on `GhostSMS-Event-Id`: delivery is at least once.
Headers
GhostSMS-Event-IdstringRequired- Unique per event, and the same on every retry of it.
GhostSMS-Event-Type"activation.number_changed"Required- The event, so the body can be parsed as the right thing.
GhostSMS-SignaturestringRequired- `t=<unix seconds>,v1=<hex HMAC-SHA256 of "<t>.<raw body>">`, keyed with the endpoint's signing secret. Reject a timestamp more than 5 minutes old.
Body
The activation object, exactly as a GET of it returns, frozen at the moment the event happened.
{
"object": "activation",
"id": "…",
"status": "…",
"service": {
"id": "…",
"name": "…"
},
"country": "…",
"phone_number": "…",
"price": {
"amount": 0,
"currency": "…"
},
"client_reference": "…",
"created_at": "2026-09-18T10:35:00Z",
"expires_at": "2026-09-18T10:35:00Z",
"cancel_available_at": "2026-09-18T10:35:00Z",
"no_code_available_at": "2026-09-18T10:35:00Z",
"messages_count": 0,
"messages": [
{
"object": "activation",
"id": "…",
"received_at": "2026-09-18T10:35:00Z",
"from": "…",
"text": "…",
"code": "…"
}
]
}EVENT activation.refundedActivation refunded
The activation ended without a code, and the price went back to the balance.
Verify `GhostSMS-Signature` over the raw body before trusting it, and deduplicate on `GhostSMS-Event-Id`: delivery is at least once.
Headers
GhostSMS-Event-IdstringRequired- Unique per event, and the same on every retry of it.
GhostSMS-Event-Type"activation.refunded"Required- The event, so the body can be parsed as the right thing.
GhostSMS-SignaturestringRequired- `t=<unix seconds>,v1=<hex HMAC-SHA256 of "<t>.<raw body>">`, keyed with the endpoint's signing secret. Reject a timestamp more than 5 minutes old.
Body
The activation object, exactly as a GET of it returns, frozen at the moment the event happened.
{
"object": "activation",
"id": "…",
"status": "…",
"service": {
"id": "…",
"name": "…"
},
"country": "…",
"phone_number": "…",
"price": {
"amount": 0,
"currency": "…"
},
"client_reference": "…",
"created_at": "2026-09-18T10:35:00Z",
"expires_at": "2026-09-18T10:35:00Z",
"cancel_available_at": "2026-09-18T10:35:00Z",
"no_code_available_at": "2026-09-18T10:35:00Z",
"messages_count": 0,
"messages": [
{
"object": "activation",
"id": "…",
"received_at": "2026-09-18T10:35:00Z",
"from": "…",
"text": "…",
"code": "…"
}
]
}EVENT activation.completedActivation finished
The activation's window closed after a code had arrived.
Verify `GhostSMS-Signature` over the raw body before trusting it, and deduplicate on `GhostSMS-Event-Id`: delivery is at least once.
Headers
GhostSMS-Event-IdstringRequired- Unique per event, and the same on every retry of it.
GhostSMS-Event-Type"activation.completed"Required- The event, so the body can be parsed as the right thing.
GhostSMS-SignaturestringRequired- `t=<unix seconds>,v1=<hex HMAC-SHA256 of "<t>.<raw body>">`, keyed with the endpoint's signing secret. Reject a timestamp more than 5 minutes old.
Body
The activation object, exactly as a GET of it returns, frozen at the moment the event happened.
{
"object": "activation",
"id": "…",
"status": "…",
"service": {
"id": "…",
"name": "…"
},
"country": "…",
"phone_number": "…",
"price": {
"amount": 0,
"currency": "…"
},
"client_reference": "…",
"created_at": "2026-09-18T10:35:00Z",
"expires_at": "2026-09-18T10:35:00Z",
"cancel_available_at": "2026-09-18T10:35:00Z",
"no_code_available_at": "2026-09-18T10:35:00Z",
"messages_count": 0,
"messages": [
{
"object": "activation",
"id": "…",
"received_at": "2026-09-18T10:35:00Z",
"from": "…",
"text": "…",
"code": "…"
}
]
}EVENT rental.message_receivedRental message received
A message arrived on a long-term rental.
Verify `GhostSMS-Signature` over the raw body before trusting it, and deduplicate on `GhostSMS-Event-Id`: delivery is at least once.
Headers
GhostSMS-Event-IdstringRequired- Unique per event, and the same on every retry of it.
GhostSMS-Event-Type"rental.message_received"Required- The event, so the body can be parsed as the right thing.
GhostSMS-SignaturestringRequired- `t=<unix seconds>,v1=<hex HMAC-SHA256 of "<t>.<raw body>">`, keyed with the endpoint's signing secret. Reject a timestamp more than 5 minutes old.
Body
The rental object, exactly as a GET of it returns, frozen at the moment the event happened.
{
"object": "activation",
"id": "…",
"status": "…",
"service": {
"id": "…",
"name": "…"
},
"country": "…",
"phone_number": "…",
"price": {
"amount": 0,
"currency": "…"
},
"duration": "…",
"client_reference": "…",
"created_at": "2026-09-18T10:35:00Z",
"expires_at": "2026-09-18T10:35:00Z",
"extended_at": "2026-09-18T10:35:00Z",
"cancel_available_until": "2026-09-18T10:35:00Z",
"messages_count": 0,
"messages": [
{
"object": "activation",
"id": "…",
"received_at": "2026-09-18T10:35:00Z",
"from": "…",
"text": "…",
"code": "…"
}
]
}EVENT rental.extendedRental extended
The rental's expiry moved later.
Verify `GhostSMS-Signature` over the raw body before trusting it, and deduplicate on `GhostSMS-Event-Id`: delivery is at least once.
Headers
GhostSMS-Event-IdstringRequired- Unique per event, and the same on every retry of it.
GhostSMS-Event-Type"rental.extended"Required- The event, so the body can be parsed as the right thing.
GhostSMS-SignaturestringRequired- `t=<unix seconds>,v1=<hex HMAC-SHA256 of "<t>.<raw body>">`, keyed with the endpoint's signing secret. Reject a timestamp more than 5 minutes old.
Body
The rental object, exactly as a GET of it returns, frozen at the moment the event happened.
{
"object": "activation",
"id": "…",
"status": "…",
"service": {
"id": "…",
"name": "…"
},
"country": "…",
"phone_number": "…",
"price": {
"amount": 0,
"currency": "…"
},
"duration": "…",
"client_reference": "…",
"created_at": "2026-09-18T10:35:00Z",
"expires_at": "2026-09-18T10:35:00Z",
"extended_at": "2026-09-18T10:35:00Z",
"cancel_available_until": "2026-09-18T10:35:00Z",
"messages_count": 0,
"messages": [
{
"object": "activation",
"id": "…",
"received_at": "2026-09-18T10:35:00Z",
"from": "…",
"text": "…",
"code": "…"
}
]
}EVENT rental.refundedRental refunded
The rental was cancelled inside its refund window, and the price went back.
Verify `GhostSMS-Signature` over the raw body before trusting it, and deduplicate on `GhostSMS-Event-Id`: delivery is at least once.
Headers
GhostSMS-Event-IdstringRequired- Unique per event, and the same on every retry of it.
GhostSMS-Event-Type"rental.refunded"Required- The event, so the body can be parsed as the right thing.
GhostSMS-SignaturestringRequired- `t=<unix seconds>,v1=<hex HMAC-SHA256 of "<t>.<raw body>">`, keyed with the endpoint's signing secret. Reject a timestamp more than 5 minutes old.
Body
The rental object, exactly as a GET of it returns, frozen at the moment the event happened.
{
"object": "activation",
"id": "…",
"status": "…",
"service": {
"id": "…",
"name": "…"
},
"country": "…",
"phone_number": "…",
"price": {
"amount": 0,
"currency": "…"
},
"duration": "…",
"client_reference": "…",
"created_at": "2026-09-18T10:35:00Z",
"expires_at": "2026-09-18T10:35:00Z",
"extended_at": "2026-09-18T10:35:00Z",
"cancel_available_until": "2026-09-18T10:35:00Z",
"messages_count": 0,
"messages": [
{
"object": "activation",
"id": "…",
"received_at": "2026-09-18T10:35:00Z",
"from": "…",
"text": "…",
"code": "…"
}
]
}EVENT webhook.testTest event
Sent only when you ask for one from the dashboard, to prove the endpoint works. The body is not a resource: branch on the event type before parsing it.
Verify `GhostSMS-Signature` over the raw body before trusting it, and deduplicate on `GhostSMS-Event-Id`: delivery is at least once.
Headers
GhostSMS-Event-IdstringRequired- Unique per event, and the same on every retry of it.
GhostSMS-Event-Type"webhook.test"Required- The event, so the body can be parsed as the right thing.
GhostSMS-SignaturestringRequired- `t=<unix seconds>,v1=<hex HMAC-SHA256 of "<t>.<raw body>">`, keyed with the endpoint's signing secret. Reject a timestamp more than 5 minutes old.
Body
messagestringRequired
{
"message": "…"
}