Webhooks
Signed HTTPS calls to your server when orders, trades or positions change.
List webhooks #
/v1/postbacks app sessionThe signed-in user's webhooks (never their secrets), oldest first.
More about this
Event bodies are described in the document's webhooks section (order_update, trade, account_alert, positions, ping; components WebhookOrderUpdate, WebhookTrade, WebhookAccountAlert, WebhookPositions, WebhookPing), with how deliveries are signed and retried.
Errors
| HTTP | Code | When |
|---|---|---|
| 401 | unauthorized | No credential, or the credential is invalid, expired or revoked. |
| 403 | forbidden | The credential may not use this route (missing scope, app-session-only route, IP not allowed). |
| 429 | rate_limited | Too many requests for this credential (or too many failed attempts); retry after the |
| 503 | webhooks_disabled | Webhooks are not enabled on this server. |
| 503 | service_unavailable | A dependency is temporarily unavailable, or the feature is off on this server; retry later. |
All fields (request and response schema)
Loading fields…
curl "https://cirrus.pocketful.in/v1/postbacks" \
-H "Authorization: token $CIRRUS_API_KEY"import os
import requests
response = requests.get(
"https://cirrus.pocketful.in/v1/postbacks",
headers={
"Authorization": f"token {os.environ['CIRRUS_API_KEY']}",
},
timeout=10,
)
print(response.status_code, response.json())const response = await fetch('https://cirrus.pocketful.in/v1/postbacks', {
method: 'GET',
headers: {
Authorization: `token ${process.env.CIRRUS_API_KEY}`,
},
});
const body = await response.json();
console.log(response.status, body);{
"status": "success",
"data": [
{
"id": "pb_01m3pgps59en5pjhyj92tbsq65",
"url": "http://127.0.0.1:63829/hooks/orders",
"events": [
"order_update",
"trade"
],
"accounts": [
"P1"
],
"description": "Order desk",
"enabled": true,
"disabled_reason": null,
"disabled_at": null,
"consecutive_failures": 0,
"last_success_at": null,
"last_failure_at": null,
"previous_secret_expires_at": null,
"secret_rotated_at": null,
"created_at": "2026-09-29T12:02:21.993Z",
"updated_at": "2026-09-29T12:02:21.993Z"
}
],
"error": null
}Create a webhook #
/v1/postbacks app sessionRegisters an HTTPS receiver for the chosen events (optionally only for some of the user's accounts).
More about this
The signing secret is in this response only: store it now. A user may have at most 5 webhooks. Event bodies are described in the document's webhooks section (order_update, trade, account_alert, positions, ping; components WebhookOrderUpdate, WebhookTrade, WebhookAccountAlert, WebhookPositions, WebhookPing), with how deliveries are signed and retried.
Only the account holder, signed in themselves, can create webhooks.
Body fields
- url string required
The receiver: an
https://URL on a public host (private, loopback and link-local addresses are refused). - events string[] required
Events to send, at least one:
order_update,trade,account_alert,positions(pingcannot be subscribed to).One of: order_update, trade, account_alert, positions, ping
- accounts string[] | null
Only these of the user's accounts (non-empty, the user's own); leave out or null for every account, including ones added later.
- description string | null
A note for the owner, at most 200 characters.
Errors
| HTTP | Code | When |
|---|---|---|
| 400 | malformed_json | The body is not JSON, or does not fit the request shape (unknown or missing fields, wrong types). |
| 401 | unauthorized | No credential, or the credential is invalid, expired or revoked. |
| 403 | own_session_required | Credentials can only be created from the user's own signed-in session. |
| 403 | forbidden | The credential may not use this route (missing scope, app-session-only route, IP not allowed). |
| 409 | webhook_limit_reached | The webhook limit is reached; delete one first. |
| 422 | invalid_request | The request is well-formed but not valid; |
| 429 | rate_limited | Too many requests for this credential (or too many failed attempts); retry after the |
| 503 | webhooks_disabled | Webhooks are not enabled on this server. |
| 503 | service_unavailable | A dependency is temporarily unavailable, or the feature is off on this server; retry later. |
All fields (request and response schema)
Loading fields…
curl -X POST "https://cirrus.pocketful.in/v1/postbacks" \
-H "Authorization: token $CIRRUS_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"url": "http://127.0.0.1:63829/hooks/orders",
"events": [
"order_update",
"trade"
],
"accounts": [
"P1"
],
"description": "Order desk"
}'import os
import requests
response = requests.post(
"https://cirrus.pocketful.in/v1/postbacks",
headers={
"Authorization": f"token {os.environ['CIRRUS_API_KEY']}",
},
json={
"url": "http://127.0.0.1:63829/hooks/orders",
"events": [
"order_update",
"trade",
],
"accounts": [
"P1",
],
"description": "Order desk",
},
timeout=10,
)
print(response.status_code, response.json())const response = await fetch('https://cirrus.pocketful.in/v1/postbacks', {
method: 'POST',
headers: {
Authorization: `token ${process.env.CIRRUS_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
"url": "http://127.0.0.1:63829/hooks/orders",
"events": [
"order_update",
"trade"
],
"accounts": [
"P1"
],
"description": "Order desk"
}),
});
const body = await response.json();
console.log(response.status, body);{
"status": "success",
"data": {
"id": "pb_01m3pgps59en5pjhyj92tbsq65",
"url": "http://127.0.0.1:63829/hooks/orders",
"events": [
"order_update",
"trade"
],
"accounts": [
"P1"
],
"description": "Order desk",
"enabled": true,
"disabled_reason": null,
"disabled_at": null,
"consecutive_failures": 0,
"last_success_at": null,
"last_failure_at": null,
"previous_secret_expires_at": null,
"secret_rotated_at": null,
"created_at": "2026-09-29T12:02:21.993Z",
"updated_at": "2026-09-29T12:02:21.993Z",
"secret": "whsec_kmM4VkgFv6UVjwsTRs15AdSvI23Js5hRdI8FN5OrYlQ=",
"note": "Store the secret now: it is not shown again."
},
"error": null
}Get a webhook #
/v1/postbacks/{id} app sessionOne webhook (never its secret): its settings and delivery health.
Parameters
- id path · string required
The webhook's
id.
Errors
| HTTP | Code | When |
|---|---|---|
| 401 | unauthorized | No credential, or the credential is invalid, expired or revoked. |
| 403 | forbidden | The credential may not use this route (missing scope, app-session-only route, IP not allowed). |
| 404 | webhook_not_found | No webhook with this id for the caller. |
| 429 | rate_limited | Too many requests for this credential (or too many failed attempts); retry after the |
| 503 | webhooks_disabled | Webhooks are not enabled on this server. |
| 503 | service_unavailable | A dependency is temporarily unavailable, or the feature is off on this server; retry later. |
All fields (request and response schema)
Loading fields…
curl "https://cirrus.pocketful.in/v1/postbacks/<id>" \
-H "Authorization: token $CIRRUS_API_KEY"import os
import requests
response = requests.get(
"https://cirrus.pocketful.in/v1/postbacks/<id>",
headers={
"Authorization": f"token {os.environ['CIRRUS_API_KEY']}",
},
timeout=10,
)
print(response.status_code, response.json())const response = await fetch('https://cirrus.pocketful.in/v1/postbacks/<id>', {
method: 'GET',
headers: {
Authorization: `token ${process.env.CIRRUS_API_KEY}`,
},
});
const body = await response.json();
console.log(response.status, body);{
"status": "success",
"data": {
"id": "pb_01m3pgps59en5pjhyj92tbsq65",
"url": "http://127.0.0.1:63829/hooks/orders",
"events": [
"order_update",
"trade"
],
"accounts": [
"P1"
],
"description": "Order desk",
"enabled": true,
"disabled_reason": null,
"disabled_at": null,
"consecutive_failures": 0,
"last_success_at": null,
"last_failure_at": null,
"previous_secret_expires_at": null,
"secret_rotated_at": null,
"created_at": "2026-09-29T12:02:21.993Z",
"updated_at": "2026-09-29T12:02:21.993Z"
},
"error": null
}Change a webhook #
/v1/postbacks/{id} app sessionChanges only the fields sent: url, events, accounts (null = every account), description (null removes it) and enabled.
More about this
enabled: true turns a webhook back on, also after it was turned off for failing (its failure count starts again). An empty body changes nothing.
Only the account holder, signed in themselves, can change webhooks.
Parameters
- id path · string required
The webhook's
id.
Body fields
- url string | null
A new receiver URL (same rules as on creation).
- events string[] | null
A new event list (replaces the old one; at least one).
One of: order_update, trade, account_alert, positions, ping
- accounts string[] | null
A new account list;
nullgoes back to every account. - description string | null
A new note;
nullor empty removes it. - enabled boolean | null
falseturns deliveries off;trueturns them back on (also after the webhook was turned off for failing). - trigger_updates boolean | null
truealso sendstrigger_update(a v2 trigger of the user changed; see the document'swebhookssection);falsestops it. A new webhook starts without it: opt in here.
Errors
| HTTP | Code | When |
|---|---|---|
| 400 | malformed_json | The body is not JSON, or does not fit the request shape (unknown or missing fields, wrong types). |
| 401 | unauthorized | No credential, or the credential is invalid, expired or revoked. |
| 403 | own_session_required | Credentials can only be created from the user's own signed-in session. |
| 403 | forbidden | The credential may not use this route (missing scope, app-session-only route, IP not allowed). |
| 404 | webhook_not_found | No webhook with this id for the caller. |
| 422 | invalid_request | The request is well-formed but not valid; |
| 429 | rate_limited | Too many requests for this credential (or too many failed attempts); retry after the |
| 503 | webhooks_disabled | Webhooks are not enabled on this server. |
| 503 | service_unavailable | A dependency is temporarily unavailable, or the feature is off on this server; retry later. |
All fields (request and response schema)
Loading fields…
curl -X PATCH "https://cirrus.pocketful.in/v1/postbacks/<id>" \
-H "Authorization: token $CIRRUS_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"events": [
"order_update",
"trade",
"positions"
],
"accounts": null,
"enabled": false
}'import os
import requests
response = requests.patch(
"https://cirrus.pocketful.in/v1/postbacks/<id>",
headers={
"Authorization": f"token {os.environ['CIRRUS_API_KEY']}",
},
json={
"events": [
"order_update",
"trade",
"positions",
],
"accounts": None,
"enabled": False,
},
timeout=10,
)
print(response.status_code, response.json())const response = await fetch('https://cirrus.pocketful.in/v1/postbacks/<id>', {
method: 'PATCH',
headers: {
Authorization: `token ${process.env.CIRRUS_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
"events": [
"order_update",
"trade",
"positions"
],
"accounts": null,
"enabled": false
}),
});
const body = await response.json();
console.log(response.status, body);{
"status": "success",
"data": {
"id": "pb_01m3pgps59en5pjhyj92tbsq65",
"url": "http://127.0.0.1:63829/hooks/orders",
"events": [
"order_update",
"trade",
"positions"
],
"accounts": null,
"description": "Order desk",
"enabled": false,
"disabled_reason": "disabled_by_user",
"disabled_at": "2026-09-29T12:02:21.997Z",
"consecutive_failures": 0,
"last_success_at": null,
"last_failure_at": null,
"previous_secret_expires_at": null,
"secret_rotated_at": null,
"created_at": "2026-09-29T12:02:21.993Z",
"updated_at": "2026-09-29T12:02:21.997Z"
},
"error": null
}Delete a webhook #
/v1/postbacks/{id} app sessionDeletes the webhook; nothing more is sent to it.
More about this
Only the account holder, signed in themselves, can delete webhooks.
Parameters
- id path · string required
The webhook's
id.
Errors
| HTTP | Code | When |
|---|---|---|
| 401 | unauthorized | No credential, or the credential is invalid, expired or revoked. |
| 403 | own_session_required | Credentials can only be created from the user's own signed-in session. |
| 403 | forbidden | The credential may not use this route (missing scope, app-session-only route, IP not allowed). |
| 404 | webhook_not_found | No webhook with this id for the caller. |
| 429 | rate_limited | Too many requests for this credential (or too many failed attempts); retry after the |
| 503 | webhooks_disabled | Webhooks are not enabled on this server. |
| 503 | service_unavailable | A dependency is temporarily unavailable, or the feature is off on this server; retry later. |
All fields (request and response schema)
Loading fields…
curl -X DELETE "https://cirrus.pocketful.in/v1/postbacks/<id>" \
-H "Authorization: token $CIRRUS_API_KEY"import os
import requests
response = requests.delete(
"https://cirrus.pocketful.in/v1/postbacks/<id>",
headers={
"Authorization": f"token {os.environ['CIRRUS_API_KEY']}",
},
timeout=10,
)
print(response.status_code, response.json())const response = await fetch('https://cirrus.pocketful.in/v1/postbacks/<id>', {
method: 'DELETE',
headers: {
Authorization: `token ${process.env.CIRRUS_API_KEY}`,
},
});
const body = await response.json();
console.log(response.status, body);{
"status": "success",
"data": {
"id": "pb_01m3pgps5ctt0rdj2zq50g1dad",
"deleted": true
},
"error": null
}Rotate a webhook's secret #
/v1/postbacks/{id}/rotate-secret app sessionIssues a new signing secret, shown only in this response.
More about this
For 24 hours deliveries are signed with both the new and the previous secret (one signature each in webhook-signature), so the receiver can switch without losing any. Only the account holder, signed in themselves, can rotate secrets.
Parameters
- id path · string required
The webhook's
id.
Errors
| HTTP | Code | When |
|---|---|---|
| 401 | unauthorized | No credential, or the credential is invalid, expired or revoked. |
| 403 | own_session_required | Credentials can only be created from the user's own signed-in session. |
| 403 | forbidden | The credential may not use this route (missing scope, app-session-only route, IP not allowed). |
| 404 | webhook_not_found | No webhook with this id for the caller. |
| 429 | rate_limited | Too many requests for this credential (or too many failed attempts); retry after the |
| 503 | webhooks_disabled | Webhooks are not enabled on this server. |
| 503 | service_unavailable | A dependency is temporarily unavailable, or the feature is off on this server; retry later. |
All fields (request and response schema)
Loading fields…
curl -X POST "https://cirrus.pocketful.in/v1/postbacks/<id>/rotate-secret" \
-H "Authorization: token $CIRRUS_API_KEY"import os
import requests
response = requests.post(
"https://cirrus.pocketful.in/v1/postbacks/<id>/rotate-secret",
headers={
"Authorization": f"token {os.environ['CIRRUS_API_KEY']}",
},
timeout=10,
)
print(response.status_code, response.json())const response = await fetch('https://cirrus.pocketful.in/v1/postbacks/<id>/rotate-secret', {
method: 'POST',
headers: {
Authorization: `token ${process.env.CIRRUS_API_KEY}`,
},
});
const body = await response.json();
console.log(response.status, body);{
"status": "success",
"data": {
"id": "pb_01m3pgps5ctt0rdj2zq50g1dad",
"url": "http://127.0.0.1:63815/hooks/alerts",
"events": [
"account_alert"
],
"accounts": null,
"description": null,
"enabled": true,
"disabled_reason": null,
"disabled_at": null,
"consecutive_failures": 0,
"last_success_at": null,
"last_failure_at": null,
"previous_secret_expires_at": "2026-09-30T12:02:21.998Z",
"secret_rotated_at": "2026-09-29T12:02:21.998Z",
"created_at": "2026-09-29T12:02:21.996Z",
"updated_at": "2026-09-29T12:02:21.998Z",
"secret": "whsec_sesnDRH8eVMm3rJqiKEp0+QVa3wcLxUqhsXlqR2dqeQ=",
"note": "Store the secret now: it is not shown again."
},
"error": null
}Send a test delivery #
/v1/postbacks/{id}/test app sessionSends one signed ping event (body: component WebhookPing) to the webhook now, even when it is turned off, and says how the receiver answered.
More about this
One attempt, no retry; it is logged with the webhook's deliveries. Only the account holder, signed in themselves, can send tests.
Parameters
- id path · string required
The webhook's
id.
Errors
| HTTP | Code | When |
|---|---|---|
| 401 | unauthorized | No credential, or the credential is invalid, expired or revoked. |
| 403 | own_session_required | Credentials can only be created from the user's own signed-in session. |
| 403 | forbidden | The credential may not use this route (missing scope, app-session-only route, IP not allowed). |
| 404 | webhook_not_found | No webhook with this id for the caller. |
| 429 | rate_limited | Too many requests for this credential (or too many failed attempts); retry after the |
| 503 | webhooks_disabled | Webhooks are not enabled on this server. |
| 503 | service_unavailable | A dependency is temporarily unavailable, or the feature is off on this server; retry later. |
All fields (request and response schema)
Loading fields…
curl -X POST "https://cirrus.pocketful.in/v1/postbacks/<id>/test" \
-H "Authorization: token $CIRRUS_API_KEY"import os
import requests
response = requests.post(
"https://cirrus.pocketful.in/v1/postbacks/<id>/test",
headers={
"Authorization": f"token {os.environ['CIRRUS_API_KEY']}",
},
timeout=10,
)
print(response.status_code, response.json())const response = await fetch('https://cirrus.pocketful.in/v1/postbacks/<id>/test', {
method: 'POST',
headers: {
Authorization: `token ${process.env.CIRRUS_API_KEY}`,
},
});
const body = await response.json();
console.log(response.status, body);{
"status": "success",
"data": {
"event_id": "evt_cc2f23548b726e8a6a8bf980be542540",
"delivered": true,
"status_code": 200,
"duration_ms": 0,
"error_kind": null
},
"error": null
}List a webhook's delivery attempts #
/v1/postbacks/{id}/deliveries app sessionEvery delivery attempt of the last 7 days, newest first: event, attempt number, outcome, the receiver's status and timing (never the body).
More about this
Page with limit and cursor.
Parameters
- id path · string required
The webhook's
id. - limit query · integer
Page size, 1-200 (default 50).
- cursor query · string
next_cursorof the previous page.
Errors
| HTTP | Code | When |
|---|---|---|
| 400 | invalid_query | The query string does not fit the route's parameters. |
| 401 | unauthorized | No credential, or the credential is invalid, expired or revoked. |
| 403 | forbidden | The credential may not use this route (missing scope, app-session-only route, IP not allowed). |
| 404 | webhook_not_found | No webhook with this id for the caller. |
| 422 | invalid_request | The request is well-formed but not valid; |
| 429 | rate_limited | Too many requests for this credential (or too many failed attempts); retry after the |
| 503 | webhooks_disabled | Webhooks are not enabled on this server. |
| 503 | service_unavailable | A dependency is temporarily unavailable, or the feature is off on this server; retry later. |
All fields (request and response schema)
Loading fields…
curl "https://cirrus.pocketful.in/v1/postbacks/<id>/deliveries" \
-H "Authorization: token $CIRRUS_API_KEY"import os
import requests
response = requests.get(
"https://cirrus.pocketful.in/v1/postbacks/<id>/deliveries",
headers={
"Authorization": f"token {os.environ['CIRRUS_API_KEY']}",
},
timeout=10,
)
print(response.status_code, response.json())const response = await fetch('https://cirrus.pocketful.in/v1/postbacks/<id>/deliveries', {
method: 'GET',
headers: {
Authorization: `token ${process.env.CIRRUS_API_KEY}`,
},
});
const body = await response.json();
console.log(response.status, body);{
"status": "success",
"data": {
"deliveries": [
{
"id": "01M3PGPS5DF35SYE2PF2KKBM9V",
"event_id": "evt_cc2f23548b726e8a6a8bf980be542540",
"type": "ping",
"attempt": 1,
"outcome": "delivered",
"status_code": 200,
"duration_ms": 0,
"error_kind": null,
"at": "2026-09-29T12:02:21.997Z"
}
],
"next_cursor": null
},
"error": null
}