Skip to main content
developers/donations-sdk/compliance
Developer13 min read

Compliance & Security

PCI SAQ A scope, annual self-assessment guidance, CSP and SRI recipes, data residency, and customer obligations summary.

Compliance & Security

The Donations Embed is designed so that integrating it puts you in PCI DSS SAQ A scope — the simplest of the PCI self-assessment questionnaires. Donor card data is tokenised inside an isolated iframe loaded from our domain before it ever touches your code, your servers, or any system you operate. This page documents the scope, the annual self-assessment cadence, the Content Security Policy and Subresource Integrity recipes, where data lives, and what you are responsible for.

PCI scope

What SAQ A is

The Payment Card Industry Data Security Standard (PCI DSS) defines several Self-Assessment Questionnaires (SAQs) for merchants who do not store, process, or transmit card data themselves. SAQ A is the questionnaire for merchants who:

  • Accept card-not-present transactions only (no in-person card swipes).
  • Have fully outsourced all payment processing to a PCI DSS validated third-party service provider.
  • Do not store, process, or transmit account data on their systems.
  • Do not host any HTML or JavaScript that captures account data — the payment form is served entirely from the third-party service provider's domain (in our case, the embed's tokenisation iframe is served from payments.1stflock.com for live mode, and sandbox.payments.1stflock.com for sandbox / test mode).

SAQ A merchants answer roughly 22 questions per quarter (versus hundreds for SAQ D) and have no on-site assessment requirement. It is by a wide margin the cheapest and fastest way to be PCI compliant.

Why your integration qualifies for SAQ A

When a donor enters their card, the card form rendered inside <flock-donate> is not part of your page. It is rendered inside an iframe loaded from a domain we operate, certified annually under PCI DSS as a Service Provider Level 1: payments.1stflock.com for live donations, and sandbox.payments.1stflock.com for sandbox / test donations.

The card data is tokenised inside that iframe before any field value crosses the iframe boundary. Your page never sees the card number, expiry, or CVV. Your server never sees them. Even our own backend never sees the raw card number — the tokenisation iframe sends them directly to the certified vault, which returns a single-use token that is what eventually flows through our API.

This pattern is exactly the architecture that the PCI SSC describes as the SAQ A model in their guidance. You are eligible for SAQ A from the moment you paste in the embed snippet.

Annual self-assessment

PCI compliance is an annual cycle for SAQ A merchants. Once a year (sometime within 12 months of your last attestation), you must:

  1. Re-confirm that you still meet the SAQ A eligibility criteria.
  2. Answer the 22 SAQ A questions.
  3. Sign the Attestation of Compliance (AoC) and either keep it on file or send it to your acquiring bank if asked.

To make this trivial, the Hub portal provides a pre-filled SAQ A PDF generator under Donations Embed → Compliance. It pulls your organisation profile and renders a PDF with most fields pre-filled, including:

  • The certified Service Provider's name (the company providing the underlying processing infrastructure).
  • The list of services in scope.
  • The DSS version and the AoC date.

You only need to fill in your contact information, sign, and date the document. Download the latest PDF from the Compliance tab any time.

Important: The pre-filled PDF is a starting point, not legal advice. If your environment includes additional payment paths (e.g. a separate in-person donation counter, or a different giving platform alongside the embed), those may move you out of SAQ A scope and into a different SAQ. When in doubt, consult your acquiring bank or a Qualified Security Assessor (QSA).

CSP and SRI recipe

If your site sets a Content Security Policy (which it should), the embed's script and the tokenisation iframe must be allowlisted. Add the directives below to your CSP. If you do not yet have a CSP, this is a good time to start — adding one is straightforward and substantially raises the bar for cross-site scripting attacks.

Required CSP directives

Add the following sources to the matching directives. Merge with whatever you already have; do not replace.

DirectiveRequired sourcePurpose
script-srchttps://payments.1stflock.comLoads the <flock-donate> web component bundle (live mode).
script-srchttps://sandbox.payments.1stflock.comLoads the <flock-donate> web component bundle (sandbox mode).
connect-srchttps://api.1stflock.comAPI calls from the embed (/v1/embed/config, /v1/embed/sessions, etc.).
connect-srchttps://api.sandbox.1stflock.comAPI calls in sandbox mode.
frame-srchttps://payments.1stflock.comThe tokenisation iframe (live mode).
frame-srchttps://sandbox.payments.1stflock.comThe tokenisation iframe (sandbox mode).
style-src'unsafe-inline' (or a per-request nonce)The embed injects a single inline <style> per render to apply theme tokens.
img-srchttps://payments.1stflock.comBrand logos and trust-mark images (live mode).
img-srchttps://sandbox.payments.1stflock.comBrand logos and trust-mark images (sandbox mode).
font-srchttps://payments.1stflock.comEmbedded UI font (live mode, when the active theme uses a custom font).
font-srchttps://sandbox.payments.1stflock.comEmbedded UI font (sandbox mode, when the active theme uses a custom font).

