Skip to content

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
  1. DiscoverGET / returns JSON describing the service and route prefixes.
  2. 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.
  3. Create a collectionPOST /factory/certificates with nft.name, nft.symbol, and optionally nft.baseUri. Read certificateAddress from the response.
  4. MintPOST /certificates/{certificateAddress}/mint with recipient (to, recipient, or owner) and certificate fields under certificate, data, or certificateData.
  5. ReadGET /certificates/:address/token-uri/:tokenId (or .../tokens/:tokenId/tokenURI). Public NFT metadata: GET /metadata/42161/:certificateAddress/:tokenId or GET /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 an x-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_URL has no trailing slash).
  • Errors are JSON: { "message": string }.
  • Metadata for wallets and marketplaces: GET {BASE_URL}/metadata/42161/{addressOrCertificateId}/{tokenId} — public, no API key. addressOrCertificateId is either the certificate contract address or a decimal factory certificate id.
  • POST /keys returns the new secret in key once — save it immediately; list endpoints never return secrets again.

Conventions

TopicDetail
Requests with a bodyContent-Type: application/json
Onchain integers in responsesOften decimal strings (e.g. "42", "0x…" hashes as strings)
Success bodiesRoute-specific JSON (see catalog below)
Errors{ "message": string }
Typical HTTP status400 — 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.

HeaderValue
x-api-keyA 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 JSON
  • GET /metadata/... — ERC-721 metadata documents
  • OPTIONS — any path

Roles (when auth is enabled):

Role/keys/factory, /certificates
masterFull access (issue, list, revoke issued keys)All methods
minter403All methods (GET/HEAD and mutating)
read403GET 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.

FieldTypeNotes
registration_datenumber / stringInteger (Unix seconds in typical usage); accepts finite number or decimal string
delivery_correlativestring
participant_namesstring
participant_last_namesstring
course_namestring
hours_numbernumber / stringInteger
sessions_numbernumber / stringInteger
issuing_institutionstring
image_urlstring
certificate_urlstring

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 / _name and symbol / _symbol are accepted (first present wins per field group).
  • If baseUri (or alias) is omitted or empty, the server sets base_uri to
    {publicMetadataBase}/metadata/42161/{certificateId}/
    using the next certificate id, where publicMetadataBase is configured on the deployment (HTTPS/HTTP origin, no trailing slash). If that base is missing, creation fails with a server error.
  • Non-empty manual baseUri is 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

MethodPathDescription
POST/certificates/:address/mintMint one NFT; body must include recipient and certificate data
PUT/certificates/:address/tokens/:tokenIdReplace full certificate tuple for tokenId
PATCH/certificates/:address/tokens/:tokenIdPartial update (see Certificate schema / PATCH note)

POST /certificates/:address/mint body:

  • Recipient: to or recipient or owner (valid address).
  • Certificate data: object under certificate or data or certificateData (same fields as Certificate schema).
  • Optional certificateAddress (or legacy certificate as 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

MethodPathResponse (typical)
GET/certificates/:address/tokens/:tokenId/tokenURI{ "tokenURI": "…" }
GET/certificates/:address/tokens/:tokenId/certificateCertificate 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 → 400 Unsupported 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 include
Cache-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

  1. base_uri length: Onchain limit is 80 characters; longer values return a validation error.
  2. Mint path: HTTP mint uses the factory contract’s mint_certificate flow, not an NFT contract–only entrypoint you call separately.
  3. Auto base_uri when omitting nft.baseUri: The service sequences creation so tokenURI can point at this API’s /metadata/... URLs. Under heavy concurrency or multiple isolated instances, rare ordering issues are possible; your operator may coordinate writes.
  4. 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.

Released under License.