Secure Remote Activation of Speedify Devices

This article describes a scalable remote device activation system for Speedify client devices.

The usual alternative is to sign in on the device with a real account email and password, which means every router in the field is holding a credential that unlocks your whole team. This flow avoids that.


How It Works

Piece Runs where What it does
Speedify Teams API Trusted host Account-level operations, authenticated with your Speedify Teams API key in the x-api-key    header
speedify_cli Each device Communication with the local Speedify daemon, including querying an activation code

Local client devices generate activation codes; a trusted host on your infrastructure redeems it via the Speedify Team API.

Speedify device activation sequence The trusted host asks the device for a one-time activation code over SSH, then redeems that code against the Speedify Teams API using its API key. The device is verified from both sides. The API key never reaches the device. Operator / CI Operator / CI Trusted host (has API key) Trusted host (has API key) Device (no credentials) Device (no credentials) Speedify Teams API (api.speedify.com) Speedify Teams API (api.speedify.com) 1 start activation for member@team 2 ssh device speedify_cli activationcode 3 daemon generates one-time code 4 { "activationCode": "192989" } 5 PATCH /v1/teams/members/email/{email}/activate-device x-api-key: •••• | body: { "activationCode": "192989" } 6 200 { "deviceUUID": "F3C284CC-…" } 7 daemon transitions to LOGGED_IN par [ verify from both sides ] 8 ssh device speedify_cli state 9 { "state": "LOGGED_IN" } 10 GET /v1/teams/members/email/{email}/devices 11 200 [ …, { "deviceUUID": "F3C284CC-…" } ] 12 activated, verified, UUID recorded

Activation is idempotent per device. The daemon keeps its identity across restarts and reinstalls of the same install, so re-activating links the same deviceUUID    rather than burning a second seat. That UUID becomes the handle you use later to rename or unlink the device.


What You'll Need

  • A Speedify for Teams account with admin access.
  • A Teams API key. Generate one in the admin console at my.speedify.com/api by clicking +, entering a description, and clicking Generate Key.
  • A trusted host to hold that key: your workstation, a jump box, or a CI runner. This is the only machine that ever sees the key.
  • SSH access to each device, key-based rather than password-based.
  • Speedify installed and running on each device. See Install Speedify on Linux if you're starting from scratch.
  • The email address of the team member the device should be linked to. It must already be on the team.

Fleet tip: rather than linking dozens of routers to a person, create a dedicated machine account and link them all to that. When you add a member with POST /v1/teams/members    and include a password    field, the account is created directly instead of triggering an invitation email. Omit password    and the person gets an invite instead.


Step 1: Get an Activation Code From the Device

Ask the daemon on the device for a one-time code:

ssh $USER@$DEVICE /usr/share/speedify/speedify_cli activationcode

You'll get back something like this:

{"activationCode":"192989","activationUrl":"https://my.speedify.com/..."}

The code is short-lived and single-use. If you sit on it for a while before redeeming it, fetch a fresh one.


Step 2: Redeem the Code From Your Trusted Host

Send the code to the Teams API from the machine that holds your key. Keep the key in an environment variable so it never lands in your shell history or a script in version control.

The @    in the email address has to be URL-encoded as %40   , because the email sits in the URL path.

curl -X PATCH \
  "https://api.speedify.com/v1/teams/members/email/fleet%40example.com/activate-device" \
  -H "x-api-key: $SPEEDIFY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"activationCode":"192989"}'

A successful call returns 200    and the device's UUID:

{"deviceUUID":"2275583a-4587-4e5e-964f-fd4fae0508e2"}

Record that UUID. It's how you'll refer to this device from now on.

At the same moment, the daemon on the device transitions to LOGGED_IN    on its own. You don't have to run anything else on the device.


Step 3: Verify the Device From Both Sides

Confirm the result on the device and in your account. Checking both catches the case where the API call succeeded but the daemon didn't come up.

On the device:

ssh admin@device-01 /usr/share/speedify/speedify_cli state

You want {"state":"LOGGED_IN"}   . Anything else means the daemon isn't activated yet.

From your account:

curl "https://api.speedify.com/v1/teams/members/email/fleet%40example.com/devices" \
  -H "x-api-key: $SPEEDIFY_API_KEY"

Look for your UUID in the list, and check that seenActivationSuccess    is true    on that entry. Routers also report "role":"router"   , which is a quick way to tell them apart from client installs.


