curl --request DELETE \
--url https://app.stockshift.io/api/v1/apps/push-token \
--header 'Authorization: Bearer <token>'import requests
url = "https://app.stockshift.io/api/v1/apps/push-token"
headers = {"Authorization": "Bearer <token>"}
response = requests.delete(url, headers=headers)
print(response.text)<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://app.stockshift.io/api/v1/apps/push-token",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "DELETE",
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://app.stockshift.io/api/v1/apps/push-token"
req, _ := http.NewRequest("DELETE", url, nil)
req.Header.Add("Authorization", "Bearer <token>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}{
"type": "<string>",
"title": "<string>",
"status": 123,
"code": "<string>",
"detail": "<string>",
"errors": {},
"feature": "<string>",
"reason": "<string>",
"attempts_left": 123,
"rule_ids": [
"<string>"
],
"witness": "<string>",
"blind_recount": true,
"flags": [
{
"flag": "<string>",
"facts": {},
"choices": [
"<string>"
]
}
]
}{
"type": "<string>",
"title": "<string>",
"status": 123,
"code": "<string>",
"detail": "<string>",
"errors": {},
"feature": "<string>",
"reason": "<string>",
"attempts_left": 123,
"rule_ids": [
"<string>"
],
"witness": "<string>",
"blind_recount": true,
"flags": [
{
"flag": "<string>",
"facts": {},
"choices": [
"<string>"
]
}
]
}{
"type": "<string>",
"title": "<string>",
"status": 123,
"code": "<string>",
"detail": "<string>",
"errors": {},
"feature": "<string>",
"reason": "<string>",
"attempts_left": 123,
"rule_ids": [
"<string>"
],
"witness": "<string>",
"blind_recount": true,
"flags": [
{
"flag": "<string>",
"facts": {},
"choices": [
"<string>"
]
}
]
}{
"type": "<string>",
"title": "<string>",
"status": 123,
"code": "<string>",
"detail": "<string>",
"errors": {},
"feature": "<string>",
"reason": "<string>",
"attempts_left": 123,
"rule_ids": [
"<string>"
],
"witness": "<string>",
"blind_recount": true,
"flags": [
{
"flag": "<string>",
"facts": {},
"choices": [
"<string>"
]
}
]
}{
"type": "<string>",
"title": "<string>",
"status": 123,
"code": "<string>",
"detail": "<string>",
"errors": {},
"feature": "<string>",
"reason": "<string>",
"attempts_left": 123,
"rule_ids": [
"<string>"
],
"witness": "<string>",
"blind_recount": true,
"flags": [
{
"flag": "<string>",
"facts": {},
"choices": [
"<string>"
]
}
]
}Remove the calling app's push token
The device stops receiving pushes and finds everything by pulling, as a device without Google Play services does. Answers 204 whether or not it held one. Needs an access token issued to an app; any other is not found. Audited.
curl --request DELETE \
--url https://app.stockshift.io/api/v1/apps/push-token \
--header 'Authorization: Bearer <token>'import requests
url = "https://app.stockshift.io/api/v1/apps/push-token"
headers = {"Authorization": "Bearer <token>"}
response = requests.delete(url, headers=headers)
print(response.text)<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://app.stockshift.io/api/v1/apps/push-token",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "DELETE",
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://app.stockshift.io/api/v1/apps/push-token"
req, _ := http.NewRequest("DELETE", url, nil)
req.Header.Add("Authorization", "Bearer <token>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}{
"type": "<string>",
"title": "<string>",
"status": 123,
"code": "<string>",
"detail": "<string>",
"errors": {},
"feature": "<string>",
"reason": "<string>",
"attempts_left": 123,
"rule_ids": [
"<string>"
],
"witness": "<string>",
"blind_recount": true,
"flags": [
{
"flag": "<string>",
"facts": {},
"choices": [
"<string>"
]
}
]
}{
"type": "<string>",
"title": "<string>",
"status": 123,
"code": "<string>",
"detail": "<string>",
"errors": {},
"feature": "<string>",
"reason": "<string>",
"attempts_left": 123,
"rule_ids": [
"<string>"
],
"witness": "<string>",
"blind_recount": true,
"flags": [
{
"flag": "<string>",
"facts": {},
"choices": [
"<string>"
]
}
]
}{
"type": "<string>",
"title": "<string>",
"status": 123,
"code": "<string>",
"detail": "<string>",
"errors": {},
"feature": "<string>",
"reason": "<string>",
"attempts_left": 123,
"rule_ids": [
"<string>"
],
"witness": "<string>",
"blind_recount": true,
"flags": [
{
"flag": "<string>",
"facts": {},
"choices": [
"<string>"
]
}
]
}{
"type": "<string>",
"title": "<string>",
"status": 123,
"code": "<string>",
"detail": "<string>",
"errors": {},
"feature": "<string>",
"reason": "<string>",
"attempts_left": 123,
"rule_ids": [
"<string>"
],
"witness": "<string>",
"blind_recount": true,
"flags": [
{
"flag": "<string>",
"facts": {},
"choices": [
"<string>"
]
}
]
}{
"type": "<string>",
"title": "<string>",
"status": 123,
"code": "<string>",
"detail": "<string>",
"errors": {},
"feature": "<string>",
"reason": "<string>",
"attempts_left": 123,
"rule_ids": [
"<string>"
],
"witness": "<string>",
"blind_recount": true,
"flags": [
{
"flag": "<string>",
"facts": {},
"choices": [
"<string>"
]
}
]
}Authorizations
How the StockShift apps sign in. The app opens /apps/authorize in the system browser with a PKCE S256 challenge and the thumbprint of its device key. The member signs in there, with every check the web enforces. The browser returns a code to the app, which trades it at POST /apps/token with the PKCE verifier and a DPoP proof (RFC 9449) signed by the device key. The answer holds an access token of one hour, which is sent as a bearer token on every call, and a rotating refresh token of 30 days. A refresh needs a DPoP proof with the server's latest nonce, so a stolen refresh token is useless without the device key. A session ends 180 days after sign-in at most. Every app request carries StockShift-Client: / (), such as ios/1.4.2 (311). Below the minimum of GET /apps/version-policy a call is answered 426 client_upgrade_required with the minimum and the store link. Below the deprecated-below version it works and the response adds StockShift-Client-Deprecated: sunset=; minimum=. Signing in and out, the device status, wipe receipt and PIN lock calls and the version policy answer every version.
Response
No content
Was this page helpful?