We've launched a new documentation site. Visit docs.portal.io for the latest version.

Webhooks

Webhook subscriptions and delivery rules for Portal's public API.

Webhooks allow external systems to receive real-time notifications when specific events occur in Portal.

Developers can register webhook subscriptions by providing an HTTPS endpoint URL and selecting which events they want to receive. When a subscribed event occurs, Portal sends an HTTP POST request to the configured endpoint.

Each request contains a structured JSON payload describing the event.

Webhook deliveries are signed using a secret key to allow consumers to verify that the request was sent by Portal.

If a webhook delivery fails, Portal automatically retries the delivery several times. Current implementation schedule: 1 minute, 5 minutes, 30 minutes, 2 hours, 12 hours.


Security

Webhook requests are signed so consumers can verify that the request was sent by Portal.

Each subscription has a secretKey, which is used to generate a signature for every webhook request.

Signature header

Each webhook request includes the following header:

X-Webhook-Signature

Example:

X-Webhook-Signature: t=1710000000,v1=5f2b3e7a9d1c4f8e6b2a3c9d7f4e1a6b5c3d2f7e9a1b4c6d8e0f2a3b5c7d9e1

Where:

  • t - timestamp when the webhook was generated (Unix time)
  • v1 - HMAC-SHA256 signature

Signature generation

The signature is calculated using HMAC-SHA256 with the subscription secretKey.

The message being signed is:

timestamp + "." + requestBody

Example:

1710000000.{"id":10025,"number":4123,...}

Signature calculation:

signature = HMAC_SHA256(secretKey, timestamp + "." + requestBody)

Verifying the signature

Consumers should verify webhook requests using the following steps:

  1. Read the raw request body exactly as received.
  2. Read the X-Webhook-Signature header.
  3. Extract t and v1.
  4. Rebuild the signed message as t + "." + requestBody.
  5. Compute HMAC_SHA256(secretKey, signedMessage).
  6. Compare the computed value with v1.
  7. Reject the request if the values do not match.
  8. Reject the request if the timestamp is too old (recommended tolerance: 5 minutes).

Create Webhook Subscription

Creates a new webhook subscription for the authenticated dealer. The response includes the signing secret key used to verify delivered webhook requests.

Request
header Parameters
Accept
required
string

Accept Header

Value: "application/json"
X-MSS-API-APPID
required
string

Application Id

X-MSS-CUSTOM-DATE
required
string

A date timestamp of the request

X-MSS-SIGNATURE
required
string

A signature for the request

X-MSS-API-USERKEY
required
string

User API Key

Request Body schema: application/x-www-form-urlencoded
required
Url
required
string

Absolute HTTPS URL that will receive webhook POST payloads. Must use the https:// scheme and resolve to a publicly routable host — private, loopback, and link-local addresses are rejected. The value is trimmed before storage.

Description
string

Optional human-readable label for this subscription. Trimmed before storage; whitespace-only values are stored as null.

Events
required
Array of strings

One or more event-type names to subscribe to. Duplicate names are ignored case-insensitively. Returns 400 listing any unrecognised event names. Currently supported webhook event names are implementation-defined; see the published webhook documentation for the current set.

Responses
200

Success

Response Schema: application/json
subscriptionId
required
integer <int64>

Unique numeric identifier of the webhook subscription

url
required
string

HTTPS URL that receives webhook POST deliveries

description
string

Optional human-readable label for the subscription

enabled
required
boolean

Whether the subscription is enabled

secretKey
string

Signing secret used to verify webhook deliveries. Returned on create and update responses only; omitted from list responses.

events
required
Array of strings

Event names that trigger this subscription

400

Validation failed. Common causes: subscription not found or does not belong to this account, URL is not HTTPS or resolves to a private address, unrecognised event names, or no changes were provided.

401

HMAC signature validation failed or credentials are invalid. Verify X-MSS-SIGNATURE, X-MSS-CUSTOM-DATE, and X-MSS-API-USERKEY headers.

402

The dealer's subscription is inactive or expired. An active subscription is required to use this endpoint.

403

You do not have permission for this action.

post/public/webhook/subscribe
Request samples
Response samples
application/json
{
  • "subscriptionId": 0,
  • "url": "string",
  • "description": "string",
  • "enabled": true,
  • "secretKey": "string",
  • "events": [
    ]
}

List Webhook Subscriptions

Returns all active webhook subscriptions for the authenticated dealer account.

Request
header Parameters
Accept
required
string

Accept Header

Value: "application/json"
X-MSS-API-APPID
required
string

Application Id

X-MSS-CUSTOM-DATE
required
string

A date timestamp of the request

X-MSS-SIGNATURE
required
string

A signature for the request

X-MSS-API-USERKEY
required
string

