- 1Introduction
- 1.1API status and stability
- 1.2Authentication and authorisation
- 1.3Premium features
- 2Basics
- 2.1Timestamps, dates, and times
- 2.2Node
- 2.3Connection
- 2.4Standards
- 2.5Directives
- 3Domain model
- 3.1Assets
- 3.2Claims and evidence
- 3.3Updates
- 3.4Files
- 3.5Asset history
- 3.6Actors
- 3.7Networks
- 3.8Awards
- 3.9Registries
- 3.10Asset Lenses
- 3.11Asset Standards
- 3.12Integrations
- 4Queries
- 4.1Asset
- 4.2Actor
- 4.3Update
- 4.4Notifications
- 4.5File
- 4.6Networks
- 4.7Registries
- 4.8Lenses
- 4.9Asset standards
- 4.10Enumerations
- 4.11Integrations
- 4.12Filtering and ordering connections
- 5Mutations
- 5.1Users
- 5.2Actors
- 5.3Assets
- 5.4Asset relationships
- 5.5Claims
- 5.6Burning an asset
- 5.7Uploading a file
- 5.8File relationships
- 5.9Bridging an asset
- 5.10Networks
- 5.11Registries
- 5.12Lenses
- 5.13Asset standards
- 5.14Theming
- 6Subscriptions
- 6.1Update
- 7Errors
1 Introduction
The Geora protocol is a blockchain-based system for managing and securing sustainable supply chains. It provides simple tools and workflows to create solutions that provide rich data traceability, secure payments and real time finance.
This page provides reference documentation for the Geora GraphQL API. For learning-focused content and tutorials, please see https://help.geora.io.
The API schema is directly generated from this document, and you can find the generated output file here.
1.1 API status and stability
Different parts of the Geora API are classified according to their stability. Each of these stability levels have certain guarantees for the user.
- LIVE
-
Stable. No breaking changes to the API without consultation and approval from existing users
- BETA
-
Stable. Breaking changes will only occur for critical security issues.
Geora uses beta APIs in our own product and production projects, but they are newer APIs that may contain some small bugs.
- ALPHA
-
Unstable. Breaking changes may occur at any time. Do not use in production.
Geora provides early documentation of alpha APIs to encourage feedback from potential users - please feel free to contact us with thoughts and ideas on these APIs.
We include the following as breaking changes:
- Removing an existing field or object
- Removing arguments to a field, query, or mutation
- Adding non-optional arguments
- Changing existing types or response types
- Making an existing non-nullable field nullable
We do NOT class the following as breaking changes:
- Human-readable error messages: the error type and code remains constant, but the help text may change
- Additive changes, including new fields, queries, mutations, and optional arguments
- Making a nullable field non-nullable
Please note that we are in the process of making many fields in the API non-nullable which were previously nullable. For most users this will have no effect, but if you generate strong types from the GraphQL schema definition you should be aware of this change! Please reach out if this is a concern for you so we can keep you up to date.
The @alpha
and @beta
directives appear on all fields with a non-live status. You can use this during schema introspection to filter out APIs based on their stability.
1.2 Authentication and authorisation
Geora uses expiring JWTs for authentication. Read more here.
The queries and mutations which require a token are marked with the requiresActor
or requiresActorOrCapability
directives.
1.3 Premium features
While most of the Geora API is free to use, some features like theming and unlimited certificates require a paid account (see here). The requiresPayingUser
directive enforces that the calling user has the required minimum subscription plan.
2 Basics
This section explains some of the common ideas that are shared across the Geora API.
2.1 Timestamps, dates, and times
The TimestampUTC
scalar returns an ISO-8601 timestamp string in the UTC zone. TimestampTZ
does the same but includes a time zone specifier.
The Date
type represents a date as an ISO-8601 extended format calendar date string, like 2006-08-14
.
The TimeTZ
type represents a time of day as a ISO-8601 time carrying a time zone, like T02:34:56-06:00
.
2.2 Node
You can think of the Geora data model as a graph, containing objects and their links to each other. For example, an asset is linked to actors by ownership and permissions, and files are linked to assets by evidence attachments.
The Node
interface is implemented by all objects (or vertices) in this graph:
- assets
- actors
- files
- updates
The type for each of these vertices extends Node
.
The node ID
is a globally unique identifier for the vertex. Using unique IDs permits a standardised refetch query called node
, which can be used to efficiently implement UI caching and refetching.
2.3 Connection
A connection is used where a query or field returns a list of objects; it provides cursor-based pagination in an efficient way. A connection contains a list of edges, each linking to another node. For example, referring to a
Any type ending in Connection
must provide these fields:
edges
-
a list of edges.
pageInfo
-
an object which provides pagination information.
Queries that return a Connection
support forward pagination via the first
and after
arguments:
first
-
requests a certain number of edges to be returned (default: 10)
after
-
specifies an edge cursor from which to start (default: start of list)
The PageInfo
object provides metadata that helps the client determine whether there are more pages to iterate through. It has fields startCursor
and endCursor
which provide the cursor values of the first and last edges in the list.
Cursors are opaque base64-encoded strings which uniquely identify an edge in the connection.
2.3.1 Edge
An edge represents one item in the paginated list and must provide these fields:
node
-
the item (e.g. an
Asset
) cursor
-
a string identifying this edge for purposes of pagination
2.3.2 Using connections
It helps to see a concrete example of using a connection. In this case, the caller wants to see all assets that they own. They use the actor > assets
query, which returns a connection.
To see the first page of assets, they request 10 items in the connection:
{"YWN0b3J8NzJjN2U5YzMtOGViNC00ZjIyLWE5NDktYjljMTVkYTUzNzYw") {
actor(id: 10) {
assets(first:
pageInfo {
hasNextPage
hasPreviousPage
startCursor
endCursor
}
edges { cursor node { id } }
}
} }
This returns the ten assets under the edges
key, as well as a PageInfo
object that looks like:
{
"hasNextPage":true,
"hasPreviousPage":false,
"startCursor":"YXNzZXRWZXJzaW9ufDg3MjM0ODk3Mjg5NDcyMwo=",
"endCursor":"YXNzZXRWZXJzaW9ufDg3MzIxMjQyMzQzMjQK"
}
From the response, the caller can see that there is at least one more page of assets available. For the next query, they set the after
argument to the value of endCursor
, in order to see the next ten assets.
{"YWN0b3J8NzJjN2U5YzMtOGViNC00ZjIyLWE5NDktYjljMTVkYTUzNzYw") {
actor(id: 10, after: "YXNzZXRWZXJzaW9ufDg3MzIxMjQyMzQzMjQK") {
assets(first:
pageInfo {
hasNextPage
hasPreviousPage
startCursor
endCursor
}
edges {
cursor
node {
id
}
}
}
} }
When this query returns, hasNextPage
is false
and there are no more assets to view.
2.4 Standards
The Geora API implements the following GraphQL standards:
- Global Object Identification: identifies objects via a globally unique ID, which can be used to refetch using the
node
query - Relay Cursor Connections: efficiently paginates lists returned from the API
2.5 Directives
These directives are used for API implementation and should not have an effect on usage.
3 Domain model
This section describes the various objects exposed by the Geora API; in particular the top-level objects that inherit from the Node
interface.
3.1 Assets
An Asset
is a record containing the history of a supply-chain product.
A Unit
is the symbol for Geora’s supported measurement units.
A Unit
can be provided as an argument to the quantity
field to convert the primaryValue
of the asset into that unit.
The primaryUnitName
, primaryUnitPlural
and primaryUnitSymbol
will be null
if the supplied primaryUnit
on the asset does not match a Geora-supported measurement unit.
The supportedUnits
query can be used to return all of the units that Geora supports.
The AssetStatus
indicates whether an asset has been burned (made read-only), or moved to another blockchain. In the future, more asset statuses may be added as options in this enum, such as an IN_ESCROW
status for finanical agreements.
Any actor that has partial or full ownership of an asset will be present in the actorRelationships
connection.
The connection contains the related actor as its node, but additionally adds relationship data to the edges, codified in the ActorRelationshipEdge
type.
ownershipPercentage
is a percentage value between 0 and 1, but is DEPRECATED. Due to the behaviour of the GraphQL Float type, in some scenarios you will experience rounding errors which cause ownership transfers to fail. Please use exactOwnershipPercentage
instead.
exactOwnershipPercentage
is a percentage value between 0 and 1. This has a different internal representation to ownershipPercentage
.
Assets are related to other assets by relationships like collections or parenthood.
A collection is an asset which contains one or more collected assets. This represents scenarios like a grain silo; where the silo is an asset containing multiple barley assets.
A parent is an abstract “precursor” asset to the current asset. This can be used to represent processing, as in the processing of hops to make beer, or the merging of multiple assets into one.
Each asset relationship edge contains the relationship type. When viewing the asset, the bidirectional nature of relationships is shown; when asset A COLLECTS
asset B, asset B is COLLECTED_BY
asset A, and when asset C is a PARENT_OF
asset D, asset D is a CHILD_OF
asset C.
When creating relationships, AssetRelationshipInputType
is used instead.
Assets may have claims made against them, which are key-value pairs asserting information about the asset. Substantiated claims are backed up by file attachments called evidence.
Updates provide the link to past versions of an asset. On UpdateEdge
, the location will always be PAST
, representing the update occurring backwards in time in relation to the queried version. Only successful updates are shown in this connection, and are listed in reverse chronological order.
Updates in the PAST
were made before (further back in time) than the currently-queried version, and assets in the FUTURE
were made after. The update which created the currently-queried version will be the newest asset in the PAST
.
The certifications of an asset are found in the certifications
connection.
3.2 Claims and evidence
A claim is a key-value pair asserting some property of an asset, which may be backed by evidence files. Claim labels are case-insensitive, and the API gives no guarantees on the case of the returned label. Claims differ from the other types by not implementing the Node
interface.
The value
of a claim is associated with a type. This provides more information about the claim than is stored in the rawValue
.
Below is a list of supported types:
Claim Type | Description | Example |
---|---|---|
TextClaimValue NumberClaimValue QuantityClaimValue |
An arbitrary string that can have any value. A floating point, double-precision number. A floating point magnitude and a unit of measurement. | "APW1" 112.2 90.2mt |
3.3 Updates
An Update
represents a change in the asset’s history that links together two versions.
If the status is ERROR
, error
will provide a description of the error.
A successful update records the change in claims on the asset under the changes
field.
3.4 Files
Any actor can upload files to be used as evidence on asset claims.
issuer
links to the actor who uploaded the file.
All files are stored in IPFS, and ipfsHash
will return the IPFS multihash string of the file in the Geora private IPFS network (such as QmZJ1xT1T9KYkHhgRhbv8D7mYrbemaXwYUkg7CeHdrk1Ye
).
To view the file, use the url
file. This will generate a temporary link to the file in centralised storage. The link will only last for ten minutes.
The actorRelationships
connection lists actors with one or more permissions on the file. The available permissions are:
SET_PERMISSION
-
a list of edges
- pageInfo
-
an object which provides pagination information
3.5 Asset history
3.6 Actors
The Actor
node provides the actor’s name and auto-generated Ethereum address.
You can access all the assets that an actor has ownership of (i.e. ownershipPercentage > 0
) with the assets
connection.
We can list all the claims of an actor using the claims
field.
Unlike Claim
s on assets, there is no evidence as yet on ActorClaims
.
We can get all the registries an actor belongs to, along with their current certification status.
The edge’s status
field will be null
if the userType
is ISSUER
.
We can get the certification history of a user.
And their production details.
The actor’s status can be certified, uncertified, or revoked, and each case gives different data. If they’re certified the issuer who granted it, when it was granted, and when it expires is given. If they’re uncertified the time when the last certification expired is given, if they’ve never been certified this is null. If their certification was revoked then the timestamp and the issuer who revoked it is given.
Email contact information, and whether the address has been successfully verified.
3.7 Networks
Networks are the organising mechanism around which user gather to exchange assets and asset standards. Within a network a manager may issue awards to network members, and roles may be granted to confer permissions to perform certain operations or view certain data on assets.
3.7.1 Network Members
We can get the list of members of the network ordered by various fields, such as
- their name
- whether they have any awards,
- when they most recently received an award,
- the earliest time when an award they have been given will expire.
The current awards that the user holds for this network are listed on the edges of the connection.
3.7.2 Network Tags
3.8 Awards
An award may be given by managers of a network to members of the network to reflect that they have met some standard of quality or process, or just as a token of membership to the network.
Currently issued awards carry the timestamp of when they were given and when they will expire, if they have an expiry.
3.9 Registries
Registries have issuers and users, issuers manage the certification status of the users. The registry can also be queried for the overall production statistics.
There are three types of user in a registry. An issuer can issue certificates to users, and users have a certification status. If the current user is an admin user they will have ADMIN access at least to every registry if they don’t already have one of the other two levels.
The edge’s status
field will be null
if the userType
is ISSUER.
The issuer can invite new users to a registry.
3.9.1 Registry Verification
When registries are initially created, they are not verified in the Geora system. Unverified registries have a limit to the number of users that can be created and participate in the registry. Once the registry is verified by Geora, this limit is removed.
3.10 Asset Lenses
An asset lens is a view / set of permissions which can be applied to any number of assets. Each lens has a name and a description; the user can choose to show asset’s class, value, and ownership information. Optionally, time bounds on asset events can be set, and a list of claims which will be shown through the lens.
The claimsWhitelist
has some unique behaviour when creating or updating an lens
.
When creating with lensCreate
, not specifying the claimsWhitelist
means that the lens will not show any claims on this asset or, in other words, the claimsWhitelist
is empty.
When updating with lensUpdate
, not specifying the claimsWhitelist
will leave the whitelist untouched. This has 2 consequences:
- Leaving this field empty will not change the lens’ existing whitelist.
- Providing an
empty array
will blacklist all asset claims in a lens.
When a lens has been created, it can be applied to one or more assets to create lens instances. When viewing these instances, the lens filters out the information visible on the asset. A lens can be deactivated and reactivated, and we keep track of various statistics around people using the lens. Finally, visitors can leave messages for the owner of the lens to read, and they can leave a return email address if they wish.
The UpdatesConnection
in LensInstances only contains successful updates.
The decision of whether to show claim data is done in a “white-list” fashion, in that only the explicitly approved claims are revealed. If any claims are present that the lens owner failed to anticipate then they will not be visible. For each claim the lens owner can also say whether users should be able to view the evidence files attached to the claim.
3.11 Asset Standards
An asset standard is used to build assets which are compatible across multiple users and their supply chains. It consists of a set of required and optional claims, transformations, and metadata that define the “shape” of an asset.
The asset standard usage status enum is useful for filtering and sorting the most relevant standards for a user. IN_USE_BY_CALLER
means that the calling actor is the owner of at least one asset that uses this asset standard. CREATED_BY_CALLER
means that the calling actor is the creator of the standard. NETWORK
means that the standard has been created by a manager in a network that the actor is part of.
The corresponding input types:
3.11.1 Enumerations
Enumerations allow restricting the values of asset standard claims to a list of choices.
And the input types:
3.12 Integrations
4 Queries
GraphQL queries read data from the API.
Singular queries return an object by its ID. They work the same as the Node
query but don’t require fragment matching on returned type. If the caller does not have permission to view the object, the query will return null
and an error.
Plural queries return a Connection
.
4.1 Asset
The asset
query will return a single asset, if the caller has permission to view the asset.
The assets
query will return all assets for which the caller has permission to view.
4.2 Actor
The actor
query will return a single actor.
The actors
query will return all actors that were created by the calling user.
4.3 Update
The update
query will return a single update if the caller can view that update.
The updates
query will return all updates that a caller can view.
A calling actor can view an update if either of the following conditions are met:
- The actor created the update
- The actor has view permissions on the asset
4.3.1 History
The history of the user’s certification status is of interest, and can be fully queried. Any event such as granting, revoking, or extending certification is revealed here.
4.3.2 Production
The quantity in units and weight of TTO assets produced can be queried, aggregating over various time periods as given by Granularity
, grouped by certification status.
The where
defaults are from the beginning of time up to the current time, and PER_DAY
granularity.
4.4 Notifications
Give system users access to notifications addressed to them. A message may not have a from
field if it has come from an user unknown to the user. The metaData
field is a JSONified string which can be an empty JSON object.
We can set notifications as having been seen by the user so they won’t keep seeing the same ones.
4.5 File
The file
query will return a single file if the caller has the VIEW_FILE
permission.
The files
query will return all files for which the caller has the VIEW_FILE
permission.
4.6 Networks
The current actor may be a manager or a member of a network, but never both.
4.7 Registries
The edge’s status
field will be null
if the userType
is ISSUER.
4.8 Lenses
4.9 Asset standards
The assetStandard
query will return a single asset standard.
The assetStandards
query will return all asset standards and their status. It can be sorted and filtered by status to return only those standards in use or created by the caller.
4.10 Enumerations
4.11 Integrations
4.12 Filtering and ordering connections
Coming soon.
5 Mutations
Mutations make updates to the system state. All mutations are atomic.
5.1 Users
To reset the calling user’s API key and return a new autogenerated key, use userResetKey
.
5.2 Actors
You can create an actor by providing a name, and update them by changing their name. The actorCreate
mutation is the only mutation or query that doesn’t require a calling actor to be specified with the x-geora-actor
header key.
Claims which are being provided to can have absent or null ids, which means a claim with the label given is expected to not yet exist on the actor. If such a claim does exist an error is thrown. If the id given does not match the current latest version id then an error is also thrown.
An input claim can also have a null
value, in which case the claim will be deleted if the provided id is the latest id.
If you are the issuer of a registry, and want to invite new users to join Geora as part of your registry, you can use the actorCreatePending
mutation.
5.3 Assets
Assets are created and updated using the flexible AssetUpdateInput
type.
Calling any mutation that updates an Asset will return an Update
, with an initial status of pending. When the update has been processed, its status will change to successful.
When creating an asset, any omitted field will receive the default values.
class
:Unknown
quantity
:0, Unknown
claims
: noneactorRelationships
: the actor who created the asset is the owner, manager and custodian. No other actors have a relationshipassetRelationships
: none
When updating the asset, any omitted field will be unchanged in the update. Updating assets using the assetUpdate
mutation allows you to make multiple changes in the same update, but performs replacement on the provided collections. For example, providing an actorRelationships
array in assetUpdate
will replace all existing relationships. If this is not desired, use the more granular update functions below.
Any mutations to an asset are rejected if the asset status is BURNED
.
QuantityInput
is used to ensure that both quantity fields are set together or not at all.
If an assetStandard
is specified, but the asset does not conform to that standard, the update will be rejected.
5.4 Asset relationships
These functions provide finer-grained editing for relationships.
assetPut*
will update any existing relationships from the input to match the input, and create any new relationships.
assetRemove*
will remove all the specified relationships.
Note that all of the above will create a new Update
.
The assetAddToBulkCollection
mutation supports bulk “in-turns” to a silo or other container. The mutation:
- Adds a new asset relationship between the given asset and the collection asset
If transfer
is true, the mutation also:
- Increases the quantity of the collection by the quantity of the added asset
- Burns the given asset
If transfer
is true, this mutation will fail if the asset’s primary unit does not match that of the collection.
The assetRemoveFromBulkCollection
mutation does the opposite, removing the relationship and decreasing the collection quantity.
The Update
returned is for the collection asset.
5.5 Claims
assetPutClaims
will update any existing claims to match the input, and create any new claims.
5.6 Burning an asset
assetBurn
will change the status of the asset to BURNED
. This is a one-way operation.
5.7 Uploading a file
The fileCreate
mutation will upload and create a new file.
Upload
is a special type which receives a file from the request body’s multipart form data.
This means that the mutation must be called in a different way than the other mutations. Instead of taking a JSON query or mutation as the body, a form data object must be sent, containing three fields:
operations
: a JSON string containing thefileCreate
mutationmap
: a variable mapping0
: file data
To make this more concrete, a valid fileCreate
operation to upload blah.txt
with curl would look like:
curl "http://localhost:3131/v2" \
-F operations='{"query":"mutation($file: Upload!) {fileCreate(file:$file) {id}}","variables":{"file":null}}' \
-F map='{ "0": ["variables.file"] }' \
-F 0=@'blah.txt' \
-H 'x-api-user: 50d5463a-f4f1-42e3-9ebb-c20171ea0896' \
-H 'x-api-key: my-secret-key' \
-H 'x-geora-actor: YWN0b3J8NTBkNTQ2M2EtZjRmMS00MmUzLTllYmItYzIwMTcxZWEwODk2Cg=='
The map
field links the file sent in the form data with the mutation’s file variable.
5.8 File relationships
These functions provide finer-grained editing for file relationships.
filePut*
will update any existing relationships from the input to match the input, and create any new relationships.
fileRemove*
will remove all the specified relationships.
5.9 Bridging an asset
assetBridge
allows moving a Geora asset to another blockchain. Currently, we support bridging to the Ethereum mainnet. This is a one-way operation, and after bridging you will no longer be able to edit the Geora asset.
The chain
field on the Asset
type will provide details of the asset after bridging.
5.10 Networks
Creating a network requires only a name. The caller will become the first manager of the network.
5.10.1 Profile visibility
A member can change their network profile visibility with the networkProfilePrivacySet
mutation.
When PUBLIC
, a member is visible to other members in the network, and can be traded with.
When PRIVATE
, a member is only visible to network managers.
5.11 Registries
A registry can have different behaviour for passing certificates along a chain of ownership.
Anyone can create a new registry and become its first issuer.
ipfsHashOfLogo
has been deprecated - see Theme
API.
The recipient of an invitation can accept or reject it.
If for some reason an asset fails automatic certification, you can edit and resubmit it.
5.12 Lenses
Lenses can be created and updated given a definition.
Given an existing lens, the lens can be “instantiated” to apply it to an asset very easily. The underlying lens is shared between all assets it is applied to so that an update to the lens affects all instances as well.
5.13 Asset standards
Asset standards can be created and updated.
An asset standard can only be updated by its creator.
Individual stages and claims on the asset standard can be updated independently.
When using assetStandardClaimUpdate
, if the claim input has the same label as a claim that exists on that stage, the claim will be edited in-place. Otherwise, a new claim will be added to the stage.
When updating claims in asset standards, the new claims must be compatible with assets created with a previous revision of the standard. This means that new claims must either be optional or have a default value. The human-readable label and description can be changed at any time.
5.13.1 Enumerations
Enumerations allow restricting the values of asset standard claims to a list of choices.
5.14 Theming
Each registry has its own theme
attached. There is a default theme provided by Geora which can be configured by a registry issuer.
A theme
consists of a logo url and colour scheme.
The ColorHex
scalar is a hexadecimal string representing a valid CSS color. For example #e35b2f
or #f46f56
. Note that the ‘#’ should be included in the string.
The theme
of a registry can be queried by any actor (issuer or user) in the registry.
The theme
of a registry can be updated only by the issuer of a registry.
Note that fields in the ColorSchemeInput
are not compulsory. This is because each colour has a default value which will be applied if no value is given.
6 Subscriptions
To support instantaneous information when an event has been processed by the blockchain, the Geora API uses GraphQL Subscriptions to allow clients to connect and receive events from the server.
6.1 Update
Mutations performed in the Geora API are asynchronous. Most mutations return an Update
object which remains in a PENDING
state until the blockchain has processed the information.
The API supports subscriptions for Update
objects. Whenever a user’s Update
changes from the PENDING
state, an event is emitted to all listeners with the correct permissions.
Clients can subscribe to a particular Update
as below.
// In the graphql playground
subscription UpdateStatus {
"dXBkYXRlfDBiMDY2MDllLWMwZmMtNGYzYS05NWQ3LTQzYzNjYmRlZDNiYg==") {
update(id:
result {
status
}
} }
If the id
argument is omitted, the user will be subscribed to to all updates they have permission to view.
subscription UpdateStatus {
update {
result {
status
}
} }
7 Errors
When a query or mutation fails, the returned JSON body will contain an errors
field.
For example, the following JSON is a failed request to the assetUpdate
mutation, where the calling actor does not exist.
{
"errors": [
{
"message": "Could not find actor with ID YWN0b3J8NGI3YjFkMjAtZWM3Yi00YTI5LWI5OGEtZDJiMmRiNjhhMTM1",
"locations": [
{
"line": 2,
"column": 3
}
],
"path": [
"assetUpdate"
],
"extensions": {
"code": "FORBIDDEN",
}
}
],
"data": {
"assetUpdate": null
}
}
For each error, there will be a message
provided explaining the error, as well as a code
to help categorise errors. Note that the expected return data is null
when an error occurs.