Add an App Store purchase
Checks the signed transaction from StoreKit and adds its credits once. Sending the same transaction again adds nothing. Finish the transaction in StoreKit after a 200.
POST
https://api.switchfile.io/v1/account/app-store/transactionsExample
Request
curl "https://api.switchfile.io/v1/account/app-store/transactions" \
-H "Authorization: Bearer $SWITCHFILE_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"signed_transaction": "eyJhbGciOiJFUzI1NiIsIng1YyI6WyJNSUlF..."
}'const res = await fetch("https://api.switchfile.io/v1/account/app-store/transactions", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.SWITCHFILE_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
signed_transaction: "eyJhbGciOiJFUzI1NiIsIng1YyI6WyJNSUlF..."
}),
});
if (!res.ok) throw new Error(`HTTP ${res.status}: ${await res.text()}`);
console.log(await res.json());<?php
$ch = curl_init('https://api.switchfile.io/v1/account/app-store/transactions');
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => json_encode([
'signed_transaction' => 'eyJhbGciOiJFUzI1NiIsIng1YyI6WyJNSUlF...',
]),
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('SWITCHFILE_API_KEY'),
'Content-Type: application/json',
],
CURLOPT_RETURNTRANSFER => true,
]);
$response = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
curl_close($ch);
if ($status >= 400) {
throw new RuntimeException("HTTP $status: $response");
}
print_r(json_decode($response, true));import os
import requests
res = requests.post(
"https://api.switchfile.io/v1/account/app-store/transactions",
headers={"Authorization": f"Bearer {os.environ['SWITCHFILE_API_KEY']}"},
json={
"signed_transaction": "eyJhbGciOiJFUzI1NiIsIng1YyI6WyJNSUlF...",
},
)
res.raise_for_status()
print(res.json())Request body
signed_transactionstringrequiredTransaction.jwsRepresentation from StoreKit
10 to 64000 characters
Responses
200OK
balancestring (integer) | integerrequiredcreditedbooleanrequiredfalse: nothing was added now, because the transaction was added before or Apple refunded it (finish it in StoreKit anyway)
creditsstring (integer) | integerrequiredCredits this request added (0 when nothing was added)
product_idstringrequiredrefundedbooleanrequiredtrue: Apple refunded the whole purchase, so it adds no credits
transaction_idstringrequired
200 application/json{ "transaction_id": "2000000812345678", "product_id": "io.switchfile.app.credits1000", "credits": 1000, "credited": true, "refunded": false, "balance": 2240 }401The API key is missing or not valid
UNAUTHENTICATED401 application/problem+json{ "type": "https://switchfile.io/docs/api/v1#errors-unauthenticated", "title": "Unauthenticated", "status": 401, "code": "UNAUTHENTICATED", "detail": "Missing or invalid API key." }403The purchase was made for another account (appAccountToken), or is a test purchase from an account that is not a test account
TRANSACTION_NOT_YOURS403 application/problem+json{ "type": "https://switchfile.io/docs/api/v1#errors-transaction-not-yours", "title": "Transaction not yours", "status": 403, "code": "TRANSACTION_NOT_YOURS", "detail": "This purchase was made for another switchfile account." }404Does not exist for this account
NOT_FOUND404 application/problem+json{ "type": "https://switchfile.io/docs/api/v1#errors-not-found", "title": "Not found", "status": 404, "code": "NOT_FOUND", "detail": "Not found." }409Already added to another account
TRANSACTION_ALREADY_USED409 application/problem+json{ "type": "https://switchfile.io/docs/api/v1#errors-transaction-already-used", "title": "Transaction already used", "status": 409, "code": "TRANSACTION_ALREADY_USED", "detail": "This purchase was already added to another account." }422Not signed by the App Store, or an unknown product
INVALID_TRANSACTION422 application/problem+json{ "type": "https://switchfile.io/docs/api/v1#errors-invalid-transaction", "title": "Invalid transaction", "status": 422, "code": "INVALID_TRANSACTION", "detail": "The transaction is not signed by the App Store." }429Too many requests or a daily quota is used up. See Retry-After
RATE_LIMIT_EXCEEDED429 application/problem+json{ "type": "https://switchfile.io/docs/api/v1#errors-rate-limit-exceeded", "title": "Rate limit exceeded", "status": 429, "code": "RATE_LIMIT_EXCEEDED", "detail": "Too many requests. Try again in 12 seconds." }503Not available right now or busy. See Retry-After
PURCHASES_UNAVAILABLE503 application/problem+json{ "type": "https://switchfile.io/docs/api/v1#errors-purchases-unavailable", "title": "Purchases unavailable", "status": 503, "code": "PURCHASES_UNAVAILABLE", "detail": "Purchases in the app are not available right now." }