curl --request POST \
--url https://api.surfais.com/v1/webhook-endpoints/{endpointId}/subscriptions \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"org_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"brand_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"min_delta": 1,
"sentiment_floor": 50
}
'import requests
url = "https://api.surfais.com/v1/webhook-endpoints/{endpointId}/subscriptions"
payload = {
"org_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"brand_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"min_delta": 1,
"sentiment_floor": 50
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
org_id: '3c90c3cc-0d44-4b50-8888-8dd25736052a',
brand_id: '3c90c3cc-0d44-4b50-8888-8dd25736052a',
min_delta: 1,
sentiment_floor: 50
})
};
fetch('https://api.surfais.com/v1/webhook-endpoints/{endpointId}/subscriptions', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));{
"data": {
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"endpoint_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"event_type": "scan.completed",
"org_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"brand_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"min_delta": 123,
"direction": "drop",
"sentiment_floor": 123,
"active": true,
"created_at": "2023-11-07T05:31:56Z"
}
}{
"error": {
"code": "<string>",
"message": "<string>",
"details": "<unknown>"
},
"request_id": "<string>"
}{
"error": {
"code": "<string>",
"message": "<string>",
"details": "<unknown>"
},
"request_id": "<string>"
}{
"error": {
"code": "<string>",
"message": "<string>",
"details": "<unknown>"
},
"request_id": "<string>"
}{
"error": {
"code": "<string>",
"message": "<string>",
"details": "<unknown>"
},
"request_id": "<string>"
}{
"error": {
"code": "<string>",
"message": "<string>",
"details": "<unknown>"
},
"request_id": "<string>"
}{
"error": {
"code": "<string>",
"message": "<string>",
"details": "<unknown>"
},
"request_id": "<string>"
}{
"error": {
"code": "<string>",
"message": "<string>",
"details": "<unknown>"
},
"request_id": "<string>"
}{
"error": {
"code": "<string>",
"message": "<string>",
"details": "<unknown>"
},
"request_id": "<string>"
}{
"error": {
"code": "<string>",
"message": "<string>",
"details": "<unknown>"
},
"request_id": "<string>"
}Create a subscription
Subscribe the endpoint to an event.
The body is STRICT (as the endpoint body): an unknown field is 400 validation_error, not ignored. Per-type rules (400 validation_error with the rule in details[].code): scan.completed takes no threshold fields; score.threshold_crossed requires min_delta (≥ 0) and no sentiment_floor; sentiment.threshold_crossed requires min_delta and/or sentiment_floor (0–100). direction defaults to any. org_id must be one of your active links and brand_id an own brand of that org (404 otherwise; brand_id without org_id is 400). Several subscriptions on one endpoint that match the same event produce ONE delivery, carrying the first matching subscription’s threshold block. Requires the write scope.
curl --request POST \
--url https://api.surfais.com/v1/webhook-endpoints/{endpointId}/subscriptions \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"org_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"brand_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"min_delta": 1,
"sentiment_floor": 50
}
'import requests
url = "https://api.surfais.com/v1/webhook-endpoints/{endpointId}/subscriptions"
payload = {
"org_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"brand_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"min_delta": 1,
"sentiment_floor": 50
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
org_id: '3c90c3cc-0d44-4b50-8888-8dd25736052a',
brand_id: '3c90c3cc-0d44-4b50-8888-8dd25736052a',
min_delta: 1,
sentiment_floor: 50
})
};
fetch('https://api.surfais.com/v1/webhook-endpoints/{endpointId}/subscriptions', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));{
"data": {
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"endpoint_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"event_type": "scan.completed",
"org_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"brand_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"min_delta": 123,
"direction": "drop",
"sentiment_floor": 123,
"active": true,
"created_at": "2023-11-07T05:31:56Z"
}
}{
"error": {
"code": "<string>",
"message": "<string>",
"details": "<unknown>"
},
"request_id": "<string>"
}{
"error": {
"code": "<string>",
"message": "<string>",
"details": "<unknown>"
},
"request_id": "<string>"
}{
"error": {
"code": "<string>",
"message": "<string>",
"details": "<unknown>"
},
"request_id": "<string>"
}{
"error": {
"code": "<string>",
"message": "<string>",
"details": "<unknown>"
},
"request_id": "<string>"
}{
"error": {
"code": "<string>",
"message": "<string>",
"details": "<unknown>"
},
"request_id": "<string>"
}{
"error": {
"code": "<string>",
"message": "<string>",
"details": "<unknown>"
},
"request_id": "<string>"
}{
"error": {
"code": "<string>",
"message": "<string>",
"details": "<unknown>"
},
"request_id": "<string>"
}{
"error": {
"code": "<string>",
"message": "<string>",
"details": "<unknown>"
},
"request_id": "<string>"
}{
"error": {
"code": "<string>",
"message": "<string>",
"details": "<unknown>"
},
"request_id": "<string>"
}Authorizations
A Surfais API key — an organisation key or a partner key. Issued by Surfais; shown once. Rotate by creating a new key, then revoking the old one.
Headers
Optional. 1–255 characters, unique per intended write. Same key + same request → the stored response is replayed with Idempotent-Replayed: true; same key + different request → 409 idempotency_key_reuse; still running → 409 idempotency_key_in_flight. Outside that range → 400 validation_error (invalid_header).
1 - 255Path Parameters
Webhook endpoint id owned by this partner key; another partner's id (or a never-issued one) is 404.
^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$Body
Event type a subscription may name — every type except webhook.test.
scan.completed, score.threshold_crossed, sentiment.threshold_crossed UUID.
^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$UUID.
^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$x >= 0Which moves fire the delta rule. any = a drop or a rise (never a flat move).
drop, rise, any 0 <= x <= 100Response
The subscription.
Show child attributes
Show child attributes