{
  "name": "Myela Payments — /v1",
  "version": "1",
  "items": [
    {
      "type": "folder",
      "name": "00 · Start here",
      "seq": 1,
      "root": {
        "docs": "Run this first. It answers what this key may do, and it is the only route that is not entitlement-gated — asking what you may do must never itself require permission."
      },
      "items": [
        {
          "type": "http",
          "name": "Capabilities",
          "seq": 0,
          "request": {
            "url": "{{BASE_URL}}/v1/capabilities",
            "method": "GET",
            "headers": [],
            "params": [],
            "body": {
              "mode": "none"
            },
            "auth": {
              "mode": "inherit"
            },
            "docs": "Every operation, and whether it is `active`, `unavailable` (this key lacks the entitlement) or `not_supported` (the account's provider cannot do it). Branch on this rather than discovering a 403 in production."
          }
        }
      ]
    },
    {
      "type": "folder",
      "name": "01 · Payments",
      "seq": 2,
      "root": {
        "docs": "The money-moving surface. Amounts are integers in the minor unit — 4999 is $49.99. A decimal is rejected rather than silently charged as a different figure.\n\nA payment is created against exactly ONE funding source: a `paymentToken` from browser capture, or a stored `paymentMethodId`. Sending both is refused, because which card was charged is not a question to answer afterwards."
      },
      "items": [
        {
          "type": "http",
          "name": "Create payment (sale)",
          "seq": 0,
          "request": {
            "url": "{{BASE_URL}}/v1/payments",
            "method": "POST",
            "headers": [
              {
                "name": "Content-Type",
                "value": "application/json",
                "enabled": true
              }
            ],
            "params": [],
            "body": {
              "mode": "json",
              "json": "{\n  \"amount\": 1299,\n  \"currency\": \"USD\",\n  \"paymentToken\": \"{{PAYMENT_TOKEN}}\",\n  \"capture\": true\n}"
            },
            "auth": {
              "mode": "inherit"
            },
            "docs": "`capture: true` authorizes and captures in one call. Set an `Idempotency-Key` header on retries: the same key returns the original result rather than charging twice.\n\nAmounts are integers in the minor unit — 4999 is $49.99. A decimal is rejected rather than silently charged as a different figure.\n\nEntitlement: `payments.create`\n\nNeeds these variables set first: PAYMENT_TOKEN"
          }
        },
        {
          "type": "http",
          "name": "Create payment (auth only)",
          "seq": 1,
          "request": {
            "url": "{{BASE_URL}}/v1/payments",
            "method": "POST",
            "headers": [
              {
                "name": "Content-Type",
                "value": "application/json",
                "enabled": true
              }
            ],
            "params": [],
            "body": {
              "mode": "json",
              "json": "{\n  \"amount\": 2500,\n  \"currency\": \"USD\",\n  \"paymentToken\": \"{{PAYMENT_TOKEN}}\",\n  \"capture\": false\n}"
            },
            "auth": {
              "mode": "inherit"
            },
            "docs": "Holds funds without taking them. Capture it later, or void it. An uncaptured authorization expires on the provider's schedule, not ours.\n\nEntitlement: `payments.create`\n\nNeeds these variables set first: PAYMENT_TOKEN"
          }
        },
        {
          "type": "http",
          "name": "Capture a payment",
          "seq": 2,
          "request": {
            "url": "{{BASE_URL}}/v1/payments/{{AUTH_ID}}/capture",
            "method": "POST",
            "headers": [
              {
                "name": "Content-Type",
                "value": "application/json",
                "enabled": true
              }
            ],
            "params": [],
            "body": {
              "mode": "json",
              "json": "{\n  \"amount\": 2500\n}"
            },
            "auth": {
              "mode": "inherit"
            },
            "docs": "Only valid on an open authorization. Omit `amount` to capture the full authorized amount. Whether a PARTIAL capture is permitted depends on the provider behind the account — check `capabilities` rather than assuming.\n\nEntitlement: `payments.capture`\n\nNeeds these variables set first: AUTH_ID"
          }
        },
        {
          "type": "http",
          "name": "Void a payment",
          "seq": 3,
          "request": {
            "url": "{{BASE_URL}}/v1/payments/{{PAYMENT_ID}}/void",
            "method": "POST",
            "headers": [],
            "params": [],
            "body": {
              "mode": "none"
            },
            "auth": {
              "mode": "inherit"
            },
            "docs": "Cancels an unsettled transaction. Once settled, a void is refused and a refund is the correct operation — the state machine enforces this rather than letting the provider decide.\n\nEntitlement: `payments.void`\n\nNeeds these variables set first: PAYMENT_ID"
          }
        },
        {
          "type": "http",
          "name": "Refund a payment",
          "seq": 4,
          "request": {
            "url": "{{BASE_URL}}/v1/payments/{{PAYMENT_ID}}/refund",
            "method": "POST",
            "headers": [
              {
                "name": "Content-Type",
                "value": "application/json",
                "enabled": true
              }
            ],
            "params": [],
            "body": {
              "mode": "json",
              "json": "{\n  \"amount\": 500\n}"
            },
            "auth": {
              "mode": "inherit"
            },
            "docs": "Returns money on a captured transaction. Omit `amount` for a full refund. Partial refunds may be repeated up to the captured total.\n\nEntitlement: `payments.refund`\n\nNeeds these variables set first: PAYMENT_ID"
          }
        },
        {
          "type": "http",
          "name": "Retrieve a payment",
          "seq": 5,
          "request": {
            "url": "{{BASE_URL}}/v1/payments/{{PAYMENT_ID}}",
            "method": "GET",
            "headers": [],
            "params": [],
            "body": {
              "mode": "none"
            },
            "auth": {
              "mode": "inherit"
            },
            "docs": "The authoritative state. `status` reflects settlement as reported by the provider, not an optimistic local guess.\n\nEntitlement: `payments.retrieve`\n\nNeeds these variables set first: PAYMENT_ID"
          }
        },
        {
          "type": "http",
          "name": "List payments",
          "seq": 6,
          "request": {
            "url": "{{BASE_URL}}/v1/payments",
            "method": "GET",
            "headers": [],
            "params": [
              {
                "name": "limit",
                "value": "10",
                "type": "query",
                "enabled": true
              },
              {
                "name": "startingAfter",
                "value": "",
                "type": "query",
                "enabled": false
              },
              {
                "name": "customerId",
                "value": "",
                "type": "query",
                "enabled": false
              }
            ],
            "body": {
              "mode": "none"
            },
            "auth": {
              "mode": "inherit"
            },
            "docs": "Cursor-paginated — see the collection description. `startingAfter` takes the id of the last row you saw.\n\nEntitlement: `payments.list`"
          }
        }
      ]
    },
    {
      "type": "folder",
      "name": "02 · Customers",
      "seq": 3,
      "root": {
        "docs": "A customer is the thing cards and subscriptions attach to. Creating one reserves it with the provider as well, so the same customer works for one-off charges and for recurring billing."
      },
      "items": [
        {
          "type": "http",
          "name": "Create customer",
          "seq": 0,
          "request": {
            "url": "{{BASE_URL}}/v1/customers",
            "method": "POST",
            "headers": [
              {
                "name": "Content-Type",
                "value": "application/json",
                "enabled": true
              }
            ],
            "params": [],
            "body": {
              "mode": "json",
              "json": "{\n  \"email\": \"{{$guid}}@example.com\",\n  \"name\": \"Ada Lovelace\",\n  \"phone\": \"+15555550123\"\n}"
            },
            "auth": {
              "mode": "inherit"
            },
            "docs": "Only `email` is required. `name` falls back to the local part of the email when omitted.\n\nEntitlement: `customers.create`"
          }
        },
        {
          "type": "http",
          "name": "Retrieve customer",
          "seq": 1,
          "request": {
            "url": "{{BASE_URL}}/v1/customers/{{CUSTOMER_ID}}",
            "method": "GET",
            "headers": [],
            "params": [],
            "body": {
              "mode": "none"
            },
            "auth": {
              "mode": "inherit"
            },
            "docs": "A customer id from another merchant is `not_found`, never `permission_denied` — confirming existence would leak it.\n\nEntitlement: `customers.retrieve`\n\nNeeds these variables set first: CUSTOMER_ID"
          }
        },
        {
          "type": "http",
          "name": "Update customer",
          "seq": 2,
          "request": {
            "url": "{{BASE_URL}}/v1/customers/{{CUSTOMER_ID}}",
            "method": "POST",
            "headers": [
              {
                "name": "Content-Type",
                "value": "application/json",
                "enabled": true
              }
            ],
            "params": [],
            "body": {
              "mode": "json",
              "json": "{\n  \"name\": \"Ada King\"\n}"
            },
            "auth": {
              "mode": "inherit"
            },
            "docs": "POST, not PATCH — the update convention across this API. Only the fields you send change.\n\nEntitlement: `customers.update`\n\nNeeds these variables set first: CUSTOMER_ID"
          }
        },
        {
          "type": "http",
          "name": "List customers",
          "seq": 3,
          "request": {
            "url": "{{BASE_URL}}/v1/customers",
            "method": "GET",
            "headers": [],
            "params": [
              {
                "name": "limit",
                "value": "10",
                "type": "query",
                "enabled": true
              },
              {
                "name": "startingAfter",
                "value": "",
                "type": "query",
                "enabled": false
              }
            ],
            "body": {
              "mode": "none"
            },
            "auth": {
              "mode": "inherit"
            },
            "docs": "Cursor-paginated.\n\nEntitlement: `customers.list`"
          }
        }
      ]
    },
    {
      "type": "folder",
      "name": "03 · Payment methods",
      "seq": 4,
      "root": {
        "docs": "Cards on file. The card itself is captured in the browser and never reaches your server — you exchange a single-use token for a reusable payment method here."
      },
      "items": [
        {
          "type": "http",
          "name": "Create payment method (vault a card)",
          "seq": 0,
          "request": {
            "url": "{{BASE_URL}}/v1/payment_methods",
            "method": "POST",
            "headers": [
              {
                "name": "Content-Type",
                "value": "application/json",
                "enabled": true
              }
            ],
            "params": [],
            "body": {
              "mode": "json",
              "json": "{\n  \"customerId\": \"{{CUSTOMER_ID}}\",\n  \"paymentToken\": \"{{PAYMENT_TOKEN}}\"\n}"
            },
            "auth": {
              "mode": "inherit"
            },
            "docs": "Consumes the single-use token and returns a reusable id. A card stored through `/v1` with no stated schedule is credential-on-file `unscheduled` — the merchant charges it when they charge it.\n\nEntitlement: `paymentMethods.create`\n\nNeeds these variables set first: CUSTOMER_ID, PAYMENT_TOKEN"
          }
        },
        {
          "type": "http",
          "name": "List payment methods",
          "seq": 1,
          "request": {
            "url": "{{BASE_URL}}/v1/payment_methods",
            "method": "GET",
            "headers": [],
            "params": [
              {
                "name": "customerId",
                "value": "{{CUSTOMER_ID}}",
                "type": "query",
                "enabled": true
              },
              {
                "name": "limit",
                "value": "10",
                "type": "query",
                "enabled": true
              }
            ],
            "body": {
              "mode": "none"
            },
            "auth": {
              "mode": "inherit"
            },
            "docs": "`customerId` is required — cards are always listed for one customer. The default card sorts first.\n\nEntitlement: `paymentMethods.list`\n\nNeeds these variables set first: CUSTOMER_ID"
          }
        },
        {
          "type": "http",
          "name": "Set default payment method",
          "seq": 2,
          "request": {
            "url": "{{BASE_URL}}/v1/payment_methods/{{PAYMENT_METHOD_ID}}/default",
            "method": "POST",
            "headers": [],
            "params": [],
            "body": {
              "mode": "none"
            },
            "auth": {
              "mode": "inherit"
            },
            "docs": "Which card is charged when a request names none — including a scheduled invoice collecting itself.\n\nEntitlement: `paymentMethods.setDefault`\n\nNeeds these variables set first: PAYMENT_METHOD_ID"
          }
        }
      ]
    },
    {
      "type": "folder",
      "name": "04 · Addresses",
      "seq": 5,
      "root": {
        "docs": "Billing and shipping addresses, held by Myela and mirrored to the provider where it can express them — so an address survives a change of provider."
      },
      "items": [
        {
          "type": "http",
          "name": "Create address",
          "seq": 0,
          "request": {
            "url": "{{BASE_URL}}/v1/addresses",
            "method": "POST",
            "headers": [
              {
                "name": "Content-Type",
                "value": "application/json",
                "enabled": true
              }
            ],
            "params": [],
            "body": {
              "mode": "json",
              "json": "{\n  \"customerId\": \"{{CUSTOMER_ID}}\",\n  \"firstName\": \"Ada\",\n  \"lastName\": \"Lovelace\",\n  \"line1\": \"12 Marylebone Road\",\n  \"city\": \"London\",\n  \"postalCode\": \"NW1 5JD\",\n  \"country\": \"GB\"\n}"
            },
            "auth": {
              "mode": "inherit"
            },
            "docs": "Fields are allow-listed: anything else you send is not stored.\n\nEntitlement: `addresses.create`\n\nNeeds these variables set first: CUSTOMER_ID"
          }
        },
        {
          "type": "http",
          "name": "List addresses",
          "seq": 1,
          "request": {
            "url": "{{BASE_URL}}/v1/addresses",
            "method": "GET",
            "headers": [],
            "params": [
              {
                "name": "customerId",
                "value": "{{CUSTOMER_ID}}",
                "type": "query",
                "enabled": true
              }
            ],
            "body": {
              "mode": "none"
            },
            "auth": {
              "mode": "inherit"
            },
            "docs": "Scoped to one customer.\n\nEntitlement: `addresses.list`\n\nNeeds these variables set first: CUSTOMER_ID"
          }
        },
        {
          "type": "http",
          "name": "Retrieve address",
          "seq": 2,
          "request": {
            "url": "{{BASE_URL}}/v1/addresses/{{ADDRESS_ID}}",
            "method": "GET",
            "headers": [],
            "params": [],
            "body": {
              "mode": "none"
            },
            "auth": {
              "mode": "inherit"
            },
            "docs": "\nEntitlement: `addresses.retrieve`\n\nNeeds these variables set first: ADDRESS_ID"
          }
        },
        {
          "type": "http",
          "name": "Update address",
          "seq": 3,
          "request": {
            "url": "{{BASE_URL}}/v1/addresses/{{ADDRESS_ID}}",
            "method": "POST",
            "headers": [
              {
                "name": "Content-Type",
                "value": "application/json",
                "enabled": true
              }
            ],
            "params": [],
            "body": {
              "mode": "json",
              "json": "{\n  \"city\": \"Manchester\"\n}"
            },
            "auth": {
              "mode": "inherit"
            },
            "docs": "Only the fields you send change.\n\nEntitlement: `addresses.update`\n\nNeeds these variables set first: ADDRESS_ID"
          }
        },
        {
          "type": "http",
          "name": "Set default address",
          "seq": 4,
          "request": {
            "url": "{{BASE_URL}}/v1/addresses/{{ADDRESS_ID}}/default",
            "method": "POST",
            "headers": [
              {
                "name": "Content-Type",
                "value": "application/json",
                "enabled": true
              }
            ],
            "params": [],
            "body": {
              "mode": "json",
              "json": "{\n  \"type\": \"billing\"\n}"
            },
            "auth": {
              "mode": "inherit"
            },
            "docs": "`type` is required and is either `billing` or `shipping` — a customer has one default of each, so a request that does not say which is refused rather than guessed.\n\nEntitlement: `addresses.setDefault`\n\nNeeds these variables set first: ADDRESS_ID"
          }
        }
      ]
    },
    {
      "type": "folder",
      "name": "05 · Plans and subscriptions",
      "seq": 6,
      "root": {
        "docs": "A plan is the price and cadence; a subscription binds a customer, a plan and a card. Amounts are integers in the minor unit — 4999 is $49.99. A decimal is rejected rather than silently charged as a different figure."
      },
      "items": [
        {
          "type": "http",
          "name": "Create plan",
          "seq": 0,
          "request": {
            "url": "{{BASE_URL}}/v1/plans",
            "method": "POST",
            "headers": [
              {
                "name": "Content-Type",
                "value": "application/json",
                "enabled": true
              }
            ],
            "params": [],
            "body": {
              "mode": "json",
              "json": "{\n  \"name\": \"Standard monthly\",\n  \"amount\": 4999,\n  \"currency\": \"USD\",\n  \"interval\": \"month\",\n  \"intervalCount\": 1\n}"
            },
            "auth": {
              "mode": "inherit"
            },
            "docs": "`interval` is one of `day`, `week`, `month`, `year`. An unknown interval is refused here rather than upstream.\n\nEntitlement: `plans.create`"
          }
        },
        {
          "type": "http",
          "name": "Retrieve plan",
          "seq": 1,
          "request": {
            "url": "{{BASE_URL}}/v1/plans/{{PLAN_ID}}",
            "method": "GET",
            "headers": [],
            "params": [],
            "body": {
              "mode": "none"
            },
            "auth": {
              "mode": "inherit"
            },
            "docs": "\nEntitlement: `plans.retrieve`\n\nNeeds these variables set first: PLAN_ID"
          }
        },
        {
          "type": "http",
          "name": "List plans",
          "seq": 2,
          "request": {
            "url": "{{BASE_URL}}/v1/plans",
            "method": "GET",
            "headers": [],
            "params": [
              {
                "name": "limit",
                "value": "10",
                "type": "query",
                "enabled": true
              }
            ],
            "body": {
              "mode": "none"
            },
            "auth": {
              "mode": "inherit"
            },
            "docs": "Cursor-paginated.\n\nEntitlement: `plans.list`"
          }
        },
        {
          "type": "http",
          "name": "Create subscription",
          "seq": 3,
          "request": {
            "url": "{{BASE_URL}}/v1/subscriptions",
            "method": "POST",
            "headers": [
              {
                "name": "Content-Type",
                "value": "application/json",
                "enabled": true
              }
            ],
            "params": [],
            "body": {
              "mode": "json",
              "json": "{\n  \"customerId\": \"{{CUSTOMER_ID}}\",\n  \"planId\": \"{{PLAN_ID}}\",\n  \"paymentMethodId\": \"{{PAYMENT_METHOD_ID}}\",\n  \"startAt\": \"2026-09-01\",\n  \"timezone\": \"America/New_York\"\n}"
            },
            "auth": {
              "mode": "inherit"
            },
            "docs": "Which calendar day a charge lands on is a timezone question, so `timezone` is explicit and defaults to UTC rather than being guessed.\n\nEntitlement: `subscriptions.create`\n\nNeeds these variables set first: CUSTOMER_ID, PLAN_ID, PAYMENT_METHOD_ID"
          }
        },
        {
          "type": "http",
          "name": "Retrieve subscription",
          "seq": 4,
          "request": {
            "url": "{{BASE_URL}}/v1/subscriptions/{{SUBSCRIPTION_ID}}",
            "method": "GET",
            "headers": [],
            "params": [],
            "body": {
              "mode": "none"
            },
            "auth": {
              "mode": "inherit"
            },
            "docs": "`nextBillingAt` is absent once cancelled — a stale date there is the shape of every \"we cancelled but it billed again\".\n\nEntitlement: `subscriptions.retrieve`\n\nNeeds these variables set first: SUBSCRIPTION_ID"
          }
        },
        {
          "type": "http",
          "name": "List subscriptions",
          "seq": 5,
          "request": {
            "url": "{{BASE_URL}}/v1/subscriptions",
            "method": "GET",
            "headers": [],
            "params": [
              {
                "name": "limit",
                "value": "10",
                "type": "query",
                "enabled": true
              }
            ],
            "body": {
              "mode": "none"
            },
            "auth": {
              "mode": "inherit"
            },
            "docs": "Cursor-paginated.\n\nEntitlement: `subscriptions.list`"
          }
        },
        {
          "type": "http",
          "name": "Cancel subscription",
          "seq": 6,
          "request": {
            "url": "{{BASE_URL}}/v1/subscriptions/{{SUBSCRIPTION_ID}}/cancel",
            "method": "POST",
            "headers": [],
            "params": [],
            "body": {
              "mode": "none"
            },
            "auth": {
              "mode": "inherit"
            },
            "docs": "Cancels immediately.\n\nEntitlement: `subscriptions.cancel`\n\nNeeds these variables set first: SUBSCRIPTION_ID"
          }
        }
      ]
    },
    {
      "type": "folder",
      "name": "06 · Invoices and scheduled collection",
      "seq": 7,
      "root": {
        "docs": "An invoice can be sent for someone to pay, or scheduled to collect itself from a saved card on a date. The schedule is Myela's own: no provider behind this API has a collect-on-a-date primitive."
      },
      "items": [
        {
          "type": "http",
          "name": "Create invoice",
          "seq": 0,
          "request": {
            "url": "{{BASE_URL}}/v1/invoices",
            "method": "POST",
            "headers": [
              {
                "name": "Content-Type",
                "value": "application/json",
                "enabled": true
              }
            ],
            "params": [],
            "body": {
              "mode": "json",
              "json": "{\n  \"customerId\": \"{{CUSTOMER_ID}}\",\n  \"currency\": \"USD\",\n  \"amount\": 150000,\n  \"description\": \"Consulting, August\",\n  \"dueAt\": \"2026-09-01T00:00:00.000Z\"\n}"
            },
            "auth": {
              "mode": "inherit"
            },
            "docs": "The invoice total, in minor units — there is no line-item array on this endpoint. Amounts are integers in the minor unit — 4999 is $49.99. A decimal is rejected rather than silently charged as a different figure.\n\nEntitlement: `invoices.create`\n\nNeeds these variables set first: CUSTOMER_ID"
          }
        },
        {
          "type": "http",
          "name": "Retrieve invoice",
          "seq": 1,
          "request": {
            "url": "{{BASE_URL}}/v1/invoices/{{INVOICE_ID}}",
            "method": "GET",
            "headers": [],
            "params": [],
            "body": {
              "mode": "none"
            },
            "auth": {
              "mode": "inherit"
            },
            "docs": "`url` is a Myela-hosted payment page on our own domain, safe to send to a cardholder.\n\nEntitlement: `invoices.retrieve`\n\nNeeds these variables set first: INVOICE_ID"
          }
        },
        {
          "type": "http",
          "name": "List invoices",
          "seq": 2,
          "request": {
            "url": "{{BASE_URL}}/v1/invoices",
            "method": "GET",
            "headers": [],
            "params": [
              {
                "name": "limit",
                "value": "10",
                "type": "query",
                "enabled": true
              }
            ],
            "body": {
              "mode": "none"
            },
            "auth": {
              "mode": "inherit"
            },
            "docs": "Cursor-paginated.\n\nEntitlement: `invoices.list`"
          }
        },
        {
          "type": "http",
          "name": "Schedule invoice collection",
          "seq": 3,
          "request": {
            "url": "{{BASE_URL}}/v1/invoices/{{INVOICE_ID}}/schedule",
            "method": "POST",
            "headers": [
              {
                "name": "Content-Type",
                "value": "application/json",
                "enabled": true
              }
            ],
            "params": [],
            "body": {
              "mode": "json",
              "json": "{\n  \"collectAt\": \"2026-09-01T09:00:00.000Z\",\n  \"paymentMethodId\": \"{{PAYMENT_METHOD_ID}}\"\n}"
            },
            "auth": {
              "mode": "inherit"
            },
            "docs": "Charges the named card on that date. Omit `paymentMethodId` to use the customer's default. Failed attempts retry on a backoff and are visible under Attempts.\n\nEntitlement: `invoices.schedule`\n\nNeeds these variables set first: INVOICE_ID, PAYMENT_METHOD_ID"
          }
        },
        {
          "type": "http",
          "name": "Cancel scheduled collection",
          "seq": 4,
          "request": {
            "url": "{{BASE_URL}}/v1/invoices/{{INVOICE_ID}}/cancel_schedule",
            "method": "POST",
            "headers": [],
            "params": [],
            "body": {
              "mode": "none"
            },
            "auth": {
              "mode": "inherit"
            },
            "docs": "Leaves the invoice open but stops it collecting itself.\n\nEntitlement: `invoices.schedule`\n\nNeeds these variables set first: INVOICE_ID"
          }
        },
        {
          "type": "http",
          "name": "List collection attempts",
          "seq": 5,
          "request": {
            "url": "{{BASE_URL}}/v1/invoices/{{INVOICE_ID}}/attempts",
            "method": "GET",
            "headers": [],
            "params": [],
            "body": {
              "mode": "none"
            },
            "auth": {
              "mode": "inherit"
            },
            "docs": "Every attempt made to collect it, in order — the answer to \"why has this not been paid\".\n\nEntitlement: `invoices.attempts`\n\nNeeds these variables set first: INVOICE_ID"
          }
        },
        {
          "type": "http",
          "name": "Void invoice",
          "seq": 6,
          "request": {
            "url": "{{BASE_URL}}/v1/invoices/{{INVOICE_ID}}/void",
            "method": "POST",
            "headers": [],
            "params": [],
            "body": {
              "mode": "none"
            },
            "auth": {
              "mode": "inherit"
            },
            "docs": "Terminal. A voided invoice cannot be collected or reopened.\n\nEntitlement: `invoices.void`\n\nNeeds these variables set first: INVOICE_ID"
          }
        }
      ]
    },
    {
      "type": "folder",
      "name": "07 · Webhook endpoints and deliveries",
      "seq": 8,
      "root": {
        "docs": "Where your payment events leave Myela. Entitlements here are separate from the rest of `/v1` on purpose: a key that may read invoices should not be able to point that stream somewhere new.\n\nVerify every delivery signature before acting on it — see `docs/gateway/api/WEBHOOK_SIGNATURE.md`."
      },
      "items": [
        {
          "type": "http",
          "name": "Create webhook endpoint",
          "seq": 0,
          "request": {
            "url": "{{BASE_URL}}/v1/webhook_endpoints",
            "method": "POST",
            "headers": [
              {
                "name": "Content-Type",
                "value": "application/json",
                "enabled": true
              }
            ],
            "params": [],
            "body": {
              "mode": "json",
              "json": "{\n  \"url\": \"https://example.com/webhooks/myela\",\n  \"events\": [\n    \"invoice.paid\",\n    \"payment.settled\",\n    \"payment.refunded\"\n  ]\n}"
            },
            "auth": {
              "mode": "inherit"
            },
            "docs": "The signing secret is returned once, at creation, and never again.\n\nEntitlement: `webhookEndpoints.create`"
          }
        },
        {
          "type": "http",
          "name": "List webhook endpoints",
          "seq": 1,
          "request": {
            "url": "{{BASE_URL}}/v1/webhook_endpoints",
            "method": "GET",
            "headers": [],
            "params": [],
            "body": {
              "mode": "none"
            },
            "auth": {
              "mode": "inherit"
            },
            "docs": "\nEntitlement: `webhookEndpoints.list`"
          }
        },
        {
          "type": "http",
          "name": "Retrieve webhook endpoint",
          "seq": 2,
          "request": {
            "url": "{{BASE_URL}}/v1/webhook_endpoints/{{WEBHOOK_ENDPOINT_ID}}",
            "method": "GET",
            "headers": [],
            "params": [],
            "body": {
              "mode": "none"
            },
            "auth": {
              "mode": "inherit"
            },
            "docs": "\nEntitlement: `webhookEndpoints.retrieve`\n\nNeeds these variables set first: WEBHOOK_ENDPOINT_ID"
          }
        },
        {
          "type": "http",
          "name": "Update webhook endpoint",
          "seq": 3,
          "request": {
            "url": "{{BASE_URL}}/v1/webhook_endpoints/{{WEBHOOK_ENDPOINT_ID}}",
            "method": "POST",
            "headers": [
              {
                "name": "Content-Type",
                "value": "application/json",
                "enabled": true
              }
            ],
            "params": [],
            "body": {
              "mode": "json",
              "json": "{\n  \"events\": [\n    \"invoice.paid\"\n  ]\n}"
            },
            "auth": {
              "mode": "inherit"
            },
            "docs": "\nEntitlement: `webhookEndpoints.update`\n\nNeeds these variables set first: WEBHOOK_ENDPOINT_ID"
          }
        },
        {
          "type": "http",
          "name": "Delete webhook endpoint",
          "seq": 4,
          "request": {
            "url": "{{BASE_URL}}/v1/webhook_endpoints/{{WEBHOOK_ENDPOINT_ID}}",
            "method": "DELETE",
            "headers": [],
            "params": [],
            "body": {
              "mode": "none"
            },
            "auth": {
              "mode": "inherit"
            },
            "docs": "\nEntitlement: `webhookEndpoints.delete`\n\nNeeds these variables set first: WEBHOOK_ENDPOINT_ID"
          }
        },
        {
          "type": "http",
          "name": "List deliveries",
          "seq": 5,
          "request": {
            "url": "{{BASE_URL}}/v1/webhook_deliveries",
            "method": "GET",
            "headers": [],
            "params": [
              {
                "name": "limit",
                "value": "10",
                "type": "query",
                "enabled": true
              }
            ],
            "body": {
              "mode": "none"
            },
            "auth": {
              "mode": "inherit"
            },
            "docs": "Every attempt to reach your endpoint, with the response we got.\n\nEntitlement: `webhookDeliveries.list`"
          }
        },
        {
          "type": "http",
          "name": "Retrieve delivery",
          "seq": 6,
          "request": {
            "url": "{{BASE_URL}}/v1/webhook_deliveries/{{WEBHOOK_DELIVERY_ID}}",
            "method": "GET",
            "headers": [],
            "params": [],
            "body": {
              "mode": "none"
            },
            "auth": {
              "mode": "inherit"
            },
            "docs": "\nEntitlement: `webhookDeliveries.retrieve`\n\nNeeds these variables set first: WEBHOOK_DELIVERY_ID"
          }
        },
        {
          "type": "http",
          "name": "Replay delivery",
          "seq": 7,
          "request": {
            "url": "{{BASE_URL}}/v1/webhook_deliveries/{{WEBHOOK_DELIVERY_ID}}/replay",
            "method": "POST",
            "headers": [],
            "params": [],
            "body": {
              "mode": "none"
            },
            "auth": {
              "mode": "inherit"
            },
            "docs": "Re-sends the FROZEN payload, not a rebuilt one — a replay must deliver what the event said when it happened.\n\nEntitlement: `webhookDeliveries.retrieve`\n\nNeeds these variables set first: WEBHOOK_DELIVERY_ID"
          }
        }
      ]
    },
    {
      "type": "folder",
      "name": "08 · Myela Elements (browser)",
      "seq": 9,
      "root": {
        "docs": "The only two routes a merchant's own checkout page calls, and the only two authenticated by the PUBLISHABLE key (`myela_pk_`) rather than the secret one. Set MYELA_PUBLISHABLE_KEY in the environment; the secret key must never reach a browser.\n\nA session can only be started from an origin on that key's allow-list, which the merchant manages. An empty list refuses every origin — \"not configured yet\" fails closed, because a checkout that 401s until someone adds a domain is recoverable and one open to the internet is not.\n\nThe hosted frame at js.myela.com is not serving yet, so the middle step — mounting the fields and getting an upstream token — cannot be done from these two requests alone. The server contract below is live and can be exercised today."
      },
      "items": [
        {
          "type": "http",
          "name": "Create checkout session",
          "seq": 0,
          "request": {
            "url": "{{BASE_URL}}/v1/checkout_sessions",
            "method": "POST",
            "headers": [
              {
                "name": "Content-Type",
                "value": "application/json",
                "enabled": true
              }
            ],
            "params": [],
            "body": {
              "mode": "json",
              "json": "{\n  \"intent\": \"one_time\"\n}"
            },
            "auth": {
              "mode": "bearer",
              "bearer": {
                "token": "{{MYELA_PUBLISHABLE_KEY}}"
              }
            },
            "docs": "Opens a checkout session from the merchant's page. `intent` is `one_time` (charge now) or `store` (vault the card); the whole body is optional and defaults to `one_time`.\n\nReturns `sessionId`, a `mountUrl` to iframe, `parentOrigin`, and an opaque `capture` object. Nothing in the response names a provider or differs by which one settles the account — that uniformity is the contract, not an implementation detail.\n\n**401** means the calling origin is not on this key's allow-list."
          }
        },
        {
          "type": "http",
          "name": "Exchange for a payment token",
          "seq": 1,
          "request": {
            "url": "{{BASE_URL}}/v1/tokens",
            "method": "POST",
            "headers": [
              {
                "name": "Content-Type",
                "value": "application/json",
                "enabled": true
              }
            ],
            "params": [],
            "body": {
              "mode": "json",
              "json": "{\n  \"sessionId\": \"{{CHECKOUT_SESSION_ID}}\",\n  \"upstreamToken\": \"{{UPSTREAM_TOKEN}}\"\n}"
            },
            "auth": {
              "mode": "bearer",
              "bearer": {
                "token": "{{MYELA_PUBLISHABLE_KEY}}"
              }
            },
            "docs": "Exchanges the provider token the fields produced for an opaque `mtok_`, which is what `POST /v1/payments` accepts as `paymentToken`.\n\nThe session id is the capability — there is no key on this call beyond the publishable one. A session exchanges ONCE; a second attempt is refused, and so is a replay of the resulting `mtok_`.\n\nBoth variables come from the frame, so this request cannot be driven from the collection alone until js.myela.com is serving.\n\nNeeds these variables set first: CHECKOUT_SESSION_ID, UPSTREAM_TOKEN"
          }
        }
      ]
    }
  ],
  "activeEnvironmentUid": null,
  "environments": [
    {
      "name": "Sandbox",
      "variables": [
        {
          "name": "BASE_URL",
          "value": "https://payments-api-sandbox.merchantservicedepot.com",
          "enabled": true,
          "secret": false,
          "type": "text"
        },
        {
          "name": "MYELA_API_KEY",
          "value": "myela_sk_test_REPLACE_WITH_YOUR_KEY",
          "enabled": true,
          "secret": true,
          "type": "text"
        },
        {
          "name": "PAYMENT_TOKEN",
          "value": "mtok_REPLACE_WITH_A_SINGLE_USE_TOKEN",
          "enabled": true,
          "secret": true,
          "type": "text"
        },
        {
          "name": "MYELA_PUBLISHABLE_KEY",
          "value": "myela_pk_test_REPLACE_WITH_YOUR_PUBLISHABLE_KEY",
          "enabled": true,
          "secret": false,
          "type": "text"
        }
      ]
    },
    {
      "name": "Local",
      "variables": [
        {
          "name": "BASE_URL",
          "value": "http://localhost:4002",
          "enabled": true,
          "secret": false,
          "type": "text"
        },
        {
          "name": "MYELA_API_KEY",
          "value": "myela_sk_test_REPLACE_WITH_YOUR_KEY",
          "enabled": true,
          "secret": true,
          "type": "text"
        },
        {
          "name": "PAYMENT_TOKEN",
          "value": "mtok_REPLACE_WITH_A_SINGLE_USE_TOKEN",
          "enabled": true,
          "secret": true,
          "type": "text"
        },
        {
          "name": "MYELA_PUBLISHABLE_KEY",
          "value": "myela_pk_test_REPLACE_WITH_YOUR_PUBLISHABLE_KEY",
          "enabled": true,
          "secret": false,
          "type": "text"
        }
      ]
    }
  ],
  "root": {
    "docs": "The Myela Payments public API (/v1).\n\nSet MYELA_API_KEY in the environment to a TEST key from your dashboard\n(Settings → API). Nothing here is pre-filled: a collection that ships a key\nis a collection that leaks one.\n\nA test key authenticates with the bearer token alone. A LIVE key must also\nHMAC-sign every request, which Bruno cannot do out of the box — use the SDK\nor the signing spec for live traffic.",
    "request": {
      "auth": {
        "mode": "bearer",
        "bearer": {
          "token": "{{MYELA_API_KEY}}"
        }
      }
    }
  },
  "brunoConfig": {
    "version": "1",
    "name": "Myela Payments — /v1",
    "type": "collection",
    "ignore": [
      "node_modules",
      ".git"
    ]
  }
}
