utilsio.dev is currently in Alpha, please report any issues to hi@utilsio.dev. Happy building! 🚀
curl --request DELETE \
--url https://utilsio.dev/api/v1/subscription \
--header 'Content-Type: application/json' \
--header 'X-utilsio-Signature: <api-key>' \
--header 'X-utilsio-Timestamp: <x-utilsio-timestamp>' \
--data '
{
"userId": "user_123",
"deviceId": "device_abc",
"appId": "app_xyz",
"subscriptionIds": [
"sub_abc123",
"sub_def456"
]
}
'{
"success": true
}Cancels one or more active subscriptions. Only subscriptions owned by the requesting user and belonging to the specified app can be cancelled.
curl --request DELETE \
--url https://utilsio.dev/api/v1/subscription \
--header 'Content-Type: application/json' \
--header 'X-utilsio-Signature: <api-key>' \
--header 'X-utilsio-Timestamp: <x-utilsio-timestamp>' \
--data '
{
"userId": "user_123",
"deviceId": "device_abc",
"appId": "app_xyz",
"subscriptionIds": [
"sub_abc123",
"sub_def456"
]
}
'{
"success": true
}Documentation Index
Fetch the complete documentation index at: https://utilsio.dev/docs/llms.txt
Use this file to discover all available pages before exploring further.
/subscription endpoint cancels one or more active subscriptions for a user. The cancellation is processed on-chain via the smart contract wallet system.
| Header | Required | Description |
|---|---|---|
X-utilsio-Signature | Conditional | HMAC-SHA256 signature. Required unless using Safari fallback flow (see below) |
X-utilsio-Timestamp | Conditional | Unix timestamp in seconds. Required unless using Safari fallback flow |
| Field | Type | Required | Description |
|---|---|---|---|
userId | string | Yes | User ID who owns the subscription |
deviceId | string | Conditional | Device ID. Optional if using Safari fallback - will be read from cookies |
appId | string | Yes | Your application ID |
subscriptionIds | string[] | Yes | Array of subscription IDs to cancel |
signatureCallbackUrl | string | Conditional | Required for Safari fallback when signature headers are not provided. URL to your /api/signature-callback endpoint |
deviceId is available (Chrome, Firefox, etc.), generate the signature client-side:
import { deriveAppHashHex, signRequest, nowUnixSeconds } from '@utilsio/react/server';
// Derive key (do this once at startup)
const appHashHex = deriveAppHashHex({
appSecret: process.env.UTILSIO_APP_SECRET!,
salt: process.env.UTILSIO_APP_SALT!,
});
// Sign the request
const timestamp = nowUnixSeconds();
const additionalData = subscriptionIds.sort().join(','); // Include subscription IDs in signature
const signature = signRequest({
appHashHex,
deviceId,
appId: process.env.NEXT_PUBLIC_UTILSIO_APP_ID!,
timestamp,
additionalData, // IMPORTANT: Include this for DELETE requests
});
deviceId is not available client-side. Instead:
deviceId or signature headerssignatureCallbackUrl in request bodydeviceId from first-party cookies/api/signature-callback endpoint/api/signature-callback):
export async function POST(req: NextRequest) {
const { deviceId, appId, additionalData, timestamp } = await req.json();
const signature = signRequest({
appHashHex,
deviceId,
appId,
timestamp,
additionalData, // subscriptionIds sorted and joined
});
return NextResponse.json({ signature, timestamp });
}
subscriptionIds (comma-separated) as additionalData in the signature to prevent tampering.curl -X DELETE 'https://utilsio.dev/api/v1/subscription' \
-H 'Content-Type: application/json' \
-H 'X-utilsio-Signature: abc123...' \
-H 'X-utilsio-Timestamp: 1705334400' \
-d '{
"userId": "user_123",
"deviceId": "device_abc",
"appId": "app_xyz",
"subscriptionIds": ["sub_abc123"]
}'
{
"success": true
}
| Status | Error | Cause |
|---|---|---|
| 400 | userId, appId, and subscriptionIds are required | Missing required fields |
| 400 | Device ID not found. Please ensure cookies are enabled. | Safari flow failed to read deviceId from cookies |
| 400 | signatureCallbackUrl is required when signature is not provided | Safari flow missing callback URL |
| 400 | User wallet not configured | User hasn’t set up their wallet |
| 401 | Invalid signature | Signature verification failed |
| 403 | Some subscriptions not found or unauthorized | User doesn’t own all specified subscriptions |
| 404 | No valid subscriptions found to delete | None of the provided IDs exist |
| 500 | Failed to obtain signature from app | Safari flow: callback to app failed |
| 500 | Failed to delete subscription stream | On-chain transaction failed |
'use client';
import { useUtilsio } from '@utilsio/react/client';
export default function ManageSubscription() {
const { user, deviceId, currentSubscription, cancelSubscription } = useUtilsio();
const handleCancel = async () => {
if (!currentSubscription) return;
if (!confirm('Are you sure you want to cancel your subscription?')) return;
try {
await cancelSubscription([currentSubscription.id]);
// refresh() is called automatically, component re-renders
} catch (err) {
console.error('Cancellation failed:', err);
}
};
return currentSubscription ? (
<button onClick={handleCancel}>
Cancel Subscription
</button>
) : null;
}
cancelSubscription() automatically refreshes subscription state after successHMAC signature for request authentication
Unix timestamp for request signing
Was this page helpful?