On this page

Events

Beta

8 events we post to your endpoint, each signed, and retried when your endpoint does not answer 2xx.

https://api.ghostsms.iov1openapi.json

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.

Body
{
  "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.

Body
{
  "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.

Body
{
  "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.

Body
{
  "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.

Body
{
  "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.

Body
{
  "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.

Body
{
  "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
Body
{
  "message": "…"
}