Skip to content

Testing & Deployment

This page covers how to test your Hypercerts integration locally, the validation rules and constraints your records must satisfy, privacy considerations, and a checklist for going live.


Local development

Set up a test PDS

Run a local PDS to avoid polluting production data. Self-host a test instance using the ATProto PDS distribution and follow the ATProto self-hosting guide.

Point your ATProto client to the local instance instead of production:

TypeScript
import { AtpAgent } from "@atproto/api";


const agent = new AtpAgent({ service: "http://localhost:2583" }); // Local PDS
await agent.login({
  identifier: "test-user.test",
  password: "test-password",
});

Use test identities

Create dedicated test accounts — never use production identities for testing. When running a local PDS, you can create accounts with any handle. Each test identity gets its own DID and repository, isolating test data from production.

Create and verify a test record

Create a record using the same createRecord call from the Quickstart, then read it back to confirm it was stored correctly. The returned CID is a content hash — if the record changes, the CID changes, which is how you verify data integrity.

Clean up test data

Delete test records when you're done to keep your repository clean:

TypeScript
const uri = new URL(result.data.uri);
const rkey = uri.pathname.split("/").pop();
await agent.com.atproto.repo.deleteRecord({
  repo: agent.session.did,
  collection: "org.hypercerts.claim.activity",
  rkey,
});

Deletion removes the record from your PDS. Cached copies may persist in indexers temporarily.


Record constraints

The PDS itself is schema-agnostic — it will accept any record with a valid $type. Validation against lexicon schemas happens downstream: indexers and app views ignore or reject malformed records, and client libraries may validate before submission. To ensure your records are indexed and usable across the ecosystem, they should conform to the lexicon schemas.

Required fields

Every record type has required fields defined in its lexicon. Records missing required fields will be accepted by the PDS but ignored by indexers. See the lexicon reference for required fields per record type.

Datetime format

All datetime fields must use ISO 8601 format (e.g., 2026-01-15T00:00:00Z).

Strong references

When one record references another (e.g., an evaluation referencing an activity claim), the reference must include both the AT-URI and the CID. The CID is a content hash — if the referenced record is later modified, the CID won't match, making tampering detectable. If you need the current CID, fetch the record with getRecord before creating the reference.

String and array limits

Lexicon schemas define maximum lengths for strings (in bytes and Unicode grapheme clusters) and arrays. Check the lexicon reference for specific limits on each field.

Blob uploads

Blobs (images, documents, attachment files) are uploaded to the PDS separately from records. Size limits depend on the PDS implementation — check your PDS documentation for exact values.

If your attachment files are too large for blob upload, store them externally (e.g., on IPFS or a public URL) and reference them by URI in the attachment record.

Common issues

IssueCauseFix
Missing required fieldRecord omits a field the lexicon marks as requiredInclude all required fields — see the lexicon reference
Invalid datetimeDatetime not in ISO 8601 formatUse format: 2026-01-15T00:00:00Z
Invalid strong referenceReference missing uri or cidInclude both fields — fetch the latest CID if needed
String too longString exceeds maxLength or maxGraphemesTruncate or validate before submission
Array too longArray exceeds maxLengthReduce array size
Blob too largeFile exceeds PDS size limitCompress, split, or use external storage with a URI

Rate limits

PDS implementations impose rate limits on API requests. Specific limits vary by PDS — check your provider's documentation. If you hit a rate limit, retry with exponential backoff.


Privacy

Records are public by default

All ATProto records are public. Anyone can read records from any PDS. Never store sensitive personal data in hypercert records.

Include in records:

  • Public work descriptions (e.g., "Planted 500 trees in Borneo")
  • Aggregated impact metrics (e.g., "Reduced CO₂ by 50 tons")
  • Public contributor identities (DIDs, handles)
  • Links to public attachments (URLs, IPFS CIDs)

Keep off-protocol:

  • Personal contact information (email, phone, address)
  • Proprietary methodologies or trade secrets
  • Participant consent forms or private agreements
  • Raw data containing PII (personally identifiable information)

Store sensitive data in a private database and reference it by ID if needed.

Deletion and GDPR

You can delete records from your PDS at any time. However:

  • Indexers (like Hyperindex) may cache records and take time to update
  • Other users may have already fetched and stored copies
  • The deletion event itself is visible in your repository history

If you accidentally publish PII, delete the record immediately and contact indexer operators to request cache purging.


Authentication in production

Use OAuth for production applications. OAuth lets users authorize your app without sharing credentials. See the Quickstart for the authentication setup and the ATProto OAuth spec for the full protocol details.

Instead of using generic transitional permission scopes like transition:generic use granular scopes as much as possible. Example: repo:org.hypercerts.claim.activity?action=create&action=update.


Going live checklist

Before deploying to production:

  • [ ] Tested record creation and retrieval — Created and read back at least one hypercert successfully in a test environment.
  • [ ] Validated records against lexicon schemas — All required fields present, datetimes in ISO 8601, strong references include both URI and CID.
  • [ ] Verified your DID and handle — Confirmed your DID resolves correctly and your handle matches your intended identity.
  • [ ] Stored credentials securely — No secrets in source code. Environment variables or secret management in production.
  • [ ] Reviewed records for accidental PII — No sensitive personal data in any record fields.
  • [ ] Tested cross-PDS references — If your app references records from other PDSs or repositories, verified those references resolve correctly.
  • [ ] Implemented error handling — Your app handles validation errors, rate limits, and network failures gracefully.

See also