Webhooks
Introduction¶
Webhooks are a way for the custodian to communicate with MMI’s backend. MMI’s backend must keep track of transactions and signed messages for the following reasons:
- Providing updates of the status of transactions to the extension
- Billing of users, which is based on the AUD of custodial addresses.
- Tracking of activation, engagement, retention metrics
- Broadcasting transactions in the event that the custodian is not broadcasting them
MMI provides custodians with a URL, and credentials, and custodians are required to request these URLs with those credentials when the status of a transaction or signed message changes.
For example:
- When a transaction is create
- When a transaction is rejected or aborted
- When a transaction is complete
- When a signed message is signed
- When a signed message is rejected
The specification for webhooks is given in this appendix.
MMI will provide the custodian with the URL and credentials to use when making requests to MMI’s backend.
Webhook Specification¶
Endpoint: /v2/webhook/custodian
class WebhookRequest {
transaction?: {
id: string // This must match the transaction ID from the custodian_createTransaction method
type: string // In hexlified (0x...) format
from: string // Hexlified
to: string // Contract address or recipient (hexlified)
value: string // Can be null, 0x, 0x0 etc
gas: string // Hexlified
gasPrice?: string // Hexlified
maxFeePerGas?: string // Hexlified
maxPriorityFeePerGas?: string // Hexlified
signedRawTransaction?: string | null // The RLP-encoded signed transaction in hexlified format if the transaction is signed
nonce: string // Hexlified
data: string // Can be null, 0x, 0x0 etc
hash: string
status: {
finished: boolean // This transaction is finished - it has failed, or succeeded (been mined). There will be no more webhooks
submitted: boolean // The transaction has been submitted to the blockchain
signed: boolean // The transaction has been signed, and the nonce/hash is available
success: boolean // The transaction was successful, or is successful so far.
displayText: string // Text which is displayed to users
reason: string // The reason for the transaction status - for example, the failure reason
}
}
signedMessage?: {
id: string // This must match the signature ID from the custodian_sign or custodian_signTypeData method
address: string // Hexlified
signatureVersion: string // v3, v4 or personalSign
signature: string, // The hexlified signature
status: {
finished: boolean
signed: boolean
success: boolean
displayText: string
reason: string // The reason for the transaction status
}
},
metadata: {
userId: string // This must match the `sub` claim of the customer proof of the user who created the transaction
customerId: string // If users are part of some group, e.g. an organisation or fund, a unique ID for this organisation or fund (used for billing)
customerName: string // If users are part of some group, e.g. an organisation or fund, a human readable name for this organisation or fund (used for billing)
chainId?: string // In hexlified (0x...) format. Not usually included for signed messages
originUrl: string // As passed from the extension when the transaction was created
transactionCategory: string // As passed from the extension when the transaction was created
note: string // As passed from the extension when the transaction was created
traceId?: string // An ID for the webhook, which could be used for debugging
rpcUrl?: string // // The URL to which the transaction will be published. This can be omitted if none was originally sent or if the custodian does not wish to share this information
custodianPublishesTransaction?: boolean // Whether the custodian was requested to publish/broadcast the transaction - present in the original transaction parameters n
isTest?: boolean // Whether this is a test transaction or should otherwise be ignored for billing purposes
}
}
-
During development, we will provide a specific environment for the custodian as a sandbox for webhooks.
-
We assume that custodians are maintaining a separate dev or staging environment which triggers webhooks in our staging environment.
Headers¶
Content-type: application/json
Authorization: Bearer <your oauth token>
Obtaining the Oauth token¶
We provide the following:
- Client ID.
- Client secret.
- Auth audience.
- Token endpoint.
- Webhook endpoint.
Sample token request¶
curl --request POST \
--url $TOKEN_ENDPOINT \
--header 'content-type: application/json' \
--data '{"client_id":"$CLIENT_ID",,"client_secret":"$CLIENT_SECRET","audience": "$AUTH_AUDIENCE" grant_type":"client_credentials"}'
Sample token response¶
{"access_token":"<your-access-token>","expires_in":86400,"token_type":"Bearer"}
- Tokens last one day by default.
- There needs to be a mechanism to obtain new ones after they expire.
- The token is a JWT, so you can introspect the token and look for the exp property before using it. This is the epoch timestamp after which the token is expired.