User API Key

Responses
200

Success

Response Schema: application/json
Array
subscriptionId
required
integer <int64>

Unique numeric identifier of the webhook subscription

url
required
string

HTTPS URL that receives webhook POST deliveries

description
string

Optional human-readable label for the subscription

enabled
required
boolean

Whether the subscription is enabled

secretKey
string

Signing secret used to verify webhook deliveries. Returned on create and update responses only; omitted from list responses.

events
required
Array of strings

Event names that trigger this subscription

401

HMAC signature validation failed or credentials are invalid. Verify X-MSS-SIGNATURE, X-MSS-CUSTOM-DATE, and X-MSS-API-USERKEY headers.

402

The dealer's subscription is inactive or expired. An active subscription is required to use this endpoint.

403

You do not have permission for this action.

get/public/webhook/subscriptions
Request samples
Response samples
application/json
[
  • {
    }
]

Update Webhook Subscription

Partially updates an existing webhook subscription. Only supplied fields are changed; omitted (null) fields retain their current values. At least one field must be provided.

Request
path Parameters
SubscriptionId
required
integer <int64>

Numeric ID of the webhook subscription to update. Must belong to the authenticated account; returns 400 if not found.

header Parameters
Accept
required
string

Accept Header

Value: "application/json"
X-MSS-API-APPID
required
string

Application Id

X-MSS-CUSTOM-DATE
required
string

A date timestamp of the request

X-MSS-SIGNATURE
required
string

A signature for the request

X-MSS-API-USERKEY
required
string

User API Key

Request Body schema: application/x-www-form-urlencoded
Url
string

New HTTPS URL for the webhook endpoint. Must use the https:// scheme and resolve to a publicly routable host — private, loopback, and link-local addresses are rejected. Omit (null) to keep the current URL.

Description
string

New human-readable label for this subscription. Send an empty string to clear the current description. Omit (null) to keep the current value. Trimmed before storage.

Enabled
boolean

When false, the subscription is paused and no events will be delivered until re-enabled. Omit to leave the current state unchanged.

Events
Array of strings

Replacement list of event-type names. When provided, completely replaces the existing event list. Omit to leave the current list unchanged.

Responses
200

Success

Response Schema: application/json
subscriptionId
required
integer <int64>

Unique numeric identifier of the webhook subscription

url
required
string

HTTPS URL that receives webhook POST deliveries

description
string

Optional human-readable label for the subscription

enabled
required
boolean

Whether the subscription is enabled

secretKey
string

Signing secret used to verify webhook deliveries. Returned on create and update responses only; omitted from list responses.

events
required
Array of strings

Event names that trigger this subscription

400

Validation failed. Common causes: subscription not found or does not belong to this account, URL is not HTTPS or resolves to a private address, unrecognised event names, or no changes were provided.

401

HMAC signature validation failed or credentials are invalid. Verify X-MSS-SIGNATURE, X-MSS-CUSTOM-DATE, and X-MSS-API-USERKEY headers.

402

The dealer's subscription is inactive or expired. An active subscription is required to use this endpoint.

403

You do not have permission for this action.

post/public/webhook/subscription/{SubscriptionId}
Request samples
Response samples
application/json
{
  • "subscriptionId": 0,
  • "url": "string",
  • "description": "string",
  • "enabled": true,
  • "secretKey": "string",
  • "events": [
    ]
}

Delete Webhook Subscription

Permanently deletes a webhook subscription and all of its event bindings. No further events will be delivered to the endpoint.

Request
path Parameters
SubscriptionId
required
integer <int64>

Numeric ID of the webhook subscription to permanently delete. Must belong to the authenticated account; returns 400 if not found.

header Parameters
Accept
required
string

Accept Header

Value: "application/json"
X-MSS-API-APPID
required
string

Application Id

X-MSS-CUSTOM-DATE
required
string

A date timestamp of the request

X-MSS-SIGNATURE
required
string

A signature for the request

X-MSS-API-USERKEY
required
string

User API Key

Responses
200

Success

Response Schema: application/json
success
required
boolean

Always true for a successful delete response

subscriptionId
required
integer <int64>

Identifier of the deleted webhook subscription

400

No active webhook subscription with the given SubscriptionId exists for the authenticated account.

401

HMAC signature validation failed or credentials are invalid. Verify X-MSS-SIGNATURE, X-MSS-CUSTOM-DATE, and X-MSS-API-USERKEY headers.

402

The dealer's subscription is inactive or expired. An active subscription is required to use this endpoint.

403

You do not have permission for this action.

delete/public/webhook/unsubscribe/{SubscriptionId}
Request samples
Response samples
application/json
{
  • "success": true,
  • "subscriptionId": 0
}