{
  "info": {
    "name": "Wallet Pass API",
    "_postman_id": "walletpass-api-v3-collection",
    "description": "Complete Postman collection for the Wallet Pass API.\n\nBase URL: https://api.walletpassapi.com\nDocs:     https://walletpassapi.com/docs\nOpenAPI:  https://walletpassapi.com/openapi.json\n\n## Quick start\n1. Run \"1. Create account\" — sk_key saved automatically.\n2. Run \"2. Create workspace\" — wk_key saved automatically.\n3. Run \"3. List templates\" — template_id saved automatically.\n4. Run \"4. Issue pass\" — pass_id saved automatically.\n5. Continue through the numbered requests in order.\n\n## Authentication\n  sk_ keys — account-level (Accounts, Workspaces folders)\n  wk_ keys — workspace-level (Templates, Issue, Passes, Batch folders)\nSet sk_key and wk_key to the full \"Bearer sk_...\" / \"Bearer wk_...\" value.\nEach folder sets the correct key — requests inherit from their folder.\n\n## Collection variables (auto-managed by test scripts)\n  base_url      : https://api.walletpassapi.com\n  sk_key        : \"Bearer sk_...\" — set by Create account / Rotate API key\n  wk_key        : \"Bearer wk_...\" — set by Create workspace / Rotate workspace key\n  workspace_id  : set by Create workspace\n  template_id   : set by List templates (first result)\n  pass_id       : set by Issue pass\n  job_id        : set by Create batch job",
    "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
  },
  "auth": {
    "type": "apikey",
    "apikey": [
      {
        "key": "key",
        "value": "Authorization",
        "type": "string"
      },
      {
        "key": "value",
        "value": "{{sk_key}}",
        "type": "string"
      },
      {
        "key": "in",
        "value": "header",
        "type": "string"
      }
    ]
  },
  "variable": [
    {
      "key": "base_url",
      "value": "https://api.walletpassapi.com",
      "type": "string"
    },
    {
      "key": "sk_key",
      "value": "Bearer sk_your_key_here",
      "type": "string",
      "description": "Account key — paste your full \"Bearer sk_...\" value here"
    },
    {
      "key": "wk_key",
      "value": "Bearer wk_your_key_here",
      "type": "string",
      "description": "Workspace key — paste your full \"Bearer wk_...\" value here"
    },
    {
      "key": "workspace_id",
      "value": "",
      "type": "string",
      "description": "Auto-set by Create workspace"
    },
    {
      "key": "template_id",
      "value": "",
      "type": "string",
      "description": "Auto-set by List templates"
    },
    {
      "key": "pass_id",
      "value": "",
      "type": "string",
      "description": "Auto-set by Issue pass"
    },
    {
      "key": "job_id",
      "value": "",
      "type": "string",
      "description": "Auto-set by Create batch job"
    },
    {
      "key": "webhook_secret",
      "value": "",
      "type": "string",
      "description": "Auto-set by Create account"
    }
  ],
  "item": [
    {
      "name": "🚀 Quickstart — run in order",
      "description": "End-to-end walkthrough. Each request auto-saves IDs and keys for the next step.",
      "item": [
        {
          "name": "1. Create account",
          "auth": {
            "type": "noauth"
          },
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base_url}}/api/v1/accounts",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "api",
                "v1",
                "accounts"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"name\": \"Acme Corp\",\n  \"email\": \"admin@acme.com\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "description": "No auth required. Returns `api_key` (sk_ prefix) — shown once only."
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "var r = pm.response.json();",
                  "if (r.api_key)        pm.collectionVariables.set(\"sk_key\",         \"Bearer \" + r.api_key);",
                  "if (r.webhook_secret) pm.collectionVariables.set(\"webhook_secret\", r.webhook_secret);",
                  "pm.test(\"Created\", () => pm.response.to.have.status(201));"
                ]
              }
            }
          ]
        },
        {
          "name": "2. Create workspace",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base_url}}/api/v1/workspaces",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "api",
                "v1",
                "workspaces"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"name\": \"My Workspace\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "description": "Returns `api_key` (wk_ prefix) — shown once only."
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "var r = pm.response.json();",
                  "if (r.api_key) pm.collectionVariables.set(\"wk_key\",      \"Bearer \" + r.api_key);",
                  "if (r.id)      pm.collectionVariables.set(\"workspace_id\", r.id);",
                  "pm.test(\"Created\", () => pm.response.to.have.status(201));"
                ]
              }
            }
          ],
          "auth": {
            "type": "apikey",
            "apikey": [
              {
                "key": "key",
                "value": "Authorization",
                "type": "string"
              },
              {
                "key": "value",
                "value": "{{sk_key}}",
                "type": "string"
              },
              {
                "key": "in",
                "value": "header",
                "type": "string"
              }
            ]
          }
        },
        {
          "name": "3. List templates",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{base_url}}/api/v1/templates",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "api",
                "v1",
                "templates"
              ]
            },
            "description": "Templates are designed in the portal. Use this to look up template IDs and variable schemas."
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "var r = pm.response.json();",
                  "if (r.data && r.data.length > 0) pm.collectionVariables.set(\"template_id\", r.data[0].id);",
                  "pm.test(\"OK\", () => pm.response.to.have.status(200));"
                ]
              }
            }
          ],
          "auth": {
            "type": "apikey",
            "apikey": [
              {
                "key": "key",
                "value": "Authorization",
                "type": "string"
              },
              {
                "key": "value",
                "value": "{{wk_key}}",
                "type": "string"
              },
              {
                "key": "in",
                "value": "header",
                "type": "string"
              }
            ]
          }
        },
        {
          "name": "4. Issue pass",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base_url}}/api/v1/issue",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "api",
                "v1",
                "issue"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"template_id\": \"{{template_id}}\",\n  \"email\": \"customer@example.com\",\n  \"first_name\": \"Jane\",\n  \"last_name\": \"Smith\",\n  \"sms_mobile\": \"+1555000000\",\n  \"external_id\": \"cust_1234\",\n  \"tags\": [\n    \"vip\",\n    \"newsletter\"\n  ],\n  \"variables\": {\n    \"points\": \"150\",\n    \"tier\": \"Gold\",\n    \"expiry\": \"Dec 2026\"\n  }\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "description": "**Create**: returns 201 with `pkpass_url` and `google_save_url`.\n**Update** (same email or external_id): returns 200 with `updated: true` and pushes a live update to the device."
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "var r = pm.response.json();",
                  "if (r.id) pm.collectionVariables.set(\"pass_id\", r.id);",
                  "pm.test(\"Success\", () => pm.expect(pm.response.code).to.be.oneOf([200, 201]));"
                ]
              }
            }
          ],
          "auth": {
            "type": "apikey",
            "apikey": [
              {
                "key": "key",
                "value": "Authorization",
                "type": "string"
              },
              {
                "key": "value",
                "value": "{{wk_key}}",
                "type": "string"
              },
              {
                "key": "in",
                "value": "header",
                "type": "string"
              }
            ]
          }
        },
        {
          "name": "5. Get pass",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{base_url}}/api/v1/passes/{{pass_id}}",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "api",
                "v1",
                "passes",
                "{{pass_id}}"
              ]
            },
            "description": "Returns the full pass including email, variables, tags, device_count, and wallet URLs."
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"OK\", () => pm.response.to.have.status(200));",
                  "pm.test(\"ID matches\", () => pm.expect(pm.response.json().id).to.eql(pm.collectionVariables.get(\"pass_id\")));"
                ]
              }
            }
          ],
          "auth": {
            "type": "apikey",
            "apikey": [
              {
                "key": "key",
                "value": "Authorization",
                "type": "string"
              },
              {
                "key": "value",
                "value": "{{wk_key}}",
                "type": "string"
              },
              {
                "key": "in",
                "value": "header",
                "type": "string"
              }
            ]
          }
        },
        {
          "name": "6. Update pass",
          "request": {
            "method": "PUT",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base_url}}/api/v1/passes/{{pass_id}}",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "api",
                "v1",
                "passes",
                "{{pass_id}}"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"variables\": {\n    \"points\": \"500\",\n    \"tier\": \"Platinum\"\n  },\n  \"first_name\": \"Jane\",\n  \"tags\": [\n    \"vip\"\n  ]\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "description": "Pass `variables` to re-substitute the template and push a live update to devices. Add `\"silent\": true` to update without pushing."
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"OK\", () => pm.response.to.have.status(200));",
                  "pm.test(\"push_sent_to is a number\", () => pm.expect(pm.response.json().push_sent_to).to.be.a(\"number\"));"
                ]
              }
            }
          ],
          "auth": {
            "type": "apikey",
            "apikey": [
              {
                "key": "key",
                "value": "Authorization",
                "type": "string"
              },
              {
                "key": "value",
                "value": "{{wk_key}}",
                "type": "string"
              },
              {
                "key": "in",
                "value": "header",
                "type": "string"
              }
            ]
          }
        },
        {
          "name": "7. Send push notification",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base_url}}/api/v1/passes/{{pass_id}}/notify",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "api",
                "v1",
                "passes",
                "{{pass_id}}",
                "notify"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"message\": \"You earned 50 bonus points — thanks for visiting!\",\n  \"label\": \"Bonus\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "description": "Sends a silent push to Apple Wallet devices so they re-download the latest pass. Optionally writes a message to a back field."
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"OK\", () => pm.response.to.have.status(200));",
                  "pm.test(\"push_sent_to is a number\", () => pm.expect(pm.response.json().push_sent_to).to.be.a(\"number\"));"
                ]
              }
            }
          ],
          "auth": {
            "type": "apikey",
            "apikey": [
              {
                "key": "key",
                "value": "Authorization",
                "type": "string"
              },
              {
                "key": "value",
                "value": "{{wk_key}}",
                "type": "string"
              },
              {
                "key": "in",
                "value": "header",
                "type": "string"
              }
            ]
          }
        },
        {
          "name": "8. Create batch job",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base_url}}/api/v1/passes/batch",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "api",
                "v1",
                "passes",
                "batch"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"webhook_url\": \"https://yourapp.com/webhooks/wallet\",\n  \"passes\": [\n    {\n      \"template_id\": \"{{template_id}}\",\n      \"email\": \"alice@example.com\",\n      \"first_name\": \"Alice\",\n      \"variables\": {\n        \"points\": \"100\",\n        \"tier\": \"Silver\"\n      }\n    },\n    {\n      \"template_id\": \"{{template_id}}\",\n      \"email\": \"bob@example.com\",\n      \"first_name\": \"Bob\",\n      \"variables\": {\n        \"points\": \"250\",\n        \"tier\": \"Gold\"\n      }\n    },\n    {\n      \"template_id\": \"{{template_id}}\",\n      \"email\": \"carol@example.com\",\n      \"first_name\": \"Carol\",\n      \"variables\": {\n        \"points\": \"500\",\n        \"tier\": \"Platinum\"\n      }\n    }\n  ]\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "description": "Queue up to 1,000 passes for async creation. Returns `job_id` immediately. Poll or use `webhook_url` to receive a `batch.completed` event."
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "var r = pm.response.json();",
                  "if (r.job_id) pm.collectionVariables.set(\"job_id\", r.job_id);",
                  "pm.test(\"Accepted\", () => pm.response.to.have.status(202));",
                  "pm.test(\"job_id returned\", () => pm.expect(r.job_id).to.be.a(\"string\"));"
                ]
              }
            }
          ],
          "auth": {
            "type": "apikey",
            "apikey": [
              {
                "key": "key",
                "value": "Authorization",
                "type": "string"
              },
              {
                "key": "value",
                "value": "{{wk_key}}",
                "type": "string"
              },
              {
                "key": "in",
                "value": "header",
                "type": "string"
              }
            ]
          }
        },
        {
          "name": "9. Get batch job status",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{base_url}}/api/v1/passes/batch/{{job_id}}",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "api",
                "v1",
                "passes",
                "batch",
                "{{job_id}}"
              ]
            },
            "description": "Status transitions: queued → processing → completed / failed. Poll until `status === \"completed\"`."
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"OK\", () => pm.response.to.have.status(200));",
                  "var r = pm.response.json();",
                  "pm.test(\"Has status\", () => pm.expect(r.status).to.be.a(\"string\"));",
                  "console.log(\"Batch status:\", r.status, \"| Completed:\", r.completed_count, \"/\", r.pass_count);"
                ]
              }
            }
          ],
          "auth": {
            "type": "apikey",
            "apikey": [
              {
                "key": "key",
                "value": "Authorization",
                "type": "string"
              },
              {
                "key": "value",
                "value": "{{wk_key}}",
                "type": "string"
              },
              {
                "key": "in",
                "value": "header",
                "type": "string"
              }
            ]
          }
        }
      ]
    },
    {
      "name": "Accounts",
      "auth": {
        "type": "apikey",
        "apikey": [
          {
            "key": "key",
            "value": "Authorization",
            "type": "string"
          },
          {
            "key": "value",
            "value": "{{sk_key}}",
            "type": "string"
          },
          {
            "key": "in",
            "value": "header",
            "type": "string"
          }
        ]
      },
      "description": "Account self-management. Requests inherit sk_ key auth from this folder.",
      "item": [
        {
          "name": "Create account",
          "auth": {
            "type": "noauth"
          },
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base_url}}/api/v1/accounts",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "api",
                "v1",
                "accounts"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"name\": \"Acme Corp\",\n  \"email\": \"admin@acme.com\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "description": "No auth required. Returns `api_key` (sk_ prefix) — shown once only."
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "var r = pm.response.json();",
                  "if (r.api_key)        pm.collectionVariables.set(\"sk_key\",         \"Bearer \" + r.api_key);",
                  "if (r.webhook_secret) pm.collectionVariables.set(\"webhook_secret\", r.webhook_secret);",
                  "pm.test(\"Created\", () => pm.response.to.have.status(201));"
                ]
              }
            }
          ]
        },
        {
          "name": "Get account",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{base_url}}/api/v1/accounts/me",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "api",
                "v1",
                "accounts",
                "me"
              ]
            },
            "description": "Returns account details for the authenticated sk_ key."
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"OK\", () => pm.response.to.have.status(200));"
                ]
              }
            }
          ]
        },
        {
          "name": "Update account",
          "request": {
            "method": "PUT",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base_url}}/api/v1/accounts/me",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "api",
                "v1",
                "accounts",
                "me"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"name\": \"Acme Corp\",\n  \"webhook_url\": \"https://yourapp.com/webhooks/wallet\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "description": "Update name or webhook URL. Pass `rotate_webhook_secret: true` to regenerate the signing secret."
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"OK\", () => pm.response.to.have.status(200));"
                ]
              }
            }
          ]
        },
        {
          "name": "Rotate API key",
          "request": {
            "method": "POST",
            "header": [],
            "body": {
              "mode": "raw",
              "raw": "{}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "url": {
              "raw": "{{base_url}}/api/v1/accounts/me/rotate-key",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "api",
                "v1",
                "accounts",
                "me",
                "rotate-key"
              ]
            },
            "description": "Invalidates the current sk_ key immediately. New key returned — update `sk_key` variable."
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "var r = pm.response.json();",
                  "if (r.api_key) pm.collectionVariables.set(\"sk_key\", \"Bearer \" + r.api_key);",
                  "pm.test(\"OK\", () => pm.response.to.have.status(200));"
                ]
              }
            }
          ]
        },
        {
          "name": "Upload Apple + Google credentials",
          "request": {
            "method": "PUT",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base_url}}/api/v1/accounts/me/credentials",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "api",
                "v1",
                "accounts",
                "me",
                "credentials"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"apple_p12_cert\": \"<base64-encoded .p12 file>\",\n  \"apple_p12_password\": \"your-p12-password\",\n  \"apple_pass_type_identifier\": \"pass.com.yourcompany.yourapp\",\n  \"apple_team_id\": \"XXXXXXXXXX\",\n  \"apple_apns_private_key\": \"<base64-encoded .p8 APNs key>\",\n  \"apple_apns_key_id\": \"XXXXXXXXXX\",\n  \"google_issuer_id\": \"3388000000012345678\",\n  \"google_service_account_email\": \"wallet@your-project.iam.gserviceaccount.com\",\n  \"google_service_account_key\": \"<base64-encoded service-account.json>\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "description": "Account-level credentials used as fallback when a workspace has none. All binary/key fields must be base64-encoded."
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"OK\", () => pm.response.to.have.status(200));"
                ]
              }
            }
          ]
        },
        {
          "name": "Delete account",
          "request": {
            "method": "DELETE",
            "header": [],
            "url": {
              "raw": "{{base_url}}/api/v1/accounts/me",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "api",
                "v1",
                "accounts",
                "me"
              ]
            },
            "description": "⚠️ Permanently deletes your account and all associated data."
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"OK\", () => pm.response.to.have.status(200));"
                ]
              }
            }
          ]
        }
      ]
    },
    {
      "name": "Workspaces",
      "auth": {
        "type": "apikey",
        "apikey": [
          {
            "key": "key",
            "value": "Authorization",
            "type": "string"
          },
          {
            "key": "value",
            "value": "{{sk_key}}",
            "type": "string"
          },
          {
            "key": "in",
            "value": "header",
            "type": "string"
          }
        ]
      },
      "description": "Workspaces group templates and passes. Requests inherit sk_ key auth from this folder.",
      "item": [
        {
          "name": "Create workspace",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base_url}}/api/v1/workspaces",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "api",
                "v1",
                "workspaces"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"name\": \"My Workspace\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "description": "Returns `api_key` (wk_ prefix) — shown once only."
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "var r = pm.response.json();",
                  "if (r.api_key) pm.collectionVariables.set(\"wk_key\",      \"Bearer \" + r.api_key);",
                  "if (r.id)      pm.collectionVariables.set(\"workspace_id\", r.id);",
                  "pm.test(\"Created\", () => pm.response.to.have.status(201));"
                ]
              }
            }
          ]
        },
        {
          "name": "List workspaces",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{base_url}}/api/v1/workspaces?limit=20&offset=0",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "api",
                "v1",
                "workspaces"
              ],
              "query": [
                {
                  "key": "limit",
                  "value": "20"
                },
                {
                  "key": "offset",
                  "value": "0"
                }
              ]
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"OK\", () => pm.response.to.have.status(200));"
                ]
              }
            }
          ]
        },
        {
          "name": "Get workspace",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{base_url}}/api/v1/workspaces/{{workspace_id}}",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "api",
                "v1",
                "workspaces",
                "{{workspace_id}}"
              ]
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"OK\", () => pm.response.to.have.status(200));"
                ]
              }
            }
          ]
        },
        {
          "name": "Rotate workspace key",
          "request": {
            "method": "POST",
            "header": [],
            "body": {
              "mode": "raw",
              "raw": "{}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "url": {
              "raw": "{{base_url}}/api/v1/workspaces/{{workspace_id}}/rotate-key",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "api",
                "v1",
                "workspaces",
                "{{workspace_id}}",
                "rotate-key"
              ]
            },
            "description": "Invalidates the current wk_ key. New key returned — update `wk_key` variable."
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "var r = pm.response.json();",
                  "if (r.api_key) pm.collectionVariables.set(\"wk_key\", \"Bearer \" + r.api_key);",
                  "pm.test(\"OK\", () => pm.response.to.have.status(200));"
                ]
              }
            }
          ]
        }
      ]
    },
    {
      "name": "Templates",
      "auth": {
        "type": "apikey",
        "apikey": [
          {
            "key": "key",
            "value": "Authorization",
            "type": "string"
          },
          {
            "key": "value",
            "value": "{{wk_key}}",
            "type": "string"
          },
          {
            "key": "in",
            "value": "header",
            "type": "string"
          }
        ]
      },
      "description": "Read-only — templates are designed in the portal. Requests inherit wk_ key auth from this folder.",
      "item": [
        {
          "name": "List templates",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{base_url}}/api/v1/templates",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "api",
                "v1",
                "templates"
              ]
            },
            "description": "Templates are designed in the portal. Use this to look up template IDs and variable schemas."
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "var r = pm.response.json();",
                  "if (r.data && r.data.length > 0) pm.collectionVariables.set(\"template_id\", r.data[0].id);",
                  "pm.test(\"OK\", () => pm.response.to.have.status(200));"
                ]
              }
            }
          ]
        },
        {
          "name": "Get template",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{base_url}}/api/v1/templates/{{template_id}}",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "api",
                "v1",
                "templates",
                "{{template_id}}"
              ]
            },
            "description": "Returns template details including `variable_schema` — the list of variables the template expects."
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"OK\", () => pm.response.to.have.status(200));"
                ]
              }
            }
          ]
        },
        {
          "name": "List passes for template",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{base_url}}/api/v1/templates/{{template_id}}/passes?limit=20&offset=0",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "api",
                "v1",
                "templates",
                "{{template_id}}",
                "passes"
              ],
              "query": [
                {
                  "key": "limit",
                  "value": "20"
                },
                {
                  "key": "offset",
                  "value": "0"
                }
              ]
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"OK\", () => pm.response.to.have.status(200));"
                ]
              }
            }
          ]
        }
      ]
    },
    {
      "name": "Issue",
      "auth": {
        "type": "apikey",
        "apikey": [
          {
            "key": "key",
            "value": "Authorization",
            "type": "string"
          },
          {
            "key": "value",
            "value": "{{wk_key}}",
            "type": "string"
          },
          {
            "key": "in",
            "value": "header",
            "type": "string"
          }
        ]
      },
      "description": "Primary pass creation path — creates or upserts by email / external_id. Requests inherit wk_ key auth from this folder.",
      "item": [
        {
          "name": "Issue pass",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base_url}}/api/v1/issue",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "api",
                "v1",
                "issue"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"template_id\": \"{{template_id}}\",\n  \"email\": \"customer@example.com\",\n  \"first_name\": \"Jane\",\n  \"last_name\": \"Smith\",\n  \"sms_mobile\": \"+1555000000\",\n  \"external_id\": \"cust_1234\",\n  \"tags\": [\n    \"vip\",\n    \"newsletter\"\n  ],\n  \"variables\": {\n    \"points\": \"150\",\n    \"tier\": \"Gold\",\n    \"expiry\": \"Dec 2026\"\n  }\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "description": "**Create**: returns 201 with `pkpass_url` and `google_save_url`.\n**Update** (same email or external_id): returns 200 with `updated: true` and pushes a live update to the device."
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "var r = pm.response.json();",
                  "if (r.id) pm.collectionVariables.set(\"pass_id\", r.id);",
                  "pm.test(\"Success\", () => pm.expect(pm.response.code).to.be.oneOf([200, 201]));"
                ]
              }
            }
          ]
        },
        {
          "name": "Issue pass (upsert by external_id)",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base_url}}/api/v1/issue",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "api",
                "v1",
                "issue"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"template_id\": \"{{template_id}}\",\n  \"email\": \"customer@example.com\",\n  \"external_id\": \"cust_1234\",\n  \"variables\": {\n    \"points\": \"300\"\n  }\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "description": "When `external_id` is provided it takes precedence over `email` for the upsert lookup."
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "var r = pm.response.json();",
                  "if (r.id) pm.collectionVariables.set(\"pass_id\", r.id);",
                  "pm.test(\"Success\", () => pm.expect(pm.response.code).to.be.oneOf([200, 201]));"
                ]
              }
            }
          ]
        }
      ]
    },
    {
      "name": "Passes",
      "auth": {
        "type": "apikey",
        "apikey": [
          {
            "key": "key",
            "value": "Authorization",
            "type": "string"
          },
          {
            "key": "value",
            "value": "{{wk_key}}",
            "type": "string"
          },
          {
            "key": "in",
            "value": "header",
            "type": "string"
          }
        ]
      },
      "description": "List, fetch, update, delete, and notify passes. Requests inherit wk_ key auth from this folder (Download .pkpass overrides to no auth — it's a public endpoint).",
      "item": [
        {
          "name": "List passes",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{base_url}}/api/v1/passes?limit=20&offset=0",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "api",
                "v1",
                "passes"
              ],
              "query": [
                {
                  "key": "limit",
                  "value": "20"
                },
                {
                  "key": "offset",
                  "value": "0"
                },
                {
                  "key": "template_id",
                  "value": "",
                  "disabled": true
                },
                {
                  "key": "tag",
                  "value": "",
                  "disabled": true
                },
                {
                  "key": "email",
                  "value": "",
                  "disabled": true
                }
              ]
            },
            "description": "Returns full pass objects including identity and variable fields."
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"OK\", () => pm.response.to.have.status(200));",
                  "pm.test(\"Has data array\", () => pm.expect(pm.response.json().data).to.be.an(\"array\"));"
                ]
              }
            }
          ]
        },
        {
          "name": "Get pass",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{base_url}}/api/v1/passes/{{pass_id}}",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "api",
                "v1",
                "passes",
                "{{pass_id}}"
              ]
            },
            "description": "Returns the full pass including email, variables, tags, device_count, and wallet URLs."
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"OK\", () => pm.response.to.have.status(200));",
                  "pm.test(\"ID matches\", () => pm.expect(pm.response.json().id).to.eql(pm.collectionVariables.get(\"pass_id\")));"
                ]
              }
            }
          ]
        },
        {
          "name": "Update pass",
          "request": {
            "method": "PUT",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base_url}}/api/v1/passes/{{pass_id}}",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "api",
                "v1",
                "passes",
                "{{pass_id}}"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"variables\": {\n    \"points\": \"500\",\n    \"tier\": \"Platinum\"\n  },\n  \"first_name\": \"Jane\",\n  \"tags\": [\n    \"vip\"\n  ]\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "description": "Pass `variables` to re-substitute the template and push a live update to devices. Add `\"silent\": true` to update without pushing."
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"OK\", () => pm.response.to.have.status(200));",
                  "pm.test(\"push_sent_to is a number\", () => pm.expect(pm.response.json().push_sent_to).to.be.a(\"number\"));"
                ]
              }
            }
          ]
        },
        {
          "name": "Update pass (silent)",
          "request": {
            "method": "PUT",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base_url}}/api/v1/passes/{{pass_id}}",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "api",
                "v1",
                "passes",
                "{{pass_id}}"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"silent\": true,\n  \"variables\": {\n    \"points\": \"500\"\n  }\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "description": "Update pass data without sending a push notification to devices."
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"OK\", () => pm.response.to.have.status(200));"
                ]
              }
            }
          ]
        },
        {
          "name": "Delete pass",
          "request": {
            "method": "DELETE",
            "header": [],
            "url": {
              "raw": "{{base_url}}/api/v1/passes/{{pass_id}}",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "api",
                "v1",
                "passes",
                "{{pass_id}}"
              ]
            },
            "description": "Returns `{ deleted: true, push_sent_to: N }` where N is the number of devices notified."
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"OK\", () => pm.response.to.have.status(200));",
                  "pm.test(\"Deleted\", () => pm.expect(pm.response.json().deleted).to.be.true);"
                ]
              }
            }
          ]
        },
        {
          "name": "Send push notification",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base_url}}/api/v1/passes/{{pass_id}}/notify",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "api",
                "v1",
                "passes",
                "{{pass_id}}",
                "notify"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"message\": \"You earned 50 bonus points — thanks for visiting!\",\n  \"label\": \"Bonus\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "description": "Sends a silent push to Apple Wallet devices so they re-download the latest pass. Optionally writes a message to a back field."
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"OK\", () => pm.response.to.have.status(200));",
                  "pm.test(\"push_sent_to is a number\", () => pm.expect(pm.response.json().push_sent_to).to.be.a(\"number\"));"
                ]
              }
            }
          ]
        },
        {
          "name": "Download .pkpass",
          "auth": {
            "type": "noauth"
          },
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{base_url}}/api/v1/passes/{{pass_id}}/pkpass",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "api",
                "v1",
                "passes",
                "{{pass_id}}",
                "pkpass"
              ]
            },
            "description": "No auth required. Returns the signed .pkpass bundle. Link to this URL in email or an \"Add to Apple Wallet\" button."
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"OK\", () => pm.response.to.have.status(200));",
                  "pm.test(\"Content-Type is pkpass\", () => pm.expect(pm.response.headers.get(\"Content-Type\")).to.include(\"apple.pkpass\"));"
                ]
              }
            }
          ]
        },
        {
          "name": "Get Google Wallet JWT",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{base_url}}/api/v1/passes/{{pass_id}}/google-jwt",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "api",
                "v1",
                "passes",
                "{{pass_id}}",
                "google-jwt"
              ]
            },
            "description": "Returns a fresh `google_jwt` and `google_save_url`. Use `google_save_url` as the href for an \"Add to Google Wallet\" button."
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"OK\", () => pm.response.to.have.status(200));",
                  "pm.test(\"google_save_url returned\", () => pm.expect(pm.response.json().google_save_url).to.be.a(\"string\"));"
                ]
              }
            }
          ]
        }
      ]
    },
    {
      "name": "Batch",
      "auth": {
        "type": "apikey",
        "apikey": [
          {
            "key": "key",
            "value": "Authorization",
            "type": "string"
          },
          {
            "key": "value",
            "value": "{{wk_key}}",
            "type": "string"
          },
          {
            "key": "in",
            "value": "header",
            "type": "string"
          }
        ]
      },
      "description": "Create up to 1,000 passes asynchronously. Requests inherit wk_ key auth from this folder.",
      "item": [
        {
          "name": "Create batch job",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base_url}}/api/v1/passes/batch",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "api",
                "v1",
                "passes",
                "batch"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"webhook_url\": \"https://yourapp.com/webhooks/wallet\",\n  \"passes\": [\n    {\n      \"template_id\": \"{{template_id}}\",\n      \"email\": \"alice@example.com\",\n      \"first_name\": \"Alice\",\n      \"variables\": {\n        \"points\": \"100\",\n        \"tier\": \"Silver\"\n      }\n    },\n    {\n      \"template_id\": \"{{template_id}}\",\n      \"email\": \"bob@example.com\",\n      \"first_name\": \"Bob\",\n      \"variables\": {\n        \"points\": \"250\",\n        \"tier\": \"Gold\"\n      }\n    },\n    {\n      \"template_id\": \"{{template_id}}\",\n      \"email\": \"carol@example.com\",\n      \"first_name\": \"Carol\",\n      \"variables\": {\n        \"points\": \"500\",\n        \"tier\": \"Platinum\"\n      }\n    }\n  ]\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "description": "Queue up to 1,000 passes for async creation. Returns `job_id` immediately. Poll or use `webhook_url` to receive a `batch.completed` event."
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "var r = pm.response.json();",
                  "if (r.job_id) pm.collectionVariables.set(\"job_id\", r.job_id);",
                  "pm.test(\"Accepted\", () => pm.response.to.have.status(202));",
                  "pm.test(\"job_id returned\", () => pm.expect(r.job_id).to.be.a(\"string\"));"
                ]
              }
            }
          ]
        },
        {
          "name": "Get batch job status",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{base_url}}/api/v1/passes/batch/{{job_id}}",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "api",
                "v1",
                "passes",
                "batch",
                "{{job_id}}"
              ]
            },
            "description": "Status transitions: queued → processing → completed / failed. Poll until `status === \"completed\"`."
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"OK\", () => pm.response.to.have.status(200));",
                  "var r = pm.response.json();",
                  "pm.test(\"Has status\", () => pm.expect(r.status).to.be.a(\"string\"));",
                  "console.log(\"Batch status:\", r.status, \"| Completed:\", r.completed_count, \"/\", r.pass_count);"
                ]
              }
            }
          ]
        }
      ]
    }
  ]
}