Submitting a MassID
End-to-end guide for submitting a MassID — resolve participants, create the document, add events, and close.
Last updated on
Use this sequence as the base implementation pattern for submitting a complete MassID lifecycle through the Carrot API.
Prerequisites
Before you begin, ensure you have:
- A registered Network Integrator account with valid API credentials
- Participant and address data ready — resolve each one first (retrieve by key or create it) so you can
reference it by
participantIdandaddressId, as shown in Step 1 - Familiarity with core concepts — especially the immutable event-sourced model
Step 1: Resolve participants and addresses
Documents and events reference participants and addresses by ID (some events, like CLOSE, only need a participant). Before submitting, resolve each
one — look it up by key, or create it — and keep the returned participantId and addressId.
Retrieve by key. Look up an existing participant by its natural key — country code, tax ID type, and tax ID:
GET /participants?countryCode=BR&taxIdType=CNPJ&taxId=11111111111111If it exists, reuse the returned participantId and list its addresses to find the addressId:
GET /participants/{participantId}/addressesCreate when missing. If the participant does not exist yet, create it, then add an address to it:
POST /participants
{
"countryCode": "BR",
"name": "Example Company",
"taxId": "11111111111111",
"taxIdType": "CNPJ",
"type": "COMPANY"
}POST /participants/{participantId}/addresses
{
"name": "Main Facility",
"street": "Rua das Colinas",
"number": "500",
"neighborhood": "Centro",
"city": "São Paulo",
"countryState": "São Paulo",
"countryCode": "BR",
"zipCode": "08575720",
"latitude": -23.5489,
"longitude": -46.6388
}Each create call returns the generated id — use it as participantId / addressId in the next steps.
Required fields: participant — countryCode, name, taxId, taxIdType, type; address — city,
countryCode, countryState, name, number, street. See the
Participants API for the full request and response schema.
Reusing existing records
Creating a participant or address that already exists is safe only if you send identical data — the platform matches on the natural key and rejects conflicting values. Prefer retrieving by key and reusing the returned ID.
Step 2: Create the document
Create the root record with classification and baseline visibility fields, referencing the participant and address you resolved in Step 1:
POST /v1/documents
{
"category": "MassID",
"type": "YOUR_WASTE_TYPE",
"measurementUnit": "kg",
"externalCreatedAt": "2026-03-01T10:00:00.000Z",
"isPublic": true,
"isPubliclySearchable": true,
"participantId": "participant-id-from-step-1",
"addressId": "address-id-from-step-1",
"externalId": "your-internal-tracking-id",
"deduplicationId": "unique-id-generated-before-first-attempt"
}| Field | Required | Description |
|---|---|---|
category | Yes | Always MassID for mass tracking documents |
type | Yes | Waste type — defined per methodology (see note below) |
measurementUnit | Yes | kg for recycling, kg CO₂e for carbon |
externalCreatedAt | Yes | ISO 8601 timestamp of the real-world document creation |
isPublic | Yes | Whether the document is publicly visible |
isPubliclySearchable | Yes | Whether the document appears in public search |
participantId | Yes | ID of the participant resolved in Step 1 |
addressId | Yes | ID of the address resolved in Step 1 |
externalId | No | Your internal ID for reconciliation — useful for mapping back to your system |
deduplicationId | No | Idempotency key — see tip below |
Deprecated: inline participant and address
You can still send full participant and address objects inline instead of
participantId/addressId, and the platform will create them on first use. This inline form is
deprecated and will be removed in a future release — resolve participants and addresses in
Step 1 and reference them by ID instead.
Methodology-specific values
The type field (waste type) and measurementUnit are defined by your target methodology. See
the methodology integration guides for the
specific values required.
Reference: Documents API.
Step 3: Append timeline events
Append events in chronological order to represent operational steps. Each event is immutable once created.
ACTOR events
ACTOR events register participant roles on the document timeline. Each requires a label identifying the role, plus the participant and address it applies to, referenced by ID:
POST /v1/documents/{documentId}/events
{
"name": "ACTOR",
"label": "YOUR_ROLE_LABEL",
"externalCreatedAt": "2026-03-01T10:05:00.000Z",
"isPublic": true,
"participantId": "actor-participant-id",
"addressId": "actor-address-id"
}The label value (e.g. "Waste Generator", "Hauler", "Processor") is defined by each methodology. See your methodology guide for the required roles and their labels.
Resolve each actor's participant and address the same way as in Step 1, then reference them by participantId and addressId.
CUSTOM events
CUSTOM events represent methodology-specific operational steps. The event name, required metadata attributes, and sequence are all defined by the methodology:
POST /v1/documents/{documentId}/events
{
"name": "YOUR_EVENT_NAME",
"externalCreatedAt": "2026-03-01T11:00:00.000Z",
"isPublic": true,
"participantId": "participant-id-from-step-1",
"addressId": "address-id-from-step-1",
"metadata": {
"attributes": [
{ "name": "YOUR_ATTRIBUTE_NAME", "value": "attribute-value" }
]
},
"value": 150.5
}The value field on events contributes to the document's currentValue. For example, a weighing event with value: 150.5 sets the tracked weight.
Deprecated: inline participant and address
Events accept the same deprecated inline participant and address objects as documents.
Reference participantId and addressId instead — the inline form will be removed in a future
release.
Methodology guides
Each methodology defines the specific event sequence, event names, and required metadata attributes. See the methodology integration guides for the values required by each methodology.
Document status lifecycle
Documents follow a strict status lifecycle:
OPEN— Default status after creation. Events can be appended freely.CLOSEevent — Transitions the document toCLOSED. After closing, onlyRELATEDevents are accepted.CANCELevent — Transitions the document toCANCELLED. No further events are accepted.
Send a CLOSE event when the supply chain lifecycle is complete:
POST /v1/documents/{documentId}/events
{
"name": "CLOSE",
"externalCreatedAt": "2026-03-02T16:00:00.000Z",
"isPublic": true,
"participantId": "integrator-participant-id"
}See Event Specification for the full list of event categories.
Reference: Events API.
For high-volume integrations, consider the batch events endpoint to submit multiple events per request.
Step 4: Attach evidence files (optional)
Some methodology rules require evidence attachments (e.g. scale tickets, transport manifests). The pattern is:
- Request a pre-signed upload URL via the Attachments API
- Upload the file directly to the pre-signed URL
- Reference the attachment in the relevant event's
attachmentsarray
Attachments are linked to specific events, not to the document as a whole. This ensures each piece of evidence is tied to the operational step it documents.
Reference: Attachments API.
Step 5: Retrieve and validate final state
Fetch the document and verify before considering the submission complete:
- Event count and ordering — all expected events are present in chronological order
- Status is
CLOSED— the document has been properly closed currentValue> 0 — the document has a positive tracked value- At least one
ACTORevent — the required participant roles are registered - Participant and address links — all references resolve correctly
- Metadata completeness — required attributes are present on each event per the methodology
Reference: GET document by ID.
Operational tips
deduplicationId
Always send deduplicationId on retryable write calls (document creation and event creation).
Generate a unique ID before the first attempt, store it, and reuse the same ID on every
retry. The ID is scoped per integrator — two different integrators can use the same ID without
conflict. This guarantees at-most-once semantics: if the server received your first request but
the response was lost, the retry will return the original result instead of creating a duplicate.
- Use
externalIdon documents and events for reconciliation with your internal systems. - Treat
4xxas data/integration issues and5xxas transient failures — see Error Handling. - Keep your source timestamp strategy deterministic — see Data Formats.