Skip to content

Changelog

Released: 2026

API responses now carry only the documented fields of each object, and a project API key only reaches the payment links of its project. Charges, customers and subscriptions are processed as before.

  • GET /v1/charges and GET /v1/charges/:id return the fields listed in The charge object. Responses no longer include internal fields: the raw processor response, the payer’s IP address and user agent, the idempotency key, internal provider and order references, reconciliation bookkeeping and deletedAt
  • expand accepts customer and product; any other value returns 400 ERR_INVALID_RELATIONS. A fields value naming a field that is not part of the charge object returns 400 ERR_INVALID_FIELDS
  • POST /v1/charges responses keep the same documented fields
  • Every customer returned by the API (the /v1/customers endpoints, GET /v1/subscriptions/:id, the PATCH /v1/subscriptions/:id/items and PATCH /v1/subscriptions/:id/customer responses, and expand=customer) uses the fields listed in The customer object. Responses no longer include customerVaultId, cardBin or cardExp; paymentProvider, cardLast4 and cardBrand stay
  • The card’s BIN and expiry are still delivered in the customer.created webhook
  • POST /v1/customers/:id/vault stores the vault id, BIN and expiry as before, and answers with the customer object without them
  • A fields value naming a field that is not part of the customer object returns 400 ERR_INVALID_FIELDS on GET /v1/customers
  • With a project API key, GET /v1/payment-links, GET /v1/payment-links/{hashUrl} and PATCH /v1/payment-links/{hashUrl}/cancel only reach the links of the key’s project, that is, the links created with the project’s key (POST /v1/payment-links and the collection endpoints). Regenerating the project’s key keeps access to them
  • Links created from the dashboard or with another project’s key are not listed and are not counted in total; reading or cancelling one returns 404 ERR_PAYMENT_LINK_NOT_FOUND, the same response as a link that does not exist
  • Account-level API keys keep access to every payment link of the account
  • If your integration read cardBin or cardExp from an API response, take them from the customer.created webhook instead
  • If your integration read a charge field that is no longer returned, contact support with the field and what you use it for
  • To list, read or cancel payment links created from the dashboard or by another project, use an account-level API key

Released: 2026

  • New optional expiresInDays field on POST /v1/payment-links: an integer from 1 to 60 that sets how many days the link stays payable
  • Without expiresInDays the link still expires 3 days after it is created
  • expiresAt in the response is the creation time plus expiresInDays days
  • Values below 1, above 60, not whole numbers, or not numbers return 400 with the failing field in error.issues
  • Collection and customer-payment links of the Integration API keep their fixed 3-day lifetime
  • The quick start said links created through the API last 7 days. They last 3 days by default
  • The example responses of the Integration API links showed a 7-day lifetime. Those links last 3 days
  • Rate limiting: the limit is 60 requests per fixed 60-second window per API key, shared by every /v1 endpoint. RateLimit-Reset is the number of seconds until the window resets, not a Unix timestamp; responses also carry RateLimit-Policy, and a 429 carries Retry-After. A 429 has a plain-text body and no error code (ERR_RATE_LIMIT_EXCEEDED was never returned)
  • Authentication errors: a missing X-API-Key header returns 401 ERR_API_KEY_MISSING (not ERR_MISSING_API_KEY); an unknown key returns 404 ERR_ACCOUNT_API_KEY_NOT_FOUND with message "Api key not found" (not ERR_API_KEY_NOT_FOUND or ERR_INVALID_API_KEY)
  • Minimum amount: an amount from 1 to 99 cents returns 400 ERR_AMOUNT_BELOW_NMI_MINIMUM in the standard error envelope, not a validation error; project-scoped keys also get a payment_link.rejected webhook
  • Expired links: links are marked expired lazily, when a listing returns them, so a link past expiresAt can still read pending. Compare expiresAt with the current time
  • List endpoint: lim is 1-100 (default 10); the response is { paymentLinks, total } with no pagination object and no customerEmail; the paymentProvider parameter is accepted but ignored for API-key requests
  • Response fields: optional fields (customerEmail, cancelledAt, completedAt, redirectUrl, metadata, paymentMethods) are omitted when empty, never null; message is always present; ids are numeric strings with no prefix
  • Validation: metadata keys accept any characters (1-40); customerName is 1-120 characters; redirectUrl must be http or https; sending customerEmail without requestCustomerEmail keeps the email step on
  • Webhooks: failed deliveries are retried after a fixed 15 seconds (no exponential backoff), up to 6 attempts, with a 60-second timeout per attempt; 3xx and other 4xx responses are dead-lettered immediately; there are no manual retries and no per-event selection. eventId is a UUID. payment.failed, receipt.created, charge.deferred and payment_link.rejected are now documented

