Open dashboardwalletap.com

Authentication

Create API keys, choose what each one may do, send them with your requests, and rotate or turn them off when you need to.

Web

Every API request carries an API key, and the key decides two things: which account the request acts on, and what it is allowed to do there. Give each integration its own key with only the scopes it needs, so you can rotate or turn one off without touching anything else.

Paid plans

Before you start#

  • You are the account owner. People you invite to your account do not see the API keys section.
  • Your account is on a plan that includes API access.

Create a key#

  1. Open the API keys section
  2. Start a new key

    Click Create at the top of the section. The New API key dialog opens.

  3. Choose what the key can do

    Under What this key can do, pick one of the presets. Manage passes is selected by default and is the right choice for most integrations. The presets are described in Scopes below.

    The New API key dialog with four preset cards, Manage passes selected, and a Label field reading Harbour CRM
  4. Label it

    Type a Label that says where the key will live, such as Harbour CRM or Website sign-up. You will use it later to tell keys apart. Click Create.

  5. Copy the key

    The Key created dialog shows the full key, which starts with wtap_sk_. Click Copy key and store it in your secret manager or your server's environment, then click Done.

Important

The full key is shown once. Walletap stores only a fingerprint of it, so it can never be displayed again. If you lose it, rotate the key to get a new value.

Send the key#

Put the key in the X-API-Key header of every request:

Shell
curl https://api.walletap.com/templates \
  -H "X-API-Key: $WALLETAP_API_KEY"

X-API-Key works on every endpoint. Some endpoints also read Authorization: Bearer <key>, but POST /pass, GET /pass and the notify and resend endpoints read only X-API-Key, so standardise on that header.

To check that a key works and see which account it belongs to, call POST /auth. It answers with the account's name and email, whatever the key's scopes:

Shell
curl -X POST https://api.walletap.com/auth \
  -H "X-API-Key: $WALLETAP_API_KEY"
JSON
{ "displayName": "Alex Morgan", "email": "alex@harbour.example" }

Scopes#

A key's scopes cap what it may do. A request that needs a scope the key lacks answers 403 and names the missing scope in error, for example Missing permission: passes.create. On /pass and the notify, resend and template notification endpoints, the body also carries "code": "insufficient_scope".

Presets#
PresetScopesUse it for
Full accesseverythingYour own back office. Treat it like a password
Manage passespasses.create, passes.edit, passes.viewAll, templates.viewAll, campaigns.sendIssuing, reading and updating passes, and notifying holders
Issue access badgesbadges.issue, badges.viewAllAn HR system that sends staff their door badge
Read onlypasses.viewAll, templates.viewAll, analytics.view, badges.viewAllReporting and lookups
What each scope allows over the API#
ScopeAllows
passes.createPOST /pass
passes.viewAllGET /pass, GET /passes, GET /passes/search
passes.editPATCH /pass field changes, voiding and reactivating, stating a stamp count or balance directly
scanning.stampPATCH /pass with a stampOperation
scanning.redeemPATCH /pass with a balanceOperation
campaigns.sendPOST /pass/{passId}/notify, POST /pass/{passId}/resend, POST /template/{templateId}/notification
members.exportGET /passes/export
templates.viewAllGET /templates, GET /templates/{id}, reading files
templates.createPOST /templates, uploading files; with templates.duplicate, POST /templates/{id}/duplicate
templates.editPATCH /templates/{id}, uploading files
templates.deleteDELETE /templates/{id}, deleting files
files.read, files.write, files.deleteReading, uploading and deleting files on their own
badges.viewAllReading access badges, invites, holders and their badges
badges.issueInviting someone to a badge and cancelling an invite
badges.editRenaming a badge holder, refreshing a badge's design in the wallet
badges.revokeSuspending, resuming and revoking badges, removing a holder

scanning.stamp, scanning.redeem, members.export and badges.revoke are in no preset other than Full access. To get a key that holds them without full access, create it with custom scopes, as below.

Create a key with custom scopes#

POST /api-keys creates a key with exactly the scopes you list. Call it with a Full access key:

Shell
curl -X POST https://api.walletap.com/api-keys \
  -H "X-API-Key: $WALLETAP_FULL_ACCESS_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "label": "Harbour POS",
    "scopes": ["passes.viewAll", "scanning.stamp", "scanning.redeem"]
  }'

The response holds the new key's details and, in plaintext, the key itself — the only time it is returned:

JSON
{
  "key": {
    "id": "key_123",
    "label": "Harbour POS",
    "prefix": "wtap_sk_3f9a1c07",
    "scopes": ["passes.viewAll", "scanning.stamp", "scanning.redeem"],
    "createdAt": 1760180400000,
    "lastUsedAt": null,
    "disabledAt": null,
    "rotatedAt": null
  },
  "plaintext": "wtap_sk_3f9a1c07…"
}

The key appears in SettingsAPI keys like any other. Owner-only permissions — companies, billing, custom domains, API keys themselves — cannot be given to a scoped key; only a Full access key can manage keys.

The default key#

Every account has a Default key with full access. The dashboard and the Walletap apps use it too, which is why it can be copied in full and rotated, but not renamed or turned off. Create a separate key for each integration rather than using the default one, so that rotating or turning off one integration's key never touches anything else.

Rotate a key#

Rotate a key when it may have been exposed, or on a schedule.

  1. Open the key's menu

    In SettingsAPI keys, click the menu at the end of the key's row and choose Rotate….

  2. Confirm

    Click Rotate in the Rotate key? dialog. The old value stops working immediately, so any integration using it fails until you give it the new one.

  3. Copy the new value

    The Key rotated dialog shows the new value once. Copy it and update the integration. The label and scopes stay the same.

Rotating a disabled key also turns it back on.

Rename a key#

To change a key's label, choose Rename from its menu, type the new Label in the Rename key dialog and click Save. The key's value and scopes stay the same, so integrations using it keep working.

Turn a key off#

To revoke a key, choose Disable from its menu. It stops authenticating immediately and stays in the list marked Disabled, with its label and scopes, so you can see what it was. Enable turns it back on with the same value.

Keys are never deleted, so the list is also your record of every key the account has had. Last used shows when each key last made a request, which tells you whether a key is still in use before you turn it off.

Manage keys over the API#

A Full access key can manage keys itself, for example to rotate them on a schedule:

RequestDoes
GET /api-keysLists the default key, including its full value, and every other key without its value
POST /api-keysCreates a key, as above
PATCH /api-keys/{id}Renames a key with label, or turns it off and on with disabled: true or false
POST /api-keys/{id}/rotateRotates a key and returns the new value in plaintext

A scoped key calling these answers 403 with This API key is scoped and cannot perform owner actions.

Keep keys secret#

  • Server side only. Never put a key in a website's JavaScript, a mobile app or anything else that runs on a customer's device. Anyone who can read the key can act as your account within its scopes.
  • One key per integration. A leak then costs you one integration, and Last used tells you which one is talking.
  • Least privilege. Use Manage passes or Read only wherever full access is not needed.
  • Rotate after people leave. Rotate any key a departing developer or agency has seen.

If something goes wrong#

401 "Invalid API key" or "You are not authorized for this action" — the key is mistyped, has been rotated, or is disabled. Check that the whole value was copied, including wtap_sk_.

401 on a request that sends Authorization: Bearer — that endpoint reads only X-API-Key. Send the key in X-API-Key instead.

403 "Missing permission: …" — the key's scopes do not cover this request. Create a key with the scope named in the message.

402 "API keys is available on a paid plan." — creating keys needs a plan with API access. See plans.

Next steps#