Getting started

A quick start guide for sending events to Castle's API

Castle is the developer platform for account protection. Feed our APIs any user event for real-time risk scoring and threat detection. Receive synchronous decisions to deny spam registrations and account takeover attempts. Our risk score is displayed in the response, alongside a device management token for follow-up workflows.


Quick start

  1. Send Requests to your Castle Sandbox
  2. Observe How Castle Blocks Malicious Logins During a Credential Stuffing Attack
  3. Observe How Castle Blocks Spam Registration Campaigns
  4. Integrate with Your Application

1. Send requests

  1. Log in to the Castle Dashboard. If you don’t have an account, you can sign up for free.
  2. Choose your “Sandbox” environment and copy your API key from Settings -> General
  3. Set your API key as a shell variable (copy and paste into your shell, changing your_api_key):
export SECRET=your_api_key
  1. Send a successful login event to Castle (copy and paste into your shell).
echo "\nReceived correct password for: castle-docs-user (castle-docs-user@example.net)\nSending request to Castle's /authenticate endpoint:\n\"event\": \"\$login.succeeded\"\n"
curl -s https://api.castle.io/v1/authenticate \
  -X POST \
  -u ":$SECRET" \
  -H "Content-Type: application/json" \
  -d '
  {
    "event": "$login.succeeded",
    "user_id": "castle-docs-user",
    "user_traits": {
      "email": "castle-docs-user@example.net"
    },
    "context": {
      "client_id": false,
      "ip": "37.46.187.90",
      "headers": {
        "Accept": "application/xml",
        "Accept-Encoding": "gzip, br",
        "Cache-Control": "max-age=680",
        "Content-Type": "multipart/form-data",
        "Content-Length": "157",
        "Connection": "close",
        "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_9 rv:2.0; MK) AppleWebKit/538.0.2 (KHTML, like Gecko) Version/5.0.0 Safari/538.0.2/765.251",
        "Accept-Charset": "utf-8",
        "Accept-Language": "en-us",
        "Cookie": "bandwidth=0af87174-37b4-4adc-a1a6-eb7c7e4ca440",
        "Host": "http://example.com",
        "Referer": "http://ignacio.net"
      }
    }
  }' | json_pp
  1. You should receive "action": "allow" in the response. Success! Castle has learned about the castle-docs-user and the device they’ve used to access their account.

If you didn’t receive the correct response, then you or someone on your team probably went through these steps already. Try deleting the user, then starting over, by running the command below:

# to delete the user 'castle-docs-user':
curl https://api.castle.io/v1/privacy/users/castle-docs-user \
	-X DELETE \
	-u ":$SECRET"

2. Login verdicts

This assumes you completed Step 1 above - we’ll try to breach the castle-docs-user’s account.

Credential stuffing attacks typically come from a wide variety of IP addresses, in order to circumvent WAF rate-limiting rules. To simulate a credential stuffing attack, we’ll simulate 30 failed login events from a random set of IP addresses. These requests are sent from the application to Castle’s /track endpoint. Each failed login attempt will signify that the attacker was using an invalid username/password combo. After those 30 failed login attempts, we’ll send a successful login event (representing a correct username and password combo), which signifies that our castle-docs-user’s valid credentials were on the attacker’s list.

  1. Send 30 failed login attempts, each from a different IP address (copy and paste into your shell):
for i in {1..30}
do
  echo "\nReceived wrong username and/or password for: target_user_$i@example.net\nSending a request to Castle's /track endpoint:\n\"event\": \"\$login.failed\", \n(number $i of 30)\n"
  RANDOCTET1=$((RANDOM%256))
  RANDOCTET2=$((RANDOM%256))
  curl -s https://api.castle.io/v1/track \
    -X POST \
    -u ":$SECRET" \
    -H "Content-Type: application/json" \
    -d '
  {
    "event": "$login.failed",
    "user_traits": {
      "email": "target_user_'$i'@example.net"
    },
    "context": {
      "client_id": false,
      "ip": "100.101.'$RANDOCTET1'.'$RANDOCTET2'",
      "headers": {
        "Accept": "application/*",
        "User-Agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/74.0.3729.157 Safari/537.36",
        "Host": "http://example.com"
      }
    }
  }'
done
  1. Send a $login.succeeded event to Castle’s /authenticate endpoint. This signifies that the attacker submitted a valid password while attempting to breach the castle-docs-user’s account (copy and paste into your shell):
echo "\nReceived correct password for: castle-docs-user (castle-docs-user@example.net)\nSending request to Castle's /authenticate endpoint:\n\"event\": \"\$login.succeeded\"\n"
RANDOCTET1=$((RANDOM%256))
RANDOCTET2=$((RANDOM%256))
curl -s https://api.castle.io/v1/authenticate \
  -X POST \
  -u ":$SECRET" \
  -H "Content-Type: application/json" \
  -d '
  {
    "event": "$login.succeeded",
    "user_id": "castle-docs-user",
    "user_traits": {
      "email": "castle-docs-user@example.net"
    },
    "context": {
      "client_id": false,
      "ip": "100.101.'$RANDOCTET1'.'$RANDOCTET2'",
      "headers": {
        "Accept": "application/*",
        "User-Agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/74.0.3729.157 Safari/537.36",
        "Host": "http://example.com"
      }
    }
  }' | json_pp
  1. Note that Castle returns "action": "deny" in the response. Success! The application knows to deny this login from proceeding. Castle has detected a credential stuffing attack being executed on your login endpoint.

3. Registration verdicts

  1. Send a handful of registration attempts from a distributed bot network:
for i in {1..10}
do
  RANDOCTET1=$((RANDOM%256))
  RANDOCTET2=$((RANDOM%256))
  echo "\nSending Registration attempt no. $i of 10:"
  curl https://api.castle.io/v1/authenticate \
    -X POST \
    -u ":$SECRET" \
    -H "Content-Type: application/json" \
    -d '
  {
    "event": "$registration.attempted",
    "user_traits": {
      "email": "fake_user_'$i'@example.net"
    },
    "context": {
      "client_id": false,
      "ip": "100.101.'$RANDOCTET1'.'$RANDOCTET2'",
      "headers": {
        "Accept": "application/*",
        "User-Agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/74.0.3729.157 Safari/537.36",
        "Host": "http://example.com"
      }
    }
  }' | json_pp
done
  1. Note that Castle returns "action": "deny" for ALL of those bot signups! Success!

4. Integrate with Your application

The requests you sent in steps 1-3 above contain minimum requirements to interface with the Castle API. You can code the same request bodies and headers in your application code.

If you’d prefer to use a Castle SDK to streamline the integration process in your application, check out our SDK links (linked at the bottom of the left-side page menu).

We suggest Getting started with login or registration events.