A production-ready CSP that supports the embed:

Content-Security-Policy:
  default-src 'self';
  script-src 'self' https://payments.1stflock.com https://sandbox.payments.1stflock.com;
  style-src 'self' 'unsafe-inline';
  connect-src 'self' https://api.1stflock.com https://api.sandbox.1stflock.com;
  frame-src 'self' https://payments.1stflock.com https://sandbox.payments.1stflock.com;
  img-src 'self' data: https://payments.1stflock.com https://sandbox.payments.1stflock.com;
  font-src 'self' https://payments.1stflock.com https://sandbox.payments.1stflock.com;
  object-src 'none';
  base-uri 'self';
  form-action 'self';

If your site already uses a CSP nonce strategy, you can replace 'unsafe-inline' for style-src with a per-request nonce — generate the nonce, attach it to your <style> tags, and include 'nonce-<value>' in the CSP.

For a sandbox-only environment, you may omit the live sources (https://api.1stflock.com, https://payments.1stflock.com). For a live-only environment, you may omit the sandbox sources (https://api.sandbox.1stflock.com, https://sandbox.payments.1stflock.com). Both pairs are listed above so a single header works in either environment.

Cross-mismatch enforcement. If you load the SDK from payments.1stflock.com but supply a pk_test_* key, the SDK throws with: Live SDK cannot use test keys. Load https://sandbox.payments.1stflock.com/v1.js instead. Same in reverse for sandbox.payments.1stflock.com + pk_live_*.

Subresource Integrity (SRI)

When you load the embed via <script> tag (rather than a bundler import), you can pin the bundle's hash so a tampered file is rejected by the browser. Because SRI ties a hash to an exact set of bytes, always pin against the immutable, versioned URL (/<version>/donations-embed.js) — never the mutable /v1.js major alias, which rolls forward on every patch and would break the hash.

Each published version exposes its SRI metadata as JSON at /sri/<version>.json:

{
  "version": "1.3.3",
  "bundle": "donations-embed.iife.js",
  "integrity": "sha384-77ho1Y9fH4MDaqEDhX45l1A8IR/ZIl5GbGqT8F9X/nmlbgsV3BAPYdMGRDdqwlx8",
  "size_bytes": 484710,
  "algorithm": "sha384"
}

Copy the integrity value into the tag, and point src at the matching version:

<script
  type="module"
  src="https://payments.1stflock.com/v1.3.3/donations-embed.js"
  integrity="sha384-77ho1Y9fH4MDaqEDhX45l1A8IR/ZIl5GbGqT8F9X/nmlbgsV3BAPYdMGRDdqwlx8"
  crossorigin="anonymous"
></script>

For sandbox / test-mode integrations, replace the src host with https://sandbox.payments.1stflock.com/v1.3.3/donations-embed.js. Both environments serve byte-for-byte identical bundles for a given version, so the integrity value is the same on either host. Versioned URLs and their /sri/<version>.json files are public and permanent — pin to whichever version you have reviewed.

Note: SRI is optional. The bundle is served from a domain we control with TLS and HSTS; tampering at the network layer is already infeasible. SRI adds a defence-in-depth layer for high-security environments.

Data residency

Where data lives

DataWhere it is storedEncryption
Donor PII (name, email, address)1st Flock managed databases in the United States.TLS 1.2+ in transit, AES-256 at rest.
Card details (PAN, expiry, CVV)A PCI DSS Level 1 certified third-party vault. Never stored by 1st Flock.TLS 1.2+ in transit, vendor-side AES-256 at rest.
ACH bank details (routing, account)A PCI DSS Level 1 certified third-party vault. Never stored by 1st Flock.TLS 1.2+ in transit, vendor-side AES-256 at rest.
Donation records (amount, fund, status, timestamps)1st Flock managed databases in the United States.TLS 1.2+ in transit, AES-256 at rest.
Receipt PDFs and donor statements1st Flock managed object storage in the United States.TLS 1.2+ in transit, AES-256 at rest.
Webhook signing secrets1st Flock managed secrets store.Encrypted at rest with KMS-managed keys; not retrievable in plaintext after creation.

If you have customers outside the United States and need data-residency commitments in a different region, contact your account manager — we offer EU-resident environments for organisations subject to GDPR-style data localisation.

What is encrypted

  • All data in transit is TLS 1.2 or newer. We do not accept TLS 1.0/1.1.
  • All data at rest is AES-256.
  • API keys (publishable and secret) are stored as Argon2id-hashed digests; we cannot recover the plaintext of a secret key after creation. Lost secret keys must be rotated.
  • Webhook signing secrets follow the same pattern — stored as a hash, not retrievable after creation.

Backups and retention

  • Donations are retained for the lifetime of your subscription plus 7 years (the standard nonprofit accounting retention window in the United States).
  • Webhook delivery records (the response body and headers your endpoint returned) are retained for 30 days.
  • Audit logs (every API call by an authenticated principal) are retained for 1 year.
  • Donor PII can be deleted on request — see the Customer obligations section below for the GDPR / CCPA workflow.

Customer obligations

The following are your responsibilities, not ours. None are difficult; we list them so there is no ambiguity.

1. Protect your secret keys

Secret keys (sk_…) are bearer tokens. Anyone who possesses one can act as your organisation against the API. Store them in a secrets manager (your platform's environment-variable store, AWS Secrets Manager, GCP Secret Manager, HashiCorp Vault, etc.). Never:

  • Commit them to source control.
  • Embed them in client-side code.
  • Log them in plaintext.
  • Share them via email or chat.
  • Reuse a live key in sandbox.

If you suspect a key is compromised, rotate it immediately from the Hub portal. The previous pair stays valid for 24 hours after rotation as a grace window so you can deploy the new key without downtime.

2. Protect your webhook signing secret

The signing secret is what gives your endpoint confidence that an inbound delivery is genuinely from us. Treat it like a secret key — store in a secrets manager, never log in plaintext. To rotate, change the endpoint URL in the Hub; we generate a new secret and return it once.

3. Use SAQ A self-assessment annually

You are responsible for completing your SAQ A and Attestation of Compliance once every 12 months, regardless of whether your acquiring bank asks for it. The Hub provides the pre-filled PDF; you sign and date it.

4. Set up a Content Security Policy

Per the recipe above. A CSP is not strictly required for the embed to work, but your security posture (and your SAQ A answers) are stronger with one in place.

5. Honour donor data deletion requests

If a donor invokes their GDPR (Right to Erasure) or CCPA (Right to Delete) rights, you must initiate the deletion via the Hub's Donor Privacy tab, which:

  1. Anonymises donation records associated with that donor (replaces PII fields with a deterministic hash so amount totals stay accurate but the donor cannot be re-identified from the record).
  2. Removes the donor from any future communication targeting.
  3. Records the deletion request in your audit log.

Donor records subject to legally-required retention (for example, the 7-year nonprofit accounting window for receipted donations in the United States) are anonymised in place; the underlying record persists in tax-compliant form, but cannot be linked back to the donor.

6. Validate webhook signatures on every delivery

Every webhook delivery is signed. Validating the signature is not optional — without it, an attacker who learns your webhook URL can submit forged events. The SDKs do this for you in one line; if you are not using an SDK, see the Webhooks → Signature verification reference implementation.

7. Dedupe webhook deliveries by event ID

Delivery is at-least-once. Persist event.id and short-circuit re-deliveries. See Webhooks → Idempotency on your side for the recipe in each SDK.

8. Use the appropriate environment

Use sandbox keys (pk_test_… / sk_test_…) in development, staging, CI, demo environments, and any other non-production system. Use live keys (pk_live_… / sk_live_…) only in production. Mixing them is rejected at the API edge, but the rejection is a 401 — you want to catch this before you ship, not at runtime in production.

9. Monitor webhook delivery health

The Hub portal's Donations Embed → Webhooks → Deliveries tab surfaces delivery success rate and latency. We alert internally if your endpoint's failure rate spikes, but the responsibility for ensuring your endpoint is up and responding within 10 seconds is yours.

10. Keep your contact information current

Notifications about platform changes, planned maintenance, deprecation timelines, and security advisories are delivered to the email addresses on your organisation profile. Keep them current under Account → Profile.

A note on vendor independence

This documentation is intentionally vendor-neutral. The underlying tokenisation vault, payment gateway, and infrastructure providers are implementation details that may change over time without notice to you. The vendor-neutral identifiers in our API responses (processor_transaction_id, processor_refund_id, processor_subscription_id) are stable across vendor changes. The webhook event payloads and HTTP error envelopes are stable across vendor changes. The SDKs are stable across vendor changes.

In other words: nothing in your integration code should ever need to know who the underlying vendor is. If you find yourself wanting to look it up, please open a ticket — we want to know about whatever leak made you feel that need so we can plug it.

Compliance summary downloads

The Hub provides downloadable artifacts for your compliance file:

  • SAQ A pre-filled PDF — under Donations Embed → Compliance → SAQ A PDF.
  • Service Provider Attestation of Compliance (AoC) — under Donations Embed → Compliance → Provider AoC. Updated annually.
  • Subprocessor list — under Account → Privacy → Subprocessors. Lists every subprocessor that may handle your data, with their purpose and data-residency commitments.
  • Data Processing Addendum (DPA) — under Account → Privacy → DPA. Pre-signed; counter-sign and return for your records.

Next steps

Developer Portal