Credza API
Create, share and verify certificates from your own system. Your people never need a Credza account.
Base URL
https://server.credza.app/v1How it works
- Upload your finished certificate as a PNG, JPG or PDF, and say where each detail goes: the name, the programme, a photo.
- Issue a credential for each person, with your own ID for them (for example a student number).
- 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.
- 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 }
}| background | string | Your 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[].key | string | Lowercase letters, numbers and underscores. You send a value for each key when issuing. |
| fields[].type | text | image | Text by default. Image fields take a picture per person, such as a photo. |
| fields[].size | number | Font size in points. Default 24. |
| fields[].font | sans | serif | script | Default sans. |
| fields[].align | center | left | right | Default center. |
| fields[].color | #RRGGBB | Default #111111. |
| fields[].text | string | Optional wording around the value, e.g. "Awarded {{date}}". |
| qr | object | false | Where 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.pngMove 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[].name | string | The person’s name. Fills a name or full_name field automatically. |
| recipients[].external_id | string | Your ID for the person. Used to look up their credentials later. |
| recipients[].fields | object | A value for every text field in the template. |
| recipients[].images | object | Pictures for image fields, as base64 (PNG, JPG or WebP, 2 MB each). |
| recipients[].email / phone | string | Optional. Needed only if Credza should send the link. Texts go to Ghana mobile numbers. |
| send | array | ["email"], ["sms"] or both. Only new credentials are sent. |
| expires_at | YYYY-MM-DD | Optional 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/:id | One credential. | |
| POST /credentials/:id/revoke | { reason? } | Marks it revoked everywhere, straight away. Its image and PDF stop working. |
| POST /credentials/:id/reinstate | Undoes a revoke. | |
| POST /credentials/:id/send | { channels } | Emails and/or texts the link again. |
| DELETE /templates/:id | Removes 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 unauthorized | Missing, wrong or revoked key. | |
| 402 insufficient_credits | Not enough credits. details has needed and balance. | |
| 404 not_found | No such template or credential in your organisation. | |
| 409 conflict | The action doesn’t fit the current state, e.g. sending a revoked credential. | |
| 413 payload_too_large | Requests are up to 20 MB. Send fewer people at a time. | |
| 422 validation_error | Check details for what to fix. | |
| 429 rate_limited | Up to 300 requests a minute per key, and 30 a minute for previews, templates and issuing. Wait for Retry-After seconds. |

