Quick Start
Get a pass into a user's wallet in under 5 minutes.
Step 1 โ Get a Token
Exchange your tenant + application credentials for a Bearer JWT (valid 60 minutes).
POST
/api/v1/auth/token
{
"tenant_id": "your-tenant-id",
"application_id": "your-app-id",
"application_secret": "wp_your_secret",
"grant_type": "client_credentials"
}
โ 200 OK
{
"access_token": "eyJhbGciOiJSUzI1NiIs...",
"token_type": "Bearer",
"expires_in": 3599,
"scope": "passes:read passes:write templates:read messages:read messages:write webhooks:write analytics:read"
}
curl -X POST https://api.walletplatform.io/api/v1/auth/token \
-H "Content-Type: application/json" \
-d '{
"tenant_id": "your-tenant-id",
"application_id": "your-app-id",
"application_secret": "wp_your_secret",
"grant_type": "client_credentials"
}'using var client = new HttpClient();
var response = await client.PostAsJsonAsync(
"https://api.walletplatform.io/api/v1/auth/token",
new
{
tenant_id = "your-tenant-id",
application_id = "your-app-id",
application_secret = "wp_your_secret",
grant_type = "client_credentials"
});
var body = await response.Content.ReadFromJsonAsync<JsonElement>();
var token = body.GetProperty("access_token").GetString();const response = await fetch(
'https://api.walletplatform.io/api/v1/auth/token',
{
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
tenant_id: 'your-tenant-id',
application_id: 'your-app-id',
application_secret: 'wp_your_secret',
grant_type: 'client_credentials'
})
}
);
const { access_token } = await response.json();import requests
r = requests.post(
'https://api.walletplatform.io/api/v1/auth/token',
json={
'tenant_id': 'your-tenant-id',
'application_id': 'your-app-id',
'application_secret': 'wp_your_secret',
'grant_type': 'client_credentials'
}
)
token = r.json()['access_token']<?php
$payload = json_encode([
'tenant_id' => 'your-tenant-id',
'application_id' => 'your-app-id',
'application_secret' => 'wp_your_secret',
'grant_type' => 'client_credentials',
]);
$response = file_get_contents(
'https://api.walletplatform.io/api/v1/auth/token',
false,
stream_context_create([
'http' => [
'method' => 'POST',
'header' => "Content-Type: application/json\r\n",
'content' => $payload,
],
])
);
$token = json_decode($response)->access_token;Step 2 โ Create a Pass
POST to /passes with a template id and your customer data:
POST
/api/v1/passes
Headers:
Authorization: Bearer eyJhbGci...
Content-Type: application/json
Idempotency-Key: customer-12345-pass-001
Body:
{
"template_id": "3f2a1b4c-8d9e-4c5b-9a3e-7d1f8e4a2c5b",
"intent": "loyalty_card",
"external_ref": "customer-12345",
"data": {
"member_name": "Max Mustermann",
"member_id": "MBR001",
"points": "1500",
"logo_url": "https://yourdomain.com/logo.png"
}
}
โ 202 Accepted
{
"id": "57725a27-2093-42d0-8cb9-d4f1a5e9b3c7",
"status": "pending",
"external_ref": "customer-12345",
"providers": {
"google": { "status": "queued" }
},
"job_id": "5b0c61cf-...",
"created_at": "2026-05-18T10:00:00Z"
}
curl -X POST https://api.walletplatform.io/api/v1/passes \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: customer-12345-pass-001" \
-d '{
"template_id": "3f2a1b4c-8d9e-4c5b-9a3e-7d1f8e4a2c5b",
"intent": "loyalty_card",
"external_ref": "customer-12345",
"data": {
"member_name": "Max Mustermann",
"member_id": "MBR001",
"points": "1500"
}
}'using var client = new HttpClient();
client.DefaultRequestHeaders.Authorization =
new AuthenticationHeaderValue("Bearer", token);
client.DefaultRequestHeaders.Add("Idempotency-Key", "customer-12345-pass-001");
var response = await client.PostAsJsonAsync(
"https://api.walletplatform.io/api/v1/passes",
new
{
template_id = "3f2a1b4c-8d9e-4c5b-9a3e-7d1f8e4a2c5b",
intent = "loyalty_card",
external_ref = "customer-12345",
data = new
{
member_name = "Max Mustermann",
member_id = "MBR001",
points = "1500"
}
});
var pass = await response.Content.ReadFromJsonAsync<JsonElement>();
var passId = pass.GetProperty("id").GetString();const response = await fetch(
'https://api.walletplatform.io/api/v1/passes',
{
method: 'POST',
headers: {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json',
'Idempotency-Key': 'customer-12345-pass-001'
},
body: JSON.stringify({
template_id: '3f2a1b4c-8d9e-4c5b-9a3e-7d1f8e4a2c5b',
intent: 'loyalty_card',
external_ref: 'customer-12345',
data: {
member_name: 'Max Mustermann',
member_id: 'MBR001',
points: '1500'
}
})
}
);
const pass = await response.json();import requests
headers = {
'Authorization': f'Bearer {token}',
'Idempotency-Key': 'customer-12345-pass-001',
}
r = requests.post(
'https://api.walletplatform.io/api/v1/passes',
headers=headers,
json={
'template_id': '3f2a1b4c-8d9e-4c5b-9a3e-7d1f8e4a2c5b',
'intent': 'loyalty_card',
'external_ref': 'customer-12345',
'data': {
'member_name': 'Max Mustermann',
'member_id': 'MBR001',
'points': '1500',
},
},
)
pass_data = r.json()$payload = json_encode([
'template_id' => '3f2a1b4c-8d9e-4c5b-9a3e-7d1f8e4a2c5b',
'intent' => 'loyalty_card',
'external_ref' => 'customer-12345',
'data' => [
'member_name' => 'Max Mustermann',
'member_id' => 'MBR001',
'points' => '1500',
],
]);
$response = file_get_contents(
'https://api.walletplatform.io/api/v1/passes',
false,
stream_context_create([
'http' => [
'method' => 'POST',
'header' => implode("\r\n", [
"Authorization: Bearer $token",
'Content-Type: application/json',
'Idempotency-Key: customer-12345-pass-001',
]),
'content' => $payload,
],
])
);
$pass = json_decode($response);Step 3 โ Poll for Status
Pass creation is asynchronous. Poll GET /passes/{id} until
status is active (all providers completed) or
partial (some completed, others still in-flight).
# Poll until status = active or partial
while true; do
r=$(curl -s https://api.walletplatform.io/api/v1/passes/$PASS_ID \
-H "Authorization: Bearer $TOKEN")
status=$(echo $r | jq -r .status)
echo "Status: $status"
[[ "$status" =~ ^(active|partial)$ ]] && break
sleep 2
done
echo $r | jq .providers.google.save_linkstring? googleSaveLink = null;
while (googleSaveLink is null)
{
await Task.Delay(TimeSpan.FromSeconds(2));
var r = await client.GetFromJsonAsync<JsonElement>(
$"https://api.walletplatform.io/api/v1/passes/{passId}");
var status = r.GetProperty("status").GetString();
if (status is "active" or "partial")
{
googleSaveLink = r.GetProperty("providers")
.GetProperty("google")
.GetProperty("save_link").GetString();
}
}
Console.WriteLine(googleSaveLink); // pay.google.com/gp/v/save/...async function waitForPass(passId) {
while (true) {
const r = await fetch(
`https://api.walletplatform.io/api/v1/passes/${passId}`,
{ headers: { 'Authorization': `Bearer ${token}` } }
);
const pass = await r.json();
if (['active', 'partial'].includes(pass.status)) return pass.providers;
await new Promise(rs => setTimeout(rs, 2000));
}
}
const providers = await waitForPass(passId);
window.location.href = providers.google.save_link;import time
while True:
r = requests.get(
f'https://api.walletplatform.io/api/v1/passes/{pass_id}',
headers={'Authorization': f'Bearer {token}'},
)
data = r.json()
if data['status'] in ('active', 'partial'):
save_link = data['providers']['google']['save_link']
print(f'Google Wallet: {save_link}')
break
time.sleep(2)do {
sleep(2);
$r = json_decode(file_get_contents(
"https://api.walletplatform.io/api/v1/passes/$passId",
false,
stream_context_create(['http' => [
'header' => "Authorization: Bearer $token",
]])
));
} while (!in_array($r->status, ['active', 'partial']));
$saveLink = $r->providers->google->save_link;
๐ That's it!
Your pass is now in the user's wallet. For production, use
webhooks to get notified instead of polling.