Skip to content
NyriaDocs
Set up your source

Send alerts from your own bot

Point your own bot or service at a Nyria strategy's webhook, so its alerts place orders through your connected broker.

Your own bot sends an alert to Nyria as an HTTPS POST to the strategy's webhook URL. The body can be JSON with a ticker and an action, or plain text like AAPL long entry; the token in the URL is the only authentication, and the bot's budget per entry sets the size. The answer is a status code and a JSON body your script can act on.

Any program that can make an HTTPS request can send alerts to a Nyria strategy. TradingView and TrendSpider post to this same endpoint, so a body that works from curl works from them too.

Use this if you already have something that sends alerts: a Python script, a Node service, a no-code automation tool or your own scanner. For TradingView, Discord or Telegram, follow those guides instead.

You need

  • A Nyria account with a strategy set up (entry and exit rules) and a bot on it.
  • A connected broker. The examples use Alpaca, but the same payload works for every connectable broker.
  • Anything that can send an HTTPS POST: curl, a backend job, a Zapier or Make webhook step, your own dashboard.

Steps

Copy your strategy webhook URL

In Nyria, open your strategy and go to the Integration tab. Copy the webhook URL. It looks like this:

https://trades.nyria.io/webhooks/4f9c2a91b7d34e0fae9c1b6d2e8f0a4c8e1b7d34e0fae9c1b6d2e8f0a4c9b3d2

The part after /webhooks/ is your strategy's webhook token (tokenHash). It's the only authentication on the request: there is no Authorization header.

Treat the URL like a password. Anyone who has it can send alerts to your strategy. If it leaks, select Rotate token on the Integration tab: the old URL stops working at once.

Send the smallest payload

The smallest valid body has two fields, ticker and action. In a terminal, 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 webhook token from step 1. Nyria finds the strategy by token, matches buy to your entry rule, sizes the order from the bot's settings, and sends it to the connected broker.

The alert shows in the strategy's Logs tab within a second.

Set the order type for a single alert

The bot's budget per entry always sets the size, and no field in an alert changes it. You can set the order type per alert:

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": 340.50
  }'
  • order_type: market or limit. Leave it out to use the strategy's order type. Nyria reads it on an alert that names action and direction, as this one does. On an options strategy set to Provided in alert it's ignored, and the strategy's order type applies. See when Nyria reads order_type.
  • price: the limit price. Required when order_type is limit.
  • How long an order stays open comes from the strategy's Duration setting (Day, Good till canceled or Fill or kill); the alert has no field for it.

Send a plain-text body instead of JSON

JSON is the better format, but if your source can only send free text (older alert tools, some IFTTT or Zapier steps), Nyria reads plain text too:

curl -X POST https://trades.nyria.io/webhooks/REPLACE_WITH_YOUR_TOKEN \
  -H "Content-Type: text/plain" \
  --data-binary "AAPL long entry"

Nyria reads the ticker (AAPL), the direction (long) and the action (entry). Set Content-Type: text/plain so Nyria does not try to decode the body as JSON.

Paste the text into the alert tester first to see how Nyria reads it.

Make repeat sends safe

If your script retries after network failures, or your provider delivers the same alert twice, Nyria catches it. An identical body received again within 30 seconds, or within 5 minutes with no other alert in between, counts as a duplicate, and only the first one places an order.

Nyria matches duplicates on metadata.message_id when you send one, and on a hash of the whole body when you do not. 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-2027-06-04T13:31:15Z" }
  }'

Anything unique works: a counter in your script, a timestamp, or a new UUID per alert.

Handle the response

Nyria answers with an HTTP status code and a JSON body. Have your sender log or alert on non-2xx responses.

StatusBodyWhat to do
200"status": "processed"Nothing. Nyria read it and handed it to your bots. Check the bot's Logs tab to confirm the fill.
200"rejected": trueThe strategy is not Active. Check its alert format on the Integration tab.
200"status": "rejected" + reasonNormal: the ticker isn't in the strategy's list, the direction is turned off, or there was no position to close.
200"status": "duplicate"A repeat of an earlier body (see duplicate rules). Change the body if you meant to repeat it.
400structured errorThe token in the URL is malformed. Copy the URL again.
404structured errorNo strategy matches that token. Copy the URL again.
413structured errorPayload over 256KB. Trim it.
422structured errorNyria couldn't use the alert, for example a missing field or an unknown symbol. userMessage names the cause.
429structured errorOver the limit of 10 alerts at once, then 1 a second. Wait as long as Retry-After says, then resend.
503structured errorA temporary failure reading the alert or fetching market data. Send it again.
500structured errorEverything else. The strategy's Logs tab has the reason.

A minimal Python sender that reports 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 read 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 and 5xx into exceptions your retry logic can see. It does not catch a rejection or a duplicate, which answer 200, so check status too. Always set a timeout. Nyria answers quickly, but a hung socket can stall your sender.

Confirm the order in the broker

Open your broker dashboard, or the bot in Nyria, and check the order is there. With the curl from step 2 on a paper account, you see an AAPL market buy at the bot's size.

If the order is not there, check the strategy's Logs tab. Each alert has a row there, and a rejected or failed one carries its reason. Duplicate deliveries are logged at most once every 5 minutes, so a missing row can also mean a duplicate.

JSON or plain text

Use JSON whenUse plain text when
You control the source (your own script or service).Your source only sends free text (an older alert tool).
You need order_type, price or option legs.A two-word alert (AAPL long) is enough.
You want response codes your retry logic can act on.You are trying something out.
You send option spreads (the legs array needs JSON).n/a

For option spreads, multi-leg orders and every accepted field, see the webhook reference.

Duplicate rules

  • Same body within 30 seconds → a duplicate. Retries are safe without anything extra.
  • Same body within 5 minutes, with no other alert in between → a duplicate, so a fixed scale-in alert sent twice trades once.
  • Same body after a different alert, or after 5 minutes → 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 200 with {"status": "duplicate"}.
  • A unique metadata.message_id → used to match duplicates instead of the body hash.

Duplicates are matched per strategy. Two strategies that get the same payload in the same second each place their own order. Send one alert to several strategies and expect several orders.

Sample: full crypto buy with 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": 64000
  }'

On a spot crypto strategy, this places a resting limit buy at $64,000. The size comes from the bot's settings, not the alert.

Sample: full equity exit with 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 with the direction of the position you are closing is the standard full-close alert, from any source. Nyria closes the whole open position. There is no partial-close field.

Troubleshooting

  • Nothing happens after the POST. Check the strategy's Logs tab. If there is no row, the request never reached Nyria. Check the URL, and that your sender uses https://, not http://.
  • 404 Not Found, or 400 Bad Request. The token is wrong, was rotated, or was copied with a stray space. Copy the URL again from the strategy's Integration tab.
  • 422, 500 or 503. The alert reached Nyria but couldn't be processed. The strategy's Logs tab has the reason; on a 422, userMessage names it too.
  • Order placed on the wrong ticker. Nyria read a different ticker from your text. Switch to JSON and set ticker.
  • Duplicates dropped when you meant to scale in. Vary the body, or set a unique metadata.message_id per intended order.

Troubleshooting lists fixes for common failures.

Next steps

Your edge, on autopilot.

Trading carries risk. Read the risk disclosure.

© 2026 Nyria LLC. All rights reserved.