Released: 2026

  • New payment method "paypal" for the paymentMethods field when creating payment links: customers pay with a PayPal account, or with a debit/credit card through PayPal’s guest checkout (no PayPal account needed)
  • Available for one-time payment links only (links created with POST /v1/payment-links); collection and customer-payment links remain card-only
  • As with other methods, "paypal" must be active on the account for the link’s environment, otherwise ERR_INACTIVE_PAYMENT_METHOD is returned
  • New paypal value for the paymentProvider query parameter on GET /v1/payment-links (the parameter is accepted but currently ignored for API-key requests; see the 1.3.0 documentation fixes)
  • New processing value for the status query parameter on GET /v1/payment-links. A link is processing while a payment is being confirmed; with PayPal this can last up to several days
  • payment.success and payment.failed events can carry transaction.paymentProvider: "paypal"
  • transaction.paymentMethod is "paypal" (PayPal account) or "credit_card" (card through PayPal’s guest checkout)
  • For PayPal, transaction.externalPaymentId is the PayPal capture id
  • For PayPal, payment.failed is sent only for real declines; closing the PayPal window or abandoning the payment sends no event
  • PATCH /v1/payment-links/{hashUrl}/cancel returns 409 with ERR_PAYMENT_IN_PROGRESS while the link is processing

Released: 2026

  • New paymentMethods field when creating payment links
  • Accepts an array of "yappy" and/or "card"
  • Validates that specified methods are active on the account
  • New error code ERR_INACTIVE_PAYMENT_METHOD when a method is not active
  • New requestCustomerEmail field when creating payment links
  • When true, the hosted payment page prompts the customer for their email
  • Defaults to true when omitted
  • Cannot be true when customerEmail is already provided
  • New paymentProvider query parameter on GET /v1/payment-links: nmi, emetec, or yappy
  • The parameter is validated (an unknown value returns 400) but it does not filter API-key requests: the list and total include links of every provider
  • Payment link responses now include paymentMethods and requestCustomerEmail fields
  • Cancel endpoint returns a compact response: hashUrl, customerName, concept, amount, status, createdAt, cancelledAt
  • transaction.isTest field added to payment.success webhook events

Released: 2025

  • Payment link management (create, list, retrieve, cancel)
  • API key authentication with rate limiting (60 requests/min)
  • Webhook support for payment.success and webhook.ping events
  • Metadata support (up to 20 keys, 8KB total)
  • Test mode for sandbox testing

Public API (API Key Auth)

  • GET /v1/payment-links - List payment links
  • GET /v1/payment-links/{hashUrl} - Retrieve payment link
  • POST /v1/payment-links - Create payment link
  • PATCH /v1/payment-links/{hashUrl}/cancel - Cancel payment link
  • Uses lim (limit) and off (offset) parameters
  • lim: Positive integer for page size
  • off: Non-negative integer for offset
  • Amount: 100-200,000 cents ($1.00-$2,000.00)
  • Concept: Required, non-empty string
  • Customer Name: Required, non-empty string
  • Customer Email: Optional, valid email format
  • Request Customer Email: Optional boolean, defaults to true, cannot be true with customerEmail
  • Redirect URL: Optional, valid URL, max 2048 characters
  • Metadata: Optional, max 20 keys, key length 1-40 chars, max 8KB total, cannot be empty object if provided
  • Payment Methods: Optional array of "yappy" / "card", no duplicates, at least 1 when specified
  • 60 requests per minute per API key
  • Headers: RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset
  • HTTPS only
  • HMAC-SHA256 signature verification
  • Up to 6 delivery attempts (1 + 5 retries), 15 seconds apart; 60-second timeout per attempt
  • Headers: Zeltapay-Signature, Zeltapay-Timestamp, Zeltapay-Event-Id, Zeltapay-Event-Type, Zeltapay-Delivery-Attempt

All API responses follow a consistent JSON structure:

  • Success responses include success: true, data, optional message, and timestamp
  • Error responses include success: false, message, error object with code and optional details, and timestamp
  • 200 OK - Request successful
  • 201 Created - Resource created successfully
  • 400 Bad Request - Invalid request data or validation error
  • 401 Unauthorized - Missing or invalid API key
  • 403 Forbidden - Account suspended
  • 404 Not Found - Resource not found
  • 429 Too Many Requests - Rate limit exceeded
  • 500 Internal Server Error - Server error

None


Future API changes and new versions will be documented here. Breaking changes will be introduced under new version paths (e.g., /v2/payment-links).