Skip to content

Autoblow API V1

The Autoblow API is hosted on multiple clusters around the world. When a device goes online it will connect to the lowest latency server. To control the device you must connect to the same cluster as the device. You can find the cluster your device is connected to by checking the cluster property in the /autoblow/connected response.

https://us-east-1.autoblowapi.com
https://us-east-2.autoblowapi.com
https://us-west-1.autoblowapi.com
https://us-west-2.autoblowapi.com
https://ca-central-1.autoblowapi.com
https://ap-southeast-2.autoblowapi.com
https://eu-west-2.autoblowapi.com
https://eu-central-1.autoblowapi.com

Every request below takes the device token in the x-device-token header. Requests with a body use Content-Type: application/json; send requests without a body without a Content-Type header, because the API rejects an empty JSON body. Most commands respond with the device state; the ones that return something else say so. The examples use the eu-central-1 cluster and YOUR_DEVICE_TOKEN.

Check if a device is connected and get the cluster it is connected to. This request can be performed on any cluster but for reliability purposes we recommend using https://latency.autoblowapi.com which will connect you to the cluster with the lowest latency. All the other requests can only be performed on the cluster the device is connected to; on any other cluster they fail with 502. deviceType is autoblow-ultra for the Ultra. For a vacuglide or vacupump use the Vacuglide API or the VacuPump API instead. A device that is offline returns { "connected": false }.

Terminal window
curl --request GET \
--url https://latency.autoblowapi.com/autoblow/connected \
--header 'x-device-token: YOUR_DEVICE_TOKEN'
{ "connected": true, "cluster": "eu-central-1.autoblowapi.com", "deviceType": "autoblow-ultra" }

Get the firmware and hardware version and the device MAC. firmwareStatus is UP_TO_DATE, UPDATE_AVAILABLE or UPDATE_REQUIRED.

Terminal window
curl --request GET \
--url https://eu-central-1.autoblowapi.com/autoblow/info \
--header 'x-device-token: YOUR_DEVICE_TOKEN'
{
"firmwareStatus": "UP_TO_DATE",
"firmwareVersion": 1.01,
"firmwareBranch": "prod",
"hardwareVersion": "ultra",
"mac": "aabbccddeeff",
"deviceType": "autoblow-ultra"
}

Get the current device state.

Terminal window
curl --request GET \
--url https://eu-central-1.autoblowapi.com/autoblow/state \
--header 'x-device-token: YOUR_DEVICE_TOKEN'

Positions and speeds are percentages from 0 to 100.

Set the oscillator and start it: the stroker moves between minY and maxY at speed. minY and maxY must be at least 10 apart.

namerequiredtypedescription
speed
(body)
yesnumberOscillator speed (0 to 100)
minY
(body)
yesnumberOscillator low point (0 to 100)
maxY
(body)
yesnumberOscillator high point (0 to 100)
Terminal window
curl --request PUT \
--url https://eu-central-1.autoblowapi.com/autoblow/oscillate \
--header 'Content-Type: application/json' \
--header 'x-device-token: YOUR_DEVICE_TOKEN' \
--data '{"speed": 50, "minY": 5, "maxY": 100}'

PUT /autoblow/oscillate/start, /autoblow/oscillate/stop

Section titled “PUT /autoblow/oscillate/start, /autoblow/oscillate/stop”

Start the oscillator with the last settings, or pause it (OSCILLATOR_PAUSED). No body.

Terminal window
curl --request PUT \
--url https://eu-central-1.autoblowapi.com/autoblow/oscillate/start \
--header 'x-device-token: YOUR_DEVICE_TOKEN'

Sync scripts are funscripts played in sync with a video. Upload a script or load one by token, call start with the video position whenever the video starts playing or the user seeks, and stop when it pauses.

The uploads accept a funscript or a CSV file. The backend converts the script to the binary format the Ultra plays and stores it for 9 days under a new token, which you can later pass to load-token. Positions are percentages from 0 to 100 and times are milliseconds from the start of the video.

A funscript is JSON with an actions array:

{
"actions": [
{ "at": 0, "pos": 0 },
{ "at": 500, "pos": 100 },
{ "at": 1000, "pos": 0 }
]
}

A CSV file has one time,position pair per line and no header. End the file with a newline; the last line is dropped otherwise.

0,0
500,100
1000,0

Limits: at most 100,000 actions, and the last one at most 16,777,214 ms (about 4.6 hours).

PUT /autoblow/sync-script/upload-funscript, /autoblow/sync-script/upload-csv

Section titled “PUT /autoblow/sync-script/upload-funscript, /autoblow/sync-script/upload-csv”

