PassHive API
Issue Apple Wallet and Google Wallet loyalty cards from your own POS, app or website. Base URL: https://passhive.app/v1. Requests and responses are JSON.
Authentication
Create a key in the dashboard (API keys). Send it as a bearer token. Keys are shown once; keep them on your server, never in a browser or app.
Authorization: Bearer ph_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
GET/v1/me
Returns your business, card design and plan.
Customers and cards
Each customer has one loyalty card. Create the customer, then send them addToAppleWallet or addToGoogleWallet (or cardUrl, a page with both buttons). The saved card updates by itself when stamps or points change.
POST/v1/customers
| Field | Type | Notes |
|---|---|---|
name | string | Shown on the card. Up to 60 characters. |
phone | string | Optional, international format. Unique per business. |
externalId | string | Optional, your own id (POS customer id). Unique per business. Sending an existing one returns that customer. |
branchId | string | Optional. If the branch is switched off, its cards stop. |
Returns 201 for a new customer, 200 with "created": false if the phone or externalId already exists.
{
"data": {
"id": "cu_8f2c1e0b5a7d4c3b9e6f1a2d",
"name": "Lina",
"phone": "+962790000000",
"externalId": "pos-4471",
"branchId": "br_...",
"stamps": 3,
"stampTarget": 10,
"points": 0,
"pointsPerReward": null,
"rewardsAvailable": 0,
"rewardsClaimed": 1,
"visits": 13,
"status": "active",
"cardUrl": "https://passhive.app/c/cu_....sig",
"addToAppleWallet": "https://passhive.app/c/cu_....sig/apple.pkpass",
"addToGoogleWallet": "https://passhive.app/c/cu_....sig/google",
"createdAt": "2026-11-02T09:12:00.000Z",
"updatedAt": "2026-11-02T10:40:00.000Z"
}
}
GET/v1/customers?phone=+962790000000
GET/v1/customers?externalId=pos-4471
GET/v1/customers?limit=50&before=<next>
Lists newest first. Use the next value for the following page.
GET/v1/customers/{id}
Stamps, points, rewards
Stamp cards use /stamps; points cards use /points. When a card is full, a reward is added and the counter starts again. Customers get a notification on the phone.
POST/v1/customers/{id}/stamps
{ "count": 1, "branchId": "br_..." }
POST/v1/customers/{id}/points
{ "points": 25 }
POST/v1/customers/{id}/redeem
Uses one available reward. Fails with no_reward_available if there is none.
Messages
Puts an offer on saved cards. On iPhone it shows as a notification from the card; on Android Google shows it on the card with an alert. Leave out customerId to send to everyone. Limited to 3 sends a day per audience.
POST/v1/messages
{ "title": "Weekend offer", "body": "2 stamps for every coffee this Friday.", "customerId": null }
Branches
Branch locations are added to the cards (Apple: up to 10, shown near the branch on the lock screen). Your plan sets how many branches can be active.
GET/v1/branches
POST/v1/branches
{ "name": "Abdoun", "address": "Abdoun Circle, Amman", "lat": 31.9539, "lng": 35.8836 }
PATCH/v1/branches/{id}
{ "active": false }
Errors and limits
Errors return a status code and {"error": "code"}.
| Status | Code | Meaning |
|---|---|---|
| 400 | invalid_json, invalid_phone, invalid_amount, card_uses_points | Fix the request. |
| 401 | missing_api_key, invalid_api_key | Check the Authorization header. |
| 402 | branch_limit_reached | Upgrade the plan or switch a branch off. |
| 404 | customer_not_found | Wrong id or another business. |
| 429 | rate_limited | 600 requests a minute per key; 3 message sends a day. |