CredzaAPI

Credza API

Create, share and verify certificates from your own system. Your people never need a Credza account.

Base URL

https://server.credza.app/v1

How it works

  1. Upload your finished certificate as a PNG, JPG or PDF, and say where each detail goes: the name, the programme, a photo.
  2. Issue a credential for each person, with your own ID for them (for example a student number).
  3. Show it in your app. When someone signs in to your portal, look up their credentials by your ID and show the image or PDF.
  4. Anyone can check it’s genuine by scanning its QR code, or on your own verification page using the API.

Everything issued through the API also appears in your Credza workspace, where your team can download, resend or revoke it.

Authentication

Create a key in Credza → Settings → Developers. Send it with every request. Keys are secret: call the API from your server, never from a web page or mobile app.

curl https://server.credza.app/v1/templates \
  -H "Authorization: Bearer cz_live_…"

Templates

A template is your certificate artwork plus the places to fill in. Positions are in the artwork’s pixels — open it in any image editor to read them — or in millimetres with "unit": "mm".

Text is placed by the point it’s centred on: x is the middle of the text (or its start with "align": "left") and y is the middle of the line. Images and the QR code are placed by their top-left corner.

POST /templates

{
  "name": "Graduation 2026",
  "background": "data:application/pdf;base64,JVBERi0xLjcK…",
  "fields": [
    { "key": "name",      "x": 1754, "y": 1180, "size": 40, "font": "script" },
    { "key": "programme", "x": 1754, "y": 1400, "size": 18 },
    { "key": "date",      "x": 700,  "y": 2050, "size": 14, "text": "Awarded {{date}}" },
    { "key": "photo", "type": "image", "x": 180, "y": 180, "width": 420, "height": 520 }
  ],
  "qr": { "x": 3000, "y": 1950, "size": 380 }
}
backgroundstringYour artwork as base64 or a data: URL. PNG, JPG, WebP or a one-page PDF, up to 10 MB. PDFs keep their page size; images default to A4.
fields[].keystringLowercase letters, numbers and underscores. You send a value for each key when issuing.
fields[].typetext | imageText by default. Image fields take a picture per person, such as a photo.
fields[].sizenumberFont size in points. Default 24.
fields[].fontsans | serif | scriptDefault sans.
fields[].aligncenter | left | rightDefault center.
fields[].color#RRGGBBDefault #111111.
fields[].textstringOptional wording around the value, e.g. "Awarded {{date}}".
qrobject | falseWhere the verification QR code goes. Leave it out for the bottom-right corner, or false for none.

Check the positions with a preview before issuing — it returns a PNG and stores nothing:

curl https://server.credza.app/v1/templates/TEMPLATE_ID/preview \
  -H "Authorization: Bearer cz_live_…" -H "Content-Type: application/json" \
  -d '{ "fields": { "name": "Ama Mensah", "programme": "BSc Nursing" } }' --output preview.png

Move fields with PATCH /templates/:id (credentials already issued keep their layout). GET /templates lists every template, including ones designed in the Credza studio.

Issuing

Send up to 500 people at a time. Give each person your own external_id: if you send the same person again, you get their existing credential back instead of a duplicate, so retries are always safe.

POST /credentials

{
  "template_id": "TEMPLATE_ID",
  "recipients": [
    {
      "name": "Ama Mensah",
      "external_id": "UG-2041",
      "email": "ama@example.com",
      "fields": { "programme": "BSc Nursing", "date": "12 July 2026" },
      "images": { "photo": "data:image/jpeg;base64,/9j/4AAQ…" }
    }
  ],
  "send": ["email"]
}
recipients[].namestringThe person’s name. Fills a name or full_name field automatically.
recipients[].external_idstringYour ID for the person. Used to look up their credentials later.
recipients[].fieldsobjectA value for every text field in the template.
recipients[].imagesobjectPictures for image fields, as base64 (PNG, JPG or WebP, 2 MB each).
recipients[].email / phonestringOptional. Needed only if Credza should send the link. Texts go to Ghana mobile numbers.
sendarray["email"], ["sms"] or both. Only new credentials are sent.
expires_atYYYY-MM-DDOptional expiry date.

For one person, send recipient instead of recipients and you get a single credential back.

Each new credential uses 1 credit from your organisation’s balance; people who already hold one aren’t charged again. Check the balance with GET /credits. If there aren’t enough, nothing is issued and you get a 402 — top up in Credza → Billing.

Response

{
  "data": [{
    "id": "7F3K-9Q2M-XA",
    "status": "valid",
    "external_id": "UG-2041",
    "recipient": { "name": "Ama Mensah", "email": "ama@example.com", "phone": null },
    "fields": { "name": "Ama Mensah", "programme": "BSc Nursing", "date": "12 July 2026" },
    "verify_url": "https://credza.app/verify/7F3K-9Q2M-XA",
    "image_url": "https://server.credza.app/api/public/credentials/7F3K-9Q2M-XA/image",
    "pdf_url": "https://server.credza.app/api/public/credentials/7F3K-9Q2M-XA/pdf",
    "issued_at": "2026-07-12T09:30:00.000Z",
    "created": true
  }],
  "created": 1,
  "existing": 0
}

Showing credentials

When someone signs in to your app, fetch their credentials with your ID for them:

curl "https://server.credza.app/v1/credentials?external_id=UG-2041" \
  -H "Authorization: Bearer cz_live_…"

The image_url, pdf_url and verify_url links are public and safe to put straight into your page. Add ?width=800 to the image for a smaller size.

In your page

<img src="{image_url}?width=1200" alt="Ama Mensah’s certificate">
<a href="{pdf_url}">Download PDF</a>
<a href="{verify_url}">Verify</a>

Lists are newest first, 25 at a time (up to 100 with limit). Pass next_cursor as cursor for the next page. Filter by template with template_id.

Verifying

Every credential has a public verification page at its verify_url, which its QR code opens. To build your own, look up the ID someone enters — any case, with or without dashes:

curl https://server.credza.app/v1/verify/7f3k9q2mxa \
  -H "Authorization: Bearer cz_live_…"

The response is the credential with "valid": true when it’s neither revoked nor expired, and a 404 for IDs your organisation didn’t issue.

Revoke and resend

GET /credentials/:idOne credential.
POST /credentials/:id/revoke{ reason? }Marks it revoked everywhere, straight away. Its image and PDF stop working.
POST /credentials/:id/reinstateUndoes a revoke.
POST /credentials/:id/send{ channels }Emails and/or texts the link again.
DELETE /templates/:idRemoves a template. Credentials issued from it stay valid.

Errors and limits

Errors return a status code and a message you can show or log. Validation errors list every problem at once:

HTTP 422
{
  "error": {
    "code": "validation_error",
    "message": "1 problem with this request.",
    "details": [{ "path": "recipients.0.fields.programme", "message": "Required by this template." }]
  }
}
401 unauthorizedMissing, wrong or revoked key.
402 insufficient_creditsNot enough credits. details has needed and balance.
404 not_foundNo such template or credential in your organisation.
409 conflictThe action doesn’t fit the current state, e.g. sending a revoked credential.
413 payload_too_largeRequests are up to 20 MB. Send fewer people at a time.
422 validation_errorCheck details for what to fix.
429 rate_limitedUp to 300 requests a minute per key, and 30 a minute for previews, templates and issuing. Wait for Retry-After seconds.