Upload a script file, store it and load it on the device. The body is multipart/form-data with the file in one part, up to 60 MB; curl’s --form sets the header. The device downloads the script before the request responds, so allow a request timeout of at least 60 seconds. The response is the device state: syncScriptToken holds the new token and operationalMode is SYNC_SCRIPT_PAUSED, as after load-token.

namerequiredtypedescription
file
(multipart)
yesfileThe .funscript or .csv file
Terminal window
curl --request PUT \
--url https://eu-central-1.autoblowapi.com/autoblow/sync-script/upload-funscript \
--header 'x-device-token: YOUR_DEVICE_TOKEN' \
--form 'file=@/path/to/script.funscript'

PUT /autoblow/sync-script/upload-funscript-url, /autoblow/sync-script/upload-csv-url

Section titled “PUT /autoblow/sync-script/upload-funscript-url, /autoblow/sync-script/upload-csv-url”

The same as the file uploads, but the API downloads the script from url. The URL must serve the file directly; redirects are not followed.

namerequiredtypedescription
url
(body)
yesstringhttp or https URL of the script file
Terminal window
curl --request PUT \
--url https://eu-central-1.autoblowapi.com/autoblow/sync-script/upload-funscript-url \
--header 'Content-Type: application/json' \
--header 'x-device-token: YOUR_DEVICE_TOKEN' \
--data '{"url": "https://example.com/scripts/test.funscript"}'

Load a previously uploaded script by its token. The device downloads the script before responding, so allow a request timeout of at least 60 seconds. Loading never starts playback: whatever the device was playing, it switches to SYNC_SCRIPT_PAUSED and stops moving, and looping is turned off.

namerequiredtypedescription
scriptToken
(body)
yesstringToken of an uploaded script
Terminal window
curl --request PUT \
--url https://eu-central-1.autoblowapi.com/autoblow/sync-script/load-token \
--header 'Content-Type: application/json' \
--header 'x-device-token: YOUR_DEVICE_TOKEN' \
--data '{"scriptToken": "7a93bfc5-4043-4ade-aee5-bec8012b0e12"}'

Start playing the loaded script from a video position, or seek while it plays. Without a loaded script it fails with 400 (SYNC_SCRIPT_NOT_LOADED).

namerequiredtypedescription
startTimeMs
(body)
yesnumberVideo position in ms
Terminal window
curl --request PUT \
--url https://eu-central-1.autoblowapi.com/autoblow/sync-script/start \
--header 'Content-Type: application/json' \
--header 'x-device-token: YOUR_DEVICE_TOKEN' \
--data '{"startTimeMs": 24000}'

Pause playback (SYNC_SCRIPT_PAUSED). The script stays loaded, so a later start resumes or seeks without loading it again. No body.

Terminal window
curl --request PUT \
--url https://eu-central-1.autoblowapi.com/autoblow/sync-script/stop \
--header 'x-device-token: YOUR_DEVICE_TOKEN'

Compensate the latency between your player and the device. The offset stays set across script loads until the device restarts.

namerequiredtypedescription
offsetTimeMs
(body)
yesnumberOffset in whole ms, positive or negative; positive means the device runs ahead of the video
Terminal window
curl --request PUT \
--url https://eu-central-1.autoblowapi.com/autoblow/sync-script/offset \
--header 'Content-Type: application/json' \
--header 'x-device-token: YOUR_DEVICE_TOKEN' \
--data '{"offsetTimeMs": 100}'

Restart the script from the beginning when it ends. Without looping the device pauses at the end (SYNC_SCRIPT_PAUSED). Loading a script turns looping off, so send this after loading.

namerequiredtypedescription
loop
(body)
yesboolWhether to restart the script at the end
Terminal window
curl --request PUT \
--url https://eu-central-1.autoblowapi.com/autoblow/sync-script/loop \
--header 'Content-Type: application/json' \
--header 'x-device-token: YOUR_DEVICE_TOKEN' \
--data '{"loop": true}'

Local scripts are the stroke patterns stored on the device.

Play a local script at a speed.

namerequiredtypedescription
localScriptIndex
(body)
yesnumberLocal script to play (0 to 9)
speedIndex
(body)
yesnumberSpeed level (0 to 9)
Terminal window
curl --request PUT \
--url https://eu-central-1.autoblowapi.com/autoblow/local-script \
--header 'Content-Type: application/json' \
--header 'x-device-token: YOUR_DEVICE_TOKEN' \
--data '{"localScriptIndex": 5, "speedIndex": 2}'

PUT /autoblow/local-script/start, /autoblow/local-script/stop

Section titled “PUT /autoblow/local-script/start, /autoblow/local-script/stop”

stop pauses the playing local script (LOCAL_SCRIPT_PAUSED) and start resumes it. In any other mode they change nothing; use /autoblow/local-script to play a script. No body.

Terminal window
curl --request PUT \
--url https://eu-central-1.autoblowapi.com/autoblow/local-script/stop \
--header 'x-device-token: YOUR_DEVICE_TOKEN'

