Use a Custom Webhook Source
Wire any service that can POST HTTP to Nyria. By the end you will have a working custom webhook firing real orders through your connected broker.
By the end you will have a custom-built script (or third-party service) firing alerts into Nyria, parsed against your strategy, and routed to a connected broker, using the same webhook endpoint that TradingView and Discord use under the hood.
Who this is for. You already have something that emits signals: a Python script, a Node service, a no-code automation tool, a proprietary scanner. You want it to place orders through your Nyria-connected broker. If you're using TradingView or Discord instead, use those guides: this page covers the raw HTTP integration.
What you need before you start
- A Nyria account with a configured strategy (entry/exit rules, position sizing).
- A connected broker. The walkthrough uses Alpaca but the same payload works for every broker in the catalog.
- Anything that can send an HTTPS
POST:curl, a backend job, a Zapier/Make webhook step, a custom dashboard.
Steps
Copy your strategy webhook URL
In the Nyria app, open your strategy and go to the Integration tab. Copy the webhook URL. It looks like this:
https://trades.nyria.io/webhooks/4f9c2a91b7d34e0fae9c1b6d2e8f0a4c8e1b7d34e0fae9c1b6d2e8f0a4c9b3d2The path segment after /webhooks/ is your strategy's token
hash (tokenHash), a 64-character lowercase hexadecimal string
with no prefix. It's the only authentication on the request, so
treat it like a password. There is no separate Authorization
header.
Do not commit the URL to a public repo. The token hash is the full authentication. Anyone who has it can fire alerts at your strategy. If it leaks, regenerate it from the Integration tab. That rotates the token and invalidates the old one immediately.
Send the minimum-viable payload
The smallest valid body is two fields: ticker and action. Open
a terminal and run:
curl -X POST https://trades.nyria.io/webhooks/REPLACE_WITH_YOUR_TOKEN \
-H "Content-Type: application/json" \
-d '{
"ticker": "AAPL",
"action": "buy"
}'Replace REPLACE_WITH_YOUR_TOKEN with the token hash you copied
in Step 1. Nyria looks up the strategy by token, matches buy
against your entry rule, builds the order using the strategy's
position-sizing config, and forwards it to the connected broker.
You should see the alert show up in the strategy's Logs tab within a second or two.
Set the order type for a single alert
Position size always comes from the bot's sizing config; no field in an entry alert changes it. What you can set per alert is the order type:
curl -X POST https://trades.nyria.io/webhooks/REPLACE_WITH_YOUR_TOKEN \
-H "Content-Type: application/json" \
-d '{
"ticker": "AAPL",
"action": "OPEN",
"direction": "LONG",
"order_type": "limit",
"price": 175.50
}'order_type:marketorlimit. Omit it to use the strategy's configured type.price: the limit price. Required whenorder_typeislimit.duration:day,gtc, orfok. Default isday.
Send a plain-text body instead of JSON
JSON is the recommended format, but if your source can only emit free-form text (older alerting platforms, some IFTTT/Zapier steps), Nyria's parser also reads plain text:
curl -X POST https://trades.nyria.io/webhooks/REPLACE_WITH_YOUR_TOKEN \
-H "Content-Type: text/plain" \
--data-binary "AAPL long entry"The parser extracts the instrument (AAPL), the direction (long),
and the action (entry). Set Content-Type: text/plain so Nyria
doesn't try to JSON-decode the body.
JSON is more deterministic. Plain text is convenient, but the
parser has to infer fields. For production setups where every
alert matters, send JSON with explicit ticker + action.
Make repeat sends safe
If your script retries on network failures (or your provider delivers the same alert twice), Nyria's default behavior protects you: an identical body received again within about five minutes is treated as a duplicate, and only the first one places an order.
The dedup key is metadata.message_id when you send one, and a hash
of the whole body when you do not. So if you actually want to scale
into the same position, the body has to differ. Set a unique
metadata.message_id:
curl -X POST https://trades.nyria.io/webhooks/REPLACE_WITH_YOUR_TOKEN \
-H "Content-Type: application/json" \
-d '{
"ticker": "AAPL",
"action": "OPEN",
"direction": "LONG",
"metadata": { "message_id": "scale-in-2026-06-05T09:31:15Z" }
}'Anything unique works: a counter your script tracks, a timestamp, or a UUID minted per alert.
Handle the response
Nyria responds with an HTTP status code and a JSON body. Wire your sender to log or alert on non-2xx responses.
| Status | Body | What to do |
|---|---|---|
200 | "status": "processed" | Nothing. Nyria parsed it and handed it to your bots. Check the bot's Logs tab to confirm the fill. |
200 | "rejected": true | The strategy is not Active. Validate its alert formats on the Integration tab. |
200 | "status": "rejected" + reason | Expected: the instrument is not on the strategy's list, the direction is disabled, or there was no position to close. |
200 | "status": "duplicate" | The identical body already arrived in the last few minutes. Vary the body if the repeat was intentional. |
400 | structured error | The token in the URL is malformed. Re-copy the URL. |
404 | structured error | No strategy matches that token. Re-copy the URL. |
413 | structured error | Payload over 256KB. Trim it. |
422 | structured error | More option legs than an order supports. |
429 | "error": "rate limit exceeded" | Over 60 alerts a minute. Back off and retry. |
500 | "error": "<reason>" | Everything else. The text says what failed. |
A minimal Python sender that surfaces failures:
import requests
WEBHOOK_URL = "https://trades.nyria.io/webhooks/REPLACE_WITH_YOUR_TOKEN"
def fire_alert(payload: dict) -> None:
r = requests.post(WEBHOOK_URL, json=payload, timeout=10)
r.raise_for_status()
status = r.json().get("status")
if status == "processed":
print("Nyria parsed the alert")
else:
print(f"Nyria did not act on it: {r.json()}")
fire_alert({"ticker": "AAPL", "action": "OPEN", "direction": "LONG"})raise_for_status() turns 4xx/5xx into exceptions so your retry
logic can see them. It will not catch a rejection or a duplicate:
those answer 200, so check status as well. Always use a finite
timeout. Nyria responds quickly, but a hung socket can wedge your
producer.
Confirm the order in the broker
Open your broker dashboard (or the Nyria app's bot view) and verify
the order landed. If you used the curl from Step 2 against a paper
account, you should see an AAPL market buy at the strategy's
default size.
If the order is not there, check the strategy's Logs tab. A parsed alert is logged at INFO, a rejection at WARN with its reason, and a failure at ERROR. Duplicate deliveries are logged at most once every few minutes, so a missing row can also mean a duplicate.
JSON vs plain text: when to use which
| Use JSON when | Use plain text when |
|---|---|
| You control the source (custom script, backend service). | Your source only emits free-form strings (legacy alert tool). |
You need explicit order_type, price, duration, or option legs. | A two-word signal (AAPL long) is enough. |
| You want the response codes to map cleanly to your retry logic. | You're prototyping and just need something to fire. |
You're sending option spreads (the legs array requires JSON). | n/a |
For everything beyond the basics (option spreads, multi-leg orders, every accepted field), see the Webhook Payload Reference.
Idempotency rules at a glance
- Same body within about five minutes → treated as a duplicate automatically. Nothing extra is needed for retry safety.
- Same body after that → treated as a new alert, and it trades.
- Any change to the body → a new alert, even if every other field matches. This is the scale-in path.
- A repeat that is dropped → answered
200with{"status": "duplicate"}. - A unique
metadata.message_id→ used as the dedup key in place of the body hash.
The dedupe window is per strategy. Two different strategies receiving the same payload at the same second are independent; each will fire its own order. If you fan one signal out to multiple strategies, expect multiple orders.
Sample: full crypto buy via curl
A complete crypto example that places a limit order:
curl -X POST https://trades.nyria.io/webhooks/REPLACE_WITH_YOUR_TOKEN \
-H "Content-Type: application/json" \
-d '{
"ticker": "BTC/USDT",
"action": "OPEN",
"direction": "LONG",
"order_type": "limit",
"price": 65000
}'For a spot crypto strategy on a connected exchange, this rests a limit buy at $65,000. The size comes from the bot's sizing config, not the alert.
Sample: full equity exit via curl
curl -X POST https://trades.nyria.io/webhooks/REPLACE_WITH_YOUR_TOKEN \
-H "Content-Type: application/json" \
-d '{
"ticker": "AAPL",
"action": "CLOSE",
"direction": "LONG"
}'CLOSE plus the direction of the position you are closing is the
canonical full-close alert, and it works from any source. Nyria closes
the whole open position; there is no partial-close field.
Troubleshooting
- Nothing happens after the POST. Check the strategy Logs tab.
If there is no row, the request never reached Nyria. Verify the
URL and that your sender is hitting
https://(nothttp://). 404 Not Found, or400 Bad Request. The token is wrong, has been rotated, or was copied with a stray space. Re-copy the URL from the strategy's Integration tab.500with anerrorstring. The alert reached Nyria but could not be processed. The text names the cause.- Order placed but on the wrong instrument. The parser inferred
a different ticker from your text. Switch to JSON and set
tickerexplicitly. - Duplicates dropped when you meant to scale in. Vary the body,
or set a unique
metadata.message_idper intended order.
Troubleshooting maps the common failures to fixes.
What's next
- Webhook Payload Reference: every field Nyria accepts, with examples for every broker.
- Alpaca Integration: connect the broker used in this tutorial.
- Alert Sources: TradingView and Discord setups built on the same webhook (Telegram coming soon).
- Strategies: entry/exit rules and sizing config that this webhook flows into.
Connect TrendSpider alerts to Nyria
Send TrendSpider Alerts and Strategy Bot signals to Nyria as webhooks, with copy-paste payloads using TrendSpider's own %alert_symbol% variables.
Strategies
A strategy is the rulebook for a set of alerts: the source, the equity type, the trading behavior and the option selection. Build one, then deploy bots on it.