Once you have a UUID, two v2 endpoints handle day-to-day device management.

Give the device a readable name so your device list isn't a wall of UUIDs:

curl -X PATCH \
  "https://api.speedify.com/v2/teams/members/fleet%40example.com/devices/$DEVICE_UUID" \
  -H "x-api-key: $SPEEDIFY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"friendlyName":"warehouse-router-03"}'

Unlink a device that's been retired, sold, or stolen. This frees the seat and cuts the device off:

curl -X DELETE \
  "https://api.speedify.com/v2/teams/members/fleet%40example.com/devices/$DEVICE_UUID" \
  -H "x-api-key: $SPEEDIFY_API_KEY"

If a device is stuck holding an active session, DELETE /v2/teams/members/{email}/devices/{deviceUUID}/active    resets the session without unlinking the device.


Where the Secrets Live

The point of this flow is that no single compromised device gives an attacker anything useful. Here's what each party actually holds:

Secret or artifact Trusted host Device Speedify cloud Lifetime
Teams API key Yes, in an env var Never Verifies it Until revoked
Activation code Passes through once Originates here Redeems it Minutes, void after use
SSH private key Yes No No Rotate at will
SSH public key Yes In authorized_keys    No Not secret
Account password No No Yes Never used in this flow
deviceUUID    Logged Implicit Yes Handle for rename and unlink

What Happens If Something Goes Wrong

Scenario What you do about it
A device is stolen or rooted There are no credentials on it to find. Unlink its UUID to evict it from the team.
An activation code is intercepted Redeeming it can only add that one device to your own team, where it shows up immediately in the device list.
The trusted host is compromised Revoke the key with DELETE /v2/teams/api-keys/{apiKey}    and issue a new one. Already-activated devices keep working.
A key gets committed to a repo Same fix: revoke and reissue. Then pin the new key to your egress IPs with PUT /v2/teams/api-keys/{apiKey}/allowed-ips   .

You can create keys with POST /v2/teams/api-keys   , passing a description    and, if you want the restriction from day one, an allowedIPs    value with comma-separated addresses or CIDR ranges.


If Activation Fails

Status What it means Fix
400    The code is malformed or expired Fetch a fresh code from the device and retry right away
401    The API key is missing or invalid Check that $SPEEDIFY_API_KEY    is set and current. Rotate it if you suspect it leaked
403    The key is valid but not allowed to do this Check the key's role and its IP allow list. Device management needs an admin key
404    That email isn't on your team Add the member first with POST /v1/teams/members   , then retry
429    No seats left when adding a member Increase seats, or unlink devices and remove members you no longer need
500    Server error Retry with backoff

If the API returns 200    but the device never reaches LOGGED_IN   , check that the daemon is actually running. speedify_cli version    is the fastest liveness test.


Command Reference

On the Device

Every speedify_cli    command returns JSON.

Command Purpose Example output
activationcode    Generates a one-time activation code for this device {"activationCode":"192989","activationUrl":"..."}   
state    Reports the daemon state {"state":"LOGGED_OUT"}    then {"state":"LOGGED_IN"}   
version    Liveness check and version {"maj":16,"min":9,"bug":1,"build":12934}   

From the Trusted Host

Base URL is https://api.speedify.com   , and every request carries the x-api-key    header.

Task Method and path Body
Activate a device PATCH /v1/teams/members/email/{email}/activate-device    {"activationCode":"192989"}   
List a member's devices GET /v1/teams/members/email/{email}/devices    None
Rename a device PATCH /v2/teams/members/{email}/devices/{deviceUUID}    {"friendlyName":"warehouse-router-03"}   
Unlink a device DELETE /v2/teams/members/{email}/devices/{deviceUUID}    None
Reset an active session DELETE /v2/teams/members/{email}/devices/{deviceUUID}/active    None
Create an API key POST /v2/teams/api-keys    {"description":"CI pipeline","allowedIPs":"10.0.0.0/8"}   
Revoke an API key DELETE /v2/teams/api-keys/{apiKey}    None
Restrict a key to your IPs PUT /v2/teams/api-keys/{apiKey}/allowed-ips    {"allowedIPs":"203.0.113.4,10.0.0.0/8"}   

The full reference, including every endpoint not covered here, lives in the Speedify Teams API documentation.