Skip to main content

Authentication

Every GoPay API request — payments (C2B) and transfers (B2C) alike — is authenticated with a detached Ed25519 signature sent in HTTP headers. Your private key stays on your servers; GoPay stores only the public verification key. This means a compromise of GoPay’s database can never be used to forge requests on your behalf.

API Keys

Create API keys in the merchant dashboard. Each key has:
  • A public key identifier — sent with every request in the X-Public-Key header
  • An Ed25519 key pair — you sign with the private half, GoPay verifies with the public half
  • Permissionsc2b (accept payments), b2c (make transfers), or both
  • Optional IP allowlist, per-merchant rate limit, and expiry
Two ways to get a key pair:
GoPay generates the key pair and returns the private key once, at creation time. Store it in a secrets manager immediately — GoPay does not keep a copy and cannot recover it.
If a private key is lost or leaked, rotate it from the dashboard. Rotation takes effect within seconds.

Required Headers

The Canonical String (v1)

The signature is computed over this string — lines joined with \n, no trailing newline:
Sign the canonical string with your Ed25519 private key and base64-encode the 64-byte result.
Because the host is part of the canonical string, a signature created for the sandbox cannot be replayed against production (and vice versa). Always sign with the exact host you send the request to.

Signing Helpers

Your private key is the base64 string shown once at key creation — it decodes to a 64-byte key (some libraries want only the first 32 bytes, the seed). These helpers return the exact headers to attach to any GoPay API request.

What Else Is Checked

Beyond the signature, GoPay enforces per key:
  1. Permission — the key must carry c2b for payments or b2c for transfers
  2. IP allowlist — if configured, requests from other IPs are rejected
  3. Replay protection — each X-Request-ID is accepted exactly once
  4. Rate limit — a per-merchant request budget
Failed authentication returns a deliberately generic error — the response never reveals which check failed. See Errors for the full taxonomy.

Common Mistakes

  • Re-serializing the JSON body after signing — hash, sign, and send the same bytes. Serialize once.
  • Signing with the wrong host — sandbox and production signatures are not interchangeable; the host is part of the canonical string.
  • Reusing an X-Request-ID — each one is accepted exactly once; generate a fresh UUID per request (including retries).
  • Timestamps in milliseconds — the API expects unix seconds.
  • Signing with the wrong key half — some libraries want the 64-byte private key, others the 32-byte seed (its first half).

Verifying Webhooks

The same scheme runs in reverse for callbacks: GoPay signs every webhook with its gateway private key, and you verify with the gateway public key you receive at onboarding. See Webhooks for verification code.