Appearance
EBG Tokenizer — API reference (for integrators and LLM-assisted clients)
This document is self-contained: you do not need access to any source repository. Paste it into a chat with an LLM when building clients, curl scripts, or integrations.
The EBG Tokenizer is a JSON HTTP API that talks to certificate (ERC-721) collections and a factory on Arbitrum (chainId 42161). Clients send JSON only and never submit private keys. Write actions (deploy collection, mint, update certificate data) are submitted onchain by the hosted service when that deployment is set up for signing.
Reference deployment (replace with your operator’s URL if different):
bash
BASE_URL="https://ebg-tokenizer.u3dev.deno.net"All example paths below are appended to BASE_URL (e.g. GET https://ebg-tokenizer.u3dev.deno.net/).
Quickstart
Typical flow: discover the API → (if required) send x-api-key on protected routes → create a certificate collection → mint an NFT → read tokenURI or public metadata.
flowchart LR create["POST /factory/certificates"] mint["POST /certificates/:address/mint"] create -->|certificateAddress| mint
- Discover —
GET /returns JSON describing the service and route prefixes. - Authentication — If your operator gave you an API key, add
x-api-key: <secret>on/factory,/certificates, and/keys. If you get 401, you need a key or the wrong key. Omit the header only when the operator confirms auth is disabled for that deployment. - Create a collection —
POST /factory/certificateswithnft.name,nft.symbol, and optionallynft.baseUri. ReadcertificateAddressfrom the response. - Mint —
POST /certificates/{certificateAddress}/mintwith recipient (to,recipient, orowner) and certificate fields undercertificate,data, orcertificateData. - Read —
GET /certificates/:address/token-uri/:tokenId(or.../tokens/:tokenId/tokenURI). Public NFT metadata:GET /metadata/42161/:certificateAddress/:tokenIdorGET /metadata/42161/:certificateId/:tokenId.
Example curls (add -H "x-api-key: YOUR_KEY" to the POST lines when your deployment requires it):
bash
BASE_URL="https://ebg-tokenizer.u3dev.deno.net"
curl -sS "$BASE_URL/"
curl -sS -X POST "$BASE_URL/factory/certificates" \
-H "Content-Type: application/json" \
-H "x-api-key: YOUR_KEY" \
-d '{"nft":{"name":"My Cohort","symbol":"CERT","baseUri":"https://example.com/meta/"}}'
curl -sS -X POST "$BASE_URL/certificates/0xYourCertificate/mint" \
-H "Content-Type: application/json" \
-H "x-api-key: YOUR_KEY" \
-d '{"to":"0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb","certificate":{"registration_date":1710892800,"delivery_correlative":"2024-001","participant_names":"Ada","participant_last_names":"Lovelace","course_name":"Intro","hours_number":40,"sessions_number":10,"issuing_institution":"Example University","image_url":"https://example.com/img.png","certificate_url":"https://example.com/cert.pdf"}}'Using this document with an LLM
- Include this entire file plus concrete values:
BASE_URL, whether you have anx-api-key, certificate contract address (0x…), and token IDs. - Requests with a JSON body must use
Content-Type: application/json. - Build URLs as
{BASE_URL}{path}with no double slashes (e.g.BASE_URLhas no trailing slash). - Errors are JSON:
{ "message": string }. - Metadata for wallets and marketplaces:
GET {BASE_URL}/metadata/42161/{addressOrCertificateId}/{tokenId}— public, no API key.addressOrCertificateIdis either the certificate contract address or a decimal factory certificate id. POST /keysreturns the new secret inkeyonce — save it immediately; list endpoints never return secrets again.
Conventions
| Topic | Detail |
|---|---|
| Requests with a body | Content-Type: application/json |
| Onchain integers in responses | Often decimal strings (e.g. "42", "0x…" hashes as strings) |
| Success bodies | Route-specific JSON (see catalog below) |
| Errors | { "message": string } |
| Typical HTTP status | 400 — validation / bad input; 401 — missing or invalid API key; 403 — wrong key capability; 404 — not found; 500 — server/config (e.g. reverts surfaced as messages); 502 — some upstream/chain errors |
Use the BASE_URL your operator provides. The URL above is the reference hosted instance; other operators may expose the same API at a different origin.
Authentication (x-api-key)
Whether API keys are required depends on how the deployment was configured. If authentication is enabled, requests to /factory, /certificates, and /keys must include a valid key. If you receive 401, supply x-api-key or ask your operator for a key.
| Header | Value |
|---|---|
x-api-key | A master, minter, or read key from your operator, or a minter/read key previously issued via POST /keys (master only) |
OPTIONS requests skip API key validation (CORS preflight).
Public (no x-api-key when auth is enabled):
GET /— API discovery JSONGET /metadata/...— ERC-721 metadata documentsOPTIONS— any path
Roles (when auth is enabled):
| Role | /keys | /factory, /certificates |
|---|---|---|
| master | Full access (issue, list, revoke issued keys) | All methods |
| minter | 403 | All methods (GET/HEAD and mutating) |
| read | 403 | GET and HEAD only; POST/PUT/PATCH/DELETE → 403 |
Issued keys: POST /keys (master only) creates minter/read keys; the plaintext secret is returned once in the response. Bootstrap keys from the operator are not created through HTTP.
Certificate JSON schema
Used for mint (POST .../mint), full replace (PUT .../tokens/:tokenId), and parsed fields on PATCH. Field names are exact.
| Field | Type | Notes |
|---|---|---|
registration_date | number / string | Integer (Unix seconds in typical usage); accepts finite number or decimal string |
delivery_correlative | string | |
participant_names | string | |
participant_last_names | string | |
course_name | string | |
hours_number | number / string | Integer |
sessions_number | number / string | Integer |
issuing_institution | string | |
image_url | string | |
certificate_url | string |
API response shape for onchain certificate reads mirrors the struct with bigint fields as strings:
registration_date, hours_number, sessions_number as decimal strings; other fields unchanged strings.
PATCH (PATCH /certificates/:address/tokens/:tokenId) applies only keys present in the body. Updatable keys (each may trigger a separate transaction): registration_date, delivery_correlative, participant_names, participant_last_names, course_name, hours_number, sessions_number, issuing_institution, image_url, certificate_url. Empty patch → 400 No certificate fields to update. Response: { "txHash": "<last tx>", "updatedFields": <number> }.
GET /
Returns JSON metadata for the service, for example:
json
{
"title": "EBG Tokenizer API",
"version": "1.0.0",
"description": "API for the EBG Tokenizer",
"routes": [
{ "path": "/factory", "description": "Factory routes" },
{ "path": "/certificates", "description": "Certificate routes" },
{ "path": "/metadata", "description": "Metadata routes" },
{ "path": "/keys", "description": "API key management" }
]
}/factory
Base path: /factory. These routes read or write the onchain factory contract configured for the deployment. Write routes return 5xx if the operator has not enabled server-side transaction submission.
POST /factory/certificates
Creates a new certificate collection onchain.
Body:
json
{
"nft": {
"name": "…",
"symbol": "…",
"baseUri": "optional; aliases: base_uri, _base_uri"
}
}name/_nameandsymbol/_symbolare accepted (first present wins per field group).- If
baseUri(or alias) is omitted or empty, the server setsbase_urito{publicMetadataBase}/metadata/42161/{certificateId}/
using the next certificate id, wherepublicMetadataBaseis configured on the deployment (HTTPS/HTTP origin, no trailing slash). If that base is missing, creation fails with a server error. - Non-empty manual
baseUriis used as-is; length must fit onchain (max 80 characters).
Success: txHash, certificateAddress, certificateId, index, details (id, address, name), resolvedBaseUri.
Failure: 400 for invalid/missing JSON or fields; 500 if certificate id mismatch after create (e.g. concurrency).
GET /factory/certificate-count
Response: { "certificateCount": "<bigint string>" }.
GET /factory/certificates
Lists all certificate collections. Response: certificateCount, certificates (array of { id, address, name }).
GET /factory/certificates/:index
index must be an integer. 404 if no contract at index (zeroAddress). Response: index, certificateAddress, details.
GET /factory/minter-role
Response: { "minterRole": "0x…" }.
GET /factory/mints
Response: { "mints": "<bigint string>" }.
GET /factory/maximum-mints
Response: { "maximumMints": "<bigint string>" }.
/certificates
Base path: /certificates. :address is the certificate contract (checksummed 0x).
Mutating routes require the deployment to submit transactions on your behalf. Mint is executed on the factory as mint_certificate with the certificate address, tuple, and recipient.
Writes
| Method | Path | Description |
|---|---|---|
POST | /certificates/:address/mint | Mint one NFT; body must include recipient and certificate data |
PUT | /certificates/:address/tokens/:tokenId | Replace full certificate tuple for tokenId |
PATCH | /certificates/:address/tokens/:tokenId | Partial update (see Certificate schema / PATCH note) |
POST /certificates/:address/mint body:
- Recipient:
toorrecipientorowner(valid address). - Certificate data: object under
certificateordataorcertificateData(same fields as Certificate schema). - Optional
certificateAddress(or legacycertificateas string): if present, must match:address.
Success: mint (tokenId, certificateAddress, mintedTo), transaction (hash, blockNumber, status, gasUsed).
PUT … body: certificate object only (full tuple). Response: { "txHash": "…" }.
Reads
| Method | Path | Response (typical) |
|---|---|---|
GET | /certificates/:address/tokens/:tokenId/tokenURI | { "tokenURI": "…" } |
GET | /certificates/:address/tokens/:tokenId/certificate | Certificate JSON (numeric fields as strings) |
GET | /certificates/:address/balance-of/:account | { "balance": "…" } |
GET | /certificates/:address/owner-of/:tokenId | { "owner": "0x…" } |
GET | /certificates/:address/approved/:tokenId | { "approved": "0x…" } |
GET | /certificates/:address/token-uri/:tokenId | { "tokenURI": "…" } (alias path) |
GET | /certificates/:address/total-supply | { "totalSupply": "…" } |
GET | /certificates/:address/token-by-index/:index | { "tokenId": "…" } |
GET | /certificates/:address/token-of-owner-by-index/:owner/:index | { "tokenId": "…" } |
GET | /certificates/:address/name | { "name": "…" } |
GET | /certificates/:address/symbol | { "symbol": "…" } |
GET | /certificates/:address/owner | { "owner": "0x…" } (contract owner) |
GET | /certificates/:address/is-approved-for-all/:ownerParam/:operator | { "isApprovedForAll": true/false } |
GET | /certificates/:address/is-minter/:account | { "isMinter": true/false } |
GET | /certificates/:address/nonces/:tokenId | { "nonce": "…" } |
Enumeration of deployed collections uses GET /factory/certificates and GET /factory/certificate-count, not this prefix.
Example mint body
json
{
"to": "0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb",
"certificate": {
"registration_date": 1710892800,
"delivery_correlative": "2024-001",
"participant_names": "Ada",
"participant_last_names": "Lovelace",
"course_name": "Introduction to Topics",
"hours_number": 40,
"sessions_number": 10,
"issuing_institution": "Example University",
"image_url": "https://example.com/image.png",
"certificate_url": "https://example.com/certificate.pdf"
}
}/metadata
Public: no API key. Serves ERC-721/OpenSea-style metadata JSON so tokenURI (baseURI + decimal tokenId) can resolve to this HTTP resource.
GET /metadata/:chainId/:addressOrCertificateId/:tokenId
chainId: must be 42161. Other values → 400Unsupported chainId.addressOrCertificateId: either a checksummed certificate contract address (0x…), or a decimal non-negative certificate id (factory ordering); the service resolves a numeric id to the contract address. Invalid → 400; missing deployment → 404.tokenId: decimal integer.
Reads onchain certificate data for tokenId and returns JSON. Response headers includeCache-Control: public, max-age=3600, s-maxage=86400.
Shape (illustrative):
json
{
"name": "…",
"description": "…",
"image": "https://…",
"external_url": "https://…",
"attributes": [
{ "trait_type": "Registration date", "value": "…" },
{ "trait_type": "Course name", "value": "…" }
]
}image and external_url map from image_url and certificate_url onchain; attributes list echoes certificate fields.
/keys
When API key auth is enabled, only a master key may access these routes.
POST /keys
Body: { "role": "minter" | "read", "label"?: string }
201 response: id, key (plaintext secret; store immediately), role, optional label, createdAt.
GET /keys
200: { "keys": [ { "id", "role", "createdAt", "label"? }, … ] } (secrets are never listed).
DELETE /keys/:id
204 if revoked; 404 if id unknown.
Integration notes
base_urilength: Onchain limit is 80 characters; longer values return a validation error.- Mint path: HTTP mint uses the factory contract’s
mint_certificateflow, not an NFT contract–only entrypoint you call separately. - Auto
base_uriwhen omittingnft.baseUri: The service sequences creation sotokenURIcan point at this API’s/metadata/...URLs. Under heavy concurrency or multiple isolated instances, rare ordering issues are possible; your operator may coordinate writes. - Trust and network access: Treat write endpoints like privileged infrastructure. Use API keys and network controls when the operator exposes this API beyond trusted callers.