Move the stroker to a position at a speed. The command is sent to the device without waiting for it, so the request responds right away with { "success": true }, which means the command was sent, not that the move finished. The device switches to GO_TO; poll /autoblow/state to follow it.

namerequiredtypedescription
position
(body)
yesnumberTarget position in percent (0 to 100)
speed
(body)
yesnumberSpeed in percent (0 to 100)
Terminal window
curl --request PUT \
--url https://eu-central-1.autoblowapi.com/autoblow/goto \
--header 'Content-Type: application/json' \
--header 'x-device-token: YOUR_DEVICE_TOKEN' \
--data '{"position": 100, "speed": 10}'
{ "success": true }

Server-sent events for one device. Open the stream on the cluster the device is connected to; this request takes the token in the deviceToken query parameter instead of the header. The stream starts with a connected event and sends a heartbeat every 30 seconds.

While the Ultra is online its mode, pause and speed buttons do nothing on the device; each press is sent as an event instead, so your app decides what it does:

  • mode-button-pressed
  • pause-button-pressed
  • speed-up-button-pressed
  • speed-down-button-pressed
namerequiredtypedescription
deviceToken
(query)
yesstringThe device token
Terminal window
curl --no-buffer \
--url 'https://eu-central-1.autoblowapi.com/events/stream?deviceToken=YOUR_DEVICE_TOKEN'
event: connected
data: {"connectionId":"bedffe18-f62e-4c9c-8e9b-7082f88d5f0c","subscribedDevice":"YOUR_DEVICE_TOKEN"}
event: mode-button-pressed
data: {"deviceToken":"YOUR_DEVICE_TOKEN","payload":{"type":"mode-button-pressed","rawData":null,"args":[]},"timestamp":1752685746276}
event: heartbeat
data: {"timestamp":1752685776276}
nametypedescription
operationalModeenum: POWERED_OFF, CALIBRATION, REST_AT_TOP, INIT, ONLINE_CONNECTED, SYNC_SCRIPT_PLAYING, SYNC_SCRIPT_PAUSED, LOCAL_SCRIPT_PLAYING, LOCAL_SCRIPT_PAUSED, OSCILLATOR_PLAYING, OSCILLATOR_PAUSED, GO_TO, SETUP, ERROR, LOADING, FIRMWARE_UPDATING, ERROR_MOTOR_STUCK, ERROR_CALIBRATION, ERROR_OVERHEATINGThe current operational mode (see below)
localScriptnumber (0 to 9)Selected local script
localScriptSpeednumber (0 to 9)Local script speed level
motorTemperaturenumberMotor temperature in °C
oscillatorTargetSpeednumber (0 to 100)Oscillator speed in percent
oscillatorLowPointnumber (0 to 100)Oscillator low point in percent (minY)
oscillatorHighPointnumber (0 to 100)Oscillator high point in percent (maxY)
syncScriptCurrentTimenumberCurrent position of the sync script in ms
syncScriptOffsetTimenumberApplied sync offset in ms
syncScriptTokenstringToken of the loaded sync script; empty when none is loaded
syncScriptLoopboolWhether the sync script restarts when it ends
operationalModedescription
ONLINE_CONNECTEDConnected and idle, ready for commands
OSCILLATOR_PLAYING, OSCILLATOR_PAUSEDThe oscillator is running or paused
SYNC_SCRIPT_PLAYING, SYNC_SCRIPT_PAUSEDThe sync script is playing or paused
LOCAL_SCRIPT_PLAYING, LOCAL_SCRIPT_PAUSEDA local script is playing or paused
GO_TOMoving after a goto command
FIRMWARE_UPDATINGUpdating its firmware
ERROR_MOTOR_STUCK, ERROR_CALIBRATION, ERROR_OVERHEATING, ERRORThe motor is stuck, calibration failed, the motor overheated, or another error
POWERED_OFF, CALIBRATION, REST_AT_TOP, INIT, SETUP, LOADINGStart-up, Wi-Fi setup and connecting states before the device is online

Example (a sync script playing from the start):

{
"operationalMode": "SYNC_SCRIPT_PLAYING",
"localScript": 0,
"localScriptSpeed": 0,
"motorTemperature": 30,
"oscillatorTargetSpeed": 50,
"oscillatorLowPoint": 0,
"oscillatorHighPoint": 100,
"syncScriptCurrentTime": 15,
"syncScriptOffsetTime": 0,
"syncScriptToken": "7a93bfc5-4043-4ade-aee5-bec8012b0e12",
"syncScriptLoop": false
}

Requests are limited per device token. Each response carries x-ratelimit-limit, x-ratelimit-remaining and x-ratelimit-reset headers. A 429 response means the limit was hit; wait before retrying.